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