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