- remove unneccesary ISF_MyComputer_Constructor() declaration
[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 static void PathGetShortPathA(LPSTR pszPath)
240 {
241         CHAR path[MAX_PATH];
242
243         TRACE("%s\n", pszPath);
244
245         if (GetShortPathNameA(pszPath, path, MAX_PATH))
246         {
247           lstrcpyA(pszPath, path);
248         }
249 }
250
251 /*************************************************************************
252  * PathGetShortPathW [internal]
253  */
254 static void PathGetShortPathW(LPWSTR pszPath)
255 {
256         WCHAR path[MAX_PATH];
257
258         TRACE("%s\n", debugstr_w(pszPath));
259
260         if (GetShortPathNameW(pszPath, path, MAX_PATH))
261         {
262           lstrcpyW(pszPath, path);
263         }
264 }
265
266 /*************************************************************************
267  * PathGetShortPath [SHELL32.92]
268  */
269 VOID WINAPI PathGetShortPathAW(LPVOID pszPath)
270 {
271         if(SHELL_OsIsUnicode())
272           PathGetShortPathW(pszPath);
273         PathGetShortPathA(pszPath);
274 }
275
276 /*************************************************************************
277  * PathRemoveBlanks [SHELL32.33]
278  */
279 void WINAPI PathRemoveBlanksAW(LPVOID str)
280 {
281         if(SHELL_OsIsUnicode())
282             PathRemoveBlanksW(str);
283         else
284             PathRemoveBlanksA(str);
285 }
286
287 /*************************************************************************
288  * PathQuoteSpaces [SHELL32.55]
289  */
290 VOID WINAPI PathQuoteSpacesAW (LPVOID lpszPath)
291 {
292         if(SHELL_OsIsUnicode())
293             PathQuoteSpacesW(lpszPath);
294         else
295             PathQuoteSpacesA(lpszPath);
296 }
297
298 /*************************************************************************
299  * PathUnquoteSpaces [SHELL32.56]
300  */
301 VOID WINAPI PathUnquoteSpacesAW(LPVOID str)
302 {
303         if(SHELL_OsIsUnicode())
304           PathUnquoteSpacesW(str);
305         else
306           PathUnquoteSpacesA(str);
307 }
308
309 /*************************************************************************
310  * PathParseIconLocation        [SHELL32.249]
311  */
312 int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
313 {
314         if(SHELL_OsIsUnicode())
315           return PathParseIconLocationW(lpszPath);
316         return PathParseIconLocationA(lpszPath);
317 }
318
319 /*
320         ########## Path Testing ##########
321 */
322 /*************************************************************************
323  * PathIsUNC            [SHELL32.39]
324  */
325 BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
326 {
327         if (SHELL_OsIsUnicode())
328           return PathIsUNCW( lpszPath );
329         return PathIsUNCA( lpszPath );
330 }
331
332 /*************************************************************************
333  *  PathIsRelative      [SHELL32.40]
334  */
335 BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
336 {
337         if (SHELL_OsIsUnicode())
338           return PathIsRelativeW( lpszPath );
339         return PathIsRelativeA( lpszPath );
340 }
341
342 /*************************************************************************
343  * PathIsRoot           [SHELL32.29]
344  */
345 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath)
346 {
347         if (SHELL_OsIsUnicode())
348           return PathIsRootW(lpszPath);
349         return PathIsRootA(lpszPath);
350 }
351
352 /*************************************************************************
353  *  PathIsExeA          [internal]
354  */
355 static BOOL PathIsExeA (LPCSTR lpszPath)
356 {
357         LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
358         int i;
359         static const char * const lpszExtensions[] =
360             {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL };
361
362         TRACE("path=%s\n",lpszPath);
363
364         for(i=0; lpszExtensions[i]; i++)
365           if (!strcasecmp(lpszExtension,lpszExtensions[i])) return TRUE;
366
367         return FALSE;
368 }
369
370 /*************************************************************************
371  *  PathIsExeW          [internal]
372  */
373 static BOOL PathIsExeW (LPCWSTR lpszPath)
374 {
375         LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
376         int i;
377         static const WCHAR lpszExtensions[][4] =
378             {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','f','\0'},
379              {'c','m','d','\0'}, {'b','a','t','\0'}, {'s','c','f','\0'},
380              {'s','c','r','\0'}, {'\0'} };
381
382         TRACE("path=%s\n",debugstr_w(lpszPath));
383
384         for(i=0; lpszExtensions[i][0]; i++)
385           if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE;
386
387         return FALSE;
388 }
389
390 /*************************************************************************
391  *  PathIsExe           [SHELL32.43]
392  */
393 BOOL WINAPI PathIsExeAW (LPCVOID path)
394 {
395         if (SHELL_OsIsUnicode())
396           return PathIsExeW (path);
397         return PathIsExeA(path);
398 }
399
400 /*************************************************************************
401  * PathIsDirectory      [SHELL32.159]
402  */
403 BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
404 {
405         if (SHELL_OsIsUnicode())
406           return PathIsDirectoryW (lpszPath);
407         return PathIsDirectoryA (lpszPath);
408 }
409
410 /*************************************************************************
411  * PathFileExists       [SHELL32.45]
412  */
413 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
414 {
415         if (SHELL_OsIsUnicode())
416           return PathFileExistsW (lpszPath);
417         return PathFileExistsA (lpszPath);
418 }
419
420 /*************************************************************************
421  * PathMatchSpec        [SHELL32.46]
422  */
423 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask)
424 {
425         if (SHELL_OsIsUnicode())
426           return PathMatchSpecW( name, mask );
427         return PathMatchSpecA( name, mask );
428 }
429
430 /*************************************************************************
431  * PathIsSameRoot       [SHELL32.650]
432  */
433 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
434 {
435         if (SHELL_OsIsUnicode())
436           return PathIsSameRootW(lpszPath1, lpszPath2);
437         return PathIsSameRootA(lpszPath1, lpszPath2);
438 }
439
440 /*************************************************************************
441  * IsLFNDriveA          [SHELL32.41]
442  */
443 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath)
444 {
445     DWORD       fnlen;
446
447     if (!GetVolumeInformationA(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
448         return FALSE;
449     return fnlen > 12;
450 }
451
452 /*************************************************************************
453  * IsLFNDriveW          [SHELL32.42]
454  */
455 BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath)
456 {
457     DWORD       fnlen;
458
459     if (!GetVolumeInformationW(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0))
460         return FALSE;
461     return fnlen > 12;
462 }
463
464 /*************************************************************************
465  * IsLFNDrive           [SHELL32.119]
466  */
467 BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath)
468 {
469         if (SHELL_OsIsUnicode())
470           return IsLFNDriveW(lpszPath);
471         return IsLFNDriveA(lpszPath);
472 }
473
474 /*
475         ########## Creating Something Unique ##########
476 */
477 /*************************************************************************
478  * PathMakeUniqueNameA  [internal]
479  */
480 BOOL WINAPI PathMakeUniqueNameA(
481         LPSTR lpszBuffer,
482         DWORD dwBuffSize,
483         LPCSTR lpszShortName,
484         LPCSTR lpszLongName,
485         LPCSTR lpszPathName)
486 {
487         FIXME("%p %lu %s %s %s stub\n",
488          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
489          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
490         return TRUE;
491 }
492
493 /*************************************************************************
494  * PathMakeUniqueNameW  [internal]
495  */
496 BOOL WINAPI PathMakeUniqueNameW(
497         LPWSTR lpszBuffer,
498         DWORD dwBuffSize,
499         LPCWSTR lpszShortName,
500         LPCWSTR lpszLongName,
501         LPCWSTR lpszPathName)
502 {
503         FIXME("%p %lu %s %s %s stub\n",
504          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
505          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
506         return TRUE;
507 }
508
509 /*************************************************************************
510  * PathMakeUniqueName   [SHELL32.47]
511  */
512 BOOL WINAPI PathMakeUniqueNameAW(
513         LPVOID lpszBuffer,
514         DWORD dwBuffSize,
515         LPCVOID lpszShortName,
516         LPCVOID lpszLongName,
517         LPCVOID lpszPathName)
518 {
519         if (SHELL_OsIsUnicode())
520           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
521         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
522 }
523
524 /*************************************************************************
525  * PathYetAnotherMakeUniqueName [SHELL32.75]
526  *
527  * NOTES
528  *     exported by ordinal
529  */
530 BOOL WINAPI PathYetAnotherMakeUniqueName(
531         LPWSTR lpszBuffer,
532         LPCWSTR lpszPathName,
533         LPCWSTR lpszShortName,
534         LPCWSTR lpszLongName)
535 {
536     FIXME("(%p, %s, %s ,%s):stub.\n",
537           lpszBuffer, debugstr_w(lpszPathName), debugstr_w(lpszShortName), debugstr_w(lpszLongName));
538     return TRUE;
539 }
540
541
542 /*
543         ########## cleaning and resolving paths ##########
544  */
545
546 /*************************************************************************
547  * PathFindOnPath       [SHELL32.145]
548  */
549 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
550 {
551         if (SHELL_OsIsUnicode())
552           return PathFindOnPathW(sFile, (LPCWSTR *)sOtherDirs);
553         return PathFindOnPathA(sFile, (LPCSTR *)sOtherDirs);
554 }
555
556 /*************************************************************************
557  * PathCleanupSpec      [SHELL32.171]
558  */
559 DWORD WINAPI PathCleanupSpecAW (LPCVOID x, LPVOID y)
560 {
561     FIXME("(%p, %p) stub\n",x,y);
562     return TRUE;
563 }
564
565 /*************************************************************************
566  * PathQualifyA         [SHELL32]
567  */
568 BOOL WINAPI PathQualifyA(LPCSTR pszPath)
569 {
570         FIXME("%s\n",pszPath);
571         return 0;
572 }
573
574 /*************************************************************************
575  * PathQualifyW         [SHELL32]
576  */
577 BOOL WINAPI PathQualifyW(LPCWSTR pszPath)
578 {
579         FIXME("%s\n",debugstr_w(pszPath));
580         return 0;
581 }
582
583 /*************************************************************************
584  * PathQualify  [SHELL32.49]
585  */
586 BOOL WINAPI PathQualifyAW(LPCVOID pszPath)
587 {
588         if (SHELL_OsIsUnicode())
589           return PathQualifyW(pszPath);
590         return PathQualifyA(pszPath);
591 }
592
593 /*************************************************************************
594  * PathResolveA [SHELL32.51]
595  */
596 BOOL WINAPI PathResolveA(
597         LPSTR lpszPath,
598         LPCSTR *alpszPaths,
599         DWORD dwFlags)
600 {
601         FIXME("(%s,%p,0x%08lx),stub!\n",
602           lpszPath, *alpszPaths, dwFlags);
603         return 0;
604 }
605
606 /*************************************************************************
607  * PathResolveW [SHELL32]
608  */
609 BOOL WINAPI PathResolveW(
610         LPWSTR lpszPath,
611         LPCWSTR *alpszPaths,
612         DWORD dwFlags)
613 {
614         FIXME("(%s,%p,0x%08lx),stub!\n",
615           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
616         return 0;
617 }
618
619 /*************************************************************************
620  * PathResolve [SHELL32.51]
621  */
622 BOOL WINAPI PathResolveAW(
623         LPVOID lpszPath,
624         LPCVOID *alpszPaths,
625         DWORD dwFlags)
626 {
627         if (SHELL_OsIsUnicode())
628           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
629         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
630 }
631
632 /*************************************************************************
633 *       PathProcessCommandA     [SHELL32.653]
634 */
635 HRESULT WINAPI PathProcessCommandA (
636         LPCSTR lpszPath,
637         LPSTR lpszBuff,
638         DWORD dwBuffSize,
639         DWORD dwFlags)
640 {
641         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
642         lpszPath, lpszBuff, dwBuffSize, dwFlags);
643         strcpy(lpszBuff, lpszPath);
644         return 0;
645 }
646
647 /*************************************************************************
648 *       PathProcessCommandW
649 */
650 HRESULT WINAPI PathProcessCommandW (
651         LPCWSTR lpszPath,
652         LPWSTR lpszBuff,
653         DWORD dwBuffSize,
654         DWORD dwFlags)
655 {
656         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
657         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
658         strcpyW(lpszBuff, lpszPath);
659         return 0;
660 }
661
662 /*************************************************************************
663 *       PathProcessCommand (SHELL32.653)
664 */
665 HRESULT WINAPI PathProcessCommandAW (
666         LPCVOID lpszPath,
667         LPVOID lpszBuff,
668         DWORD dwBuffSize,
669         DWORD dwFlags)
670 {
671         if (SHELL_OsIsUnicode())
672           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
673         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
674 }
675
676 /*
677         ########## special ##########
678 */
679
680 /*************************************************************************
681  * PathSetDlgItemPath (SHELL32.48)
682  */
683 VOID WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath)
684 {
685         if (SHELL_OsIsUnicode())
686             PathSetDlgItemPathW(hDlg, id, pszPath);
687         else
688             PathSetDlgItemPathA(hDlg, id, pszPath);
689 }
690
691 /*************************************************************************
692  * SHGetFolderPathW                     [SHELL32.@]
693  *
694  * converts csidl to path
695  */
696
697 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'};
698 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'};
699 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'};
700 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'};
701
702 typedef struct
703 {
704     DWORD dwFlags;
705     HKEY hRootKey;
706     LPCSTR szValueName;
707     LPCSTR szDefaultPath; /* fallback string; sub dir of windows directory */
708 } CSIDL_DATA;
709
710 #define CSIDL_MYFLAG_SHFOLDER   1
711 #define CSIDL_MYFLAG_SETUP      2
712 #define CSIDL_MYFLAG_CURRVER    4
713 #define CSIDL_MYFLAG_RELATIVE   8
714
715 #define HKLM HKEY_LOCAL_MACHINE
716 #define HKCU HKEY_CURRENT_USER
717 static const CSIDL_DATA CSIDL_Data[] =
718 {
719     { /* CSIDL_DESKTOP */
720         9, HKCU,
721         "Desktop",
722         "Desktop"
723     },
724     { /* CSIDL_INTERNET */
725         0, (HKEY)1, /* FIXME */
726         NULL,
727         NULL,
728     },
729     { /* CSIDL_PROGRAMS */
730         9, HKCU,
731         "Programs",
732         "Start Menu\\Programs"
733     },
734     { /* CSIDL_CONTROLS (.CPL files) */
735         10, HKLM,
736         "SysDir",
737         "SYSTEM"
738     },
739     { /* CSIDL_PRINTERS */
740         10, HKLM,
741         "SysDir",
742         "SYSTEM"
743     },
744     { /* CSIDL_PERSONAL */
745         1, HKCU,
746         "Personal",
747         "My Documents"
748     },
749     { /* CSIDL_FAVORITES */
750         9, HKCU,
751         "Favorites",
752         "Favorites"
753     },
754     { /* CSIDL_STARTUP */
755         9, HKCU,
756         "StartUp",
757         "Start Menu\\Programs\\StartUp"
758     },
759     { /* CSIDL_RECENT */
760         9, HKCU,
761         "Recent",
762         "Recent"
763     },
764     { /* CSIDL_SENDTO */
765         9, HKCU,
766         "SendTo",
767         "SendTo"
768     },
769     { /* CSIDL_BITBUCKET - Recycle Bin */
770         0, (HKEY)1, /* FIXME */
771         NULL,
772         "recycled"
773     },
774     { /* CSIDL_STARTMENU */
775         9, HKCU,
776         "Start Menu",
777         "Start Menu"
778     },
779     { /* CSIDL_MYDOCUMENTS */
780         0, (HKEY)1, /* FIXME */
781         NULL,
782         NULL
783     },
784     { /* CSIDL_MYMUSIC */
785         1, HKCU,
786         "My Music",
787         "My Documents\\My Music"
788     },
789     { /* CSIDL_MYMUSIC */
790         1, HKCU,
791         "My Video",
792         "My Documents\\My Video"
793     },
794     { /* unassigned */
795         0, 0,
796         NULL,
797         NULL,
798     },
799     { /* CSIDL_DESKTOPDIRECTORY */
800         9, HKCU,
801         "Desktop",
802         "Desktop"
803     },
804     { /* CSIDL_DRIVES */
805         0, (HKEY)1, /* FIXME */
806         NULL,
807         "My Computer"
808     },
809     { /* CSIDL_NETWORK */
810         0, (HKEY)1, /* FIXME */
811         NULL,
812         "Network Neighborhood"
813     },
814     { /* CSIDL_NETHOOD */
815         9, HKCU,
816         "NetHood",
817         "NetHood"
818     },
819     { /* CSIDL_FONTS */
820         9, HKCU,
821         "Fonts",
822         "Fonts"
823     },
824     { /* CSIDL_TEMPLATES */
825         9, HKCU,
826         "Templates",
827         "ShellNew"
828     },
829     { /* CSIDL_COMMON_STARTMENU */
830         9, HKLM,
831         "Common Start Menu",
832         "Start Menu"
833     },
834     { /* CSIDL_COMMON_PROGRAMS */
835         9, HKLM,
836         "Common Programs",
837         ""
838     },
839     { /* CSIDL_COMMON_STARTUP */
840         9, HKLM,
841         "Common StartUp",
842         "All Users\\Start Menu\\Programs\\StartUp"
843     },
844     { /* CSIDL_COMMON_DESKTOPDIRECTORY */
845         9, HKLM,
846         "Common Desktop",
847         "Desktop"
848     },
849     { /* CSIDL_APPDATA */
850         9, HKCU,
851         "AppData",
852         "Application Data"
853     },
854     { /* CSIDL_PRINTHOOD */
855         9, HKCU,
856         "PrintHood",
857         "PrintHood"
858     },
859     { /* CSIDL_LOCAL_APPDATA (win2k only/undocumented) */
860         1, HKCU,
861         "Local AppData",
862         "Local Settings\\Application Data",
863     },
864     { /* CSIDL_ALTSTARTUP */
865         0, (HKEY)1, /* FIXME */
866         NULL,
867         NULL
868     },
869     { /* CSIDL_COMMON_ALTSTARTUP */
870         0, (HKEY)1, /* FIXME */
871         NULL,
872         NULL
873     },
874     { /* CSIDL_COMMON_FAVORITES */
875         9, HKCU,
876         "Favorites",
877         "Favorites"
878     },
879     { /* CSIDL_INTERNET_CACHE (32) */
880         9, HKCU,
881         "Cache",
882         "Temporary Internet Files"
883     },
884     { /* CSIDL_COOKIES (33) */
885         9, HKCU,
886         "Cookies",
887         "Cookies"
888     },
889     { /* CSIDL_HISTORY (34) */
890         9, HKCU,
891         "History",
892         "History"
893     },
894     { /* CSIDL_COMMON_APPDATA */
895         9, HKLM,
896         "Common AppData",
897         "All Users\\Application Data"
898     },
899     { /* CSIDL_WINDOWS */
900         2, HKLM,
901         "WinDir",
902         "Windows"
903     },
904     { /* CSIDL_SYSTEM */
905         10, HKLM,
906         "SysDir",
907         "SYSTEM"
908     },
909     { /* CSIDL_PROGRAM_FILES */
910         4, HKLM,
911         "ProgramFilesDir",
912         "Program Files"
913     },
914     { /* CSIDL_MYPICTURES */
915         1, HKCU,
916         "My Pictures",
917         "My Documents\\My Pictures"
918     },
919     { /* CSIDL_PROFILE */
920         10, HKLM,
921         "WinDir", /* correct ? */
922         ""
923     },
924     { /* CSIDL_SYSTEMX86 */
925         10, HKLM,
926         "SysDir",
927         "SYSTEM"
928     },
929     { /* CSIDL_PROGRAM_FILESX86 */
930         4, HKLM,
931         "ProgramFilesDir",
932         "Program Files"
933     },
934     { /* CSIDL_PROGRAM_FILES_COMMON */
935         4, HKLM,
936         "CommonFilesDir",
937         "Program Files\\Common Files" /* ? */
938     },
939     { /* CSIDL_PROGRAM_FILES_COMMONX86 */
940         4, HKLM,
941         "CommonFilesDir",
942         "Program Files\\Common Files" /* ? */
943     },
944     { /* CSIDL_COMMON_TEMPLATES */
945         9, HKLM,
946         "Common Templates",
947         /*"Documents and Settings\\"*/"All Users\\Templates"
948     },
949     { /* CSIDL_COMMON_DOCUMENTS */
950         9, HKLM,
951         "Common Documents",
952         /*"Documents and Settings\\"*/"All Users\\Documents"
953     },
954     { /* CSIDL_COMMON_ADMINTOOLS */
955         9, HKLM,
956         "Common Administrative Tools",
957         /*"Documents and Settings\\"*/"All Users\\Start Menu\\Programs\\Administrative Tools"
958     },
959     { /* CSIDL_ADMINTOOLS */
960         9, HKCU,
961         "Administrative Tools",
962         "Start Menu\\Programs\\Administrative Tools"
963     },
964     { /* CSIDL_CONNECTIONS */
965         0, 0, /* FIXME */
966         NULL,
967         NULL
968     },
969     { /* CSIDL_COMMON_MUSIC */
970         9, HKLM,
971         "CommonMusic",
972         /*"Documents and Settings\\"*/"All Users\\Documents\\My Music"
973     },
974     { /* CSIDL_COMMON_PICTURES */
975         9, HKLM,
976         "CommonPictures",
977         /*"Documents and Settings\\"*/"All Users\\Documents\\My Pictures"
978     },
979     { /* CSIDL_COMMON_VIDEO */
980         9, HKLM,
981         "CommonVideo",
982         /*"Documents and Settings\\"*/"All Users\\Documents\\My Video"
983     },
984     { /* CSIDL_RESOURCES */
985         0, 0, /* FIXME */
986         NULL,
987         NULL
988     },
989     { /* CSIDL_RESOURCES_LOCALIZED */
990         0, 0, /* FIXME */
991         NULL,
992         NULL
993     },
994     { /* CSIDL_COMMON_OEM_LINKS */
995         0, 0, /* FIXME */
996         NULL,
997         NULL
998     },
999     { /* CSIDL_CDBURN_AREA */
1000         1, HKCU,
1001         "CD Burning",
1002         "Local Settings\\Application Data\\Microsoft\\CD Burning"
1003     },
1004     { /* unassigned 3C */
1005         0, 0,
1006         NULL,
1007         NULL
1008     },
1009     { /* CSIDL_COMPUTERSNEARME */
1010         0, 0, /* FIXME */
1011         NULL,
1012         NULL
1013     },
1014     { /* CSIDL_PROFILES */
1015         0, 0, /* FIXME */
1016         NULL,
1017         NULL
1018     }
1019 };
1020 #undef HKCU
1021 #undef HKLM
1022
1023 HRESULT WINAPI SHGetFolderPathW(
1024         HWND hwndOwner,
1025         int csidl,
1026         HANDLE hToken,  /* [in] FIXME: get paths for specific user */
1027         DWORD dwFlags,  /* [in] FIXME: SHGFP_TYPE_CURRENT|SHGFP_TYPE_DEFAULT */
1028         LPWSTR pszPath)
1029 {
1030         WCHAR   szValueName[MAX_PATH], szDefaultPath[MAX_PATH], szBuildPath[MAX_PATH];
1031         HKEY    hRootKey, hKey;
1032         DWORD   dwCsidlFlags;
1033         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1034         DWORD   folder = csidl & CSIDL_FOLDER_MASK;
1035         WCHAR   *p;
1036
1037         TRACE("%p,%p,csidl=0x%04x\n", hwndOwner,pszPath,csidl);
1038
1039         if ((folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) ||
1040             (CSIDL_Data[folder].hRootKey == 0))
1041         {
1042             ERR("folder 0x%04lx unknown or not allowed\n", folder);
1043             return E_FAIL;
1044         }
1045         if (CSIDL_Data[folder].hRootKey == (HKEY)1)
1046         {
1047             FIXME("folder 0x%04lx unknown, please add.\n", folder);
1048             return E_FAIL;
1049         }
1050
1051         dwCsidlFlags = CSIDL_Data[folder].dwFlags;
1052         hRootKey = CSIDL_Data[folder].hRootKey;
1053         MultiByteToWideChar(CP_ACP, 0, CSIDL_Data[folder].szValueName, -1, szValueName, MAX_PATH);
1054         MultiByteToWideChar(CP_ACP, 0, CSIDL_Data[folder].szDefaultPath, -1, szDefaultPath, MAX_PATH);
1055
1056         if (dwCsidlFlags & CSIDL_MYFLAG_SHFOLDER)
1057         {
1058           /*   user shell folders */
1059           if   (RegCreateKeyExW(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return E_FAIL;
1060
1061           if   (RegQueryValueExW(hKey,szValueName,NULL,&dwType,(LPBYTE)pszPath,&dwPathLen))
1062           {
1063             RegCloseKey(hKey);
1064
1065             /* shell folders */
1066             if (RegCreateKeyExW(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return E_FAIL;
1067
1068             if (RegQueryValueExW(hKey,szValueName,NULL,&dwType,(LPBYTE)pszPath,&dwPathLen))
1069             {
1070
1071               /* value not existing */
1072               if (dwCsidlFlags & CSIDL_MYFLAG_RELATIVE)
1073               {
1074                 GetWindowsDirectoryW(pszPath, MAX_PATH);
1075                 PathAddBackslashW(pszPath);
1076                 strcatW(pszPath, szDefaultPath);
1077               }
1078               else
1079               {
1080                 GetSystemDirectoryW(pszPath, MAX_PATH);
1081                 strcpyW(pszPath + 3, szDefaultPath);
1082               }
1083               dwType=REG_SZ;
1084               RegSetValueExW(hKey,szValueName,0,REG_SZ,(LPBYTE)pszPath,strlenW(pszPath)+1);
1085             }
1086           }
1087           RegCloseKey(hKey);
1088         }
1089         else
1090         {
1091           LPCWSTR pRegPath;
1092
1093           if (dwCsidlFlags & CSIDL_MYFLAG_SETUP)
1094             pRegPath = szSetup;
1095           else if (dwCsidlFlags & CSIDL_MYFLAG_CURRVER)
1096             pRegPath = szCurrentVersion;
1097           else
1098           {
1099             ERR("folder settings broken, please correct !\n");
1100             return E_FAIL;
1101           }
1102
1103           if   (RegCreateKeyExW(hRootKey,pRegPath,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return E_FAIL;
1104
1105           if   (RegQueryValueExW(hKey,szValueName,NULL,&dwType,(LPBYTE)pszPath,&dwPathLen))
1106           {
1107             /* value not existing */
1108             if (dwCsidlFlags & CSIDL_MYFLAG_RELATIVE)
1109             {
1110               GetWindowsDirectoryW(pszPath, MAX_PATH);
1111               PathAddBackslashW(pszPath);
1112               strcatW(pszPath, szDefaultPath);
1113             }
1114             else
1115             {
1116               GetSystemDirectoryW(pszPath, MAX_PATH);
1117               strcpyW(pszPath + 3, szDefaultPath);
1118             }
1119             dwType=REG_SZ;
1120             RegSetValueExW(hKey,szValueName,0,REG_SZ,(LPBYTE)pszPath,strlenW(pszPath)+1);
1121           }
1122           RegCloseKey(hKey);
1123         }
1124
1125         /* expand paths like %USERPROFILE% */
1126         if (dwType == REG_EXPAND_SZ)
1127         {
1128           ExpandEnvironmentStringsW(pszPath, szDefaultPath, MAX_PATH);
1129           strcpyW(pszPath, szDefaultPath);
1130         }
1131
1132         /* if we don't care about existing directories we are ready */
1133         if(csidl & CSIDL_FLAG_DONT_VERIFY) return S_OK;
1134
1135         if (PathFileExistsW(pszPath)) return S_OK;
1136
1137         /* not existing but we are not allowed to create it */
1138         if (!(csidl & CSIDL_FLAG_CREATE)) return E_FAIL;
1139
1140         /* create directory/directories */
1141         strcpyW(szBuildPath, pszPath);
1142         p = strchrW(szBuildPath, '\\');
1143         while (p)
1144         {
1145             *p = 0;
1146             if (!PathFileExistsW(szBuildPath))
1147             {
1148                 if (!CreateDirectoryW(szBuildPath,NULL))
1149                 {
1150                     ERR("Failed to create directory '%s'.\n", debugstr_w(pszPath));
1151                     return E_FAIL;
1152                 }
1153             }
1154             *p = '\\';
1155             p = strchrW(p+1, '\\');
1156         }
1157         /* last component must be created too. */
1158         if (!PathFileExistsW(szBuildPath))
1159         {
1160             if (!CreateDirectoryW(szBuildPath,NULL))
1161             {
1162                 ERR("Failed to create directory '%s'.\n", debugstr_w(pszPath));
1163                 return E_FAIL;
1164             }
1165         }
1166
1167         TRACE("Created missing system directory '%s'\n", debugstr_w(pszPath));
1168         return S_OK;
1169 }
1170
1171 /*************************************************************************
1172  * SHGetFolderPathA                     [SHELL32.@]
1173  */
1174 HRESULT WINAPI SHGetFolderPathA(
1175         HWND hwndOwner,
1176         int csidl,
1177         HANDLE hToken,
1178         DWORD dwFlags,
1179         LPSTR pszPath)
1180 {
1181         WCHAR szTemp[MAX_PATH];
1182         HRESULT hr;
1183
1184         hr = SHGetFolderPathW(hwndOwner, csidl, hToken, dwFlags, szTemp);
1185         if (hr == S_OK)
1186         {
1187             if (!WideCharToMultiByte( CP_ACP, 0, szTemp, -1, pszPath, MAX_PATH, NULL, NULL ))
1188                 pszPath[MAX_PATH - 1] = 0;
1189         }
1190
1191         TRACE("%p,%p,csidl=0x%04x\n",hwndOwner,pszPath,csidl);
1192
1193         return hr;
1194 }
1195
1196 /*************************************************************************
1197  * SHGetSpecialFolderPathA [SHELL32.@]
1198  */
1199 BOOL WINAPI SHGetSpecialFolderPathA (
1200         HWND hwndOwner,
1201         LPSTR szPath,
1202         int csidl,
1203         BOOL bCreate)
1204 {
1205         return (SHGetFolderPathA(
1206                 hwndOwner,
1207                 csidl + (bCreate ? CSIDL_FLAG_CREATE : 0),
1208                 NULL,
1209                 0,
1210                 szPath)) == S_OK ? TRUE : FALSE;
1211 }
1212
1213 /*************************************************************************
1214  * SHGetSpecialFolderPathW
1215  */
1216 BOOL WINAPI SHGetSpecialFolderPathW (
1217         HWND hwndOwner,
1218         LPWSTR szPath,
1219         int csidl,
1220         BOOL bCreate)
1221 {
1222         return (SHGetFolderPathW(
1223                 hwndOwner,
1224                 csidl + (bCreate ? CSIDL_FLAG_CREATE : 0),
1225                 NULL,
1226                 0,
1227                 szPath)) == S_OK ? TRUE : FALSE;
1228 }
1229
1230 /*************************************************************************
1231  * SHGetSpecialFolderPath (SHELL32.175)
1232  */
1233 BOOL WINAPI SHGetSpecialFolderPathAW (
1234         HWND hwndOwner,
1235         LPVOID szPath,
1236         int csidl,
1237         BOOL bCreate)
1238
1239 {
1240         if (SHELL_OsIsUnicode())
1241           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
1242         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
1243 }