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