Added window classes in the server, and support for inter-process
[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  * IsLFNDriveA          [SHELL32.41]
430  */
431 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
432 {
433     DWORD       fnlen;
434
435     if (!GetVolumeInformationA(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
436         return FALSE;
437     return fnlen > 12;
438 }
439
440 /*************************************************************************
441  * IsLFNDriveW          [SHELL32.42]
442  */
443 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath)
444 {
445     DWORD       fnlen;
446
447     if (!GetVolumeInformationW(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
448         return FALSE;
449     return fnlen > 12;
450 }
451
452 /*************************************************************************
453  * IsLFNDrive           [SHELL32.119]
454  */
455 BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath)
456 {
457         if (SHELL_OsIsUnicode())
458           return IsLFNDriveW(lpszPath);
459         return IsLFNDriveA(lpszPath);
460 }
461
462 /*
463         ########## Creating Something Unique ##########
464 */
465 /*************************************************************************
466  * PathMakeUniqueNameA  [internal]
467  */
468 BOOL WINAPI PathMakeUniqueNameA(
469         LPSTR lpszBuffer,
470         DWORD dwBuffSize,
471         LPCSTR lpszShortName,
472         LPCSTR lpszLongName,
473         LPCSTR lpszPathName)
474 {
475         FIXME("%p %lu %s %s %s stub\n",
476          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
477          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
478         return TRUE;
479 }
480
481 /*************************************************************************
482  * PathMakeUniqueNameW  [internal]
483  */
484 BOOL WINAPI PathMakeUniqueNameW(
485         LPWSTR lpszBuffer,
486         DWORD dwBuffSize,
487         LPCWSTR lpszShortName,
488         LPCWSTR lpszLongName,
489         LPCWSTR lpszPathName)
490 {
491         FIXME("%p %lu %s %s %s stub\n",
492          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
493          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
494         return TRUE;
495 }
496
497 /*************************************************************************
498  * PathMakeUniqueName   [SHELL32.47]
499  */
500 BOOL WINAPI PathMakeUniqueNameAW(
501         LPVOID lpszBuffer,
502         DWORD dwBuffSize,
503         LPCVOID lpszShortName,
504         LPCVOID lpszLongName,
505         LPCVOID lpszPathName)
506 {
507         if (SHELL_OsIsUnicode())
508           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
509         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
510 }
511
512 /*************************************************************************
513  * PathYetAnotherMakeUniqueName [SHELL32.75]
514  *
515  * NOTES
516  *     exported by ordinal
517  */
518 BOOL WINAPI PathYetAnotherMakeUniqueNameA(
519         LPSTR lpszBuffer,
520         LPCSTR lpszPathName,
521         LPCSTR lpszShortName,
522         LPCSTR lpszLongName)
523 {
524     FIXME("(%p,%p, %p ,%p):stub.\n",
525      lpszBuffer, lpszPathName, lpszShortName, lpszLongName);
526     return TRUE;
527 }
528
529
530 /*
531         ########## cleaning and resolving paths ##########
532  */
533
534 /*************************************************************************
535  * PathFindOnPath       [SHELL32.145]
536  */
537 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
538 {
539         if (SHELL_OsIsUnicode())
540           return PathFindOnPathW(sFile, (LPCWSTR *)sOtherDirs);
541         return PathFindOnPathA(sFile, (LPCSTR *)sOtherDirs);
542 }
543
544 /*************************************************************************
545  * PathCleanupSpec      [SHELL32.171]
546  */
547 DWORD WINAPI PathCleanupSpecAW (LPCVOID x, LPVOID y)
548 {
549     FIXME("(%p, %p) stub\n",x,y);
550     return TRUE;
551 }
552
553 /*************************************************************************
554  * PathQualifyA         [SHELL32]
555  */
556 BOOL WINAPI PathQualifyA(LPCSTR pszPath)
557 {
558         FIXME("%s\n",pszPath);
559         return 0;
560 }
561
562 /*************************************************************************
563  * PathQualifyW         [SHELL32]
564  */
565 BOOL WINAPI PathQualifyW(LPCWSTR pszPath)
566 {
567         FIXME("%s\n",debugstr_w(pszPath));
568         return 0;
569 }
570
571 /*************************************************************************
572  * PathQualify  [SHELL32.49]
573  */
574 BOOL WINAPI PathQualifyAW(LPCVOID pszPath)
575 {
576         if (SHELL_OsIsUnicode())
577           return PathQualifyW(pszPath);
578         return PathQualifyA(pszPath);
579 }
580
581 /*************************************************************************
582  * PathResolveA [SHELL32.51]
583  */
584 BOOL WINAPI PathResolveA(
585         LPSTR lpszPath,
586         LPCSTR *alpszPaths,
587         DWORD dwFlags)
588 {
589         FIXME("(%s,%p,0x%08lx),stub!\n",
590           lpszPath, *alpszPaths, dwFlags);
591         return 0;
592 }
593
594 /*************************************************************************
595  * PathResolveW [SHELL32]
596  */
597 BOOL WINAPI PathResolveW(
598         LPWSTR lpszPath,
599         LPCWSTR *alpszPaths,
600         DWORD dwFlags)
601 {
602         FIXME("(%s,%p,0x%08lx),stub!\n",
603           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
604         return 0;
605 }
606
607 /*************************************************************************
608  * PathResolve [SHELL32.51]
609  */
610 BOOL WINAPI PathResolveAW(
611         LPVOID lpszPath,
612         LPCVOID *alpszPaths,
613         DWORD dwFlags)
614 {
615         if (SHELL_OsIsUnicode())
616           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
617         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
618 }
619
620 /*************************************************************************
621 *       PathProcessCommandA     [SHELL32.653]
622 */
623 HRESULT WINAPI PathProcessCommandA (
624         LPCSTR lpszPath,
625         LPSTR lpszBuff,
626         DWORD dwBuffSize,
627         DWORD dwFlags)
628 {
629         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
630         lpszPath, lpszBuff, dwBuffSize, dwFlags);
631         strcpy(lpszBuff, lpszPath);
632         return 0;
633 }
634
635 /*************************************************************************
636 *       PathProcessCommandW
637 */
638 HRESULT WINAPI PathProcessCommandW (
639         LPCWSTR lpszPath,
640         LPWSTR lpszBuff,
641         DWORD dwBuffSize,
642         DWORD dwFlags)
643 {
644         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
645         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
646         strcpyW(lpszBuff, lpszPath);
647         return 0;
648 }
649
650 /*************************************************************************
651 *       PathProcessCommand (SHELL32.653)
652 */
653 HRESULT WINAPI PathProcessCommandAW (
654         LPCVOID lpszPath,
655         LPVOID lpszBuff,
656         DWORD dwBuffSize,
657         DWORD dwFlags)
658 {
659         if (SHELL_OsIsUnicode())
660           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
661         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
662 }
663
664 /*
665         ########## special ##########
666 */
667
668 /*************************************************************************
669  * PathSetDlgItemPath (SHELL32.48)
670  */
671 VOID WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath)
672 {
673         if (SHELL_OsIsUnicode())
674             PathSetDlgItemPathW(hDlg, id, pszPath);
675         else
676             PathSetDlgItemPathA(hDlg, id, pszPath);
677 }
678
679
680 /*************************************************************************
681  * SHGetSpecialFolderPathA [SHELL32.@]
682  *
683  * converts csidl to path
684  */
685
686 static const char * const szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
687 static const char * const szSHUserFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
688 static const char * const szSetup = "Software\\Microsoft\\Windows\\CurrentVersion\\Setup";
689 static const char * const szCurrentVersion = "Software\\Microsoft\\Windows\\CurrentVersion";
690 #if 0
691 static const char * const szEnvUserProfile = "%USERPROFILE%";
692 static const char * const szEnvSystemRoot = "%SYSTEMROOT%";
693 #endif
694
695 typedef struct
696 {
697     DWORD dwFlags;
698     HKEY hRootKey;
699     LPCSTR szValueName;
700     LPCSTR szDefaultPath; /* fallback string; sub dir of windows directory */
701 } CSIDL_DATA;
702
703 #define CSIDL_MYFLAG_SHFOLDER   1
704 #define CSIDL_MYFLAG_SETUP      2
705 #define CSIDL_MYFLAG_CURRVER    4
706 #define CSIDL_MYFLAG_RELATIVE   8
707
708 #define HKLM HKEY_LOCAL_MACHINE
709 #define HKCU HKEY_CURRENT_USER
710 static const CSIDL_DATA CSIDL_Data[] =
711 {
712     { /* CSIDL_DESKTOP */
713         9, HKCU,
714         "Desktop",
715         "Desktop"
716     },
717     { /* CSIDL_INTERNET */
718         0, (HKEY)1, /* FIXME */
719         NULL,
720         NULL,
721     },
722     { /* CSIDL_PROGRAMS */
723         9, HKCU,
724         "Programs",
725         "Start Menu\\Programs"
726     },
727     { /* CSIDL_CONTROLS (.CPL files) */
728         10, HKLM,
729         "SysDir",
730         "SYSTEM"
731     },
732     { /* CSIDL_PRINTERS */
733         10, HKLM,
734         "SysDir",
735         "SYSTEM"
736     },
737     { /* CSIDL_PERSONAL */
738         1, HKCU,
739         "Personal",
740         "My Documents"
741     },
742     { /* CSIDL_FAVORITES */
743         9, HKCU,
744         "Favorites",
745         "Favorites"
746     },
747     { /* CSIDL_STARTUP */
748         9, HKCU,
749         "StartUp",
750         "Start Menu\\Programs\\StartUp"
751     },
752     { /* CSIDL_RECENT */
753         9, HKCU,
754         "Recent",
755         "Recent"
756     },
757     { /* CSIDL_SENDTO */
758         9, HKCU,
759         "SendTo",
760         "SendTo"
761     },
762     { /* CSIDL_BITBUCKET (is this c:\recycled ?) */
763         0, (HKEY)1, /* FIXME */
764         NULL,
765         "recycled"
766     },
767     { /* CSIDL_STARTMENU */
768         9, HKCU,
769         "Start Menu",
770         "Start Menu"
771     },
772     { /* CSIDL_MYDOCUMENTS */
773         0, (HKEY)1, /* FIXME */
774         NULL,
775         NULL,
776     },
777     { /* CSIDL_MYMUSIC */
778         0, (HKEY)1, /* FIXME */
779         NULL,
780         NULL,
781     },
782     { /* CSIDL_MYVIDEO */
783         0, (HKEY)1, /* FIXME */
784         NULL,
785         NULL,
786     },
787     { /* unassigned */
788         0, 0,
789         NULL,
790         NULL,
791     },
792     { /* CSIDL_DESKTOPDIRECTORY */
793         9, HKCU,
794         "Desktop",
795         "Desktop"
796     },
797     { /* CSIDL_DRIVES */
798         0, (HKEY)1, /* FIXME */
799         NULL,
800         "My Computer"
801     },
802     { /* CSIDL_NETWORK */
803         0, (HKEY)1, /* FIXME */
804         NULL,
805         "Network Neighborhood"
806     },
807     { /* CSIDL_NETHOOD */
808         9, HKCU,
809         "NetHood",
810         "NetHood"
811     },
812     { /* CSIDL_FONTS */
813         9, HKCU,
814         "Fonts",
815         "Fonts"
816     },
817     { /* CSIDL_TEMPLATES */
818         9, HKCU,
819         "Templates",
820         "ShellNew"
821     },
822     { /* CSIDL_COMMON_STARTMENU */
823         9, HKLM,
824         "Common Start Menu",
825         "Start Menu"
826     },
827     { /* CSIDL_COMMON_PROGRAMS */
828         9, HKLM,
829         "Common Programs",
830         ""
831     },
832     { /* CSIDL_COMMON_STARTUP */
833         9, HKLM,
834         "Common StartUp",
835         "All Users\\Start Menu\\Programs\\StartUp"
836     },
837     { /* CSIDL_COMMON_DESKTOPDIRECTORY */
838         9, HKLM,
839         "Common Desktop",
840         "Desktop"
841     },
842     { /* CSIDL_APPDATA */
843         9, HKCU,
844         "AppData",
845         "Application Data"
846     },
847     { /* CSIDL_PRINTHOOD */
848         9, HKCU,
849         "PrintHood",
850         "PrintHood"
851     },
852     { /* CSIDL_LOCAL_APPDATA (win2k only/undocumented) */
853         1, HKCU,
854         "Local AppData",
855         "Local Settings\\Application Data",
856     },
857     { /* CSIDL_ALTSTARTUP */
858         0, (HKEY)1, /* FIXME */
859         NULL,
860         NULL
861     },
862     { /* CSIDL_COMMON_ALTSTARTUP */
863         0, (HKEY)1, /* FIXME */
864         NULL,
865         NULL
866     },
867     { /* CSIDL_COMMON_FAVORITES */
868         9, HKCU,
869         "Favorites",
870         "Favorites"
871     },
872     { /* CSIDL_INTERNET_CACHE */
873         9, HKCU,
874         "Cache",
875         "Temporary Internet Files"
876     },
877     { /* CSIDL_COOKIES */
878         9, HKCU,
879         "Cookies",
880         "Cookies"
881     },
882     { /* CSIDL_HISTORY */
883         9, HKCU,
884         "History",
885         "History"
886     },
887     { /* CSIDL_COMMON_APPDATA */
888         9, HKLM,
889         "Common AppData",
890         "All Users\\Application Data"
891     },
892     { /* CSIDL_WINDOWS */
893         2, HKLM,
894         "WinDir",
895         "Windows"
896     },
897     { /* CSIDL_SYSTEM */
898         10, HKLM,
899         "SysDir",
900         "SYSTEM"
901     },
902     { /* CSIDL_PROGRAM_FILES */
903         4, HKLM,
904         "ProgramFilesDir",
905         "Program Files"
906     },
907     { /* CSIDL_MYPICTURES */
908         1, HKCU,
909         "My Pictures",
910         "My Documents\\My Pictures"
911     },
912     { /* CSIDL_PROFILE */
913         10, HKLM,
914         "WinDir", /* correct ? */
915         ""
916     },
917     { /* CSIDL_SYSTEMX86 */
918         10, HKLM,
919         "SysDir",
920         "SYSTEM"
921     },
922     { /* CSIDL_PROGRAM_FILESX86 */
923         4, HKLM,
924         "ProgramFilesDir",
925         "Program Files"
926     },
927     { /* CSIDL_PROGRAM_FILES_COMMON */
928         4, HKLM,
929         "CommonFilesDir",
930         "Program Files\\Common Files" /* ? */
931     },
932     { /* CSIDL_PROGRAM_FILES_COMMONX86 */
933         4, HKLM,
934         "CommonFilesDir",
935         "Program Files\\Common Files" /* ? */
936     },
937     { /* CSIDL_COMMON_TEMPLATES */
938         0, (HKEY)1, /* FIXME */
939         NULL,
940         NULL
941     },
942     { /* CSIDL_COMMON_DOCUMENTS */
943         0, (HKEY)1, /* FIXME */
944         NULL,
945         NULL
946     },
947     { /* CSIDL_COMMON_ADMINTOOLS */
948         0, (HKEY)1, /* FIXME */
949         NULL,
950         NULL
951     },
952     { /* CSIDL_ADMINTOOLS */
953         9, HKCU,
954         "Administrative Tools",
955         "Start Menu\\Programs\\Administrative Tools"
956     },
957     { /* CSIDL_CONNECTIONS */
958         0, (HKEY)1, /* FIXME */
959         NULL,
960         NULL
961     },
962     { /* unassigned 32*/
963         0, 0,
964         NULL,
965         NULL,
966     },
967     { /* unassigned 33*/
968         0, 0,
969         NULL,
970         NULL,
971     },
972     { /* unassigned 34*/
973         0, 0,
974         NULL,
975         NULL,
976     },
977     { /* CSIDL_COMMON_MUSIC */
978         0, 0, /* FIXME */
979         NULL,
980         NULL,
981     },
982     { /* CSIDL_COMMON_PICTURES */
983         0, 0, /* FIXME */
984         NULL,
985         NULL,
986     },
987     { /* CSIDL_COMMON_VIDEO */
988         0, 0, /* FIXME */
989         NULL,
990         NULL,
991     },
992     { /* CSIDL_RESOURCES */
993         0, 0, /* FIXME */
994         NULL,
995         NULL,
996     },
997     { /* CSIDL_RESOURCES_LOCALIZED */
998         0, 0, /* FIXME */
999         NULL,
1000         NULL,
1001     },
1002     { /* CSIDL_COMMON_OEM_LINKS */
1003         0, 0, /* FIXME */
1004         NULL,
1005         NULL,
1006     },
1007     { /* CSIDL_CDBURN_AREA */
1008         0, 0, /* FIXME */
1009         NULL,
1010         NULL,
1011     },
1012     { /* unassigned 3C */
1013         0, 0,
1014         NULL,
1015         NULL,
1016     },
1017     { /* CSIDL_COMPUTERSNEARME */
1018         0, 0, /* FIXME */
1019         NULL,
1020         NULL,
1021     },
1022     { /* CSIDL_PROFILES */
1023         0, 0, /* FIXME */
1024         NULL,
1025         NULL,
1026     }
1027 };
1028 #undef HKCU
1029 #undef HKLM
1030
1031 /**********************************************************************/
1032
1033 BOOL WINAPI SHGetSpecialFolderPathA (
1034         HWND hwndOwner,
1035         LPSTR szPath,
1036         int csidl,
1037         BOOL bCreate)
1038 {
1039         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH], szBuildPath[MAX_PATH];
1040         HKEY    hRootKey, hKey;
1041         DWORD   dwFlags;
1042         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1043         DWORD   folder = csidl & CSIDL_FOLDER_MASK;
1044         CHAR    *p;
1045
1046         TRACE("%p,%p,csidl=%d,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1047
1048         if ((folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) ||
1049             (CSIDL_Data[folder].hRootKey == 0))
1050         {
1051             ERR("folder 0x%04lx unknown or not allowed\n", folder);
1052             return FALSE;
1053         }
1054         if (CSIDL_Data[folder].hRootKey == (HKEY)1)
1055         {
1056             FIXME("folder 0x%04lx unknown, please add.\n", folder);
1057             return FALSE;
1058         }
1059
1060         dwFlags = CSIDL_Data[folder].dwFlags;
1061         hRootKey = CSIDL_Data[folder].hRootKey;
1062         strcpy(szValueName, CSIDL_Data[folder].szValueName);
1063         strcpy(szDefaultPath, CSIDL_Data[folder].szDefaultPath);
1064
1065         if (dwFlags & CSIDL_MYFLAG_SHFOLDER)
1066         {
1067           /*   user shell folders */
1068           if   (RegCreateKeyExA(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
1069
1070           if   (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
1071           {
1072             RegCloseKey(hKey);
1073
1074             /* shell folders */
1075             if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
1076
1077             if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
1078             {
1079
1080               /* value not existing */
1081               if (dwFlags & CSIDL_MYFLAG_RELATIVE)
1082               {
1083                 GetWindowsDirectoryA(szPath, MAX_PATH);
1084                 PathAddBackslashA(szPath);
1085                 strcat(szPath, szDefaultPath);
1086               }
1087               else
1088               {
1089                 strcpy(szPath, "C:\\"); /* FIXME ??? */
1090                 strcat(szPath, szDefaultPath);
1091               }
1092               dwType=REG_SZ;
1093               RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
1094             }
1095           }
1096           RegCloseKey(hKey);
1097         }
1098         else
1099         {
1100           LPCSTR pRegPath;
1101
1102           if (dwFlags & CSIDL_MYFLAG_SETUP)
1103             pRegPath = szSetup;
1104           else
1105           if (dwFlags & CSIDL_MYFLAG_CURRVER)
1106             pRegPath = szCurrentVersion;
1107           else
1108           {
1109             ERR("folder settings broken, please correct !\n");
1110             return FALSE;
1111           }
1112
1113           if   (RegCreateKeyExA(hRootKey,pRegPath,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
1114
1115           if   (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
1116           {
1117             /* value not existing */
1118             if (dwFlags & CSIDL_MYFLAG_RELATIVE)
1119             {
1120               GetWindowsDirectoryA(szPath, MAX_PATH);
1121               PathAddBackslashA(szPath);
1122               strcat(szPath, szDefaultPath);
1123             }
1124             else
1125             {
1126               strcpy(szPath, "C:\\");   /* FIXME ??? */
1127               strcat(szPath, szDefaultPath);
1128             }
1129             dwType=REG_SZ;
1130             RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
1131           }
1132           RegCloseKey(hKey);
1133         }
1134
1135         /* expand paths like %USERPROFILE% */
1136         if (dwType == REG_EXPAND_SZ)
1137         {
1138           ExpandEnvironmentStringsA(szPath, szDefaultPath, MAX_PATH);
1139           strcpy(szPath, szDefaultPath);
1140         }
1141
1142         /* if we don't care about existing directories we are ready */
1143         if(csidl & CSIDL_FLAG_DONT_VERIFY) return TRUE;
1144
1145         if (PathFileExistsA(szPath)) return TRUE;
1146
1147         /* not existing but we are not allowed to create it */
1148         if (!bCreate) return FALSE;
1149
1150         /* create directory/directories */
1151         strcpy(szBuildPath, szPath);
1152         p = strchr(szBuildPath, '\\');
1153         while (p)
1154         {
1155             *p = 0;
1156             if (!PathFileExistsA(szBuildPath))
1157             {
1158                 if (!CreateDirectoryA(szBuildPath,NULL))
1159                 {
1160                     ERR("Failed to create directory '%s'.\n", szPath);
1161                     return FALSE;
1162                 }
1163             }
1164             *p = '\\';
1165             p = strchr(p+1, '\\');
1166         }
1167         /* last component must be created too. */
1168         if (!PathFileExistsA(szBuildPath))
1169         {
1170             if (!CreateDirectoryA(szBuildPath,NULL))
1171             {
1172                 ERR("Failed to create directory '%s'.\n", szPath);
1173                 return FALSE;
1174             }
1175         }
1176
1177         TRACE("Created missing system directory '%s'\n", szPath);
1178         return TRUE;
1179 }
1180
1181 /*************************************************************************
1182  * SHGetSpecialFolderPathW
1183  */
1184 BOOL WINAPI SHGetSpecialFolderPathW (
1185         HWND hwndOwner,
1186         LPWSTR szPath,
1187         int csidl,
1188         BOOL bCreate)
1189 {
1190         char szTemp[MAX_PATH];
1191
1192         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
1193         {
1194             if (!MultiByteToWideChar( CP_ACP, 0, szTemp, -1, szPath, MAX_PATH ))
1195                 szPath[MAX_PATH-1] = 0;
1196         }
1197
1198         TRACE("%p,%p,csidl=%d,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1199
1200         return TRUE;
1201 }
1202
1203 /*************************************************************************
1204  * SHGetSpecialFolderPath (SHELL32.175)
1205  */
1206 BOOL WINAPI SHGetSpecialFolderPathAW (
1207         HWND hwndOwner,
1208         LPVOID szPath,
1209         int csidl,
1210         BOOL bCreate)
1211
1212 {
1213         if (SHELL_OsIsUnicode())
1214           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
1215         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
1216 }
1217
1218 /*************************************************************************
1219  * SHGetFolderPathA                     [SHELL32.@]
1220  */
1221 HRESULT WINAPI SHGetFolderPathA(
1222         HWND hwndOwner,
1223         int nFolder,
1224         HANDLE hToken,  /* [in] FIXME: get paths for specific user */
1225         DWORD dwFlags,  /* [in] FIXME: SHGFP_TYPE_CURRENT|SHGFP_TYPE_DEFAULT */
1226         LPSTR pszPath)
1227 {
1228         return (SHGetSpecialFolderPathA(
1229                 hwndOwner,
1230                 pszPath,
1231                 CSIDL_FOLDER_MASK & nFolder,
1232                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
1233 }
1234
1235 /*************************************************************************
1236  * SHGetFolderPathW                     [SHELL32.@]
1237  */
1238 HRESULT WINAPI SHGetFolderPathW(
1239         HWND hwndOwner,
1240         int nFolder,
1241         HANDLE hToken,
1242         DWORD dwFlags,
1243         LPWSTR pszPath)
1244 {
1245         return (SHGetSpecialFolderPathW(
1246                 hwndOwner,
1247                 pszPath,
1248                 CSIDL_FOLDER_MASK & nFolder,
1249                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
1250 }