Fixed some issues found by winapi_check.
[wine] / dlls / shell32 / shellpath.c
1 /*
2  * Path Functions
3  *
4  * Many of this functions are in SHLWAPI.DLL also
5  *
6  */
7 #include <string.h>
8 #include <ctype.h>
9 #include "debugtools.h"
10 #include "winnls.h"
11 #include "winversion.h"
12 #include "winreg.h"
13
14 #include "shlobj.h"
15 #include "shell32_main.h"
16 #include "windef.h"
17 #include "options.h"
18 #include "wine/undocshell.h"
19 #include "wine/unicode.h"
20 #include "shlwapi.h"
21
22 DEFAULT_DEBUG_CHANNEL(shell);
23
24 #define isSlash(x) ((x)=='\\' || (x)=='/')
25 /*
26         ########## Combining and Constructing paths ##########
27 */
28
29 /*************************************************************************
30  * PathAppendA          [SHLWAPI.@]
31  * 
32  * NOTES
33  *  concat path lpszPath2 onto lpszPath1
34  *
35  * FIXME
36  *  the resulting path is also canonicalized
37  */
38 BOOL WINAPI PathAppendA(
39         LPSTR lpszPath1,
40         LPCSTR lpszPath2) 
41 {
42         TRACE("%s %s\n",lpszPath1, lpszPath2);
43         while (lpszPath2[0]=='\\') lpszPath2++;
44         PathCombineA(lpszPath1,lpszPath1,lpszPath2);
45         return TRUE;
46 }
47
48 /*************************************************************************
49  * PathAppendW          [SHLWAPI.@]
50  */
51 BOOL WINAPI PathAppendW(
52         LPWSTR lpszPath1,
53         LPCWSTR lpszPath2) 
54 {
55         TRACE("%s %s\n",debugstr_w(lpszPath1), debugstr_w(lpszPath2));
56         while (lpszPath2[0]=='\\') lpszPath2++;
57         PathCombineW(lpszPath1,lpszPath1,lpszPath2);
58         return TRUE;
59 }
60
61 /*************************************************************************
62  * PathAppendAW         [SHELL32.36]
63  */
64 BOOL WINAPI PathAppendAW(
65         LPVOID lpszPath1,
66         LPCVOID lpszPath2)
67 {
68         if (VERSION_OsIsUnicode())
69           return PathAppendW(lpszPath1, lpszPath2);
70         return PathAppendA(lpszPath1, lpszPath2);
71 }
72
73 /*************************************************************************
74  * PathCombineA         [SHLWAPI.@]
75  * 
76  * NOTES
77  *  if lpszFile='.' skip it
78  *  szDest can be equal to lpszFile. Thats why we use sTemp
79  *
80  * FIXME
81  *  the resulting path is also canonicalized
82  */
83 LPSTR WINAPI PathCombineA(
84         LPSTR szDest,
85         LPCSTR lpszDir,
86         LPCSTR lpszFile) 
87 {
88         char sTemp[MAX_PATH];
89         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
90         
91         
92         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 
93         {
94           strcpy(szDest,lpszDir);
95           return szDest;
96         }
97
98         /*  if lpszFile is a complete path don't care about lpszDir */
99         if (PathGetDriveNumberA(lpszFile) != -1)
100         {
101           strcpy(szDest,lpszFile);
102         }
103         else if (lpszFile[0] == '\\' )
104         {
105           strcpy(sTemp,lpszDir);
106           PathStripToRootA(sTemp);
107           strcat(sTemp,lpszFile);
108           strcpy(szDest,sTemp);
109         }
110         else
111         {
112           strcpy(sTemp,lpszDir);
113           PathAddBackslashA(sTemp);
114           strcat(sTemp,lpszFile);
115           strcpy(szDest,sTemp);
116         }
117         return szDest;
118 }
119
120 /*************************************************************************
121  * PathCombineW          [SHLWAPI.@]
122  */
123 LPWSTR WINAPI PathCombineW(
124         LPWSTR szDest,
125         LPCWSTR lpszDir,
126         LPCWSTR lpszFile) 
127 {
128         WCHAR sTemp[MAX_PATH];
129         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
130                          lpszFile, debugstr_w(lpszFile));
131         
132         
133         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
134         {
135           strcpyW(szDest,lpszDir);
136           return szDest;
137         }
138
139         /*  if lpszFile is a complete path don't care about lpszDir */
140         if (PathGetDriveNumberW(lpszFile) != -1)
141         {
142             strcpyW(szDest,lpszFile);
143         }
144         else if (lpszFile[0] == (WCHAR)'\\' )
145         {
146           strcpyW(sTemp,lpszDir);
147           PathStripToRootW(sTemp);
148           strcatW(sTemp,lpszFile);
149           strcpyW(szDest,sTemp);
150         }
151         else
152         {
153           strcpyW(sTemp,lpszDir);
154           PathAddBackslashW(sTemp);
155           strcatW(sTemp,lpszFile);
156           strcpyW(szDest,sTemp);
157         }
158         return szDest;
159 }
160
161 /*************************************************************************
162  * PathCombineAW         [SHELL32.37]
163  */
164 LPVOID WINAPI PathCombineAW(
165         LPVOID szDest,
166         LPCVOID lpszDir,
167         LPCVOID lpszFile) 
168 {
169         if (VERSION_OsIsUnicode())
170           return PathCombineW( szDest, lpszDir, lpszFile );
171         return PathCombineA( szDest, lpszDir, lpszFile );
172 }
173
174 /*************************************************************************
175  * PathAddBackslashA    [SHLWAPI.@]
176  *
177  * NOTES
178  *     append \ if there is none
179  */
180 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
181 {
182         int len;
183         TRACE("%p->%s\n",lpszPath,lpszPath);
184
185         len = strlen(lpszPath);
186         if (len && lpszPath[len-1]!='\\') 
187         {
188           lpszPath[len]  = '\\';
189           lpszPath[len+1]= 0x00;
190           return lpszPath+len+1;
191         }
192         return lpszPath+len;
193 }
194
195 /*************************************************************************
196  * PathAddBackslashW    [SHLWAPI.@]
197  */
198 LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
199 {
200         int len;
201         TRACE("%p->%s\n",lpszPath,debugstr_w(lpszPath));
202
203         len = strlenW(lpszPath);
204         if (len && lpszPath[len-1]!=(WCHAR)'\\') 
205         {
206           lpszPath[len]  = (WCHAR)'\\';
207           lpszPath[len+1]= 0x00;
208           return lpszPath+len+1;
209         }
210         return lpszPath+len;
211 }
212
213 /*************************************************************************
214  * PathAddBackslashAW           [SHELL32.32]
215  */
216 LPVOID WINAPI PathAddBackslashAW(LPVOID lpszPath)
217 {
218         if(VERSION_OsIsUnicode())
219           return PathAddBackslashW(lpszPath);
220         return PathAddBackslashA(lpszPath);
221 }
222
223 /*************************************************************************
224  * PathBuildRootA               [SHLWAPI.@]
225  */
226 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 
227 {
228         TRACE("%p %i\n",lpszPath, drive);
229
230         strcpy(lpszPath,"A:\\");
231         lpszPath[0]+=drive;
232         return lpszPath;
233 }
234
235 /*************************************************************************
236  * PathBuildRootW               [SHLWAPI.@]
237  */
238 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 
239 {
240         TRACE("%p %i\n",debugstr_w(lpszPath), drive);
241
242         lstrcpyAtoW(lpszPath,"A:\\");
243         lpszPath[0]+=drive;
244         return lpszPath;
245 }
246
247 /*************************************************************************
248  * PathBuildRootAW              [SHELL32.30]
249  */
250 LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive)
251 {
252         if(VERSION_OsIsUnicode())
253           return PathBuildRootW(lpszPath, drive);
254         return PathBuildRootA(lpszPath, drive);
255 }
256
257 /*
258         Extracting Component Parts
259 */
260
261 /*************************************************************************
262  * PathFindFileNameA    [SHLWAPI.@]
263  */
264 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
265 {
266         LPCSTR lastSlash = lpszPath;
267
268         TRACE("%s\n",lpszPath);
269         while (*lpszPath) 
270         {
271           if ( isSlash(lpszPath[0]) && lpszPath[1])
272               lastSlash = lpszPath+1;
273           lpszPath = CharNextA(lpszPath);
274         }
275         return (LPSTR)lastSlash;
276
277 }
278
279 /*************************************************************************
280  * PathFindFileNameW    [SHLWAPI.@]
281  */
282 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
283 {
284         LPCWSTR wslash;
285         wslash = lpszPath;
286
287         TRACE("%s\n",debugstr_w(wslash));
288         while (lpszPath[0]) 
289         {
290           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
291             wslash = lpszPath+1;
292           lpszPath = CharNextW(lpszPath);
293         }
294         return (LPWSTR)wslash;  
295 }
296
297 /*************************************************************************
298  * PathFindFileNameAW   [SHELL32.34]
299  */
300 LPVOID WINAPI PathFindFileNameAW(LPCVOID lpszPath)
301 {
302         if(VERSION_OsIsUnicode())
303           return PathFindFileNameW(lpszPath);
304         return PathFindFileNameA(lpszPath);
305 }
306
307 /*************************************************************************
308  * PathFindExtensionA   [SHLWAPI.@]
309  *
310  * NOTES
311  *     returns pointer to last . in last lpszPath component or at \0.
312  */
313
314 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath) 
315 {
316         LPCSTR   lastpoint = NULL;
317
318         TRACE("%p %s\n",lpszPath,lpszPath);
319
320         while (*lpszPath) 
321         {
322           if (*lpszPath=='\\'||*lpszPath==' ')
323             lastpoint=NULL;
324           if (*lpszPath=='.')
325             lastpoint=lpszPath;
326           lpszPath = CharNextA(lpszPath);
327         }
328         return (LPSTR)(lastpoint?lastpoint:lpszPath);
329 }
330
331 /*************************************************************************
332  * PathFindExtensionW   [SHLWAPI.@]
333  */
334 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath) 
335 {
336         LPCWSTR   lastpoint = NULL;
337
338         TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath));
339
340         while (*lpszPath)
341         {
342           if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ')
343             lastpoint=NULL;
344           if (*lpszPath==(WCHAR)'.')
345             lastpoint=lpszPath;
346           lpszPath = CharNextW(lpszPath);
347         }
348         return (LPWSTR)(lastpoint?lastpoint:lpszPath);
349 }
350
351 /*************************************************************************
352  * PathFindExtensionAW          [SHELL32.31]
353  */
354 LPVOID WINAPI PathFindExtensionAW(LPCVOID lpszPath) 
355 {
356         if (VERSION_OsIsUnicode())
357           return PathFindExtensionW(lpszPath);
358         return PathFindExtensionA(lpszPath);
359
360 }
361
362 /*************************************************************************
363  * PathGetExtensionA            [internal]
364  *
365  * NOTES
366  *  exported by ordinal
367  *  return value points to the first char after the dot
368  */
369 LPSTR WINAPI PathGetExtensionA(LPCSTR lpszPath)
370 {
371         TRACE("(%s)\n",lpszPath);
372
373         lpszPath = PathFindExtensionA(lpszPath);
374         return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath);
375 }
376
377 /*************************************************************************
378  * PathGetExtensionW            [internal]
379  */
380 LPWSTR WINAPI PathGetExtensionW(LPCWSTR lpszPath)
381 {
382         TRACE("(%s)\n",debugstr_w(lpszPath));
383
384         lpszPath = PathFindExtensionW(lpszPath);
385         return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath);
386 }
387
388 /*************************************************************************
389  * PathGetExtensionAW           [SHELL32.158]
390  */
391 LPVOID WINAPI PathGetExtensionAW(LPCVOID lpszPath) 
392 {
393         if (VERSION_OsIsUnicode())
394           return PathGetExtensionW(lpszPath);
395         return PathGetExtensionA(lpszPath);
396 }
397
398 /*************************************************************************
399  * PathGetArgsA         [SHLWAPI.@]
400  *
401  * NOTES
402  *     look for next arg in string. handle "quoted" strings
403  *     returns pointer to argument *AFTER* the space. Or to the \0.
404  *
405  * FIXME
406  *     quoting by '\'
407  */
408 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 
409 {
410         BOOL    qflag = FALSE;
411
412         TRACE("%s\n",lpszPath);
413
414         while (*lpszPath) 
415         {
416           if ((*lpszPath==' ') && !qflag)
417             return (LPSTR)lpszPath+1;
418           if (*lpszPath=='"')
419             qflag=!qflag;
420           lpszPath = CharNextA(lpszPath);
421         }
422         return (LPSTR)lpszPath;
423 }
424
425 /*************************************************************************
426  * PathGetArgsW         [SHLWAPI.@]
427  */
428 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 
429 {
430         BOOL    qflag = FALSE;
431
432         TRACE("%s\n",debugstr_w(lpszPath));
433
434         while (*lpszPath) 
435         {
436           if ((*lpszPath==' ') && !qflag)
437             return (LPWSTR)lpszPath+1;
438           if (*lpszPath=='"')
439             qflag=!qflag;
440           lpszPath = CharNextW(lpszPath);
441         }
442         return (LPWSTR)lpszPath;
443 }
444
445 /*************************************************************************
446  * PathGetArgsAW        [SHELL32.52]
447  */
448 LPVOID WINAPI PathGetArgsAW(LPVOID lpszPath) 
449 {
450         if (VERSION_OsIsUnicode())
451           return PathGetArgsW(lpszPath);
452         return PathGetArgsA(lpszPath);
453 }
454
455 /*************************************************************************
456  * PathGetDriveNumberA  [SHLWAPI.@]
457  */
458 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
459 {
460         int chr = tolower(lpszPath[0]);
461         
462         TRACE ("%s\n",debugstr_a(lpszPath));
463
464         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
465         return tolower(lpszPath[0]) - 'a' ;
466 }
467
468 /*************************************************************************
469  * PathGetDriveNumberW  [SHLWAPI.@]
470  */
471 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
472 {
473         int chr = tolowerW(lpszPath[0]);
474         
475         TRACE ("%s\n",debugstr_w(lpszPath));
476
477         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
478         return tolowerW(lpszPath[0]) - 'a' ;
479 }
480
481 /*************************************************************************
482  * PathGetDriveNumber   [SHELL32.57]
483  */
484 int WINAPI PathGetDriveNumberAW(LPVOID lpszPath) 
485 {
486         if (VERSION_OsIsUnicode())
487           return PathGetDriveNumberW(lpszPath);
488         return PathGetDriveNumberA(lpszPath);
489 }
490
491 /*************************************************************************
492  * PathRemoveFileSpecA  [SHLWAPI.@]
493  * 
494  * NOTES
495  *     truncates passed argument to a valid path
496  *     returns if the string was modified or not.
497  *     "\foo\xx\foo"-> "\foo\xx"
498  *     "\" -> "\"
499  *     "a:\foo" -> "a:\"
500  */
501 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
502 {
503         LPSTR cutplace = lpszPath;
504         BOOL ret = FALSE;
505         
506         TRACE("%s\n",lpszPath);
507
508         if(lpszPath)
509         {
510           while (*lpszPath == '\\') cutplace = ++lpszPath;
511           
512           while (*lpszPath)
513           {
514             if(lpszPath[0] == '\\') cutplace = lpszPath;
515           
516             if(lpszPath[0] == ':')
517             {
518               cutplace = lpszPath + 1;
519               if (lpszPath[1] == '\\') cutplace++;
520               lpszPath++;
521             }
522             lpszPath = CharNextA(lpszPath);
523             if (!lpszPath) break;
524           }
525           
526           ret = (*cutplace!='\0');
527           *cutplace = '\0';
528         }
529         return ret;
530 }
531
532 /*************************************************************************
533  * PathRemoveFileSpecW  [SHLWAPI.@]
534  */
535 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
536 {
537         LPWSTR cutplace = lpszPath;
538         BOOL ret = FALSE;
539
540         TRACE("%s\n",debugstr_w(lpszPath));
541
542         if(lpszPath)
543         {
544           while (*lpszPath == '\\') cutplace = ++lpszPath;
545           
546           while (*lpszPath)
547           {
548             if(lpszPath[0] == '\\') cutplace = lpszPath;
549           
550             if(lpszPath[0] == ':')
551             {
552               cutplace = lpszPath + 1;
553               if (lpszPath[1] == '\\') cutplace++;
554               lpszPath++;
555             }
556             lpszPath = CharNextW(lpszPath);
557             if (!lpszPath) break;
558           }
559           
560           ret = (*cutplace!='\0');
561           *cutplace = '\0';
562         }
563         return ret;
564 }
565
566 /*************************************************************************
567  * PathRemoveFileSpec [SHELL32.35]
568  */
569 BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath) 
570 {
571         if (VERSION_OsIsUnicode())
572           return PathRemoveFileSpecW(lpszPath);
573         return PathRemoveFileSpecA(lpszPath);
574 }
575
576 /*************************************************************************
577  * PathStripPathA       [SHELLWAPI.@]
578  * 
579  * NOTES
580  *  removes the path from the beginning of a filename
581  */
582 void WINAPI PathStripPathA(LPSTR lpszPath)
583 {
584         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
585
586         TRACE("%s\n", lpszPath);
587
588         if(lpszFileName)
589           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 
590 }
591
592 /*************************************************************************
593  * PathStripPathW       [SHELLWAPI.@]
594  */
595 void WINAPI PathStripPathW(LPWSTR lpszPath)
596 {
597         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
598
599         TRACE("%s\n", debugstr_w(lpszPath));
600         if(lpszFileName)
601           RtlMoveMemory(lpszPath, lpszFileName, (lstrlenW(lpszFileName)+1)*sizeof(WCHAR)); 
602 }
603
604 /*************************************************************************
605  * PathStripPathAW      [SHELL32.38]
606  */
607 void WINAPI PathStripPathAW(LPVOID lpszPath) 
608 {
609         if (VERSION_OsIsUnicode())
610           return PathStripPathW(lpszPath);
611         return PathStripPathA(lpszPath);
612 }
613
614 /*************************************************************************
615  * PathStripToRootA     [SHLWAPI.@]
616  */
617 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
618 {
619         TRACE("%s\n", lpszPath);
620
621         if (!lpszPath) return FALSE;
622         while(!PathIsRootA(lpszPath))
623           if (!PathRemoveFileSpecA(lpszPath)) return FALSE;
624         return TRUE;
625 }
626
627 /*************************************************************************
628  * PathStripToRootW     [SHLWAPI.@]
629  */
630 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
631 {
632         TRACE("%s\n", debugstr_w(lpszPath));
633
634         if (!lpszPath) return FALSE;
635         while(!PathIsRootW(lpszPath))
636           if (!PathRemoveFileSpecW(lpszPath)) return FALSE;
637         return TRUE;
638 }
639
640 /*************************************************************************
641  * PathStripToRootAW    [SHELL32.50]
642  */
643 BOOL WINAPI PathStripToRootAW(LPVOID lpszPath) 
644 {
645         if (VERSION_OsIsUnicode())
646           return PathStripToRootW(lpszPath);
647         return PathStripToRootA(lpszPath);
648 }
649
650 /*************************************************************************
651  * PathRemoveArgsA      [SHLWAPI.@]
652  *
653  */
654 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
655 {
656         TRACE("%s\n",lpszPath);
657         
658         if(lpszPath)
659         {
660           LPSTR lpszArgs = PathGetArgsA(lpszPath);
661           if (!*lpszArgs)
662           {
663             LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
664             if(*lpszLastChar==' ') *lpszLastChar = '\0';
665           }
666         }
667 }
668
669 /*************************************************************************
670  * PathRemoveArgsW      [SHLWAPI.@]
671  */
672 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
673 {
674         TRACE("%s\n", debugstr_w(lpszPath));
675
676         if(lpszPath)
677         {
678           LPWSTR lpszArgs = PathGetArgsW(lpszPath);
679           if (!*lpszArgs)
680           {
681             LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs);
682             if(*lpszLastChar==' ') *lpszLastChar = '\0';
683           }
684         }
685 }
686
687 /*************************************************************************
688  * PathRemoveArgsAW     [SHELL32.251]
689  */
690 void WINAPI PathRemoveArgsAW(LPVOID lpszPath) 
691 {
692         if (VERSION_OsIsUnicode())
693           PathRemoveArgsW(lpszPath);
694         PathRemoveArgsA(lpszPath);
695 }
696
697 /*************************************************************************
698  * PathRemoveExtensionA         [SHLWAPI.@]
699  */
700 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
701 {
702         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
703
704         TRACE("%s\n", lpszPath);
705
706         if (lpszExtension) *lpszExtension='\0';
707 }
708
709 /*************************************************************************
710  * PathRemoveExtensionW         [SHLWAPI.@]
711  */
712 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
713 {
714         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
715
716         TRACE("%s\n", debugstr_w(lpszPath));
717
718         if (lpszExtension) *lpszExtension='\0';
719 }
720
721 /*************************************************************************
722  * PathRemoveExtensionAW        [SHELL32.250]
723  */
724 void WINAPI PathRemoveExtensionAW(LPVOID lpszPath) 
725 {
726         if (VERSION_OsIsUnicode())
727           return PathRemoveExtensionW(lpszPath);
728         return PathRemoveExtensionA(lpszPath);
729 }
730
731 /*************************************************************************
732  * PathRemoveBackslashA [SHLWAPI.@]
733  *
734  * If the path ends in a backslash it is replaced by a NULL
735  * and the address of the NULL is returned
736  * Otherwise 
737  * the address of the last character is returned.
738  *
739  * FIXME
740  *  "c:\": keep backslash
741  */
742 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
743 {
744         int len;
745         LPSTR szTemp = NULL;
746         
747         if(lpszPath)
748         {
749           len = strlen(lpszPath);
750           szTemp = CharPrevA(lpszPath, lpszPath+len);
751           if (! PathIsRootA(lpszPath))
752           {
753             if (*szTemp == '\\') *szTemp = '\0';
754           }
755         }
756         return szTemp;
757 }
758
759 /*************************************************************************
760  * PathRemoveBackslashW [SHLWAPI.@]
761  */
762 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
763 {
764         int len;
765         LPWSTR szTemp = NULL;
766         
767         if(lpszPath)
768         {
769           len = lstrlenW(lpszPath);
770           szTemp = CharPrevW(lpszPath, lpszPath+len);
771           if (! PathIsRootW(lpszPath))
772           {
773             if (*szTemp == '\\') *szTemp = '\0';
774           }
775         }
776         return szTemp;
777 }
778
779 /*
780         Path Manipulations
781 */
782
783 /*************************************************************************
784  * PathGetShortPathA [internal]
785  */
786 LPSTR WINAPI PathGetShortPathA(LPSTR lpszPath)
787 {
788         FIXME("%s stub\n", lpszPath);
789         return NULL;
790 }
791
792 /*************************************************************************
793  * PathGetShortPathW [internal]
794  */
795 LPWSTR WINAPI PathGetShortPathW(LPWSTR lpszPath)
796 {
797         FIXME("%s stub\n", debugstr_w(lpszPath));
798         return NULL;
799 }
800
801 /*************************************************************************
802  * PathGetShortPathAW [SHELL32.92]
803  */
804 LPVOID WINAPI PathGetShortPathAW(LPVOID lpszPath)
805 {
806         if(VERSION_OsIsUnicode())
807           return PathGetShortPathW(lpszPath);
808         return PathGetShortPathA(lpszPath);
809 }
810
811 /*************************************************************************
812  * PathRemoveBlanksA [SHLWAPI.@]
813  * 
814  * NOTES
815  *     remove spaces from beginning and end of passed string
816  */
817 void WINAPI PathRemoveBlanksA(LPSTR str)
818 {
819         LPSTR x = str;
820
821         TRACE("%s\n",str);
822
823         if(str)
824         {
825           while (*x==' ') x = CharNextA(x);
826           if (x!=str) strcpy(str,x);
827           x=str+strlen(str)-1;
828           while (*x==' ') x = CharPrevA(str, x);
829           if (*x==' ') *x='\0';
830         }
831 }
832
833 /*************************************************************************
834  * PathRemoveBlanksW [SHLWAPI.@]
835  */
836 void WINAPI PathRemoveBlanksW(LPWSTR str)
837 {
838         LPWSTR x = str;
839
840         TRACE("%s\n",debugstr_w(str));
841
842         if(str)
843         {
844           while (*x==' ') x = CharNextW(x);
845           if (x!=str) lstrcpyW(str,x);
846           x=str+lstrlenW(str)-1;
847           while (*x==' ') x = CharPrevW(str, x);
848           if (*x==' ') *x='\0';
849         }
850 }
851
852 /*************************************************************************
853  * PathRemoveBlanksAW [SHELL32.33]
854  */
855 void WINAPI PathRemoveBlanksAW(LPVOID str)
856 {
857         if(VERSION_OsIsUnicode())
858           PathRemoveBlanksW(str);
859         PathRemoveBlanksA(str);
860 }
861
862 /*************************************************************************
863  * PathQuoteSpacesA [SHLWAPI.@]
864  * 
865  */
866 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath)
867 {
868         TRACE("%s\n",lpszPath);
869
870         if(StrChrA(lpszPath,' '))
871         {
872           int len = strlen(lpszPath);
873           RtlMoveMemory(lpszPath+1, lpszPath, len);
874           *(lpszPath++) = '"';
875           lpszPath += len;
876           *(lpszPath++) = '"';
877           *(lpszPath) = '\0';
878           return --lpszPath;
879         }
880         return 0;
881 }
882
883 /*************************************************************************
884  * PathQuoteSpacesW [SHLWAPI.@]
885  */
886 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
887 {
888         TRACE("%s\n",debugstr_w(lpszPath));
889
890         if(StrChrW(lpszPath,' '))
891         {
892           int len = lstrlenW(lpszPath);
893           RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR));
894           *(lpszPath++) = '"';
895           lpszPath += len;
896           *(lpszPath++) = '"';
897           *(lpszPath) = '\0';
898           return --lpszPath;
899         }
900         return 0;
901 }
902
903 /*************************************************************************
904  * PathQuoteSpacesAW [SHELL32.55]
905  */
906 LPVOID WINAPI PathQuoteSpacesAW (LPVOID lpszPath)
907 {
908         if(VERSION_OsIsUnicode())
909           return PathQuoteSpacesW(lpszPath);
910         return PathQuoteSpacesA(lpszPath);
911 }
912
913 /*************************************************************************
914  * PathUnquoteSpacesA [SHLWAPI.@]
915  * 
916  * NOTES
917  *     unquote string (remove ")
918  */
919 VOID WINAPI PathUnquoteSpacesA(LPSTR str) 
920 {
921         DWORD len = lstrlenA(str);
922
923         TRACE("%s\n",str);
924
925         if (*str!='"')
926           return;
927         if (str[len-1]!='"')
928           return;
929         str[len-1]='\0';
930         lstrcpyA(str,str+1);
931         return;
932 }
933
934 /*************************************************************************
935  * PathUnquoteSpacesW [SHLWAPI.@]
936  */
937 VOID WINAPI PathUnquoteSpacesW(LPWSTR str) 
938 {
939         DWORD len = strlenW(str);
940
941         TRACE("%s\n",debugstr_w(str));
942
943         if (*str!='"')
944           return;
945         if (str[len-1]!='"')
946           return;
947         str[len-1]='\0';
948         strcpyW(str,str+1);
949         return;
950 }
951
952 /*************************************************************************
953  * PathUnquoteSpacesAW [SHELL32.56]
954  */
955 VOID WINAPI PathUnquoteSpacesAW(LPVOID str) 
956 {
957         if(VERSION_OsIsUnicode())
958           PathUnquoteSpacesW(str);
959         else
960           PathUnquoteSpacesA(str);
961 }
962
963 /*************************************************************************
964  * PathParseIconLocationA       [SHLWAPI.@]
965  */
966 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
967 {
968         LPSTR lpstrComma = strchr(lpszPath, ',');
969         
970         FIXME("%s stub\n", debugstr_a(lpszPath));
971
972         if (lpstrComma && lpstrComma[1])
973         {
974           lpstrComma[0]='\0';
975 /*        return atoi(&lpstrComma[1]);  FIXME */
976         }
977         
978         PathUnquoteSpacesA(lpszPath);
979         return 0;
980 }
981
982 /*************************************************************************
983  * PathParseIconLocationW       [SHLWAPI.@]
984  */
985 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
986 {
987         LPWSTR lpstrComma = strchrW(lpszPath, ',');
988         
989         FIXME("%s stub\n", debugstr_w(lpszPath));
990
991         if (lpstrComma && lpstrComma[1])
992         {
993           lpstrComma[0]='\0';
994 /*        return _wtoi(&lpstrComma[1]); FIXME */
995         }
996         PathUnquoteSpacesW(lpszPath);
997         return 0;
998 }
999
1000 /*************************************************************************
1001  * PathParseIconLocationAW      [SHELL32.249]
1002  */
1003 int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
1004 {
1005         if(VERSION_OsIsUnicode())
1006           return PathParseIconLocationW(lpszPath);
1007         return PathParseIconLocationA(lpszPath);
1008 }
1009
1010 /*
1011         ########## Path Testing ##########
1012 */
1013 /*************************************************************************
1014  * PathIsUNCA           [SHLWAPI.@]
1015  * 
1016  * NOTES
1017  *     PathIsUNC(char*path);
1018  */
1019 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 
1020 {
1021         TRACE("%s\n",lpszPath);
1022
1023         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
1024 }
1025
1026 /*************************************************************************
1027  * PathIsUNCW           [SHLWAPI.@]
1028  */
1029 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 
1030 {
1031         TRACE("%s\n",debugstr_w(lpszPath));
1032
1033         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
1034 }
1035
1036 /*************************************************************************
1037  * PathIsUNCAW          [SHELL32.39]
1038  */
1039 BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
1040 {
1041         if (VERSION_OsIsUnicode())
1042           return PathIsUNCW( lpszPath );
1043         return PathIsUNCA( lpszPath );  
1044 }
1045
1046 /*************************************************************************
1047  *  PathIsRelativeA     [SHLWAPI.@]
1048  */
1049 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
1050 {
1051         TRACE("lpszPath=%s\n",lpszPath);
1052
1053         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
1054 }
1055
1056 /*************************************************************************
1057  *  PathIsRelativeW     [SHLWAPI.@]
1058  */
1059 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
1060 {
1061         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
1062
1063         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
1064 }
1065
1066 /*************************************************************************
1067  *  PathIsRelativeAW    [SHELL32.40]
1068  */
1069 BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
1070 {
1071         if (VERSION_OsIsUnicode())
1072           return PathIsRelativeW( lpszPath );
1073         return PathIsRelativeA( lpszPath );  
1074 }
1075
1076 /*************************************************************************
1077  * PathIsRootA          [SHLWAPI.@]
1078  *
1079  * notes
1080  *  TRUE if the path points to a root directory
1081  */
1082 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
1083 {
1084         TRACE("%s\n",lpszPath);
1085
1086         /* X:\ */
1087         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
1088           return TRUE;
1089
1090         /* "\" */
1091         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
1092           return TRUE;
1093
1094         /* UNC "\\<computer>\<share>" */
1095         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1096         {
1097           int foundbackslash = 0;
1098           lpszPath += 2;
1099           while (*lpszPath)
1100           {
1101             if (*lpszPath=='\\') foundbackslash++;
1102             lpszPath = CharNextA(lpszPath);
1103           }
1104           if (foundbackslash <= 1)
1105             return TRUE;
1106         }
1107         return FALSE;
1108 }
1109
1110 /*************************************************************************
1111  * PathIsRootW          [SHLWAPI.@]
1112  */
1113 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 
1114 {
1115         TRACE("%s\n",debugstr_w(lpszPath));
1116
1117         /* X:\ */
1118         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
1119           return TRUE;
1120
1121         /* "\" */
1122         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
1123           return TRUE;
1124
1125         /* UNC "\\<computer>\<share>" */
1126         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
1127         {
1128           int foundbackslash = 0;
1129           lpszPath += 2;
1130           while (*lpszPath)
1131           {
1132             if (*lpszPath=='\\') foundbackslash++;
1133             lpszPath = CharNextW(lpszPath);
1134           }
1135           if (foundbackslash <= 1)
1136             return TRUE;
1137         }
1138         return FALSE;
1139
1140 }
1141
1142 /*************************************************************************
1143  * PathIsRootAW         [SHELL32.29]
1144  */
1145 BOOL WINAPI PathIsRootAW(LPCVOID lpszPath) 
1146 {
1147         if (VERSION_OsIsUnicode())
1148           return PathIsRootW(lpszPath);
1149         return PathIsRootA(lpszPath);
1150 }
1151
1152 /*************************************************************************
1153  *  PathIsExeA          [internal]
1154  */
1155 BOOL WINAPI PathIsExeA (LPCSTR lpszPath)
1156 {
1157         LPCSTR lpszExtension = PathGetExtensionA(lpszPath);
1158         int i = 0;
1159         static char * lpszExtensions[6] = {"exe", "com", "pid", "cmd", "bat", NULL };
1160         
1161         TRACE("path=%s\n",lpszPath);
1162
1163         for(i=0; lpszExtensions[i]; i++)
1164           if (!strcasecmp(lpszExtension,lpszExtensions[i])) return TRUE;
1165           
1166         return FALSE;
1167 }
1168
1169 /*************************************************************************
1170  *  PathIsExeW          [internal]
1171  */
1172 BOOL WINAPI PathIsExeW (LPCWSTR lpszPath)
1173 {
1174         LPCWSTR lpszExtension = PathGetExtensionW(lpszPath);
1175         int i = 0;
1176         static WCHAR lpszExtensions[6][4] =
1177           {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','d','\0'},
1178            {'c','m','d','\0'}, {'b','a','t','\0'}, {'\0'} };
1179         
1180         TRACE("path=%s\n",debugstr_w(lpszPath));
1181
1182         for(i=0; lpszExtensions[i]; i++)
1183           if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE;
1184           
1185         return FALSE;
1186 }
1187
1188 /*************************************************************************
1189  *  PathIsExeAW         [SHELL32.43]
1190  */
1191 BOOL WINAPI PathIsExeAW (LPCVOID path)
1192 {
1193         if (VERSION_OsIsUnicode())
1194           return PathIsExeW (path);
1195         return PathIsExeA(path);
1196 }
1197
1198 /*************************************************************************
1199  * PathIsDirectoryA     [SHLWAPI.@]
1200  */
1201 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
1202 {
1203         DWORD dwAttr;
1204
1205         TRACE("%s\n", debugstr_a(lpszPath));
1206
1207         dwAttr = GetFileAttributesA(lpszPath);
1208         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
1209 }
1210
1211 /*************************************************************************
1212  * PathIsDirectoryW     [SHLWAPI.@]
1213  */
1214 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
1215 {
1216         DWORD dwAttr;
1217         
1218         TRACE("%s\n", debugstr_w(lpszPath));
1219
1220         dwAttr = GetFileAttributesW(lpszPath);
1221         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
1222 }
1223
1224 /*************************************************************************
1225  * PathIsDirectoryAW    [SHELL32.159]
1226  */
1227 BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
1228 {
1229         if (VERSION_OsIsUnicode())
1230           return PathIsDirectoryW (lpszPath);
1231         return PathIsDirectoryA (lpszPath);
1232 }
1233
1234 /*************************************************************************
1235  * PathFileExistsA      [SHLWAPI.@]
1236  * 
1237  * NOTES
1238  *     file_exists(char *fn);
1239  */
1240 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 
1241 {
1242         TRACE("%s\n",lpszPath);
1243         return  (GetFileAttributesA(lpszPath)!=-1);
1244 }
1245
1246 /*************************************************************************
1247  * PathFileExistsW      [SHLWAPI.@]
1248  */
1249 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 
1250 {
1251         TRACE("%s\n",debugstr_w(lpszPath));
1252         return  (GetFileAttributesW(lpszPath)!=-1);
1253 }
1254
1255 /*************************************************************************
1256  * PathFileExistsAW     [SHELL32.45]
1257  */ 
1258 BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
1259 {
1260         if (VERSION_OsIsUnicode())
1261           return PathFileExistsW (lpszPath);
1262         return PathFileExistsA (lpszPath);
1263 }
1264
1265 /*************************************************************************
1266  * PathMatchSingleMaskA [internal]
1267  * 
1268  * NOTES
1269  *     internal (used by PathMatchSpec)
1270  */
1271 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
1272 {
1273         while (*name && *mask && *mask!=';') 
1274         {
1275           if (*mask=='*') 
1276           {
1277             do 
1278             {
1279               if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
1280             } while (*name++);
1281             return 0;
1282           }
1283           if (toupper(*mask)!=toupper(*name) && *mask!='?') return 0;
1284           name = CharNextA(name);
1285           mask = CharNextA(mask);
1286         }
1287         if (!*name) 
1288         {
1289           while (*mask=='*') mask++;
1290           if (!*mask || *mask==';') return 1;
1291         }
1292         return 0;
1293 }
1294
1295 /*************************************************************************
1296  * PathMatchSingleMaskW [internal]
1297  */
1298 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
1299 {
1300         while (*name && *mask && *mask!=';') 
1301         {
1302           if (*mask=='*') 
1303           {
1304             do 
1305             {
1306               if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
1307             } while (*name++);
1308             return 0;
1309           }
1310           if (toupperW(*mask)!=toupperW(*name) && *mask!='?') return 0;
1311           name = CharNextW(name);
1312           mask = CharNextW(mask);
1313         }
1314         if (!*name) 
1315         {
1316           while (*mask=='*') mask++;
1317           if (!*mask || *mask==';') return 1;
1318         }
1319         return 0;
1320 }
1321 /*************************************************************************
1322  * PathMatchSpecA       [SHLWAPI.@]
1323  * 
1324  * NOTES
1325  *     used from COMDLG32
1326  */
1327 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask) 
1328 {
1329         TRACE("%s %s\n",name,mask);
1330
1331         if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
1332
1333         while (*mask) 
1334         {
1335           if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
1336           while (*mask && *mask!=';') mask = CharNextA(mask);
1337           if (*mask==';') 
1338           {
1339             mask++;
1340             while (*mask==' ') mask++;      /*  masks may be separated by "; " */
1341           }
1342         }
1343         return 0;
1344 }
1345
1346 /*************************************************************************
1347  * PathMatchSpecW       [SHLWAPI.@]
1348  */
1349 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask) 
1350 {
1351         WCHAR stemp[4];
1352         TRACE("%s %s\n",debugstr_w(name),debugstr_w(mask));
1353
1354         lstrcpyAtoW(stemp,"*.*");       
1355         if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
1356
1357         while (*mask) 
1358         {
1359           if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
1360           while (*mask && *mask!=';') mask = CharNextW(mask);
1361           if (*mask==';') 
1362           {
1363             mask++;
1364             while (*mask==' ') mask++;       /* masks may be separated by "; " */
1365           }
1366         }
1367         return 0;
1368 }
1369
1370 /*************************************************************************
1371  * PathMatchSpecAW      [SHELL32.46]
1372  */
1373 BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask) 
1374 {
1375         if (VERSION_OsIsUnicode())
1376           return PathMatchSpecW( name, mask );
1377         return PathMatchSpecA( name, mask );
1378 }
1379
1380 /*************************************************************************
1381  * PathIsSameRootA      [SHLWAPI.@]
1382  *
1383  * FIXME
1384  *  what to do with "\path" ??
1385  */
1386 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
1387 {
1388         TRACE("%s %s\n", lpszPath1, lpszPath2);
1389         
1390         if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE;
1391
1392         /* usual path */
1393         if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) &&
1394              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1395              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1396           return TRUE;
1397
1398         /* UNC */
1399         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1400             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1401         {
1402           int pos=2, bsfound=0;
1403           while (lpszPath1[pos] && lpszPath2[pos] &&
1404                 (lpszPath1[pos] == lpszPath2[pos]))
1405           {
1406             if (lpszPath1[pos]=='\\') bsfound++;
1407             if (bsfound == 2) return TRUE;
1408             pos++; /* fixme: use CharNext*/
1409           }
1410           return (lpszPath1[pos] == lpszPath2[pos]);
1411         }
1412         return FALSE;
1413 }
1414
1415 /*************************************************************************
1416  * PathIsSameRootW      [SHLWAPI.@]
1417  */
1418 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
1419 {
1420         TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
1421         
1422         if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE;
1423
1424         /* usual path */
1425         if ( toupperW(lpszPath1[0])==toupperW(lpszPath2[0]) &&
1426              lpszPath1[1]==':' && lpszPath2[1]==':' &&
1427              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
1428           return TRUE;
1429
1430         /* UNC */
1431         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
1432             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
1433         {
1434           int pos=2, bsfound=0;
1435           while (lpszPath1[pos] && lpszPath2[pos] &&
1436                 (lpszPath1[pos] == lpszPath2[pos]))
1437           {
1438             if (lpszPath1[pos]=='\\') bsfound++;
1439             if (bsfound == 2) return TRUE;
1440             pos++;/* fixme: use CharNext*/
1441           }
1442           return (lpszPath1[pos] == lpszPath2[pos]);
1443         }
1444         return FALSE;
1445 }
1446
1447 /*************************************************************************
1448  * PathIsSameRootAW     [SHELL32.650]
1449  */
1450 BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2)
1451 {
1452         if (VERSION_OsIsUnicode())
1453           return PathIsSameRootW(lpszPath1, lpszPath2);
1454         return PathIsSameRootA(lpszPath1, lpszPath2);
1455 }
1456
1457 /*************************************************************************
1458  * PathIsURLA
1459  */
1460 BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
1461 {
1462         LPSTR lpstrRes;
1463         int iSize, i=0;
1464         static LPSTR SupportedProtocol[] = 
1465           {"http","https","ftp","gopher","file","mailto",NULL};
1466
1467         if(!lpstrPath) return FALSE;
1468
1469         /* get protocol        */
1470         lpstrRes = strchr(lpstrPath,':');
1471         if(!lpstrRes) return FALSE;
1472         iSize = lpstrRes - lpstrPath;
1473
1474         while(SupportedProtocol[i])
1475         {
1476           if (iSize == strlen(SupportedProtocol[i]))
1477             if(!strncasecmp(lpstrPath, SupportedProtocol[i], iSize))
1478               return TRUE;
1479           i++;
1480         }
1481
1482         return FALSE;
1483 }  
1484
1485 /*************************************************************************
1486  * PathIsURLW
1487  */
1488 BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
1489 {
1490         LPWSTR lpstrRes;
1491         int iSize, i=0;
1492         static WCHAR SupportedProtocol[7][7] = 
1493           {{'h','t','t','p','\0'},{'h','t','t','p','s','\0'},{'f','t','p','\0'},
1494           {'g','o','p','h','e','r','\0'},{'f','i','l','e','\0'},
1495           {'m','a','i','l','t','o','\0'},{0}};
1496
1497         if(!lpstrPath) return FALSE;
1498
1499         /* get protocol        */
1500         lpstrRes = strchrW(lpstrPath,':');
1501         if(!lpstrRes) return FALSE;
1502         iSize = lpstrRes - lpstrPath;
1503
1504         while(SupportedProtocol[i])
1505         {
1506           if (iSize == strlenW(SupportedProtocol[i]))
1507             if(!strncmpiW(lpstrPath, SupportedProtocol[i], iSize))
1508               return TRUE;
1509           i++;
1510         }
1511
1512         return FALSE;
1513 }  
1514
1515 /*************************************************************************
1516  * IsLFNDriveA          [SHELL32.119]
1517  * 
1518  * NOTES
1519  *     exported by ordinal Name
1520  */
1521 BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath) 
1522 {
1523     DWORD       fnlen;
1524
1525     if (!GetVolumeInformationA(lpszPath,NULL,0,NULL,&fnlen,NULL,NULL,0))
1526         return FALSE;
1527     return fnlen>12;
1528 }
1529
1530 /*************************************************************************
1531  *      PathIsContentTypeA
1532  */
1533 BOOL WINAPI PathIsContentTypeA(LPCSTR pszPath, LPCSTR pszContentType)
1534 {
1535         FIXME("%s %s\n", pszPath, pszContentType);
1536         return FALSE;
1537 }
1538
1539 /*************************************************************************
1540  *      PathIsContentTypeW
1541  */
1542 BOOL WINAPI PathIsContentTypeW(LPCWSTR pszPath, LPCWSTR pszContentType)
1543 {
1544         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszContentType));
1545         return FALSE;
1546 }
1547
1548 /*************************************************************************
1549  *      PathIsFileSpecA
1550  */
1551 BOOL WINAPI PathIsFileSpecA(LPCSTR pszPath)
1552 {
1553         FIXME("%s\n", pszPath);
1554         return FALSE;
1555 }
1556
1557 /*************************************************************************
1558  *      PathIsFileSpecW
1559  */
1560 BOOL WINAPI PathIsFileSpecW(LPCWSTR pszPath)
1561 {
1562         FIXME("%s\n", debugstr_w(pszPath));
1563         return FALSE;
1564 }
1565
1566 /*************************************************************************
1567  *      PathIsPrefixA
1568  */
1569 BOOL WINAPI PathIsPrefixA(LPCSTR pszPrefix, LPCSTR pszPath)
1570 {
1571         FIXME("%s %s\n", pszPrefix, pszPath);
1572         return FALSE;
1573 }
1574
1575 /*************************************************************************
1576  *      PathIsPrefixW
1577  */
1578 BOOL WINAPI PathIsPrefixW(LPCWSTR pszPrefix, LPCWSTR pszPath)
1579 {
1580         FIXME("%s %s\n", debugstr_w(pszPrefix), debugstr_w(pszPath));
1581         return FALSE;
1582 }
1583
1584 /*************************************************************************
1585  *      PathIsSystemFolderA
1586  */
1587 BOOL WINAPI PathIsSystemFolderA(LPCSTR pszPath, DWORD dwAttrb)
1588 {
1589         FIXME("%s 0x%08lx\n", pszPath, dwAttrb);
1590         return FALSE;
1591 }
1592
1593 /*************************************************************************
1594  *      PathIsSystemFolderW
1595  */
1596 BOOL WINAPI PathIsSystemFolderW(LPCWSTR pszPath, DWORD dwAttrb)
1597 {
1598         FIXME("%s 0x%08lx\n", debugstr_w(pszPath), dwAttrb);
1599         return FALSE;
1600 }
1601
1602 /*************************************************************************
1603  *      PathIsUNCServerA
1604  */
1605 BOOL WINAPI PathIsUNCServerA(
1606         LPCSTR pszPath)
1607 {
1608         FIXME("%s\n", pszPath);
1609         return FALSE;
1610 }
1611
1612 /*************************************************************************
1613  *      PathIsUNCServerW
1614  */
1615 BOOL WINAPI PathIsUNCServerW(
1616         LPCWSTR pszPath)
1617 {
1618         FIXME("%s\n", debugstr_w(pszPath));
1619         return FALSE;
1620 }
1621
1622 /*************************************************************************
1623  *      PathIsUNCServerShareA
1624  */
1625 BOOL WINAPI PathIsUNCServerShareA(
1626         LPCSTR pszPath)
1627 {
1628         FIXME("%s\n", pszPath);
1629         return FALSE;
1630 }
1631
1632 /*************************************************************************
1633  *      PathIsUNCServerShareW
1634  */
1635 BOOL WINAPI PathIsUNCServerShareW(
1636         LPCWSTR pszPath)
1637 {
1638         FIXME("%s\n", debugstr_w(pszPath));
1639         return FALSE;
1640 }
1641
1642 /*
1643         ########## Creating Something Unique ##########
1644 */
1645 /*************************************************************************
1646  * PathMakeUniqueNameA  [internal]
1647  */
1648 BOOL WINAPI PathMakeUniqueNameA(
1649         LPSTR lpszBuffer,
1650         DWORD dwBuffSize, 
1651         LPCSTR lpszShortName,
1652         LPCSTR lpszLongName,
1653         LPCSTR lpszPathName)
1654 {
1655         FIXME("%p %lu %s %s %s stub\n",
1656          lpszBuffer, dwBuffSize, debugstr_a(lpszShortName),
1657          debugstr_a(lpszLongName), debugstr_a(lpszPathName));
1658         return TRUE;
1659 }
1660
1661 /*************************************************************************
1662  * PathMakeUniqueNameW  [internal]
1663  */
1664 BOOL WINAPI PathMakeUniqueNameW(
1665         LPWSTR lpszBuffer,
1666         DWORD dwBuffSize, 
1667         LPCWSTR lpszShortName,
1668         LPCWSTR lpszLongName,
1669         LPCWSTR lpszPathName)
1670 {
1671         FIXME("%p %lu %s %s %s stub\n",
1672          lpszBuffer, dwBuffSize, debugstr_w(lpszShortName),
1673          debugstr_w(lpszLongName), debugstr_w(lpszPathName));
1674         return TRUE;
1675 }
1676
1677 /*************************************************************************
1678  * PathMakeUniqueNameAW [SHELL32.47]
1679  */
1680 BOOL WINAPI PathMakeUniqueNameAW(
1681         LPVOID lpszBuffer,
1682         DWORD dwBuffSize, 
1683         LPCVOID lpszShortName,
1684         LPCVOID lpszLongName,
1685         LPCVOID lpszPathName)
1686 {
1687         if (VERSION_OsIsUnicode())
1688           return PathMakeUniqueNameW(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
1689         return PathMakeUniqueNameA(lpszBuffer,dwBuffSize, lpszShortName,lpszLongName,lpszPathName);
1690 }
1691
1692 /*************************************************************************
1693  * PathYetAnotherMakeUniqueNameA [SHELL32.75]
1694  * 
1695  * NOTES
1696  *     exported by ordinal
1697  */
1698 BOOL WINAPI PathYetAnotherMakeUniqueNameA(
1699         LPSTR lpszBuffer,
1700         LPCSTR lpszPathName,
1701         LPCSTR lpszShortName,
1702         LPCSTR lpszLongName)
1703 {
1704     FIXME("(%p,%p, %p ,%p):stub.\n",
1705      lpszBuffer, lpszPathName, lpszShortName, lpszLongName);
1706     return TRUE;
1707 }
1708
1709
1710 /*
1711         ########## cleaning and resolving paths ##########
1712  */
1713
1714 /*************************************************************************
1715  * PathFindOnPathA      [SHELL32.145]
1716  */
1717 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR sOtherDirs)
1718 {
1719         FIXME("%s %s\n",sFile, sOtherDirs);
1720         return FALSE;
1721 }
1722
1723 /*************************************************************************
1724  * PathFindOnPathW      [SHELL32]
1725  */
1726 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR sOtherDirs)
1727 {
1728         FIXME("%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
1729         return FALSE;
1730 }
1731
1732 /*************************************************************************
1733  * PathFindOnPathAW     [SHELL32]
1734  */
1735 BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID sOtherDirs)
1736 {
1737         if (VERSION_OsIsUnicode())
1738           return PathFindOnPathW(sFile, sOtherDirs);
1739         return PathFindOnPathA(sFile, sOtherDirs);
1740 }
1741
1742 /*************************************************************************
1743  * PathCleanupSpecA     [SHELL32.171]
1744  */
1745 DWORD WINAPI PathCleanupSpecA(LPSTR x, LPSTR y)
1746 {
1747         FIXME("(%p %s, %p %s) stub\n",x,debugstr_a(x),y,debugstr_a(y));
1748         return TRUE;
1749 }
1750
1751 /*************************************************************************
1752  * PathCleanupSpecA     [SHELL32]
1753  */
1754 DWORD WINAPI PathCleanupSpecW(LPWSTR x, LPWSTR y)
1755 {
1756         FIXME("(%p %s, %p %s) stub\n",x,debugstr_w(x),y,debugstr_w(y));
1757         return TRUE;
1758 }
1759
1760 /*************************************************************************
1761  * PathCleanupSpecAW    [SHELL32]
1762  */
1763 DWORD WINAPI PathCleanupSpecAW (LPVOID x, LPVOID y)
1764 {
1765         if (VERSION_OsIsUnicode())
1766           return PathCleanupSpecW(x,y);
1767         return PathCleanupSpecA(x,y);
1768 }
1769
1770 /*************************************************************************
1771  * PathQualifyA         [SHELL32]
1772  */
1773 BOOL WINAPI PathQualifyA(LPCSTR pszPath) 
1774 {
1775         FIXME("%s\n",pszPath);
1776         return 0;
1777 }
1778
1779 /*************************************************************************
1780  * PathQualifyW         [SHELL32]
1781  */
1782 BOOL WINAPI PathQualifyW(LPCWSTR pszPath) 
1783 {
1784         FIXME("%s\n",debugstr_w(pszPath));
1785         return 0;
1786 }
1787
1788 /*************************************************************************
1789  * PathQualifyAW        [SHELL32]
1790  */
1791 BOOL WINAPI PathQualifyAW(LPCVOID pszPath) 
1792 {
1793         if (VERSION_OsIsUnicode())
1794           return PathQualifyW(pszPath);
1795         return PathQualifyA(pszPath);
1796 }
1797
1798 /*************************************************************************
1799  * PathResolveA [SHELL32.51]
1800  */
1801 BOOL WINAPI PathResolveA(
1802         LPSTR lpszPath,
1803         LPCSTR *alpszPaths, 
1804         DWORD dwFlags)
1805 {
1806         FIXME("(%s,%p,0x%08lx),stub!\n",
1807           lpszPath, *alpszPaths, dwFlags);
1808         return 0;
1809 }
1810
1811 /*************************************************************************
1812  * PathResolveW [SHELL32]
1813  */
1814 BOOL WINAPI PathResolveW(
1815         LPWSTR lpszPath,
1816         LPCWSTR *alpszPaths, 
1817         DWORD dwFlags)
1818 {
1819         FIXME("(%s,%p,0x%08lx),stub!\n",
1820           debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags);
1821         return 0;
1822 }
1823
1824 /*************************************************************************
1825  * PathResolveAW [SHELL32]
1826  */
1827 BOOL WINAPI PathResolveAW(
1828         LPVOID lpszPath,
1829         LPCVOID *alpszPaths, 
1830         DWORD dwFlags)
1831 {
1832         if (VERSION_OsIsUnicode())
1833           return PathResolveW(lpszPath, (LPCWSTR*)alpszPaths, dwFlags);
1834         return PathResolveA(lpszPath, (LPCSTR*)alpszPaths, dwFlags);
1835 }
1836
1837 /*************************************************************************
1838 *       PathProcessCommandA     [SHELL32.653]
1839 */
1840 HRESULT WINAPI PathProcessCommandA (
1841         LPCSTR lpszPath,
1842         LPSTR lpszBuff,
1843         DWORD dwBuffSize,
1844         DWORD dwFlags)
1845 {
1846         FIXME("%s %p 0x%04lx 0x%04lx stub\n",
1847         lpszPath, lpszBuff, dwBuffSize, dwFlags);
1848         lstrcpyA(lpszBuff, lpszPath);
1849         return 0;
1850 }
1851
1852 /*************************************************************************
1853 *       PathProcessCommandW
1854 */
1855 HRESULT WINAPI PathProcessCommandW (
1856         LPCWSTR lpszPath,
1857         LPWSTR lpszBuff,
1858         DWORD dwBuffSize,
1859         DWORD dwFlags)
1860 {
1861         FIXME("(%s, %p, 0x%04lx, 0x%04lx) stub\n",
1862         debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
1863         lstrcpyW(lpszBuff, lpszPath);
1864         return 0;
1865 }
1866
1867 /*************************************************************************
1868 *       PathProcessCommandAW
1869 */
1870 HRESULT WINAPI PathProcessCommandAW (
1871         LPCVOID lpszPath,
1872         LPVOID lpszBuff,
1873         DWORD dwBuffSize,
1874         DWORD dwFlags)
1875 {
1876         if (VERSION_OsIsUnicode())
1877           return PathProcessCommandW(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1878         return PathProcessCommandA(lpszPath, lpszBuff, dwBuffSize, dwFlags);
1879 }
1880
1881 /*************************************************************************
1882  *      PathCompactPathExA
1883  */
1884 BOOL WINAPI PathCompactPathExA(
1885         LPSTR pszOut,
1886         LPCSTR pszSrc,
1887         UINT cchMax,
1888         DWORD dwFlags)
1889 {
1890         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, pszSrc, cchMax, dwFlags);
1891         return FALSE;
1892 }
1893
1894 /*************************************************************************
1895  *      PathCompactPathExW
1896  */
1897 BOOL WINAPI PathCompactPathExW(
1898         LPWSTR pszOut,
1899         LPCWSTR pszSrc,
1900         UINT cchMax,
1901         DWORD dwFlags)
1902 {
1903         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, debugstr_w(pszSrc), cchMax, dwFlags);
1904         return FALSE;
1905 }
1906
1907 /*
1908         ########## special ##########
1909 */
1910
1911 /*************************************************************************
1912  * PathSetDlgItemPathA
1913  *
1914  * NOTES
1915  *  use PathCompactPath to make sure, the path fits into the control
1916  */
1917 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath) 
1918 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
1919         return SetDlgItemTextA(hDlg, id, pszPath);
1920 }
1921
1922 /*************************************************************************
1923  * PathSetDlgItemPathW
1924  */
1925 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath) 
1926 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
1927         return SetDlgItemTextW(hDlg, id, pszPath);
1928 }
1929
1930 /*************************************************************************
1931  * PathSetDlgItemPathAW
1932  */
1933 BOOL WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath) 
1934 {       if (VERSION_OsIsUnicode())
1935           return PathSetDlgItemPathW(hDlg, id, pszPath);
1936         return PathSetDlgItemPathA(hDlg, id, pszPath);
1937 }
1938
1939
1940 /*************************************************************************
1941  * SHGetSpecialFolderPathA [SHELL32.175]
1942  * 
1943  * converts csidl to path
1944  */
1945  
1946 static char * szSHFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
1947 static char * szSHUserFolders = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
1948 #if 0
1949 static char * szEnvUserProfile = "%USERPROFILE%";
1950 static char * szEnvSystemRoot = "%SYSTEMROOT%";
1951 #endif
1952
1953 BOOL WINAPI SHGetSpecialFolderPathA (
1954         HWND hwndOwner,
1955         LPSTR szPath,
1956         DWORD csidl,
1957         BOOL bCreate)
1958 {
1959         CHAR    szValueName[MAX_PATH], szDefaultPath[MAX_PATH];
1960         HKEY    hRootKey, hKey;
1961         BOOL    bRelative = TRUE;
1962         DWORD   dwType, dwDisp, dwPathLen = MAX_PATH;
1963
1964         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
1965
1966         /* build default values */
1967         switch(csidl)
1968         {
1969           case CSIDL_APPDATA:
1970             hRootKey = HKEY_CURRENT_USER;
1971             strcpy (szValueName, "AppData");
1972             strcpy (szDefaultPath, "AppData");
1973             break;
1974
1975           case CSIDL_COOKIES:
1976             hRootKey = HKEY_CURRENT_USER;
1977             strcpy (szValueName, "Cookies");
1978             strcpy(szDefaultPath, "Cookies");
1979             break;
1980
1981           case CSIDL_DESKTOPDIRECTORY:
1982             hRootKey = HKEY_CURRENT_USER;
1983             strcpy(szValueName, "Desktop");
1984             strcpy(szDefaultPath, "Desktop");
1985             break;
1986
1987           case CSIDL_COMMON_DESKTOPDIRECTORY:
1988             hRootKey = HKEY_LOCAL_MACHINE;
1989             strcpy(szValueName, "Common Desktop");
1990             strcpy(szDefaultPath, "Desktop");
1991             break;
1992
1993           case CSIDL_FAVORITES:
1994             hRootKey = HKEY_CURRENT_USER;
1995             strcpy(szValueName, "Favorites");
1996             strcpy(szDefaultPath, "Favorites");
1997             break;
1998
1999           case CSIDL_FONTS:
2000             hRootKey = HKEY_CURRENT_USER;
2001             strcpy(szValueName, "Fonts");
2002             strcpy(szDefaultPath, "Fonts");
2003             break;
2004
2005           case CSIDL_HISTORY:
2006             hRootKey = HKEY_CURRENT_USER;
2007             strcpy(szValueName, "History");
2008             strcpy(szDefaultPath, "History");
2009             break;
2010
2011           case CSIDL_NETHOOD:
2012             hRootKey = HKEY_CURRENT_USER;
2013             strcpy(szValueName, "NetHood");
2014             strcpy(szDefaultPath, "NetHood");
2015             break;
2016
2017           case CSIDL_INTERNET_CACHE:
2018             hRootKey = HKEY_CURRENT_USER;
2019             strcpy(szValueName, "Cache");
2020             strcpy(szDefaultPath, "Temporary Internet Files");
2021             break;
2022
2023           case CSIDL_PERSONAL:
2024             hRootKey = HKEY_CURRENT_USER;
2025             strcpy(szValueName, "Personal");
2026             strcpy(szDefaultPath, "My Own Files");
2027             bRelative = FALSE;
2028             break;
2029
2030           case CSIDL_PRINTHOOD:
2031             hRootKey = HKEY_CURRENT_USER;
2032             strcpy(szValueName, "PrintHood");
2033             strcpy(szDefaultPath, "PrintHood");
2034             break;
2035
2036           case CSIDL_PROGRAMS:
2037             hRootKey = HKEY_CURRENT_USER;
2038             strcpy(szValueName, "Programs");
2039             strcpy(szDefaultPath, "StartMenu\\Programs");
2040             break;
2041
2042           case CSIDL_COMMON_PROGRAMS:
2043             hRootKey = HKEY_LOCAL_MACHINE;
2044             strcpy(szValueName, "Common Programs");
2045             strcpy(szDefaultPath, "");
2046             break;
2047
2048           case CSIDL_RECENT:
2049             hRootKey = HKEY_CURRENT_USER;
2050             strcpy(szValueName, "Recent");
2051             strcpy(szDefaultPath, "Recent");
2052             break;
2053
2054           case CSIDL_SENDTO:
2055             hRootKey = HKEY_CURRENT_USER;
2056             strcpy(szValueName, "SendTo");
2057             strcpy(szDefaultPath, "SendTo");
2058             break;
2059
2060           case CSIDL_STARTMENU:
2061             hRootKey = HKEY_CURRENT_USER;
2062             strcpy(szValueName, "StartMenu");
2063             strcpy(szDefaultPath, "StartMenu");
2064             break;
2065
2066           case CSIDL_COMMON_STARTMENU:
2067             hRootKey = HKEY_LOCAL_MACHINE;
2068             strcpy(szValueName, "Common StartMenu");
2069             strcpy(szDefaultPath, "StartMenu");
2070             break;
2071
2072           case CSIDL_STARTUP:
2073             hRootKey = HKEY_CURRENT_USER;
2074             strcpy(szValueName, "Startup");
2075             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
2076             break;
2077
2078           case CSIDL_COMMON_STARTUP:
2079             hRootKey = HKEY_LOCAL_MACHINE;
2080             strcpy(szValueName, "Common Startup");
2081             strcpy(szDefaultPath, "StartMenu\\Programs\\Startup");
2082             break;
2083
2084           case CSIDL_TEMPLATES:
2085             hRootKey = HKEY_CURRENT_USER;
2086             strcpy(szValueName, "Templates");
2087             strcpy(szDefaultPath, "ShellNew");
2088             break;
2089
2090           default:
2091             ERR("folder unknown or not allowed\n");
2092             return FALSE;
2093         }
2094
2095         /* user shell folders */
2096         if (RegCreateKeyExA(hRootKey,szSHUserFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
2097
2098         if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
2099         {
2100           RegCloseKey(hKey);
2101
2102           /* shell folders */
2103           if (RegCreateKeyExA(hRootKey,szSHFolders,0,NULL,0,KEY_ALL_ACCESS,NULL,&hKey,&dwDisp)) return FALSE;
2104
2105           if (RegQueryValueExA(hKey,szValueName,NULL,&dwType,(LPBYTE)szPath,&dwPathLen))
2106           {
2107
2108             /* value not existing */
2109             if (bRelative)
2110             {
2111               GetWindowsDirectoryA(szPath, MAX_PATH);
2112               PathAddBackslashA(szPath);
2113               strcat(szPath, szDefaultPath);
2114             }
2115             else
2116             {
2117               strcpy(szPath, "C:\\");   /* fixme ??? */
2118               strcat(szPath, szDefaultPath);
2119             }
2120             RegSetValueExA(hKey,szValueName,0,REG_SZ,(LPBYTE)szPath,strlen(szPath)+1);
2121           }
2122         }
2123         RegCloseKey(hKey);
2124
2125         /* expand paths like %USERPROFILE% */
2126         if (dwType == REG_EXPAND_SZ)
2127         {
2128           ExpandEnvironmentStringsA(szPath, szDefaultPath, MAX_PATH);
2129           strcpy(szPath, szDefaultPath);
2130         }
2131
2132         /* if we don't care about existing directorys we are ready */
2133         if(csidl & CSIDL_FLAG_DONT_VERIFY) return TRUE;
2134
2135         if (PathFileExistsA(szPath)) return TRUE;
2136
2137         /* not existing but we not allowed to create it */
2138         if (!bCreate) return FALSE;
2139         
2140         if (!CreateDirectoryA(szPath,NULL))
2141         {
2142           ERR("Failed to create directory '%s'.\n", szPath);
2143           return FALSE;
2144         }
2145
2146         MESSAGE("Created not existing system directory '%s'\n", szPath);
2147         return TRUE;
2148 }
2149
2150 /*************************************************************************
2151  * SHGetSpecialFolderPathW
2152  */
2153 BOOL WINAPI SHGetSpecialFolderPathW (
2154         HWND hwndOwner,
2155         LPWSTR szPath,
2156         DWORD csidl,
2157         BOOL bCreate)
2158 {
2159         char szTemp[MAX_PATH];
2160         
2161         if (SHGetSpecialFolderPathA(hwndOwner, szTemp, csidl, bCreate))
2162         {
2163           lstrcpynAtoW(szPath, szTemp, MAX_PATH);
2164         }
2165
2166         TRACE("0x%04x,%p,csidl=%lu,0x%04x\n", hwndOwner,szPath,csidl,bCreate);
2167
2168         return TRUE;
2169 }
2170
2171 /*************************************************************************
2172  * SHGetSpecialFolderPathAW
2173  */
2174 BOOL WINAPI SHGetSpecialFolderPathAW (
2175         HWND hwndOwner,
2176         LPVOID szPath,
2177         DWORD csidl,
2178         BOOL bCreate)
2179
2180 {
2181         if (VERSION_OsIsUnicode())
2182           return SHGetSpecialFolderPathW (hwndOwner, szPath, csidl, bCreate);
2183         return SHGetSpecialFolderPathA (hwndOwner, szPath, csidl, bCreate);
2184 }
2185
2186 /*************************************************************************
2187  * SHGetFolderPathA                     [SHFOLDER.@]
2188  */
2189 HRESULT WINAPI SHGetFolderPathA(
2190         HWND hwndOwner,
2191         int nFolder,
2192         HANDLE hToken,  /* FIXME: get paths for specific user */
2193         DWORD dwFlags,  /* FIXME: SHGFP_TYPE_CURRENT|SHGFP_TYPE_DEFAULT */
2194         LPSTR pszPath)
2195 {
2196         return (SHGetSpecialFolderPathA(
2197                 hwndOwner,
2198                 pszPath,
2199                 CSIDL_FOLDER_MASK & nFolder,
2200                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
2201 }
2202
2203 /*************************************************************************
2204  * SHGetFolderPathW                     [SHFOLDER.@]
2205  */
2206 HRESULT WINAPI SHGetFolderPathW(
2207         HWND hwndOwner,
2208         int nFolder,
2209         HANDLE hToken,
2210         DWORD dwFlags,
2211         LPWSTR pszPath)
2212 {
2213         return (SHGetSpecialFolderPathW(
2214                 hwndOwner,
2215                 pszPath,
2216                 CSIDL_FOLDER_MASK & nFolder,
2217                 CSIDL_FLAG_CREATE & nFolder )) ? S_OK : E_FAIL;
2218 }
2219
2220 /*************************************************************************
2221  * PathCanonicalizeA
2222  *
2223  *  FIXME
2224  *   returnvalue, use CharNext
2225  */
2226  
2227 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
2228 {
2229         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
2230         BOOL bModifyed = FALSE;
2231
2232         TRACE("%p %s\n", pszBuf, pszPath);
2233         
2234         pszBuf[OffsetDst]='\0';
2235
2236         /* keep the root of the path */
2237         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
2238         {
2239           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2240         }
2241         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
2242         {
2243           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2244           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2245           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
2246           {
2247             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2248             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
2249             {
2250               /* C:\. */
2251               OffsetSrc++; LenSrc--; bModifyed = TRUE;
2252             } 
2253             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
2254             {
2255               /* C:\.. */
2256               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2257             } 
2258           }
2259         }
2260         
2261         /* ".\" at the beginning of the path */
2262         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
2263         {
2264           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2265         } 
2266         
2267         while ( LenSrc )
2268         {
2269           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
2270           {
2271             /* "\.." found, go one deeper */
2272             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
2273             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
2274             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
2275             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
2276           }
2277           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
2278           {
2279             /* "\." found, skip it */
2280             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
2281           }
2282           else
2283           {
2284             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
2285           }
2286         }
2287         pszBuf[OffsetDst] = '\0';
2288         TRACE("-- %s %u\n", pszBuf, bModifyed);
2289         return bModifyed;
2290 }
2291
2292
2293 /*************************************************************************
2294  * PathCanonicalizeW
2295  *
2296  *  FIXME
2297  *   returnvalue, use CharNext
2298  */
2299 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
2300 {
2301         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = lstrlenW(pszPath);
2302         BOOL bModifyed = FALSE;
2303
2304         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
2305         
2306         pszBuf[OffsetDst]='\0';
2307
2308         /* keep the root of the path */
2309         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
2310         {
2311           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2312         }
2313         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
2314         {
2315           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2316           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2317           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
2318           {
2319             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
2320             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
2321             {
2322               /* C:\. */
2323               OffsetSrc++; LenSrc--; bModifyed = TRUE;
2324             } 
2325             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
2326             {
2327               /* C:\.. */
2328               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2329             } 
2330           }
2331         }
2332         
2333         /* ".\" at the beginning of the path */
2334         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
2335         {
2336           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
2337         } 
2338         
2339         while ( LenSrc )
2340         {
2341           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
2342           {
2343             /* "\.." found, go one deeper */
2344             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
2345             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
2346             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
2347             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
2348           }
2349           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
2350           {
2351             /* "\." found, skip it */
2352             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
2353           }
2354           else
2355           {
2356             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
2357           }
2358         }
2359         pszBuf[OffsetDst] = '\0';
2360         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
2361         return bModifyed;
2362 }
2363
2364 /*************************************************************************
2365  * PathFindNextComponentA
2366  *
2367  * NOTES
2368  * special cases:
2369  *      ""              null
2370  *      aa              "" (pointer to traling NULL)
2371  *      aa\             "" (pointer to traling NULL)
2372  *      aa\\            "" (pointer to traling NULL)
2373  *      aa\\bb          bb
2374  *      aa\\\bb         \bb
2375  *      c:\aa\          "aa\"
2376  *      \\aa            aa
2377  *      \\aa\b          aa\b
2378 */
2379 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
2380 {
2381         LPSTR pos;
2382
2383         TRACE("%s\n", pszPath);
2384
2385         if(!pszPath || !*pszPath) return NULL;
2386         if(!(pos = StrChrA(pszPath, '\\')))
2387           return (LPSTR) pszPath + strlen(pszPath);
2388         pos++;
2389         if(pos[0] == '\\') pos++;
2390         return pos;
2391 }
2392
2393 /*************************************************************************
2394  * PathFindNextComponentW
2395  */
2396 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
2397 {
2398         LPWSTR pos;
2399
2400         TRACE("%s\n", debugstr_w(pszPath));
2401         
2402         if(!pszPath || !*pszPath) return NULL;
2403         if (!(pos = StrChrW(pszPath, '\\')))
2404           return (LPWSTR) pszPath + lstrlenW(pszPath);
2405         pos++;
2406         if(pos[0] == '\\') pos++;
2407         return pos;
2408 }
2409
2410 /*************************************************************************
2411  * PathAddExtensionA
2412  *
2413  * NOTES
2414  *  it adds never a dot
2415  */
2416  
2417 BOOL WINAPI PathAddExtensionA(
2418         LPSTR  pszPath,
2419         LPCSTR pszExtension)
2420 {
2421         if (*pszPath)
2422         {
2423           if (*(PathFindExtensionA(pszPath))) return FALSE;
2424
2425           if (!pszExtension || *pszExtension=='\0')
2426             strcat(pszPath, "exe");
2427           else
2428             strcat(pszPath, pszExtension);
2429         }
2430
2431         return TRUE;
2432 }
2433
2434 /*************************************************************************
2435  *      PathAddExtensionW
2436  */
2437 BOOL WINAPI PathAddExtensionW(
2438         LPWSTR  pszPath,
2439         LPCWSTR pszExtension)
2440 {
2441         static const WCHAR ext[] = { 'e','x','e',0 };
2442
2443         if (*pszPath)
2444         {
2445           if (*(PathFindExtensionW(pszPath))) return FALSE;
2446
2447           if (!pszExtension || *pszExtension=='\0')
2448             lstrcatW(pszPath, ext);
2449           else
2450             lstrcatW(pszPath, pszExtension);
2451         }
2452         return TRUE;
2453
2454 }
2455
2456 /*************************************************************************
2457  *      PathMakePrettyA
2458  */
2459 BOOL WINAPI PathMakePrettyA(
2460         LPSTR lpPath)
2461 {
2462         FIXME("%s\n", lpPath);
2463         return TRUE;
2464 }
2465
2466 /*************************************************************************
2467  *      PathMakePrettyW
2468  */
2469 BOOL WINAPI PathMakePrettyW(
2470         LPWSTR lpPath)
2471 {
2472         FIXME("%s\n", debugstr_w(lpPath));
2473         return TRUE;
2474
2475 }
2476
2477 /*************************************************************************
2478  *      PathCommonPrefixA
2479  */
2480 int WINAPI PathCommonPrefixA(
2481         LPCSTR pszFile1,
2482         LPCSTR pszFile2,
2483         LPSTR achPath)
2484 {
2485         FIXME("%s %s %p\n", pszFile1, pszFile2, achPath);
2486         return 0;
2487 }
2488
2489 /*************************************************************************
2490  *      PathCommonPrefixW
2491  */
2492 int WINAPI PathCommonPrefixW(
2493         LPCWSTR pszFile1,
2494         LPCWSTR pszFile2,
2495         LPWSTR achPath)
2496 {
2497         FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath );
2498         return 0;
2499 }
2500
2501 /*************************************************************************
2502  *      PathCompactPathA
2503  */
2504 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR pszPath, UINT dx)
2505 {
2506         FIXME("0x%08x %s 0x%08x\n", hDC, pszPath, dx);
2507         return FALSE;
2508 }
2509
2510 /*************************************************************************
2511  *      PathCompactPathW
2512  */
2513 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR pszPath, UINT dx)
2514 {
2515         FIXME("0x%08x %s 0x%08x\n", hDC, debugstr_w(pszPath), dx);
2516         return FALSE;
2517 }
2518
2519 /*************************************************************************
2520  *      PathGetCharTypeA
2521  */
2522 UINT WINAPI PathGetCharTypeA(UCHAR ch)
2523 {
2524         FIXME("%c\n", ch);
2525         return 0;
2526 }
2527
2528 /*************************************************************************
2529  *      PathGetCharTypeW
2530  */
2531 UINT WINAPI PathGetCharTypeW(WCHAR ch)
2532 {
2533         FIXME("%c\n", ch);
2534         return 0;
2535 }
2536
2537 /*************************************************************************
2538  *      PathMakeSystemFolderA
2539  */
2540 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath)
2541 {
2542         FIXME("%s\n", pszPath);
2543         return FALSE;
2544 }
2545
2546 /*************************************************************************
2547  *      PathMakeSystemFolderW
2548  */
2549 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath)
2550 {
2551         FIXME("%s\n", debugstr_w(pszPath));
2552         return FALSE;
2553 }
2554
2555 /*************************************************************************
2556  *      PathRenameExtensionA
2557  */
2558 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt)
2559 {
2560         FIXME("%s %s\n", pszPath, pszExt);
2561         return FALSE;
2562 }
2563
2564 /*************************************************************************
2565  *      PathRenameExtensionW
2566  */
2567 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt)
2568 {
2569         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszExt));
2570         return FALSE;
2571 }
2572
2573 /*************************************************************************
2574  *      PathSearchAndQualifyA
2575  */
2576 BOOL WINAPI PathSearchAndQualifyA(
2577         LPCSTR pszPath,
2578         LPSTR pszBuf,
2579         UINT cchBuf)
2580 {
2581         FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf);
2582         return FALSE;
2583 }
2584
2585 /*************************************************************************
2586  *      PathSearchAndQualifyW
2587  */
2588 BOOL WINAPI PathSearchAndQualifyW(
2589         LPCWSTR pszPath,
2590         LPWSTR pszBuf,
2591         UINT cchBuf)
2592 {
2593         FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
2594         return FALSE;
2595 }
2596
2597 /*************************************************************************
2598  *      PathSkipRootA
2599  */
2600 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath)
2601 {
2602         FIXME("%s\n", pszPath);
2603         return (LPSTR)pszPath;
2604 }
2605
2606 /*************************************************************************
2607  *      PathSkipRootW
2608  */
2609 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath)
2610 {
2611         FIXME("%s\n", debugstr_w(pszPath));
2612         return (LPWSTR)pszPath;
2613 }
2614
2615 /*************************************************************************
2616  *      PathCreateFromUrlA
2617  */
2618 HRESULT WINAPI PathCreateFromUrlA(
2619         LPCSTR pszUrl,
2620         LPSTR pszPath,
2621         LPDWORD pcchPath,
2622         DWORD dwFlags)
2623 {
2624         FIXME("%s %p %p 0x%08lx\n",
2625           pszUrl, pszPath, pcchPath, dwFlags);
2626         return S_OK;
2627 }
2628
2629 /*************************************************************************
2630  *      PathCreateFromUrlW
2631  */
2632 HRESULT WINAPI PathCreateFromUrlW(
2633         LPCWSTR pszUrl,
2634         LPWSTR pszPath,
2635         LPDWORD pcchPath,
2636         DWORD dwFlags)
2637 {
2638         FIXME("%s %p %p 0x%08lx\n",
2639           debugstr_w(pszUrl), pszPath, pcchPath, dwFlags);
2640         return S_OK;
2641 }
2642
2643 /*************************************************************************
2644  *      PathRelativePathToA
2645  */
2646 BOOL WINAPI PathRelativePathToA(
2647         LPSTR pszPath,
2648         LPCSTR pszFrom,
2649         DWORD dwAttrFrom,
2650         LPCSTR pszTo,
2651         DWORD dwAttrTo)
2652 {
2653         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
2654           pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo);
2655         return FALSE;
2656 }
2657
2658 /*************************************************************************
2659  *      PathRelativePathToW
2660  */
2661 BOOL WINAPI PathRelativePathToW(
2662         LPWSTR pszPath,
2663         LPCWSTR pszFrom,
2664         DWORD dwAttrFrom,
2665         LPCWSTR pszTo,
2666         DWORD dwAttrTo)
2667 {
2668         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
2669           debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo);
2670         return FALSE;
2671 }
2672
2673 /*************************************************************************
2674  *      PathUnmakeSystemFolderA
2675  */
2676 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath)
2677 {
2678         FIXME("%s\n", pszPath);
2679         return FALSE;
2680 }
2681
2682 /*************************************************************************
2683  *      PathUnmakeSystemFolderW
2684  */
2685 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath)
2686 {
2687         FIXME("%s\n", debugstr_w(pszPath));
2688         return FALSE;
2689 }