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