Documentation ordinal fixes.
[wine] / dlls / shell32 / shellpath.c
1 /*
2  * Path Functions
3  *
4  * Many of this functions are in SHLWAPI.DLL also
5  *
6  */
7 #include <string.h>
8 #include <ctype.h>
9 #include "debugtools.h"
10 #include "windef.h"
11 #include "winnls.h"
12 #include "winreg.h"
13
14 #include "shlobj.h"
15 #include "shell32_main.h"
16 #include "wine/undocshell.h"
17 #include "wine/unicode.h"
18 #include "shlwapi.h"
19
20 DEFAULT_DEBUG_CHANNEL(shell);
21
22 /*
23         ########## Combining and Constructing paths ##########
24 */
25
26 /*************************************************************************
27  * PathAppendAW         [SHELL32.36]
28  */
29 BOOL WINAPI PathAppendAW(
30         LPVOID lpszPath1,
31         LPCVOID lpszPath2)
32 {
33         if (SHELL_OsIsUnicode())
34           return PathAppendW(lpszPath1, lpszPath2);
35         return PathAppendA(lpszPath1, lpszPath2);
36 }
37
38 /*************************************************************************
39  * PathCombineAW         [SHELL32.37]
40  */
41 LPVOID WINAPI PathCombineAW(
42         LPVOID szDest,
43         LPCVOID lpszDir,
44         LPCVOID lpszFile) 
45 {
46         if (SHELL_OsIsUnicode())
47           return PathCombineW( szDest, lpszDir, lpszFile );
48         return PathCombineA( szDest, lpszDir, lpszFile );
49 }
50
51 /*************************************************************************
52  * PathAddBackslashAW           [SHELL32.32]
53  */
54 LPVOID WINAPI PathAddBackslashAW(LPVOID lpszPath)
55 {
56         if(SHELL_OsIsUnicode())
57           return PathAddBackslashW(lpszPath);
58         return PathAddBackslashA(lpszPath);
59 }
60
61 /*************************************************************************
62  * PathBuildRootAW              [SHELL32.30]
63  */
64 LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive)
65 {
66         if(SHELL_OsIsUnicode())
67           return PathBuildRootW(lpszPath, drive);
68         return PathBuildRootA(lpszPath, drive);
69 }
70
71 /*
72         Extracting Component Parts
73 */
74
75 /*************************************************************************
76  * PathFindFileNameAW   [SHELL32.34]
77  */
78 LPVOID WINAPI PathFindFileNameAW(LPCVOID lpszPath)
79 {
80         if(SHELL_OsIsUnicode())
81           return PathFindFileNameW(lpszPath);
82         return PathFindFileNameA(lpszPath);
83 }
84
85 /*************************************************************************
86  * PathFindExtensionAW          [SHELL32.31]
87  */
88 LPVOID WINAPI PathFindExtensionAW(LPCVOID lpszPath) 
89 {
90         if (SHELL_OsIsUnicode())
91           return PathFindExtensionW(lpszPath);
92         return PathFindExtensionA(lpszPath);
93
94 }
95
96 /*************************************************************************
97  * PathGetExtensionA            [internal]
98  *
99  * NOTES
100  *  exported by ordinal
101  *  return value points to the first char after the dot
102  */
103 static LPSTR PathGetExtensionA(LPCSTR lpszPath)
104 {
105         TRACE("(%s)\n",lpszPath);
106
107         lpszPath = PathFindExtensionA(lpszPath);
108         return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath);
109 }
110
111 /*************************************************************************
112  * PathGetExtensionW            [internal]
113  */
114 static LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
115 {
116         TRACE("(%s)\n",debugstr_w(lpszPath));
117
118         lpszPath = PathFindExtensionW(lpszPath);
119         return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath);
120 }
121
122 /*************************************************************************
123  * PathGetExtensionAW           [SHELL32.158]
124  */
125 LPVOID WINAPI PathGetExtensionAW(LPCVOID lpszPath) 
126 {
127         if (SHELL_OsIsUnicode())
128           return PathGetExtensionW(lpszPath);
129         return PathGetExtensionA(lpszPath);
130 }
131
132 /*************************************************************************
133  * PathGetArgsAW        [SHELL32.52]
134  */
135 LPVOID WINAPI PathGetArgsAW(LPVOID lpszPath) 
136 {
137         if (SHELL_OsIsUnicode())
138           return PathGetArgsW(lpszPath);
139         return PathGetArgsA(lpszPath);
140 }
141
142 /*************************************************************************
143  * PathGetDriveNumber   [SHELL32.57]
144  */
145 int WINAPI PathGetDriveNumberAW(LPVOID lpszPath) 
146 {
147         if (SHELL_OsIsUnicode())
148           return PathGetDriveNumberW(lpszPath);
149         return PathGetDriveNumberA(lpszPath);
150 }
151
152 /*************************************************************************
153  * PathRemoveFileSpec [SHELL32.35]
154  */
155 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath) 
156 {
157         if (SHELL_OsIsUnicode())
158           return PathRemoveFileSpecW(lpszPath);
159         return PathRemoveFileSpecA(lpszPath);
160 }
161
162 /*************************************************************************
163  * PathStripPathAW      [SHELL32.38]
164  */
165 void WINAPI PathStripPathAW(LPVOID lpszPath) 
166 {
167         if (SHELL_OsIsUnicode())
168           return PathStripPathW(lpszPath);
169         return PathStripPathA(lpszPath);
170 }
171
172 /*************************************************************************
173  * PathStripToRootAW    [SHELL32.50]
174  */
175 BOOL WINAPI PathStripToRootAW(LPVOID lpszPath) 
176 {
177         if (SHELL_OsIsUnicode())
178           return PathStripToRootW(lpszPath);
179         return PathStripToRootA(lpszPath);
180 }
181
182 /*************************************************************************
183  * PathRemoveArgsAW     [SHELL32.251]
184  */
185 void WINAPI PathRemoveArgsAW(LPVOID lpszPath) 
186 {
187         if (SHELL_OsIsUnicode())
188           PathRemoveArgsW(lpszPath);
189         PathRemoveArgsA(lpszPath);
190 }
191
192 /*************************************************************************
193  * PathRemoveExtensionAW        [SHELL32.250]
194  */
195 void WINAPI PathRemoveExtensionAW(LPVOID lpszPath) 
196 {
197         if (SHELL_OsIsUnicode())
198           return PathRemoveExtensionW(lpszPath);
199         return PathRemoveExtensionA(lpszPath);
200 }
201
202
203 /*
204         Path Manipulations
205 */
206
207 /*************************************************************************
208  * PathGetShortPathA [internal]
209  */
210 LPSTR WINAPI PathGetShortPathA(LPSTR lpszPath)
211 {
212         FIXME("%s stub\n", lpszPath);
213         return NULL;
214 }
215
216 /*************************************************************************
217  * PathGetShortPathW [internal]
218  */
219 LPWSTR WINAPI PathGetShortPathW(LPWSTR lpszPath)
220 {
221         FIXME("%s stub\n", debugstr_w(lpszPath));
222         return NULL;
223 }
224
225 /*************************************************************************
226  * PathGetShortPathAW [SHELL32.92]
227  */
228 LPVOID WINAPI PathGetShortPathAW(LPVOID lpszPath)
229 {
230         if(SHELL_OsIsUnicode())
231           return PathGetShortPathW(lpszPath);
232         return PathGetShortPathA(lpszPath);
233 }
234
235 /*************************************************************************
236  * PathRemoveBlanksAW [SHELL32.33]
237  */
238 void WINAPI PathRemoveBlanksAW(LPVOID str)
239 {
240         if(SHELL_OsIsUnicode())
241           PathRemoveBlanksW(str);
242         PathRemoveBlanksA(str);
243 }
244
245 /*************************************************************************
246  * PathQuoteSpacesAW [SHELL32.55]
247  */
248 LPVOID WINAPI PathQuoteSpacesAW (LPVOID lpszPath)
249 {
250         if(SHELL_OsIsUnicode())
251           return PathQuoteSpacesW(lpszPath);
252         return PathQuoteSpacesA(lpszPath);
253 }
254
255 /*************************************************************************
256  * PathUnquoteSpacesAW [SHELL32.56]
257  */
258 VOID WINAPI PathUnquoteSpacesAW(LPVOID str) 
259 {
260         if(SHELL_OsIsUnicode())
261           PathUnquoteSpacesW(str);
262         else
263           PathUnquoteSpacesA(str);
264 }
265
266 /*************************************************************************
267  * PathParseIconLocationAW      [SHELL32.249]
268  */
269 int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
270 {
271         if(SHELL_OsIsUnicode())
272           return PathParseIconLocationW(lpszPath);
273         return PathParseIconLocationA(lpszPath);
274 }
275
276 /*
277         ########## Path Testing ##########
278 */
279 /*************************************************************************
280  * PathIsUNCAW          [SHELL32.39]
281  */
282 BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
283 {
284         if (SHELL_OsIsUnicode())
285           return PathIsUNCW( lpszPath );
286         return PathIsUNCA( lpszPath );  
287 }
288
289 /*************************************************************************
290  *  PathIsRelativeAW    [SHELL32.40]
291  */
292 BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
293 {
294         if (SHELL_OsIsUnicode())
295           return PathIsRelativeW( lpszPath );
296         return PathIsRelativeA( lpszPath );  
297 }
298
299 /*************************************************************************
300  * PathIsRootAW         [SHELL32.29]
301  */
302 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath) 
303 {
304         if (SHELL_OsIsUnicode())
305           return PathIsRootW(lpszPath);
306         return PathIsRootA(lpszPath);
307 }
308
309 /*************************************************************************
310  *  PathIsExeA          [internal]
311  */
312 static BOOL PathIsExeA (LPCSTR lpszPath)
313 {
314         LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
315         int i = 0;
316         static char * lpszExtensions[6] = {"exe", "com", "pid", "cmd", "bat", NULL };
317         
318         TRACE("path=%s\n",lpszPath);
319
320         for(i=0; lpszExtensions[i]; i++)
321           if (!strcasecmp(lpszExtension,lpszExtensions[i])) return TRUE;
322           
323         return FALSE;
324 }
325
326 /*************************************************************************
327  *  PathIsExeW          [internal]
328  */
329 static BOOL PathIsExeW (LPCWSTR lpszPath)
330 {
331         LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
332         int i = 0;
333         static WCHAR lpszExtensions[6][4] =
334           {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','d','\0'},
335            {'c','m','d','\0'}, {'b','a','t','\0'}, {'\0'} };
336         
337         TRACE("path=%s\n",debugstr_w(lpszPath));
338
339         for(i=0; lpszExtensions[i]; i++)
340           if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE;
341           
342         return FALSE;
343 }
344
345 /*************************************************************************
346  *  PathIsExeAW         [SHELL32.43]
347  */
348 BOOL WINAPI PathIsExeAW (LPCVOID path)
349 {
350         if (SHELL_OsIsUnicode())
351           return PathIsExeW (path);
352         return PathIsExeA(path);
353 }
354
355 /*************************************************************************
356  * PathIsDirectoryAW    [SHELL32.159]
357  */
358 BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
359 {
360         if (SHELL_OsIsUnicode())
361           return PathIsDirectoryW (lpszPath);
362         return PathIsDirectoryA (lpszPath);
363 }
364
365 /*************************************************************************
366  * PathFileExistsAW     [SHELL32.45]
367  */ 
368 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
369 {
370         if (SHELL_OsIsUnicode())
371           return PathFileExistsW (lpszPath);
372         return PathFileExistsA (lpszPath);
373 }
374
375 /*************************************************************************
376  * PathMatchSpecAW      [SHELL32.46]
377  */
378 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask) 
379 {
380         if (SHELL_OsIsUnicode())
381           return PathMatchSpecW( name, mask );
382         return PathMatchSpecA( name, mask );
383 }
384
385 /*************************************************************************
386  * PathIsSameRootAW     [SHELL32.650]
387  */
388 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
389 {
390         if (SHELL_OsIsUnicode())
391           return PathIsSameRootW(lpszPath1, lpszPath2);
392         return PathIsSameRootA(lpszPath1, lpszPath2);
393 }
394
395 /*************************************************************************
396  * IsLFNDriveA          [SHELL32.119]
397  * 
398  * NOTES
399  *     exported by ordinal Name
400  */
401 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath) 
402 {
403     DWORD       fnlen;
404
405     if (!GetVolumeInformationA(lpszPath,NULL,0,NULL,&fnlen,NULL,NULL,0))
406         return FALSE;
407     return fnlen>12;
408 }
409
410 /*
411         ########## Creating Something Unique ##########
412 */
413 /*************************************************************************
414  * PathMakeUniqueNameA  [internal]
415  */
416 BOOL WINAPI PathMakeUniqueNameA(
417         LPSTR lpszBuffer,
418         DWORD dwBuffSize, 
419         LPCSTR lpszShortName,
420         LPCSTR lpszLongName,
421         LPCSTR lpszPathName)
422 {
423         FIXME("%p %lu %s %s %s stub\n",
424          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
425          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
426         return TRUE;
427 }
428
429 /*************************************************************************
430  * PathMakeUniqueNameW  [internal]
431  */
432 BOOL WINAPI PathMakeUniqueNameW(
433         LPWSTR lpszBuffer,
434         DWORD dwBuffSize, 
435         LPCWSTR lpszShortName,
436         LPCWSTR lpszLongName,
437         LPCWSTR lpszPathName)
438 {
439         FIXME("%p %lu %s %s %s stub\n",
440          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
441          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
442         return TRUE;
443 }
444
445 /*************************************************************************
446  * PathMakeUniqueNameAW [SHELL32.47]
447  */
448 BOOL WINAPI PathMakeUniqueNameAW(
449         LPVOID lpszBuffer,
450         DWORD dwBuffSize, 
451         LPCVOID lpszShortName,
452         LPCVOID lpszLongName,
453         LPCVOID lpszPathName)
454 {
455         if (SHELL_OsIsUnicode())
456           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
457         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
458 }
459
460 /*************************************************************************
461  * PathYetAnotherMakeUniqueNameA [SHELL32.75]
462  * 
463  * NOTES
464  *     exported by ordinal
465  */
466 BOOL WINAPI PathYetAnotherMakeUniqueNameA(
467         LPSTR lpszBuffer,
468         LPCSTR lpszPathName,
469         LPCSTR lpszShortName,
470         LPCSTR lpszLongName)
471 {
472     FIXME("(%p,%p, %p ,%p):stub.\n",
473      lpszBuffer, lpszPathName, lpszShortName, lpszLongName);
474     return TRUE;
475 }
476
477
478 /*
479         ########## cleaning and resolving paths ##########
480  */
481
482 /*************************************************************************
483  * PathFindOnPathAW     [SHELL32]
484  */
485 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
486 {
487         if (SHELL_OsIsUnicode())
488           return PathFindOnPathW(sFile, sOtherDirs);
489         return PathFindOnPathA(sFile, sOtherDirs);
490 }
491
492 /*************************************************************************
493  * PathCleanupSpecAW    [SHELL32]
494  */
495 DWORD WINAPI PathCleanupSpecAW (LPCVOID x, LPVOID y)
496 {
497     FIXME("(%p, %p) stub\n",x,y);
498     return TRUE;
499 }
500
501 /*************************************************************************
502  * PathQualifyA         [SHELL32]
503  */
504 BOOL WINAPI PathQualifyA(LPCSTR pszPath) 
505 {
506         FIXME("%s\n",pszPath);
507         return 0;
508 }
509
510 /*************************************************************************
511  * PathQualifyW         [SHELL32]
512  */
513 BOOL WINAPI PathQualifyW(LPCWSTR pszPath) 
514 {
515         FIXME("%s\n",debugstr_w(pszPath));
516         return 0;
517 }
518
519 /*************************************************************************
520  * PathQualifyAW        [SHELL32]
521  */
522 BOOL WINAPI PathQualifyAW(LPCVOID pszPath) 
523 {
524         if (SHELL_OsIsUnicode())
525           return PathQualifyW(pszPath);
526         return PathQualifyA(pszPath);
527 }
528
529 /*************************************************************************
530  * PathResolveA [SHELL32.51]
531  */
532 BOOL WINAPI PathResolveA(
533         LPSTR lpszPath,
534         LPCSTR *alpszPaths, 
535         DWORD dwFlags)
536 {
537         FIXME("(%s,%p,0x%08lx),stub!\n",
538           lpszPath, *alpszPaths, dwFlags);
539         return 0;
540 }
541
542 /*************************************************************************
543  * PathResolveW [SHELL32]
544  */
545 BOOL WINAPI PathResolveW(
546         LPWSTR lpszPath,
547         LPCWSTR *alpszPaths, 
548         DWORD dwFlags)
549 {
550         FIXME("(%s,%p,0x%08lx),stub!\n",
551           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
552         return 0;
553 }
554
555 /*************************************************************************
556  * PathResolveAW [SHELL32]
557  */
558 BOOL WINAPI PathResolveAW(
559         LPVOID lpszPath,
560         LPCVOID *alpszPaths, 
561         DWORD dwFlags)
562 {
563         if (SHELL_OsIsUnicode())
564           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
565         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
566 }
567
568 /*************************************************************************
569 *       PathProcessCommandA     [SHELL32.653]
570 */
571 HRESULT WINAPI PathProcessCommandA (
572         LPCSTR lpszPath,
573         LPSTR lpszBuff,
574         DWORD dwBuffSize,
575         DWORD dwFlags)
576 {
577         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
578         lpszPath, lpszBuff, dwBuffSize, dwFlags);
579         strcpy(lpszBuff, lpszPath);
580         return 0;
581 }
582
583 /*************************************************************************
584 *       PathProcessCommandW
585 */
586 HRESULT WINAPI PathProcessCommandW (
587         LPCWSTR lpszPath,
588         LPWSTR lpszBuff,
589         DWORD dwBuffSize,
590         DWORD dwFlags)
591 {
592         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
593         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
594         strcpyW(lpszBuff, lpszPath);
595         return 0;
596 }
597
598 /*************************************************************************
599 *       PathProcessCommandAW (SHELL32.653)
600 */
601 HRESULT WINAPI PathProcessCommandAW (
602         LPCVOID lpszPath,
603         LPVOID lpszBuff,
604         DWORD dwBuffSize,
605         DWORD dwFlags)
606 {
607         if (SHELL_OsIsUnicode())
608           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
609         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
610 }
611
612 /*
613         ########## special ##########
614 */
615
616 /*************************************************************************
617  * PathSetDlgItemPathAW (SHELL32.48)
618  */
619 BOOL WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath) 
620 {       if (SHELL_OsIsUnicode())
621           return PathSetDlgItemPathW(hDlg, id, pszPath);
622         return PathSetDlgItemPathA(hDlg, id, pszPath);
623 }
624
625
626 /*************************************************************************
627  * SHGetSpecialFolderPathA [SHELL32.@]
628  * 
629  * converts csidl to path
630  */
631  
632 static const char * const szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
633 static const char * const szSHUserFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
634 static const char * const szSetup = "Software\\Microsoft\\Windows\\CurrentVersion\\Setup";
635 static const char * const szCurrentVersion = "Software\\Microsoft\\Windows\\CurrentVersion";
636 #if 0
637 static const char * const szEnvUserProfile = "%USERPROFILE%";
638 static const char * const szEnvSystemRoot = "%SYSTEMROOT%";
639 #endif
640
641 typedef struct
642 {
643     DWORD dwFlags;
644     HKEY hRootKey;
645     LPCSTR szValueName;
646     LPCSTR szDefaultPath; /* fallback string; sub dir of windows directory */
647 } CSIDL_DATA;
648
649 #define CSIDL_MYFLAG_SHFOLDER   1
650 #define CSIDL_MYFLAG_SETUP      2
651 #define CSIDL_MYFLAG_CURRVER    4
652 #define CSIDL_MYFLAG_RELATIVE   8
653
654 #define HKLM HKEY_LOCAL_MACHINE
655 #define HKCU HKEY_CURRENT_USER
656 static const CSIDL_DATA CSIDL_Data[] =
657 {
658     { /* CSIDL_DESKTOP */
659         9, HKCU,
660         "Desktop",
661         "Desktop"
662     },
663     { /* CSIDL_INTERNET (??) */
664         0, 1, /* FIXME */
665         NULL,
666         NULL,
667     },
668     { /* CSIDL_PROGRAMS */
669         9, HKCU,
670         "Programs",
671         "Start Menu\\Programs"
672     },
673     { /* CSIDL_CONTROLS (.CPL files) */
674         10, HKLM,
675         "SysDir",
676         "SYSTEM"
677     },
678     { /* CSIDL_PRINTERS */
679         10, HKLM,
680         "SysDir",
681         "SYSTEM"
682     },
683     { /* CSIDL_PERSONAL */
684         1, HKCU,
685         "Personal",
686         "My Documents"
687     },
688     { /* CSIDL_FAVORITES */
689         9, HKCU,
690         "Favorites",
691         "Favorites"
692     },
693     { /* CSIDL_STARTUP */
694         9, HKCU,
695         "StartUp",
696         "Start Menu\\Programs\\StartUp"
697     },
698     { /* CSIDL_RECENT */
699         9, HKCU,
700         "Recent",
701         "Recent"
702     },
703     { /* CSIDL_SENDTO */
704         9, HKCU,
705         "SendTo",
706         "SendTo"
707     },
708     { /* CSIDL_BITBUCKET (is this c:\recycled ?) */
709         0, 1, /* FIXME */
710         NULL,
711         "recycled"
712     },
713     { /* CSIDL_STARTMENU */
714         9, HKCU,
715         "Start Menu",
716         "Start Menu"
717     },
718     { /* not known */
719         0, 0,
720         NULL,
721         NULL,
722     },
723     { /* not known */
724         0, 0,
725         NULL,
726         NULL,
727     },
728     { /* not known */
729         0, 0,
730         NULL,
731         NULL,
732     },
733     { /* not known */
734         0, 0,
735         NULL,
736         NULL,
737     },
738     { /* CSIDL_DESKTOPDIRECTORY */
739         9, HKCU,
740         "Desktop",
741         "Desktop"
742     },
743     { /* CSIDL_DRIVES */
744         0, 1, /* FIXME */
745         NULL,
746         "My Computer"
747     },
748     { /* CSIDL_NETWORK */
749         0, 1, /* FIXME */
750         NULL,
751         "Network Neighborhood"
752     },
753     { /* CSIDL_NETHOOD */
754         9, HKCU,
755         "NetHood",
756         "NetHood"
757     },
758     { /* CSIDL_FONTS */
759         9, HKCU,
760         "Fonts",
761         "Fonts"
762     },
763     { /* CSIDL_TEMPLATES */
764         9, HKCU,
765         "Templates",
766         "ShellNew"
767     },
768     { /* CSIDL_COMMON_STARTMENU */
769         9, HKLM,
770         "Common Start Menu",
771         "Start Menu"
772     },
773     { /* CSIDL_COMMON_PROGRAMS */
774         9, HKLM,
775         "Common Programs",
776         ""
777     },
778     { /* CSIDL_COMMON_STARTUP */
779         9, HKLM,
780         "Common StartUp",
781         "All Users\\Start Menu\\Programs\\StartUp"
782     },
783     { /* CSIDL_COMMON_DESKTOPDIRECTORY */
784         9, HKLM,
785         "Common Desktop",
786         "Desktop"
787     },
788     { /* CSIDL_APPDATA */
789         9, HKCU,
790         "AppData",
791         "Application Data"
792     },
793     { /* CSIDL_PRINTHOOD */
794         9, HKCU,
795         "PrintHood",
796         "PrintHood"
797     },
798     { /* not known */
799         0, 0,
800         NULL,
801         NULL,
802     },
803     { /* CSIDL_ALTSTARTUP */
804         0, 1, /* FIXME */
805         NULL,
806         NULL
807     },
808     { /* CSIDL_COMMON_ALTSTARTUP */
809         0, 1, /* FIXME */
810         NULL,
811         NULL
812     },
813     { /* CSIDL_COMMON_FAVORITES */
814         9, HKCU,
815         "Favorites",
816         "Favorites"
817     },
818     { /* CSIDL_INTERNET_CACHE */
819         9, HKCU,
820         "Cache",
821         "Temporary Internet Files"
822     },
823     { /* CSIDL_COOKIES */
824         9, HKCU,
825         "Cookies",
826         "Cookies"
827     },
828     { /* CSIDL_HISTORY */
829         9, HKCU,
830         "History",
831         "History"
832     },
833     { /* CSIDL_COMMON_APPDATA */
834         9, HKLM,
835         "Common AppData",
836         "All Users\\Application Data"
837     },
838     { /* CSIDL_WINDOWS */
839         2, HKLM,
840         "WinDir",
841         "Windows"
842     },
843     { /* CSIDL_SYSTEM */
844         10, HKLM,
845         "SysDir",
846         "SYSTEM"
847     },
848     { /* CSIDL_PROGRAM_FILES */
849         4, HKLM,
850         "ProgramFilesDir",
851         "Program Files"
852     },
853     { /* CSIDL_MYPICTURES */
854         1, HKCU,
855         "My Pictures",
856         "My Documents\\My Pictures"
857     },
858     { /* CSIDL_PROFILE */
859         10, HKLM,
860         "WinDir", /* correct ? */
861         ""
862     },
863     { /* CSIDL_SYSTEMX86 */
864         10, HKLM,
865         "SysDir",
866         "SYSTEM"
867     },
868     { /* CSIDL_PROGRAM_FILESX86 */
869         4, HKLM,
870         "ProgramFilesDir",
871         "Program Files"
872     },
873     { /* CSIDL_PROGRAM_FILES_COMMON */
874         4, HKLM,
875         "CommonFilesDir", 
876         "Program Files\\Common Files" /* ? */
877     },
878     { /* CSIDL_PROGRAM_FILES_COMMONX86 */
879         4, HKLM,
880         "CommonFilesDir",
881         "Program Files\\Common Files" /* ? */
882     },
883     { /* CSIDL_COMMON_TEMPLATES */
884         0, 1, /* FIXME */
885         NULL,
886         NULL
887     },
888     { /* CSIDL_COMMON_DOCUMENTS */
889         0, 1, /* FIXME */
890         NULL,
891         NULL
892     },
893     { /* CSIDL_COMMON_ADMINTOOLS */
894         0, 1, /* FIXME */
895         NULL,
896         NULL
897     },
898     { /* CSIDL_ADMINTOOLS */
899         9, HKCU,
900         "Administrative Tools",
901         "Start Menu\\Programs\\Administrative Tools"
902     },
903     { /* CSIDL_CONNECTIONS */
904         0, 1, /* FIXME */
905         NULL,
906         NULL
907     }
908 };
909 #undef HKCU
910 #undef HKLM
911
912 /**********************************************************************/
913
914 BOOL WINAPI SHGetSpecialFolderPathA (
915         HWND hwndOwner,
916         LPSTR szPath,
917         DWORD csidl,
918         BOOL bCreate)
919 {
920         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH], szBuildPath[MAX_PATH];
921         HKEY    hRootKey, hKey;
922         DWORD   dwFlags;
923         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
924         DWORD   folder = csidl & CSIDL_FOLDER_MASK;
925         CHAR    *p;
926
927         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
928
929         if ((folder > CSIDL_CONNECTIONS) || (CSIDL_Data[folder].hRootKey == 0))
930         {
931             ERR("folder unknown or not allowed\n");
932             return FALSE;
933         }
934         if (CSIDL_Data[folder].hRootKey == 1)
935         {
936             FIXME("folder unknown, please add.\n");
937             return FALSE;
938         }
939
940         dwFlags = CSIDL_Data[folder].dwFlags;
941         hRootKey = CSIDL_Data[folder].hRootKey;
942         strcpy(szValueName, CSIDL_Data[folder].szValueName);
943         strcpy(szDefaultPath, CSIDL_Data[folder].szDefaultPath);
944
945         if (dwFlags & CSIDL_MYFLAG_SHFOLDER)
946         {
947           /*   user shell folders */
948           if   (RegCreateKeyExA(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
949
950           if   (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
951           {
952             RegCloseKey(hKey);
953
954             /* shell folders */
955             if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
956
957             if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
958             {
959
960               /* value not existing */
961               if (dwFlags & CSIDL_MYFLAG_RELATIVE)
962               {
963                 GetWindowsDirectoryA(szPath, MAX_PATH);
964                 PathAddBackslashA(szPath);
965                 strcat(szPath, szDefaultPath);
966               }
967               else
968               {
969                 strcpy(szPath, "C:\\"); /* FIXME ??? */
970                 strcat(szPath, szDefaultPath);
971               }
972               RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
973             }
974           }
975           RegCloseKey(hKey);
976         }
977         else
978         {
979           LPCSTR pRegPath;
980
981           if (dwFlags & CSIDL_MYFLAG_SETUP)
982             pRegPath = szSetup;
983           else
984           if (dwFlags & CSIDL_MYFLAG_CURRVER)
985             pRegPath = szCurrentVersion;
986           else
987           {
988             ERR("folder settings broken, please correct !\n");
989             return FALSE;
990           }
991
992           if   (RegCreateKeyExA(hRootKey,pRegPath,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
993
994           if   (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
995           {
996             /* value not existing */
997             if (dwFlags & CSIDL_MYFLAG_RELATIVE)
998             {
999               GetWindowsDirectoryA(szPath, MAX_PATH);
1000               PathAddBackslashA(szPath);
1001               strcat(szPath, szDefaultPath);
1002             }
1003             else
1004             {
1005               strcpy(szPath, "C:\\");   /* FIXME ??? */
1006               strcat(szPath, szDefaultPath);
1007             }
1008             RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
1009           }
1010           RegCloseKey(hKey);
1011         }
1012
1013         /* expand paths like %USERPROFILE% */
1014         if (dwType == REG_EXPAND_SZ)
1015         {
1016           ExpandEnvironmentStringsA(szPath, szDefaultPath, MAX_PATH);
1017           strcpy(szPath, szDefaultPath);
1018         }
1019
1020         /* if we don't care about existing directories we are ready */
1021         if(csidl & CSIDL_FLAG_DONT_VERIFY) return TRUE;
1022
1023         if (PathFileExistsA(szPath)) return TRUE;
1024
1025         /* not existing but we are not allowed to create it */
1026         if (!bCreate) return FALSE;
1027
1028         /* create directory/directories */
1029         strcpy(szBuildPath, szPath);
1030         p = strchr(szBuildPath, '\\');
1031         while (p)
1032         {
1033             *p = 0;
1034             if (!PathFileExistsA(szBuildPath))
1035             {
1036                 if (!CreateDirectoryA(szBuildPath,NULL))
1037                 {
1038                     ERR("Failed to create directory '%s'.\n", szPath);
1039                     return FALSE;
1040                 }
1041             }
1042             *p = '\\';
1043             p = strchr(p+1, '\\');
1044         }
1045         /* last component must be created too. */
1046         if (!PathFileExistsA(szBuildPath))
1047         {
1048             if (!CreateDirectoryA(szBuildPath,NULL))
1049             {
1050                 ERR("Failed to create directory '%s'.\n", szPath);
1051                 return FALSE;
1052             }
1053         }
1054
1055         MESSAGE("Created not existing system directory '%s'\n", szPath);
1056         return TRUE;
1057 }
1058
1059 /*************************************************************************
1060  * SHGetSpecialFolderPathW
1061  */
1062 BOOL WINAPI SHGetSpecialFolderPathW (
1063         HWND hwndOwner,
1064         LPWSTR szPath,
1065         DWORD csidl,
1066         BOOL bCreate)
1067 {
1068         char szTemp[MAX_PATH];
1069         
1070         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
1071         {
1072             if (!MultiByteToWideChar( CP_ACP, 0, szTemp, -1, szPath, MAX_PATH ))
1073                 szPath[MAX_PATH-1] = 0;
1074         }
1075
1076         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1077
1078         return TRUE;
1079 }
1080
1081 /*************************************************************************
1082  * SHGetSpecialFolderPathAW (SHELL32.175)
1083  */
1084 BOOL WINAPI SHGetSpecialFolderPathAW (
1085         HWND hwndOwner,
1086         LPVOID szPath,
1087         DWORD csidl,
1088         BOOL bCreate)
1089
1090 {
1091         if (SHELL_OsIsUnicode())
1092           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
1093         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
1094 }
1095
1096 /*************************************************************************
1097  * SHGetFolderPathA                     [SHFOLDER.@]
1098  */
1099 HRESULT WINAPI SHGetFolderPathA(
1100         HWND hwndOwner,
1101         int nFolder,
1102         HANDLE hToken,  /* [in] FIXME: get paths for specific user */
1103         DWORD dwFlags,  /* [in] FIXME: SHGFP_TYPE_CURRENT|SHGFP_TYPE_DEFAULT */
1104         LPSTR pszPath)
1105 {
1106         return (SHGetSpecialFolderPathA(
1107                 hwndOwner,
1108                 pszPath,
1109                 CSIDL_FOLDER_MASK & nFolder,
1110                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
1111 }
1112
1113 /*************************************************************************
1114  * SHGetFolderPathW                     [SHFOLDER.@]
1115  */
1116 HRESULT WINAPI SHGetFolderPathW(
1117         HWND hwndOwner,
1118         int nFolder,
1119         HANDLE hToken,
1120         DWORD dwFlags,
1121         LPWSTR pszPath)
1122 {
1123         return (SHGetSpecialFolderPathW(
1124                 hwndOwner,
1125                 pszPath,
1126                 CSIDL_FOLDER_MASK & nFolder,
1127                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
1128 }