Authors: Francis Beaudet <francis@macadamian.com>, Sylvain St-Germain <sylvain@macada...
[wine] / dlls / shell32 / shellpath.c
1 /*
2  * Path Functions
3  *
4  * Many of this functions are in SHLWAPI.DLL also
5  *
6  */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include "windows.h"
11 #include "winerror.h"
12 #include "file.h"
13 #include "shell.h"
14 #include "shlobj.h"
15 #include "debug.h"
16 #include "winnls.h"
17 #include "winversion.h"
18 #include "shell32_main.h"
19
20 /*************************************************************************
21  * PathIsRoot [SHELL32.29]
22  */
23 BOOL32 WINAPI PathIsRoot32A(LPCSTR x)
24 {       TRACE(shell,"%s\n",x);
25         if (*(x+1)==':' && *(x+2)=='\\')                /* "X:\" */
26           return 1;
27         if (*x=='\\')           /* "\" */
28           return 0;
29         if (x[0]=='\\' && x[1]=='\\')           /* UNC "\\<xx>\" */
30         { int   foundbackslash = 0;
31           x=x+2;
32           while (*x)
33           { if (*x++=='\\')
34               foundbackslash++;
35           }
36           if (foundbackslash<=1)        /* max 1 \ more ... */
37             return 1;
38         }
39         return 0;
40 }
41 BOOL32 WINAPI PathIsRoot32W(LPCWSTR x) 
42 {       TRACE(shell,"%s\n",debugstr_w(x));
43         if (*(x+1)==':' && *(x+2)=='\\')                /* "X:\" */
44           return 1;
45         if (*x == (WCHAR) '\\')         /* "\" */
46           return 0;
47         if (x[0]==(WCHAR)'\\' && x[1]==(WCHAR)'\\')     /* UNC "\\<xx>\" */
48         { int   foundbackslash = 0;
49           x=x+2;
50           while (*x) 
51           { if (*x++==(WCHAR)'\\')
52               foundbackslash++;
53           }
54           if (foundbackslash<=1)        /* max 1 \ more ... */
55             return 1;
56         }
57         return 0;
58 }
59 BOOL32 WINAPI PathIsRoot32AW(LPCVOID x) 
60 {       if (VERSION_OsIsUnicode())
61           return PathIsRoot32W(x);
62         return PathIsRoot32A(x);
63
64 }
65 /*************************************************************************
66  * PathBuildRoot [SHELL32.30]
67  */
68 LPSTR WINAPI PathBuildRoot(LPSTR root,BYTE drive) {
69   TRACE(shell,"%p %i\n",root, drive);
70         strcpy(root,"A:\\");
71         root[0]+=drive;
72         return root;
73 }
74
75 /*************************************************************************
76  * PathFindExtension [SHELL32.31]
77  *
78  * NOTES
79  *     returns pointer to last . in last pathcomponent or at \0.
80  */
81 LPCSTR WINAPI PathFindExtension32A(LPCSTR path) 
82 {       LPCSTR   lastpoint = NULL;
83         TRACE(shell,"%p %s\n",path,path);
84         while (*path) 
85         { if (*path=='\\'||*path==' ')
86             lastpoint=NULL;
87           if (*path=='.')
88             lastpoint=path;
89           path++;
90         }
91         return lastpoint?lastpoint:path;
92 }
93 LPCWSTR WINAPI PathFindExtension32W(LPCWSTR path) 
94 {       LPCWSTR   lastpoint = NULL;
95         TRACE(shell,"%p L%s\n",path,debugstr_w(path));
96         while (*path)
97         { if (*path==(WCHAR)'\\'||*path==(WCHAR)' ')
98             lastpoint=NULL;
99           if (*path==(WCHAR)'.')
100             lastpoint=path;
101           path++;
102         }
103         return lastpoint?lastpoint:path;
104 }
105 LPCVOID WINAPI PathFindExtension32AW(LPCVOID path) 
106 {       if (VERSION_OsIsUnicode())
107           return PathFindExtension32W(path);
108         return PathFindExtension32A(path);
109
110 }
111
112 /*************************************************************************
113  * PathAddBackslash [SHELL32.32]
114  * 
115  * NOTES
116  *     append \ if there is none
117  */
118 LPSTR WINAPI PathAddBackslash32A(LPSTR path)
119 {       int len;
120         TRACE(shell,"%p->%s\n",path,path);
121
122         len = strlen(path);
123         if (len && path[len-1]!='\\') 
124         { path[len]  = '\\';
125           path[len+1]= 0x00;
126           return path+len+1;
127         }
128         return path+len;
129 }
130 LPWSTR WINAPI PathAddBackslash32W(LPWSTR path)
131 {       int len;
132         TRACE(shell,"%p->%s\n",path,debugstr_w(path));
133
134         len = lstrlen32W(path);
135         if (len && path[len-1]!=(WCHAR)'\\') 
136         { path[len]  = (WCHAR)'\\';
137           path[len+1]= 0x00;
138           return path+len+1;
139         }
140         return path+len;
141 }
142 LPVOID WINAPI PathAddBackslash32AW(LPVOID path)
143 {       if(VERSION_OsIsUnicode())
144           return PathAddBackslash32W(path);
145         return PathAddBackslash32A(path);
146 }
147
148 /*************************************************************************
149  * PathRemoveBlanks [SHELL32.33]
150  * 
151  * NOTES
152  *     remove spaces from beginning and end of passed string
153  */
154 LPSTR WINAPI PathRemoveBlanks32A(LPSTR str)
155 {       LPSTR x = str;
156         TRACE(shell,"%s\n",str);
157         while (*x==' ') x++;
158         if (x!=str)
159           strcpy(str,x);
160         if (!*str)
161           return str;
162         x=str+strlen(str)-1;
163         while (*x==' ')
164           x--;
165         if (*x==' ')
166           *x='\0';
167         return x;
168 }
169 LPWSTR WINAPI PathRemoveBlanks32W(LPWSTR str)
170 {       LPWSTR x = str;
171         TRACE(shell,"%s\n",debugstr_w(str));
172         while (*x==' ') x++;
173         if (x!=str)
174           lstrcpy32W(str,x);
175         if (!*str)
176           return str;
177         x=str+lstrlen32W(str)-1;
178         while (*x==' ')
179           x--;
180         if (*x==' ')
181           *x='\0';
182         return x;
183 }
184 LPVOID WINAPI PathRemoveBlanks32AW(LPVOID str)
185 {       if(VERSION_OsIsUnicode())
186           return PathRemoveBlanks32W(str);
187         return PathRemoveBlanks32A(str);
188 }
189
190
191
192 /*************************************************************************
193  * PathFindFilename [SHELL32.34]
194  * 
195  * NOTES
196  *     basename(char *fn);
197  */
198 LPCSTR WINAPI PathFindFilename32A(LPCSTR aptr)
199 {       LPCSTR aslash;
200         aslash = aptr;
201
202         TRACE(shell,"%s\n",aslash);
203         while (aptr[0]) 
204         { if (((aptr[0]=='\\') || (aptr[0]==':')) && aptr[1] && aptr[1]!='\\')
205               aslash = aptr+1;
206           aptr++;
207         }
208         return aslash;
209
210 }
211 LPCWSTR WINAPI PathFindFilename32W(LPCWSTR wptr)
212 {       LPCWSTR wslash;
213         wslash = wptr;
214
215         TRACE(shell,"L%s\n",debugstr_w(wslash));
216         while (wptr[0]) 
217         { if (((wptr[0]=='\\') || (wptr[0]==':')) && wptr[1] && wptr[1]!='\\')
218             wslash = wptr+1;
219           wptr++;
220         }
221         return wslash;  
222 }
223 LPCVOID WINAPI PathFindFilename32AW(LPCVOID fn)
224 {
225         if(VERSION_OsIsUnicode())
226           return PathFindFilename32W(fn);
227         return PathFindFilename32A(fn);
228 }
229
230 /*************************************************************************
231  * PathRemoveFileSpec [SHELL32.35]
232  * 
233  * NOTES
234  *     bool getpath(char *pathname); truncates passed argument to a valid path
235  *     returns if the string was modified or not.
236  *     "\foo\xx\foo"-> "\foo\xx"
237  *     "\" -> "\"
238  *     "a:\foo" -> "a:\"
239  */
240 DWORD WINAPI PathRemoveFileSpec(LPSTR fn) {
241         LPSTR   x,cutplace;
242   TRACE(shell,"%s\n",fn);
243         if (!fn[0])
244                 return 0;
245         x=fn;
246         cutplace = fn;
247         while (*x) {
248                 if (*x=='\\') {
249                         cutplace=x++;
250                         continue;
251                 }
252                 if (*x==':') {
253                         x++;
254                         if (*x=='\\')
255                                 cutplace=++x;
256                         continue; /* already x++ed */
257                 }
258                 x++;
259         }
260         if (!*cutplace)
261                 return 0;
262         if (cutplace==fn) {
263                 if (fn[0]=='\\') {
264                         if (!fn[1])
265                                 return 0;
266                         fn[0]='\0';
267                         return 1;
268                 }
269         }
270         *cutplace='\0';
271         return 1;
272 }
273
274 /*************************************************************************
275  * PathAppend [SHELL32.36]
276  * 
277  * NOTES
278  *     concat_paths(char*target,const char*add);
279  *     concats "target\\add" and writes them to target
280  */
281 LPSTR WINAPI PathAppend(LPSTR x1,LPSTR x2) {
282   TRACE(shell,"%s %s\n",x1,x2);
283   while (x2[0]=='\\') x2++;
284   return PathCombine32A(x1,x1,x2);
285 }
286
287 /*************************************************************************
288  * PathCombine [SHELL32.37]
289  * 
290  * NOTES
291  *  if lpszFile='.' skip it
292  *  szDest can be equal to lpszFile. Thats why we use sTemp
293  */
294 LPSTR WINAPI PathCombine32A(LPSTR szDest, LPCSTR lpszDir, LPCSTR lpszFile) 
295 {       char sTemp[MAX_PATH];
296         TRACE(shell,"%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
297         
298         
299         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) ) 
300         { strcpy(szDest,lpszDir);
301           return szDest;
302         }
303
304         /*  if lpszFile is a complete path don't care about lpszDir */
305         if (PathIsRoot32A(lpszFile))
306         { strcpy(szDest,lpszFile);
307         }
308         strcpy(sTemp,lpszDir);
309         PathAddBackslash32A(sTemp);
310         strcat(sTemp,lpszFile);
311         strcpy(szDest,sTemp);
312         return szDest;
313 }
314 LPWSTR WINAPI PathCombine32W(LPWSTR szDest, LPCWSTR lpszDir, LPCWSTR lpszFile) 
315 {       WCHAR sTemp[MAX_PATH];
316         TRACE(shell,"%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
317                          lpszFile, debugstr_w(lpszFile));
318         
319         
320         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
321         { lstrcpy32W(szDest,lpszDir);
322           return szDest;
323         }
324
325         /*  if lpszFile is a complete path don't care about lpszDir */
326         if (PathIsRoot32W(lpszFile))
327         { lstrcpy32W(szDest,lpszFile);
328         }
329         lstrcpy32W(sTemp,lpszDir);
330         PathAddBackslash32W(sTemp);
331         lstrcat32W(sTemp,lpszFile);
332         lstrcpy32W(szDest,sTemp);
333         return szDest;
334 }
335 LPVOID WINAPI PathCombine32AW(LPVOID szDest, LPCVOID lpszDir, LPCVOID lpszFile) 
336 {       if (VERSION_OsIsUnicode())
337           return PathCombine32W( szDest, lpszDir, lpszFile );
338         return PathCombine32A( szDest, lpszDir, lpszFile );
339 }
340
341 /*************************************************************************
342  * PathIsUNC [SHELL32.39]
343  * 
344  * NOTES
345  *     PathIsUNC(char*path);
346  */
347 BOOL32 WINAPI PathIsUNC32A(LPCSTR path) 
348 {       TRACE(shell,"%s\n",path);
349
350         if ((path[0]=='\\') && (path[1]=='\\'))
351           return TRUE;
352         return FALSE;
353 }
354 BOOL32 WINAPI PathIsUNC32W(LPCWSTR path) 
355 {       TRACE(shell,"%s\n",debugstr_w(path));
356
357         if ((path[0]=='\\') && (path[1]=='\\'))
358           return TRUE;
359         return FALSE;
360 }
361 BOOL32 WINAPI PathIsUNC32AW (LPCVOID path)
362 {       if (VERSION_OsIsUnicode())
363           return PathIsUNC32W( path );
364         return PathIsUNC32A( path );  
365 }
366 /*************************************************************************
367  *  PathIsRelativ [SHELL32.40]
368  * 
369  */
370 BOOL32 WINAPI PathIsRelative32A (LPCSTR path)
371 {       TRACE(shell,"path=%s\n",path);
372
373         if (path && (path[0]!='\\' && path[1]==':'))
374           return TRUE;
375         return FALSE;    
376 }
377 BOOL32 WINAPI PathIsRelative32W (LPCWSTR path)
378 {       TRACE(shell,"path=%s\n",debugstr_w(path));
379
380         if (path && (path[0]!='\\' && path[1]==':'))
381           return TRUE;
382         return FALSE;    
383 }
384 BOOL32 WINAPI PathIsRelative32AW (LPCVOID path)
385 {       if (VERSION_OsIsUnicode())
386           return PathIsRelative32W( path );
387         return PathIsRelative32A( path );  
388 }
389 /*************************************************************************
390  *  PathIsExe [SHELL32.43]
391  * 
392  */
393 BOOL32 WINAPI PathIsExe (LPCSTR path)
394 {  TRACE(shell,"path=%s\n",path);
395     return FALSE;
396 }
397
398 /*************************************************************************
399  * PathFileExists [SHELL32.45]
400  * 
401  * NOTES
402  *     file_exists(char *fn);
403  */
404 BOOL32 WINAPI PathFileExists(LPSTR fn) {
405   TRACE(shell,"%s\n",fn);
406    if (GetFileAttributes32A(fn)==-1)
407         return FALSE;
408     else
409         return TRUE;
410 }
411 /*************************************************************************
412  * PathMatchSpec [SHELL32.46]
413  * 
414  * NOTES
415  *     used from COMDLG32
416  */
417
418 BOOL32 WINAPI PathMatchSpec32A(LPCSTR name, LPCSTR mask) 
419 {       LPCSTR _name;
420
421         TRACE(shell,"%s %s stub\n",name,mask);
422
423         _name = name;
424         while (*_name && *mask)
425         { if (*mask ==';')
426           { mask++;
427             _name = name;
428           }
429           else if (*mask == '*')
430           { mask++;
431             while (*mask == '*') mask++;                /* Skip consecutive '*' */
432             if (!*mask || *mask==';') return TRUE;      /* '*' matches everything */
433             while (*_name && (toupper(*_name) != toupper(*mask))) _name++;
434             if (!*_name)
435             { while ( *mask && *mask != ';') mask++;
436               _name = name;
437             }
438           }
439           else if ( (*mask == '?') || (toupper(*mask) == toupper(*_name)) )
440           { mask++;
441             _name++;
442           }
443           else
444           { while ( *mask && *mask != ';') mask++;
445           }
446         }
447         return (!*_name && (!*mask || *mask==';'));
448 }
449 BOOL32 WINAPI PathMatchSpec32W(LPCWSTR name, LPCWSTR mask) 
450 {       WCHAR stemp[4];
451         LPCWSTR _name;
452         
453         TRACE(shell,"%s %s stub\n",debugstr_w(name),debugstr_w(mask));
454
455         lstrcpyAtoW(stemp,"*.*");       
456         if (!lstrcmp32W( mask, stemp )) return 1;
457
458         _name = name;
459         while (*_name && *mask)
460         { if (*mask ==';')
461           { mask++;
462             _name = name;
463           }
464           else if (*mask == '*')
465           { mask++;
466             while (*mask == '*') mask++;                /* Skip consecutive '*' */
467             if (!*mask || *mask==';') return TRUE;      /* '*' matches everything */
468             while (*_name && (towupper(*_name) != towupper(*mask))) _name++;
469             if (!*_name)
470             { while ( *mask && *mask != ';') mask++;
471               _name = name;
472             }
473           }
474           else if ( (*mask == '?') || (towupper(*mask) == towupper(*_name)) )
475           { mask++;
476             _name++;
477           }
478           else
479           { while ( *mask && *mask != ';') mask++;
480           }
481         }
482         return (!*_name && (!*mask || *mask==';'));
483 }
484 BOOL32 WINAPI PathMatchSpec32AW(LPVOID name, LPVOID mask) 
485 {       if (VERSION_OsIsUnicode())
486           return PathMatchSpec32W( name, mask );
487         return PathMatchSpec32A( name, mask );
488 }
489 /*************************************************************************
490  * PathSetDlgItemPath32AW [SHELL32.48]
491  * NOTES
492  *  use PathCompactPath to make sure, the path fits into the control
493  */
494
495 BOOL32 WINAPI PathSetDlgItemPath32A(HWND32 hDlg, int id, LPCSTR pszPath) 
496 {       TRACE(shell,"%x %x %s\n",hDlg, id, pszPath);
497         return SetDlgItemText32A(hDlg, id, pszPath);
498 }
499 BOOL32 WINAPI PathSetDlgItemPath32W(HWND32 hDlg, int id, LPCWSTR pszPath) 
500 {       TRACE(shell,"%x %x %s\n",hDlg, id, debugstr_w(pszPath));
501         return SetDlgItemText32W(hDlg, id, pszPath);
502 }
503 BOOL32 WINAPI PathSetDlgItemPath32AW(HWND32 hDlg, int id, LPCVOID pszPath) 
504 {       if (VERSION_OsIsUnicode())
505           return PathSetDlgItemPath32W(hDlg, id, pszPath);
506         return PathSetDlgItemPath32A(hDlg, id, pszPath);
507 }
508
509 /*************************************************************************
510  * PathResolve [SHELL32.51]
511  */
512 DWORD WINAPI PathResolve(LPCSTR s,DWORD x2,DWORD x3) {
513         FIXME(shell,"(%s,0x%08lx,0x%08lx),stub!\n",s,x2,x3);
514         return 0;
515 }
516
517 /*************************************************************************
518  * PathGetArgs [SHELL32.52]
519  *
520  * NOTES
521  *     look for next arg in string. handle "quoted" strings
522  *     returns pointer to argument *AFTER* the space. Or to the \0.
523  */
524 LPVOID WINAPI PathGetArgs(LPVOID cmdline) 
525 {       BOOL32  qflag = FALSE;
526         LPWSTR wptr;
527         LPSTR aptr;
528         
529         if (VERSION_OsIsUnicode())
530         { TRACE(shell,"%sL\n",debugstr_w((LPWSTR)cmdline));
531           wptr=(LPWSTR) cmdline;
532           while (*wptr) 
533           { if ((*wptr==' ') && !qflag)
534                 return wptr+1;
535             if (*wptr=='"')
536                 qflag=!qflag;
537             wptr++;
538           }
539           return (LPVOID) wptr;
540         }
541         TRACE(shell,"%s\n",(LPSTR)cmdline);
542         aptr=(LPSTR) cmdline;
543         while (*aptr) 
544         { if ((*aptr==' ') && !qflag)
545             return aptr+1;
546           if (*aptr=='"')
547             qflag=!qflag;
548           aptr++;
549         }
550         return (LPVOID) aptr;
551 }
552 /*************************************************************************
553  * PathQuoteSpaces [SHELL32.55]
554  * 
555  * NOTES
556  *     basename(char *fn);
557  */
558 LPSTR WINAPI PathQuoteSpaces32A(LPCSTR aptr)
559 {       FIXME(shell,"%s\n",aptr);
560         return 0;
561
562 }
563 LPWSTR WINAPI PathQuoteSpaces32W(LPCWSTR wptr)
564 {       FIXME(shell,"L%s\n",debugstr_w(wptr));
565         return 0;       
566 }
567 LPVOID WINAPI PathQuoteSpaces32AW (LPCVOID fn)
568 {       if(VERSION_OsIsUnicode())
569           return PathQuoteSpaces32W(fn);
570         return PathQuoteSpaces32A(fn);
571 }
572
573
574 /*************************************************************************
575  * PathUnquoteSpaces [SHELL32.56]
576  * 
577  * NOTES
578  *     unquote string (remove ")
579  */
580 VOID WINAPI PathUnquoteSpaces(LPSTR str) {
581     DWORD      len = lstrlen32A(str);
582     TRACE(shell,"%s\n",str);
583     if (*str!='"') return;
584     if (str[len-1]!='"') return;
585     str[len-1]='\0';
586     lstrcpy32A(str,str+1);
587     return;
588 }
589
590 /*************************************************************************
591  * PathGetDriveNumber32 [SHELL32.57]
592  *
593  */
594 HRESULT WINAPI PathGetDriveNumber32(LPSTR u)
595 {       FIXME(shell,"%s stub\n",debugstr_a(u));
596         return 0;
597 }
598
599 /*************************************************************************
600  * PathYetAnotherMakeUniqueName [SHELL32.75]
601  * 
602  * NOTES
603  *     exported by ordinal
604  */
605 BOOL32 WINAPI PathYetAnotherMakeUniqueName(LPDWORD x,LPDWORD y) {
606     FIXME(shell,"(%p,%p):stub.\n",x,y);
607     return TRUE;
608 }
609
610 /*************************************************************************
611  * IsLFNDrive [SHELL32.119]
612  * 
613  * NOTES
614  *     exported by ordinal Name
615  */
616 BOOL32 WINAPI IsLFNDrive(LPCSTR path) {
617     DWORD       fnlen;
618
619     if (!GetVolumeInformation32A(path,NULL,0,NULL,&fnlen,NULL,NULL,0))
620         return FALSE;
621     return fnlen>12;
622 }
623 /*************************************************************************
624  * PathFindOnPath [SHELL32.145]
625  */
626 BOOL32 WINAPI PathFindOnPath32A(LPSTR sFile, LPCSTR sOtherDirs)
627 {       FIXME(shell,"%s %s\n",sFile, sOtherDirs);
628         return FALSE;
629 }
630 BOOL32 WINAPI PathFindOnPath32W(LPWSTR sFile, LPCWSTR sOtherDirs)
631 {       FIXME(shell,"%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
632         return FALSE;
633 }
634 BOOL32 WINAPI PathFindOnPath32AW(LPVOID sFile, LPCVOID sOtherDirs)
635 {       if (VERSION_OsIsUnicode())
636           return PathFindOnPath32W(sFile, sOtherDirs);
637         return PathFindOnPath32A(sFile, sOtherDirs);
638 }
639
640 /*************************************************************************
641  * PathGetExtension [SHELL32.158]
642  *
643  * NOTES
644  *     exported by ordinal
645  */
646 LPCSTR WINAPI PathGetExtension32A(LPCSTR path,DWORD y,DWORD z)
647 {       TRACE(shell,"(%s,%08lx,%08lx)\n",path,y,z);
648         path = PathFindExtension32A(path);
649         return *path?(path+1):path;
650 }
651 LPCWSTR WINAPI PathGetExtension32W(LPCWSTR path,DWORD y,DWORD z)
652 {       TRACE(shell,"(L%s,%08lx,%08lx)\n",debugstr_w(path),y,z);
653         path = PathFindExtension32W(path);
654         return *path?(path+1):path;
655 }
656 LPCVOID WINAPI PathGetExtension32AW(LPCVOID path,DWORD y,DWORD z) 
657 {       if (VERSION_OsIsUnicode())
658           return PathGetExtension32W(path,y,z);
659         return PathGetExtension32A(path,y,z);
660 }
661
662 /*************************************************************************
663  * SheGetDirW [SHELL32.281]
664  *
665  */
666 HRESULT WINAPI SheGetDir32W(LPWSTR u, LPWSTR v)
667 {       FIXME(shell,"%s %s stub\n",debugstr_w(u),debugstr_w(v) );
668         return 0;
669 }
670
671 /*************************************************************************
672  * SheChangeDirW [SHELL32.274]
673  *
674  */
675 HRESULT WINAPI SheChangeDir32W(LPWSTR u)
676 {       FIXME(shell,"(%s),stub\n",debugstr_w(u));
677         return 0;
678 }
679
680 /*************************************************************************
681 *       PathProcessCommand      [SHELL32.653]
682 */
683 HRESULT WINAPI PathProcessCommand (DWORD u, DWORD v, DWORD w, DWORD x)
684 {       FIXME(shell,"0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",u,v,w,x);
685         return 0;
686 }