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