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