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