Some windres versions don't like POPUP"", change to POPUP "".
[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 "pidl.h"
44 #include "wine/unicode.h"
45 #include "shlwapi.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48
49 /*
50         ########## Combining and Constructing paths ##########
51 */
52
53 /*************************************************************************
54  * PathAppend           [SHELL32.36]
55  */
56 BOOL WINAPI PathAppendAW(
57         LPVOID lpszPath1,
58         LPCVOID lpszPath2)
59 {
60         if (SHELL_OsIsUnicode())
61           return PathAppendW(lpszPath1, lpszPath2);
62         return PathAppendA(lpszPath1, lpszPath2);
63 }
64
65 /*************************************************************************
66  * PathCombine   [SHELL32.37]
67  */
68 LPVOID WINAPI PathCombineAW(
69         LPVOID szDest,
70         LPCVOID lpszDir,
71         LPCVOID lpszFile)
72 {
73         if (SHELL_OsIsUnicode())
74           return PathCombineW( szDest, lpszDir, lpszFile );
75         return PathCombineA( szDest, lpszDir, lpszFile );
76 }
77
78 /*************************************************************************
79  * PathAddBackslash             [SHELL32.32]
80  */
81 LPVOID WINAPI PathAddBackslashAW(LPVOID lpszPath)
82 {
83         if(SHELL_OsIsUnicode())
84           return PathAddBackslashW(lpszPath);
85         return PathAddBackslashA(lpszPath);
86 }
87
88 /*************************************************************************
89  * PathBuildRoot                [SHELL32.30]
90  */
91 LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive)
92 {
93         if(SHELL_OsIsUnicode())
94           return PathBuildRootW(lpszPath, drive);
95         return PathBuildRootA(lpszPath, drive);
96 }
97
98 /*
99         Extracting Component Parts
100 */
101
102 /*************************************************************************
103  * PathFindFileName     [SHELL32.34]
104  */
105 LPVOID WINAPI PathFindFileNameAW(LPCVOID lpszPath)
106 {
107         if(SHELL_OsIsUnicode())
108           return PathFindFileNameW(lpszPath);
109         return PathFindFileNameA(lpszPath);
110 }
111
112 /*************************************************************************
113  * PathFindExtension            [SHELL32.31]
114  */
115 LPVOID WINAPI PathFindExtensionAW(LPCVOID lpszPath)
116 {
117         if (SHELL_OsIsUnicode())
118           return PathFindExtensionW(lpszPath);
119         return PathFindExtensionA(lpszPath);
120
121 }
122
123 /*************************************************************************
124  * PathGetExtensionA            [internal]
125  *
126  * NOTES
127  *  exported by ordinal
128  *  return value points to the first char after the dot
129  */
130 static LPSTR PathGetExtensionA(LPCSTR lpszPath)
131 {
132         TRACE("(%s)\n",lpszPath);
133
134         lpszPath = PathFindExtensionA(lpszPath);
135         return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath);
136 }
137
138 /*************************************************************************
139  * PathGetExtensionW            [internal]
140  */
141 static LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
142 {
143         TRACE("(%s)\n",debugstr_w(lpszPath));
144
145         lpszPath = PathFindExtensionW(lpszPath);
146         return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath);
147 }
148
149 /*************************************************************************
150  * PathGetExtension             [SHELL32.158]
151  */
152 LPVOID WINAPI PathGetExtensionAW(LPCVOID lpszPath,DWORD void1, DWORD void2)
153 {
154         if (SHELL_OsIsUnicode())
155           return PathGetExtensionW(lpszPath);
156         return PathGetExtensionA(lpszPath);
157 }
158
159 /*************************************************************************
160  * PathGetArgs  [SHELL32.52]
161  */
162 LPVOID WINAPI PathGetArgsAW(LPVOID lpszPath)
163 {
164         if (SHELL_OsIsUnicode())
165           return PathGetArgsW(lpszPath);
166         return PathGetArgsA(lpszPath);
167 }
168
169 /*************************************************************************
170  * PathGetDriveNumber   [SHELL32.57]
171  */
172 int WINAPI PathGetDriveNumberAW(LPVOID lpszPath)
173 {
174         if (SHELL_OsIsUnicode())
175           return PathGetDriveNumberW(lpszPath);
176         return PathGetDriveNumberA(lpszPath);
177 }
178
179 /*************************************************************************
180  * PathRemoveFileSpec [SHELL32.35]
181  */
182 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath)
183 {
184         if (SHELL_OsIsUnicode())
185           return PathRemoveFileSpecW(lpszPath);
186         return PathRemoveFileSpecA(lpszPath);
187 }
188
189 /*************************************************************************
190  * PathStripPath        [SHELL32.38]
191  */
192 void WINAPI PathStripPathAW(LPVOID lpszPath)
193 {
194         if (SHELL_OsIsUnicode())
195             PathStripPathW(lpszPath);
196         else
197             PathStripPathA(lpszPath);
198 }
199
200 /*************************************************************************
201  * PathStripToRoot      [SHELL32.50]
202  */
203 BOOL WINAPI PathStripToRootAW(LPVOID lpszPath)
204 {
205         if (SHELL_OsIsUnicode())
206           return PathStripToRootW(lpszPath);
207         return PathStripToRootA(lpszPath);
208 }
209
210 /*************************************************************************
211  * PathRemoveArgs       [SHELL32.251]
212  */
213 void WINAPI PathRemoveArgsAW(LPVOID lpszPath)
214 {
215         if (SHELL_OsIsUnicode())
216             PathRemoveArgsW(lpszPath);
217         else
218             PathRemoveArgsA(lpszPath);
219 }
220
221 /*************************************************************************
222  * PathRemoveExtension  [SHELL32.250]
223  */
224 void WINAPI PathRemoveExtensionAW(LPVOID lpszPath)
225 {
226         if (SHELL_OsIsUnicode())
227             PathRemoveExtensionW(lpszPath);
228         else
229             PathRemoveExtensionA(lpszPath);
230 }
231
232
233 /*
234         Path Manipulations
235 */
236
237 /*************************************************************************
238  * PathGetShortPathA [internal]
239  */
240 static void PathGetShortPathA(LPSTR pszPath)
241 {
242         CHAR path[MAX_PATH];
243
244         TRACE("%s\n", pszPath);
245
246         if (GetShortPathNameA(pszPath, path, MAX_PATH))
247         {
248           lstrcpyA(pszPath, path);
249         }
250 }
251
252 /*************************************************************************
253  * PathGetShortPathW [internal]
254  */
255 static void PathGetShortPathW(LPWSTR pszPath)
256 {
257         WCHAR path[MAX_PATH];
258
259         TRACE("%s\n", debugstr_w(pszPath));
260
261         if (GetShortPathNameW(pszPath, path, MAX_PATH))
262         {
263           lstrcpyW(pszPath, path);
264         }
265 }
266
267 /*************************************************************************
268  * PathGetShortPath [SHELL32.92]
269  */
270 VOID WINAPI PathGetShortPathAW(LPVOID pszPath)
271 {
272         if(SHELL_OsIsUnicode())
273           PathGetShortPathW(pszPath);
274         PathGetShortPathA(pszPath);
275 }
276
277 /*************************************************************************
278  * PathRemoveBlanks [SHELL32.33]
279  */
280 void WINAPI PathRemoveBlanksAW(LPVOID str)
281 {
282         if(SHELL_OsIsUnicode())
283             PathRemoveBlanksW(str);
284         else
285             PathRemoveBlanksA(str);
286 }
287
288 /*************************************************************************
289  * PathQuoteSpaces [SHELL32.55]
290  */
291 VOID WINAPI PathQuoteSpacesAW (LPVOID lpszPath)
292 {
293         if(SHELL_OsIsUnicode())
294             PathQuoteSpacesW(lpszPath);
295         else
296             PathQuoteSpacesA(lpszPath);
297 }
298
299 /*************************************************************************
300  * PathUnquoteSpaces [SHELL32.56]
301  */
302 VOID WINAPI PathUnquoteSpacesAW(LPVOID str)
303 {
304         if(SHELL_OsIsUnicode())
305           PathUnquoteSpacesW(str);
306         else
307           PathUnquoteSpacesA(str);
308 }
309
310 /*************************************************************************
311  * PathParseIconLocation        [SHELL32.249]
312  */
313 int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
314 {
315         if(SHELL_OsIsUnicode())
316           return PathParseIconLocationW(lpszPath);
317         return PathParseIconLocationA(lpszPath);
318 }
319
320 /*
321         ########## Path Testing ##########
322 */
323 /*************************************************************************
324  * PathIsUNC            [SHELL32.39]
325  */
326 BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
327 {
328         if (SHELL_OsIsUnicode())
329           return PathIsUNCW( lpszPath );
330         return PathIsUNCA( lpszPath );
331 }
332
333 /*************************************************************************
334  *  PathIsRelative      [SHELL32.40]
335  */
336 BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
337 {
338         if (SHELL_OsIsUnicode())
339           return PathIsRelativeW( lpszPath );
340         return PathIsRelativeA( lpszPath );
341 }
342
343 /*************************************************************************
344  * PathIsRoot           [SHELL32.29]
345  */
346 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath)
347 {
348         if (SHELL_OsIsUnicode())
349           return PathIsRootW(lpszPath);
350         return PathIsRootA(lpszPath);
351 }
352
353 /*************************************************************************
354  *  PathIsExeA          [internal]
355  */
356 static BOOL PathIsExeA (LPCSTR lpszPath)
357 {
358         LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
359         int i;
360         static const char * const lpszExtensions[] =
361             {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL };
362
363         TRACE("path=%s\n",lpszPath);
364
365         for(i=0; lpszExtensions[i]; i++)
366           if (!strcasecmp(lpszExtension,lpszExtensions[i])) return TRUE;
367
368         return FALSE;
369 }
370
371 /*************************************************************************
372  *  PathIsExeW          [internal]
373  */
374 static BOOL PathIsExeW (LPCWSTR lpszPath)
375 {
376         LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
377         int i;
378         static const WCHAR lpszExtensions[][4] =
379             {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','f','\0'},
380              {'c','m','d','\0'}, {'b','a','t','\0'}, {'s','c','f','\0'},
381              {'s','c','r','\0'}, {'\0'} };
382
383         TRACE("path=%s\n",debugstr_w(lpszPath));
384
385         for(i=0; lpszExtensions[i][0]; i++)
386           if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE;
387
388         return FALSE;
389 }
390
391 /*************************************************************************
392  *  PathIsExe           [SHELL32.43]
393  */
394 BOOL WINAPI PathIsExeAW (LPCVOID path)
395 {
396         if (SHELL_OsIsUnicode())
397           return PathIsExeW (path);
398         return PathIsExeA(path);
399 }
400
401 /*************************************************************************
402  * PathIsDirectory      [SHELL32.159]
403  */
404 BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
405 {
406         if (SHELL_OsIsUnicode())
407           return PathIsDirectoryW (lpszPath);
408         return PathIsDirectoryA (lpszPath);
409 }
410
411 /*************************************************************************
412  * PathFileExists       [SHELL32.45]
413  */
414 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
415 {
416         if (SHELL_OsIsUnicode())
417           return PathFileExistsW (lpszPath);
418         return PathFileExistsA (lpszPath);
419 }
420
421 /*************************************************************************
422  * PathMatchSpec        [SHELL32.46]
423  */
424 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask)
425 {
426         if (SHELL_OsIsUnicode())
427           return PathMatchSpecW( name, mask );
428         return PathMatchSpecA( name, mask );
429 }
430
431 /*************************************************************************
432  * PathIsSameRoot       [SHELL32.650]
433  */
434 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
435 {
436         if (SHELL_OsIsUnicode())
437           return PathIsSameRootW(lpszPath1, lpszPath2);
438         return PathIsSameRootA(lpszPath1, lpszPath2);
439 }
440
441 /*************************************************************************
442  * IsLFNDriveA          [SHELL32.41]
443  */
444 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
445 {
446     DWORD       fnlen;
447
448     if (!GetVolumeInformationA(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
449         return FALSE;
450     return fnlen > 12;
451 }
452
453 /*************************************************************************
454  * IsLFNDriveW          [SHELL32.42]
455  */
456 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath)
457 {
458     DWORD       fnlen;
459
460     if (!GetVolumeInformationW(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
461         return FALSE;
462     return fnlen > 12;
463 }
464
465 /*************************************************************************
466  * IsLFNDrive           [SHELL32.119]
467  */
468 BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath)
469 {
470         if (SHELL_OsIsUnicode())
471           return IsLFNDriveW(lpszPath);
472         return IsLFNDriveA(lpszPath);
473 }
474
475 /*
476         ########## Creating Something Unique ##########
477 */
478 /*************************************************************************
479  * PathMakeUniqueNameA  [internal]
480  */
481 BOOL WINAPI PathMakeUniqueNameA(
482         LPSTR lpszBuffer,
483         DWORD dwBuffSize,
484         LPCSTR lpszShortName,
485         LPCSTR lpszLongName,
486         LPCSTR lpszPathName)
487 {
488         FIXME("%p %lu %s %s %s stub\n",
489          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
490          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
491         return TRUE;
492 }
493
494 /*************************************************************************
495  * PathMakeUniqueNameW  [internal]
496  */
497 BOOL WINAPI PathMakeUniqueNameW(
498         LPWSTR lpszBuffer,
499         DWORD dwBuffSize,
500         LPCWSTR lpszShortName,
501         LPCWSTR lpszLongName,
502         LPCWSTR lpszPathName)
503 {
504         FIXME("%p %lu %s %s %s stub\n",
505          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
506          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
507         return TRUE;
508 }
509
510 /*************************************************************************
511  * PathMakeUniqueName   [SHELL32.47]
512  */
513 BOOL WINAPI PathMakeUniqueNameAW(
514         LPVOID lpszBuffer,
515         DWORD dwBuffSize,
516         LPCVOID lpszShortName,
517         LPCVOID lpszLongName,
518         LPCVOID lpszPathName)
519 {
520         if (SHELL_OsIsUnicode())
521           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
522         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
523 }
524
525 /*************************************************************************
526  * PathYetAnotherMakeUniqueName [SHELL32.75]
527  *
528  * NOTES
529  *     exported by ordinal
530  */
531 BOOL WINAPI PathYetAnotherMakeUniqueName(
532         LPWSTR lpszBuffer,
533         LPCWSTR lpszPathName,
534         LPCWSTR lpszShortName,
535         LPCWSTR lpszLongName)
536 {
537     FIXME("(%p, %s, %s ,%s):stub.\n",
538           lpszBuffer, debugstr_w(lpszPathName), debugstr_w(lpszShortName), debugstr_w(lpszLongName));
539     return TRUE;
540 }
541
542
543 /*
544         ########## cleaning and resolving paths ##########
545  */
546
547 /*************************************************************************
548  * PathFindOnPath       [SHELL32.145]
549  */
550 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
551 {
552         if (SHELL_OsIsUnicode())
553           return PathFindOnPathW(sFile, (LPCWSTR *)sOtherDirs);
554         return PathFindOnPathA(sFile, (LPCSTR *)sOtherDirs);
555 }
556
557 /*************************************************************************
558  * PathCleanupSpec      [SHELL32.171]
559  */
560 DWORD WINAPI PathCleanupSpecAW (LPCVOID x, LPVOID y)
561 {
562     FIXME("(%p, %p) stub\n",x,y);
563     return TRUE;
564 }
565
566 /*************************************************************************
567  * PathQualifyA         [SHELL32]
568  */
569 BOOL WINAPI PathQualifyA(LPCSTR pszPath)
570 {
571         FIXME("%s\n",pszPath);
572         return 0;
573 }
574
575 /*************************************************************************
576  * PathQualifyW         [SHELL32]
577  */
578 BOOL WINAPI PathQualifyW(LPCWSTR pszPath)
579 {
580         FIXME("%s\n",debugstr_w(pszPath));
581         return 0;
582 }
583
584 /*************************************************************************
585  * PathQualify  [SHELL32.49]
586  */
587 BOOL WINAPI PathQualifyAW(LPCVOID pszPath)
588 {
589         if (SHELL_OsIsUnicode())
590           return PathQualifyW(pszPath);
591         return PathQualifyA(pszPath);
592 }
593
594 /*************************************************************************
595  * PathResolveA [SHELL32.51]
596  */
597 BOOL WINAPI PathResolveA(
598         LPSTR lpszPath,
599         LPCSTR *alpszPaths,
600         DWORD dwFlags)
601 {
602         FIXME("(%s,%p,0x%08lx),stub!\n",
603           lpszPath, *alpszPaths, dwFlags);
604         return 0;
605 }
606
607 /*************************************************************************
608  * PathResolveW [SHELL32]
609  */
610 BOOL WINAPI PathResolveW(
611         LPWSTR lpszPath,
612         LPCWSTR *alpszPaths,
613         DWORD dwFlags)
614 {
615         FIXME("(%s,%p,0x%08lx),stub!\n",
616           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
617         return 0;
618 }
619
620 /*************************************************************************
621  * PathResolve [SHELL32.51]
622  */
623 BOOL WINAPI PathResolveAW(
624         LPVOID lpszPath,
625         LPCVOID *alpszPaths,
626         DWORD dwFlags)
627 {
628         if (SHELL_OsIsUnicode())
629           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
630         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
631 }
632
633 /*************************************************************************
634 *       PathProcessCommandA     [SHELL32.653]
635 */
636 HRESULT WINAPI PathProcessCommandA (
637         LPCSTR lpszPath,
638         LPSTR lpszBuff,
639         DWORD dwBuffSize,
640         DWORD dwFlags)
641 {
642         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
643         lpszPath, lpszBuff, dwBuffSize, dwFlags);
644         strcpy(lpszBuff, lpszPath);
645         return 0;
646 }
647
648 /*************************************************************************
649 *       PathProcessCommandW
650 */
651 HRESULT WINAPI PathProcessCommandW (
652         LPCWSTR lpszPath,
653         LPWSTR lpszBuff,
654         DWORD dwBuffSize,
655         DWORD dwFlags)
656 {
657         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
658         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
659         strcpyW(lpszBuff, lpszPath);
660         return 0;
661 }
662
663 /*************************************************************************
664 *       PathProcessCommand (SHELL32.653)
665 */
666 HRESULT WINAPI PathProcessCommandAW (
667         LPCVOID lpszPath,
668         LPVOID lpszBuff,
669         DWORD dwBuffSize,
670         DWORD dwFlags)
671 {
672         if (SHELL_OsIsUnicode())
673           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
674         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
675 }
676
677 /*
678         ########## special ##########
679 */
680
681 /*************************************************************************
682  * PathSetDlgItemPath (SHELL32.48)
683  */
684 VOID WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath)
685 {
686         if (SHELL_OsIsUnicode())
687             PathSetDlgItemPathW(hDlg, id, pszPath);
688         else
689             PathSetDlgItemPathA(hDlg, id, pszPath);
690 }
691
692 /*************************************************************************
693  * SHGetFolderPathW                     [SHELL32.@]
694  *
695  * converts csidl to path
696  */
697
698 static const WCHAR szSHFolders[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','F','o','l','d','e','r','s','\0'};
699 static const WCHAR szSHUserFolders[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','U','s','e','r',' ','S','h','e','l','l',' ','F','o','l','d','e','r','s','\0'};
700 static const WCHAR szSetup[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r','\\','S','e','t','u','p','\0'};
701 static const WCHAR szCurrentVersion[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0'};
702
703
704
705 static const WCHAR Administrative_ToolsW[] = {'A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'};
706 static const WCHAR All_Users__Application_DataW[] = {'A','l','l',' ','U','s','e','r','s','\\',
707                                                      'A','p','p','l','i','c','a','t','i','o','n',' ','D','a','t','a','\0'};
708 static const WCHAR All_Users__DesktopW[] = {'A','l','l',' ','U','s','e','r','s','\\',
709                                               'D','e','s','k','t','o','p','\0'};
710 static const WCHAR All_Users__DocumentsW[] = {'A','l','l',' ','U','s','e','r','s','\\',
711                                               'D','o','c','u','m','e','n','t','s','\0'};
712 static const WCHAR All_Users__Documents__My_MusicW[] = {'A','l','l',' ','U','s','e','r','s','\\',
713                                                         'D','o','c','u','m','e','n','t','s','\\',
714                                                         'M','y',' ','M','u','s','i','c','\0'};
715 static const WCHAR All_Users__Documents__My_PicturesW[] = {'A','l','l',' ','U','s','e','r','s','\\',
716                                                            'D','o','c','u','m','e','n','t','s','\\',
717                                                            'M','y',' ','P','i','c','t','u','r','e','s','\0'};
718 static const WCHAR All_Users__Documents__My_VideoW[] = {'A','l','l',' ','U','s','e','r','s','\\',
719                                                         'D','o','c','u','m','e','n','t','s','\\',
720                                                         'M','y',' ','V','i','d','e','o','\0'};
721 static const WCHAR All_Users__Start_MenuW[] = {'A','l','l',' ','U','s','e','r','s','\\','S','t','a','r','t',' ','M','e','n','u','\0'};
722 static const WCHAR All_Users__Start_Menu__ProgramsW[] = {'A','l','l',' ','U','s','e','r','s','\\','S','t','a','r','t',' ','M','e','n','u','\\','P','r','o','g','r','a','m','s','\0'};
723 static const WCHAR All_Users__Start_Menu__Programs__Administrative_ToolsW[] = {'A','l','l',' ','U','s','e','r','s','\\',
724                                 'S','t','a','r','t',' ','M','e','n','u','\\','P','r','o','g','r','a','m','s','\\',
725                                 'A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'};
726 static const WCHAR All_Users__Start_Menu__Programs__StartUpW[] = {'A','l','l',' ','U','s','e','r','s','\\',
727                                                                'S','t','a','r','t',' ','M','e','n','u','\\',
728                                                                'P','r','o','g','r','a','m','s','\\',
729                                                                'S','t','a','r','t','U','p','\0'};
730 static const WCHAR All_Users__TemplatesW[] = {'A','l','l',' ','U','s','e','r','s','\\',
731                                               'T','e','m','p','l','a','t','e','s','\0'};
732 static const WCHAR AppDataW[] = {'A','p','p','D','a','t','a','\0'};
733 static const WCHAR Application_DataW[] = {'A','p','p','l','i','c','a','t','i','o','n',' ','D','a','t','a','\0'};
734 static const WCHAR CacheW[] = {'C','a','c','h','e','\0'};
735 static const WCHAR CD_BurningW[] = {'C','D',' ','B','u','r','n','i','n','g','\0'};
736 static const WCHAR Common_Administrative_ToolsW[] = {'C','o','m','m','o','n',' ','A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'};
737 static const WCHAR Common_AppDataW[] = {'C','o','m','m','o','n',' ','A','p','p','D','a','t','a','\0'};
738 static const WCHAR Common_DesktopW[] = {'C','o','m','m','o','n',' ','D','e','s','k','t','o','p','\0'};
739 static const WCHAR Common_DocumentsW[] = {'C','o','m','m','o','n',' ','D','o','c','u','m','e','n','t','s','\0'};
740 static const WCHAR CommonFilesDirW[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r','\0'};
741 static const WCHAR CommonMusicW[] = {'C','o','m','m','o','n','M','u','s','i','c','\0'};
742 static const WCHAR CommonPicturesW[] = {'C','o','m','m','o','n','P','i','c','t','u','r','e','s','\0'};
743 static const WCHAR Common_ProgramsW[] = {'C','o','m','m','o','n',' ','P','r','o','g','r','a','m','s','\0'};
744 static const WCHAR Common_StartUpW[] = {'C','o','m','m','o','n',' ','S','t','a','r','t','U','p','\0'};
745 static const WCHAR Common_Start_MenuW[] = {'C','o','m','m','o','n',' ','S','t','a','r','t',' ','M','e','n','u','\0'};
746 static const WCHAR Common_TemplatesW[] = {'C','o','m','m','o','n',' ','T','e','m','p','l','a','t','e','s','\0'};
747 static const WCHAR CommonVideoW[] = {'C','o','m','m','o','n','V','i','d','e','o','\0'};
748 static const WCHAR CookiesW[] = {'C','o','o','k','i','e','s','\0'};
749 static const WCHAR DesktopW[] = {'D','e','s','k','t','o','p','\0'};
750 static const WCHAR Empty_StringW[] = {'\0'};
751 static const WCHAR FavoritesW[] = {'F','a','v','o','r','i','t','e','s','\0'};
752 static const WCHAR FontsW[] = {'F','o','n','t','s','\0'};
753 static const WCHAR HistoryW[] = {'H','i','s','t','o','r','y','\0'};
754 static const WCHAR Local_AppDataW[] = {'L','o','c','a','l',' ','A','p','p','D','a','t','a','\0'};
755 static const WCHAR Local_Settings__Application_DataW[] = {'L','o','c','a','l',' ','S','e','t','t','i','n','g','s','\\',
756                                                          'A','p','p','l','i','c','a','t','i','o','n',' ','D','a','t','a','\0'};
757 static const WCHAR Local_Settings__Application_Data__Microsoft__CD_BurningW[] = {
758     'L','o','c','a','l',' ','S','e','t','t','i','n','g','s','\\',
759     'A','p','p','l','i','c','a','t','i','o','n',' ','D','a','t','a','\\',
760     'M','i','c','r','o','s','o','f','t','\\','C','D',' ','B','u','r','n','i','n','g','\0'};
761 static const WCHAR My_DocumentsW[] = {'M','y',' ','D','o','c','u','m','e','n','t','s','\0'};
762 static const WCHAR My_Documents__My_MusicW[] = {'M','y',' ','D','o','c','u','m','e','n','t','s','\\',
763                                                 'M','y',' ','M','u','s','i','c','\0'};
764 static const WCHAR My_Documents__My_PicturesW[] = {'M','y',' ','D','o','c','u','m','e','n','t','s','\\',
765                                                   'M','y',' ','P','i','c','t','u','r','e','s','\0'};
766 static const WCHAR My_Documents__My_VideoW[] = {'M','y',' ','D','o','c','u','m','e','n','t','s','\\',
767                                                'M','y',' ','V','i','d','e','o','\0'};
768 static const WCHAR My_MusicW[] = {'M','y',' ','M','u','s','i','c','\0'};
769 static const WCHAR My_PicturesW[] = {'M','y',' ','P','i','c','t','u','r','e','s','\0'};
770 static const WCHAR My_VideoW[] = {'M','y',' ','V','i','d','e','o','\0'};
771 static const WCHAR NetHoodW[] = {'N','e','t','H','o','o','d','\0'};
772 static const WCHAR PersonalW[] = {'P','e','r','s','o','n','a','l','\0'};
773 static const WCHAR PrintHoodW[] = {'P','r','i','n','t','H','o','o','d','\0'};
774 static const WCHAR ProgramFilesDirW[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r','\0'};
775 static const WCHAR Program_FilesW[] = {'P','r','o','g','r','a','m',' ','F','i','l','e','s','\0'};
776 static const WCHAR Program_Files__Common_FilesW[] = {'P','r','o','g','r','a','m',' ','F','i','l','e','s','\\',
777                                                      'C','o','m','m','o','n',' ','F','i','l','e','s','\0'};
778 static const WCHAR ProgramsW[] = {'P','r','o','g','r','m','s','\0'};
779 static const WCHAR RecentW[] = {'R','e','c','e','n','t','\0'};
780 static const WCHAR ResourcesW[] = {'R','e','s','o','u','r','c','e','s','\0'};
781 static const WCHAR SendToW[] = {'S','e','n','d','T','o','\0'};
782 static const WCHAR ShellNewW[] = {'S','h','e','l','l','N','e','w','\0'};
783 static const WCHAR Start_Menu__ProgramsW[] = {'S','t','a','r','t',' ','M','e','n','u','\\','P','r','o','g','r','a','m','s','\0'};
784 static const WCHAR SysDirW[] = {'S','y','s','D','i','r','\0'};
785 static const WCHAR SYSTEMW[] = {'S','Y','S','T','E','M','\0'};
786 static const WCHAR StartUpW[] = {'S','t','a','r','t','U','p','\0'};
787 static const WCHAR Start_MenuW[] = {'S','t','a','r','t',' ','M','e','n','u','\0'};
788 static const WCHAR Start_Menu__Programs__Administrative_ToolsW[] = {
789                                 'S','t','a','r','t',' ','M','e','n','u','\\','P','r','o','g','r','a','m','s','\\',
790                                 'A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'};
791 static const WCHAR Start_Menu__Programs__StartUpW[] = {'S','t','a','r','t',' ','M','e','n','u','\\',
792                                                      'P','r','o','g','r','a','m','s','\\',
793                                                      'S','t','a','r','t','U','p','\0'};
794 static const WCHAR TemplatesW[] = {'T','e','m','p','l','a','t','e','s','\0'};
795 static const WCHAR Temporary_Internet_FilesW[] = {'T','e','m','p','o','r','a','r','y',' ','I','n','t','e','r','n','e','t',' ','F','i','l','e','s','\0'};
796 static const WCHAR WinDirW[] = {'W','i','n','D','i','r','\0'};
797 static const WCHAR WindowsW[] = {'W','i','n','d','o','w','s','\0'};
798
799
800
801
802 typedef struct
803 {
804     DWORD dwFlags;
805     HKEY hRootKey;
806     LPCWSTR szValueName;
807     LPCWSTR szDefaultPath; /* fallback string; sub dir of windows directory */
808 } CSIDL_DATA;
809
810 #define CSIDL_MYFLAG_SHFOLDER   1
811 #define CSIDL_MYFLAG_SETUP      2
812 #define CSIDL_MYFLAG_CURRVER    4
813 #define CSIDL_MYFLAG_RELATIVE   8
814
815 #define HKLM HKEY_LOCAL_MACHINE
816 #define HKCU HKEY_CURRENT_USER
817 #define HKEY_DISALLOWED    (HKEY)0
818 #define HKEY_UNIMPLEMENTED (HKEY)1
819 #define HKEY_WINDOWSPATH   (HKEY)2
820 #define HKEY_NONEXISTENT   (HKEY)3
821 static const CSIDL_DATA CSIDL_Data[] =
822 {
823     { /* CSIDL_DESKTOP */
824         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
825         HKCU,
826         DesktopW,
827         DesktopW
828     },
829     { /* CSIDL_INTERNET */
830         0,
831         HKEY_DISALLOWED,
832         NULL,
833         NULL
834     },
835     { /* CSIDL_PROGRAMS */
836         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
837         HKCU,
838         ProgramsW,
839         Start_Menu__ProgramsW
840     },
841     { /* CSIDL_CONTROLS (.CPL files) */
842         CSIDL_MYFLAG_SETUP | CSIDL_MYFLAG_RELATIVE,
843         HKLM,
844         SysDirW,
845         SYSTEMW
846     },
847     { /* CSIDL_PRINTERS */
848         CSIDL_MYFLAG_SETUP | CSIDL_MYFLAG_RELATIVE,
849         HKLM,
850         SysDirW,
851         SYSTEMW
852     },
853     { /* CSIDL_PERSONAL */
854         CSIDL_MYFLAG_SHFOLDER,
855         HKCU,
856         PersonalW,
857         My_DocumentsW
858     },
859     { /* CSIDL_FAVORITES */
860         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
861         HKCU,
862         FavoritesW,
863         FavoritesW
864     },
865     { /* CSIDL_STARTUP */
866         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
867         HKCU,
868         StartUpW,
869         Start_Menu__Programs__StartUpW
870     },
871     { /* CSIDL_RECENT */
872         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
873         HKCU,
874         RecentW,
875         RecentW
876     },
877     { /* CSIDL_SENDTO */
878         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
879         HKCU,
880         SendToW,
881         SendToW
882     },
883     { /* CSIDL_BITBUCKET - Recycle Bin */
884         0,
885         HKEY_DISALLOWED,
886         NULL,
887         NULL,
888     },
889     { /* CSIDL_STARTMENU */
890         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
891         HKCU,
892         Start_MenuW,
893         Start_MenuW
894     },
895     { /* CSIDL_MYDOCUMENTS */
896         0,
897         HKEY_UNIMPLEMENTED, /* FIXME */
898         NULL,
899         NULL
900     },
901     { /* CSIDL_MYMUSIC */
902         CSIDL_MYFLAG_SHFOLDER,
903         HKCU,
904         My_MusicW,
905         My_Documents__My_MusicW
906     },
907     { /* CSIDL_MYVIDEO */
908         CSIDL_MYFLAG_SHFOLDER,
909         HKCU,
910         My_VideoW,
911         My_Documents__My_VideoW
912     },
913     { /* unassigned */
914         0,
915         HKEY_DISALLOWED,
916         NULL,
917         NULL,
918     },
919     { /* CSIDL_DESKTOPDIRECTORY */
920         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
921         HKCU,
922         DesktopW,
923         DesktopW
924     },
925     { /* CSIDL_DRIVES */
926         0,
927         HKEY_DISALLOWED,
928         NULL,
929         NULL,
930     },
931     { /* CSIDL_NETWORK */
932         0,
933         HKEY_DISALLOWED,
934         NULL,
935         NULL,
936     },
937     { /* CSIDL_NETHOOD */
938         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
939         HKCU,
940         NetHoodW,
941         NetHoodW
942     },
943     { /* CSIDL_FONTS */
944         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
945         HKCU,
946         FontsW,
947         FontsW
948     },
949     { /* CSIDL_TEMPLATES */
950         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
951         HKCU,
952         TemplatesW,
953         ShellNewW
954     },
955     { /* CSIDL_COMMON_STARTMENU */
956         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
957         HKLM,
958         Common_Start_MenuW,
959         All_Users__Start_MenuW
960     },
961     { /* CSIDL_COMMON_PROGRAMS */
962         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
963         HKLM,
964         Common_ProgramsW,
965         All_Users__Start_Menu__ProgramsW
966     },
967     { /* CSIDL_COMMON_STARTUP */
968         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
969         HKLM,
970         Common_StartUpW,
971         All_Users__Start_Menu__Programs__StartUpW
972     },
973     { /* CSIDL_COMMON_DESKTOPDIRECTORY */
974         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
975         HKLM,
976         Common_DesktopW,
977         All_Users__DesktopW
978     },
979     { /* CSIDL_APPDATA */
980         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
981         HKCU,
982         AppDataW,
983         Application_DataW
984     },
985     { /* CSIDL_PRINTHOOD */
986         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
987         HKCU,
988         PrintHoodW,
989         PrintHoodW
990     },
991     { /* CSIDL_LOCAL_APPDATA (win2k only/undocumented) */
992         CSIDL_MYFLAG_SHFOLDER,
993         HKCU,
994         Local_AppDataW,
995         Local_Settings__Application_DataW,
996     },
997     { /* CSIDL_ALTSTARTUP */
998         0,
999         HKEY_NONEXISTENT,
1000         NULL,
1001         NULL
1002     },
1003     { /* CSIDL_COMMON_ALTSTARTUP */
1004         0,
1005         HKEY_NONEXISTENT,
1006         NULL,
1007         NULL
1008     },
1009     { /* CSIDL_COMMON_FAVORITES */
1010         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1011         HKCU,
1012         FavoritesW,
1013         FavoritesW
1014     },
1015     { /* CSIDL_INTERNET_CACHE (32) */
1016         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1017         HKCU,
1018         CacheW,
1019         Temporary_Internet_FilesW
1020     },
1021     { /* CSIDL_COOKIES (33) */
1022         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1023         HKCU,
1024         CookiesW,
1025         CookiesW
1026     },
1027     { /* CSIDL_HISTORY (34) */
1028         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1029         HKCU,
1030         HistoryW,
1031         HistoryW
1032     },
1033     { /* CSIDL_COMMON_APPDATA */
1034         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1035         HKLM,
1036         Common_AppDataW,
1037         All_Users__Application_DataW
1038     },
1039     { /* CSIDL_WINDOWS */
1040         CSIDL_MYFLAG_SETUP,
1041         HKLM,
1042         WinDirW,
1043         WindowsW
1044     },
1045     { /* CSIDL_SYSTEM */
1046         CSIDL_MYFLAG_SETUP | CSIDL_MYFLAG_RELATIVE,
1047         HKLM,
1048         SysDirW,
1049         SYSTEMW
1050     },
1051     { /* CSIDL_PROGRAM_FILES */
1052         CSIDL_MYFLAG_CURRVER,
1053         HKLM,
1054         ProgramFilesDirW,
1055         Program_FilesW
1056     },
1057     { /* CSIDL_MYPICTURES */
1058         CSIDL_MYFLAG_SHFOLDER,
1059         HKCU,
1060         My_PicturesW,
1061         My_Documents__My_PicturesW
1062     },
1063     { /* CSIDL_PROFILE */
1064         CSIDL_MYFLAG_SETUP | CSIDL_MYFLAG_RELATIVE,
1065         HKLM,
1066         WinDirW, /* correct ? */
1067         Empty_StringW
1068     },
1069     { /* CSIDL_SYSTEMX86 */
1070         CSIDL_MYFLAG_SETUP | CSIDL_MYFLAG_RELATIVE,
1071         HKLM,
1072         SysDirW,
1073         SYSTEMW
1074     },
1075     { /* CSIDL_PROGRAM_FILESX86 */
1076         CSIDL_MYFLAG_CURRVER,
1077         HKLM,
1078         ProgramFilesDirW,
1079         Program_FilesW
1080     },
1081     { /* CSIDL_PROGRAM_FILES_COMMON */
1082         CSIDL_MYFLAG_CURRVER,
1083         HKLM,
1084         CommonFilesDirW,
1085         Program_Files__Common_FilesW /* ? */
1086     },
1087     { /* CSIDL_PROGRAM_FILES_COMMONX86 */
1088         CSIDL_MYFLAG_CURRVER,
1089         HKLM,
1090         CommonFilesDirW,
1091         Program_Files__Common_FilesW /* ? */
1092     },
1093     { /* CSIDL_COMMON_TEMPLATES */
1094         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1095         HKLM,
1096         Common_TemplatesW,
1097         /*"Documents and Settings\\"*/ All_Users__TemplatesW
1098     },
1099     { /* CSIDL_COMMON_DOCUMENTS */
1100         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1101         HKLM,
1102         Common_DocumentsW,
1103         /*"Documents and Settings\\"*/ All_Users__DocumentsW
1104     },
1105     { /* CSIDL_COMMON_ADMINTOOLS */
1106         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1107         HKLM,
1108         Common_Administrative_ToolsW,
1109         /*"Documents and Settings\\"*/ All_Users__Start_Menu__Programs__Administrative_ToolsW
1110     },
1111     { /* CSIDL_ADMINTOOLS */
1112         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1113         HKCU,
1114         Administrative_ToolsW,
1115         Start_Menu__Programs__Administrative_ToolsW
1116     },
1117     { /* CSIDL_CONNECTIONS */
1118         0,
1119         HKEY_DISALLOWED,
1120         NULL,
1121         NULL
1122     },
1123     { /* unassigned 32 */
1124         0,
1125         HKEY_DISALLOWED,
1126         NULL,
1127         NULL
1128     },
1129     { /* unassigned 33 */
1130         0,
1131         HKEY_DISALLOWED,
1132         NULL,
1133         NULL
1134     },
1135     { /* unassigned 34 */
1136         0,
1137         HKEY_DISALLOWED,
1138         NULL,
1139         NULL
1140     },
1141     { /* CSIDL_COMMON_MUSIC */
1142         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1143         HKLM,
1144         CommonMusicW,
1145         /*"Documents and Settings\\"*/ All_Users__Documents__My_MusicW
1146     },
1147     { /* CSIDL_COMMON_PICTURES */
1148         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1149         HKLM,
1150         CommonPicturesW,
1151         /*"Documents and Settings\\"*/ All_Users__Documents__My_PicturesW
1152     },
1153     { /* CSIDL_COMMON_VIDEO */
1154         CSIDL_MYFLAG_SHFOLDER | CSIDL_MYFLAG_RELATIVE,
1155         HKLM,
1156         CommonVideoW,
1157         /*"Documents and Settings\\"*/ All_Users__Documents__My_VideoW
1158     },
1159     { /* CSIDL_RESOURCES */
1160         0,
1161         HKEY_WINDOWSPATH,
1162         NULL,
1163         ResourcesW
1164     },
1165     { /* CSIDL_RESOURCES_LOCALIZED */
1166         0,
1167         HKEY_DISALLOWED, /* FIXME */
1168         NULL,
1169         NULL
1170     },
1171     { /* CSIDL_COMMON_OEM_LINKS */
1172         0,
1173         HKEY_DISALLOWED, /* FIXME */
1174         NULL,
1175         NULL
1176     },
1177     { /* CSIDL_CDBURN_AREA */
1178         CSIDL_MYFLAG_SHFOLDER,
1179         HKCU,
1180         CD_BurningW,
1181         Local_Settings__Application_Data__Microsoft__CD_BurningW
1182     },
1183     { /* unassigned 3C */
1184         0,
1185         HKEY_DISALLOWED,
1186         NULL,
1187         NULL
1188     },
1189     { /* CSIDL_COMPUTERSNEARME */
1190         0,
1191         HKEY_DISALLOWED, /* FIXME */
1192         NULL,
1193         NULL
1194     },
1195     { /* CSIDL_PROFILES */
1196         0,
1197         HKEY_DISALLOWED, /* FIXME */
1198         NULL,
1199         NULL
1200     }
1201 };
1202 #undef HKCU
1203 #undef HKLM
1204
1205 /**********************************************************************/
1206
1207 HRESULT WINAPI SHGetFolderPathW(
1208         HWND hwndOwner,
1209         int csidl,
1210         HANDLE hToken,  /* [in] FIXME: get paths for specific user */
1211         DWORD dwFlags,  /* [in] FIXME: SHGFP_TYPE_CURRENT|SHGFP_TYPE_DEFAULT */
1212         LPWSTR pszPath)
1213 {
1214         WCHAR   szBuildPath[MAX_PATH];
1215         HKEY    hRootKey, hKey;
1216         DWORD   dwCsidlFlags;
1217         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1218         DWORD   folder = csidl & CSIDL_FOLDER_MASK;
1219         WCHAR   *p;
1220
1221         TRACE("%p,%p,csidl=0x%04x\n", hwndOwner,pszPath,csidl);
1222
1223         if (!pszPath)
1224             return E_INVALIDARG;
1225
1226         *pszPath = '\0';
1227         if ((folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) ||
1228             (CSIDL_Data[folder].hRootKey == HKEY_DISALLOWED))
1229             return E_INVALIDARG;
1230         if (CSIDL_Data[folder].hRootKey == HKEY_UNIMPLEMENTED)
1231         {
1232             FIXME("folder 0x%04lx unknown, please add.\n", folder);
1233             return E_FAIL;
1234         }
1235         if (CSIDL_Data[folder].hRootKey == HKEY_NONEXISTENT)
1236             return S_FALSE;
1237
1238         /* Special case for some values that don't exist in registry */
1239         if (CSIDL_Data[folder].hRootKey == HKEY_WINDOWSPATH)
1240         {
1241             GetWindowsDirectoryW(pszPath, MAX_PATH);
1242             PathAddBackslashW(pszPath);
1243             strcatW(pszPath, CSIDL_Data[folder].szDefaultPath);
1244             return S_OK;
1245         }
1246         
1247         dwCsidlFlags = CSIDL_Data[folder].dwFlags;
1248         hRootKey = CSIDL_Data[folder].hRootKey;
1249
1250         if (dwCsidlFlags & CSIDL_MYFLAG_SHFOLDER)
1251         {
1252           /*   user shell folders */
1253           if   (RegCreateKeyExW(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return E_FAIL;
1254
1255           if   (RegQueryValueExW(hKey,CSIDL_Data[folder].szValueName,NULL,&dwType,(LPBYTE)pszPath,&dwPathLen))
1256           {
1257             RegCloseKey(hKey);
1258
1259             /* shell folders */
1260             if (RegCreateKeyExW(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return E_FAIL;
1261
1262             if (RegQueryValueExW(hKey,CSIDL_Data[folder].szValueName,NULL,&dwType,(LPBYTE)pszPath,&dwPathLen))
1263             {
1264
1265               /* value not existing */
1266               if (dwCsidlFlags & CSIDL_MYFLAG_RELATIVE)
1267               {
1268                 GetWindowsDirectoryW(pszPath, MAX_PATH);
1269                 PathAddBackslashW(pszPath);
1270                 strcatW(pszPath, CSIDL_Data[folder].szDefaultPath);
1271               }
1272               else
1273               {
1274                 GetSystemDirectoryW(pszPath, MAX_PATH);
1275                 strcpyW(pszPath + 3, CSIDL_Data[folder].szDefaultPath);
1276               }
1277               dwType=REG_SZ;
1278               RegSetValueExW(hKey,CSIDL_Data[folder].szValueName,0,REG_SZ,(LPBYTE)pszPath,
1279                          (strlenW(pszPath)+1)*sizeof(WCHAR));
1280             }
1281           }
1282           RegCloseKey(hKey);
1283         }
1284         else
1285         {
1286           LPCWSTR pRegPath;
1287
1288           if (dwCsidlFlags & CSIDL_MYFLAG_SETUP)
1289             pRegPath = szSetup;
1290           else if (dwCsidlFlags & CSIDL_MYFLAG_CURRVER)
1291             pRegPath = szCurrentVersion;
1292           else
1293           {
1294             ERR("folder settings broken, please correct !\n");
1295             return E_FAIL;
1296           }
1297
1298           if   (RegCreateKeyExW(hRootKey,pRegPath,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return E_FAIL;
1299
1300           if   (RegQueryValueExW(hKey,CSIDL_Data[folder].szValueName,NULL,&dwType,(LPBYTE)pszPath,&dwPathLen))
1301           {
1302             /* value not existing */
1303             if (dwCsidlFlags & CSIDL_MYFLAG_RELATIVE)
1304             {
1305               GetWindowsDirectoryW(pszPath, MAX_PATH);
1306               PathAddBackslashW(pszPath);
1307               strcatW(pszPath, CSIDL_Data[folder].szDefaultPath);
1308             }
1309             else
1310             {
1311               GetSystemDirectoryW(pszPath, MAX_PATH);
1312               strcpyW(pszPath + 3, CSIDL_Data[folder].szDefaultPath);
1313             }
1314             dwType=REG_SZ;
1315             RegSetValueExW(hKey,CSIDL_Data[folder].szValueName,0,REG_SZ,(LPBYTE)pszPath,
1316                        (strlenW(pszPath)+1)*sizeof(WCHAR));
1317           }
1318           RegCloseKey(hKey);
1319         }
1320
1321         /* expand paths like %USERPROFILE% */
1322         if (dwType == REG_EXPAND_SZ)
1323         {
1324           ExpandEnvironmentStringsW(pszPath, szBuildPath, MAX_PATH);
1325           strcpyW(pszPath, szBuildPath);
1326         }
1327
1328         /* if we don't care about existing directories we are ready */
1329         if(csidl & CSIDL_FLAG_DONT_VERIFY) return S_OK;
1330
1331         if (PathFileExistsW(pszPath)) return S_OK;
1332
1333         /* not existing but we are not allowed to create it */
1334         if (!(csidl & CSIDL_FLAG_CREATE)) return E_FAIL;
1335
1336         /* create directory/directories */
1337         strcpyW(szBuildPath, pszPath);
1338         p = strchrW(szBuildPath, '\\');
1339         while (p)
1340         {
1341             *p = 0;
1342             if (!PathFileExistsW(szBuildPath))
1343             {
1344                 if (!CreateDirectoryW(szBuildPath,NULL))
1345                 {
1346                     ERR("Failed to create directory '%s'.\n", debugstr_w(pszPath));
1347                     return E_FAIL;
1348                 }
1349             }
1350             *p = '\\';
1351             p = strchrW(p+1, '\\');
1352         }
1353         /* last component must be created too. */
1354         if (!PathFileExistsW(szBuildPath))
1355         {
1356             if (!CreateDirectoryW(szBuildPath,NULL))
1357             {
1358                 ERR("Failed to create directory '%s'.\n", debugstr_w(pszPath));
1359                 return E_FAIL;
1360             }
1361         }
1362
1363         TRACE("Created missing system directory '%s'\n", debugstr_w(pszPath));
1364         return S_OK;
1365 }
1366
1367 /*************************************************************************
1368  * SHGetFolderPathA                     [SHELL32.@]
1369  */
1370 HRESULT WINAPI SHGetFolderPathA(
1371         HWND hwndOwner,
1372         int csidl,
1373         HANDLE hToken,
1374         DWORD dwFlags,
1375         LPSTR pszPath)
1376 {
1377     WCHAR szTemp[MAX_PATH];
1378     HRESULT hr;
1379
1380     if (!pszPath)
1381         return E_INVALIDARG;
1382
1383     *pszPath = '\0';
1384     hr = SHGetFolderPathW(hwndOwner, csidl, hToken, dwFlags, szTemp);
1385     if (SUCCEEDED(hr))
1386         WideCharToMultiByte(CP_ACP, 0, szTemp, -1, pszPath, MAX_PATH, NULL,
1387          NULL);
1388
1389     TRACE("%p,%p,csidl=0x%04x\n",hwndOwner,pszPath,csidl);
1390
1391     return hr;
1392 }
1393
1394 /*************************************************************************
1395  * SHGetSpecialFolderPathA [SHELL32.@]
1396  */
1397 BOOL WINAPI SHGetSpecialFolderPathA (
1398         HWND hwndOwner,
1399         LPSTR szPath,
1400         int csidl,
1401         BOOL bCreate)
1402 {
1403         return (SHGetFolderPathA(
1404                 hwndOwner,
1405                 csidl + (bCreate ? CSIDL_FLAG_CREATE : 0),
1406                 NULL,
1407                 0,
1408                 szPath)) == S_OK ? TRUE : FALSE;
1409 }
1410
1411 /*************************************************************************
1412  * SHGetSpecialFolderPathW
1413  */
1414 BOOL WINAPI SHGetSpecialFolderPathW (
1415         HWND hwndOwner,
1416         LPWSTR szPath,
1417         int csidl,
1418         BOOL bCreate)
1419 {
1420         return (SHGetFolderPathW(
1421                 hwndOwner,
1422                 csidl + (bCreate ? CSIDL_FLAG_CREATE : 0),
1423                 NULL,
1424                 0,
1425                 szPath)) == S_OK ? TRUE : FALSE;
1426 }
1427
1428 /*************************************************************************
1429  * SHGetSpecialFolderPath (SHELL32.175)
1430  */
1431 BOOL WINAPI SHGetSpecialFolderPathAW (
1432         HWND hwndOwner,
1433         LPVOID szPath,
1434         int csidl,
1435         BOOL bCreate)
1436
1437 {
1438         if (SHELL_OsIsUnicode())
1439           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
1440         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
1441 }
1442
1443 /*************************************************************************
1444  * SHGetSpecialFolderLocation           [SHELL32.@]
1445  *
1446  * gets the folder locations from the registry and creates a pidl
1447  * creates missing reg keys and directories
1448  *
1449  * PARAMS
1450  *   hwndOwner [I]
1451  *   nFolder   [I] CSIDL_xxxxx
1452  *   ppidl     [O] PIDL of a special folder
1453  *
1454  * NOTES
1455  *   In NT5, SHGetSpecialFolderLocation needs the <winntdir>/Recent
1456  *   directory. If the directory is missing it returns a x80070002.
1457  *   In most cases, this forwards to SHGetSpecialFolderPath, but
1458  *   CSIDLs with virtual folders (not real paths) must be handled
1459  *   here.
1460  */
1461 HRESULT WINAPI SHGetSpecialFolderLocation(
1462         HWND hwndOwner,
1463         INT nFolder,
1464         LPITEMIDLIST * ppidl)
1465 {
1466     HRESULT hr = E_INVALIDARG;
1467
1468     TRACE("(%p,0x%x,%p)\n", hwndOwner,nFolder,ppidl);
1469
1470     if (!ppidl)
1471         return E_INVALIDARG;
1472
1473     *ppidl = NULL;
1474     switch (nFolder)
1475     {
1476         case CSIDL_DESKTOP:
1477             *ppidl = _ILCreateDesktop();
1478             break;
1479
1480         case CSIDL_INTERNET:
1481             *ppidl = _ILCreateIExplore();
1482             break;
1483
1484         case CSIDL_CONTROLS:
1485             *ppidl = _ILCreateControlPanel();
1486             break;
1487
1488         case CSIDL_PRINTERS:
1489             *ppidl = _ILCreatePrinters();
1490             break;
1491
1492         case CSIDL_BITBUCKET:
1493             *ppidl = _ILCreateBitBucket();
1494             break;
1495
1496         case CSIDL_DRIVES:
1497             *ppidl = _ILCreateMyComputer();
1498             break;
1499
1500         case CSIDL_NETWORK:
1501             *ppidl = _ILCreateNetwork();
1502             break;
1503
1504         case CSIDL_ALTSTARTUP:
1505         case CSIDL_COMMON_ALTSTARTUP:
1506             hr = E_FAIL;
1507             break;
1508
1509         case CSIDL_COMPUTERSNEARME:
1510             hr = E_FAIL;
1511             break;
1512
1513         default:
1514         {
1515             WCHAR szPath[MAX_PATH];
1516
1517             if (SHGetSpecialFolderPathW(hwndOwner, szPath, nFolder, TRUE))
1518             {
1519                 DWORD attributes=0;
1520
1521                 TRACE("Value=%s\n", debugstr_w(szPath));
1522                 hr = SHILCreateFromPathW(szPath, ppidl, &attributes);
1523             }
1524         }
1525     }
1526     if(*ppidl)
1527         hr = NOERROR;
1528
1529     TRACE("-- (new pidl %p)\n",*ppidl);
1530     return hr;
1531 }
1532
1533 /*************************************************************************
1534  * SHGetFolderLocation [SHELL32.@]
1535  *
1536  * NOTES
1537  *  the pidl can be a simple one. since we can't get the path out of the pidl
1538  *  we have to take all data from the pidl
1539  *  Mostly we forward to SHGetSpecialFolderLocation, but a few special cases
1540  *  we handle here.
1541  */
1542 HRESULT WINAPI SHGetFolderLocation(
1543         HWND hwnd,
1544         int csidl,
1545         HANDLE hToken,
1546         DWORD dwFlags,
1547         LPITEMIDLIST *ppidl)
1548 {
1549     HRESULT hr;
1550
1551     TRACE_(shell)("%p 0x%08x %p 0x%08lx %p\n",
1552      hwnd, csidl, hToken, dwFlags, ppidl);
1553     
1554     if (!ppidl)
1555         return E_INVALIDARG;
1556
1557     switch (csidl)
1558     {
1559         case CSIDL_ALTSTARTUP:
1560         case CSIDL_COMMON_ALTSTARTUP:
1561             *ppidl = NULL;
1562             hr = S_FALSE;
1563             break;
1564         default:
1565             hr = SHGetSpecialFolderLocation(hwnd, csidl, ppidl);
1566     }
1567     return hr;
1568 }