SHGetFileInfo32A: get SHGFI_SYSICONINDEX implemented.
[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         else
309         { strcpy(sTemp,lpszDir);
310           PathAddBackslash32A(sTemp);
311           strcat(sTemp,lpszFile);
312           strcpy(szDest,sTemp);
313         }
314         return szDest;
315 }
316 LPWSTR WINAPI PathCombine32W(LPWSTR szDest, LPCWSTR lpszDir, LPCWSTR lpszFile) 
317 {       WCHAR sTemp[MAX_PATH];
318         TRACE(shell,"%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
319                          lpszFile, debugstr_w(lpszFile));
320         
321         
322         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) ) 
323         { lstrcpy32W(szDest,lpszDir);
324           return szDest;
325         }
326
327         /*  if lpszFile is a complete path don't care about lpszDir */
328         if (PathIsRoot32W(lpszFile))
329         { lstrcpy32W(szDest,lpszFile);
330         }
331         else
332         { lstrcpy32W(sTemp,lpszDir);
333           PathAddBackslash32W(sTemp);
334           lstrcat32W(sTemp,lpszFile);
335           lstrcpy32W(szDest,sTemp);
336         }
337         return szDest;
338 }
339 LPVOID WINAPI PathCombine32AW(LPVOID szDest, LPCVOID lpszDir, LPCVOID lpszFile) 
340 {       if (VERSION_OsIsUnicode())
341           return PathCombine32W( szDest, lpszDir, lpszFile );
342         return PathCombine32A( szDest, lpszDir, lpszFile );
343 }
344
345 /*************************************************************************
346  * PathIsUNC [SHELL32.39]
347  * 
348  * NOTES
349  *     PathIsUNC(char*path);
350  */
351 BOOL32 WINAPI PathIsUNC32A(LPCSTR path) 
352 {       TRACE(shell,"%s\n",path);
353
354         if ((path[0]=='\\') && (path[1]=='\\'))
355           return TRUE;
356         return FALSE;
357 }
358 BOOL32 WINAPI PathIsUNC32W(LPCWSTR path) 
359 {       TRACE(shell,"%s\n",debugstr_w(path));
360
361         if ((path[0]=='\\') && (path[1]=='\\'))
362           return TRUE;
363         return FALSE;
364 }
365 BOOL32 WINAPI PathIsUNC32AW (LPCVOID path)
366 {       if (VERSION_OsIsUnicode())
367           return PathIsUNC32W( path );
368         return PathIsUNC32A( path );  
369 }
370 /*************************************************************************
371  *  PathIsRelativ [SHELL32.40]
372  * 
373  */
374 BOOL32 WINAPI PathIsRelative32A (LPCSTR path)
375 {       TRACE(shell,"path=%s\n",path);
376
377         if (path && (path[0]!='\\' && path[1]==':'))
378           return TRUE;
379         return FALSE;    
380 }
381 BOOL32 WINAPI PathIsRelative32W (LPCWSTR path)
382 {       TRACE(shell,"path=%s\n",debugstr_w(path));
383
384         if (path && (path[0]!='\\' && path[1]==':'))
385           return TRUE;
386         return FALSE;    
387 }
388 BOOL32 WINAPI PathIsRelative32AW (LPCVOID path)
389 {       if (VERSION_OsIsUnicode())
390           return PathIsRelative32W( path );
391         return PathIsRelative32A( path );  
392 }
393 /*************************************************************************
394  *  PathIsExe [SHELL32.43]
395  * 
396  */
397 BOOL32 WINAPI PathIsExe (LPCSTR path)
398 {  TRACE(shell,"path=%s\n",path);
399     return FALSE;
400 }
401
402 /*************************************************************************
403  * PathFileExists [SHELL32.45]
404  * 
405  * NOTES
406  *     file_exists(char *fn);
407  */
408 BOOL32 WINAPI PathFileExists(LPSTR fn) {
409   TRACE(shell,"%s\n",fn);
410    if (GetFileAttributes32A(fn)==-1)
411         return FALSE;
412     else
413         return TRUE;
414 }
415 /*************************************************************************
416  * PathMatchSpec [SHELL32.46]
417  * 
418  * NOTES
419  *     used from COMDLG32
420  */
421
422 BOOL32 WINAPI PathMatchSpec32A(LPCSTR name, LPCSTR mask) 
423 {       LPCSTR _name;
424
425         TRACE(shell,"%s %s stub\n",name,mask);
426
427         _name = name;
428         while (*_name && *mask)
429         { if (*mask ==';')
430           { mask++;
431             _name = name;
432           }
433           else if (*mask == '*')
434           { mask++;
435             while (*mask == '*') mask++;                /* Skip consecutive '*' */
436             if (!*mask || *mask==';') return TRUE;      /* '*' matches everything */
437             while (*_name && (toupper(*_name) != toupper(*mask))) _name++;
438             if (!*_name)
439             { while ( *mask && *mask != ';') mask++;
440               _name = name;
441             }
442           }
443           else if ( (*mask == '?') || (toupper(*mask) == toupper(*_name)) )
444           { mask++;
445             _name++;
446           }
447           else
448           { while ( *mask && *mask != ';') mask++;
449           }
450         }
451         return (!*_name && (!*mask || *mask==';'));
452 }
453 BOOL32 WINAPI PathMatchSpec32W(LPCWSTR name, LPCWSTR mask) 
454 {       WCHAR stemp[4];
455         LPCWSTR _name;
456         
457         TRACE(shell,"%s %s stub\n",debugstr_w(name),debugstr_w(mask));
458
459         lstrcpyAtoW(stemp,"*.*");       
460         if (!lstrcmp32W( mask, stemp )) return 1;
461
462         _name = name;
463         while (*_name && *mask)
464         { if (*mask ==';')
465           { mask++;
466             _name = name;
467           }
468           else if (*mask == '*')
469           { mask++;
470             while (*mask == '*') mask++;                /* Skip consecutive '*' */
471             if (!*mask || *mask==';') return TRUE;      /* '*' matches everything */
472             while (*_name && (towupper(*_name) != towupper(*mask))) _name++;
473             if (!*_name)
474             { while ( *mask && *mask != ';') mask++;
475               _name = name;
476             }
477           }
478           else if ( (*mask == '?') || (towupper(*mask) == towupper(*_name)) )
479           { mask++;
480             _name++;
481           }
482           else
483           { while ( *mask && *mask != ';') mask++;
484           }
485         }
486         return (!*_name && (!*mask || *mask==';'));
487 }
488 BOOL32 WINAPI PathMatchSpec32AW(LPVOID name, LPVOID mask) 
489 {       if (VERSION_OsIsUnicode())
490           return PathMatchSpec32W( name, mask );
491         return PathMatchSpec32A( name, mask );
492 }
493 /*************************************************************************
494  * PathSetDlgItemPath32AW [SHELL32.48]
495  * NOTES
496  *  use PathCompactPath to make sure, the path fits into the control
497  */
498
499 BOOL32 WINAPI PathSetDlgItemPath32A(HWND32 hDlg, int id, LPCSTR pszPath) 
500 {       TRACE(shell,"%x %x %s\n",hDlg, id, pszPath);
501         return SetDlgItemText32A(hDlg, id, pszPath);
502 }
503 BOOL32 WINAPI PathSetDlgItemPath32W(HWND32 hDlg, int id, LPCWSTR pszPath) 
504 {       TRACE(shell,"%x %x %s\n",hDlg, id, debugstr_w(pszPath));
505         return SetDlgItemText32W(hDlg, id, pszPath);
506 }
507 BOOL32 WINAPI PathSetDlgItemPath32AW(HWND32 hDlg, int id, LPCVOID pszPath) 
508 {       if (VERSION_OsIsUnicode())
509           return PathSetDlgItemPath32W(hDlg, id, pszPath);
510         return PathSetDlgItemPath32A(hDlg, id, pszPath);
511 }
512
513 /*************************************************************************
514  * PathResolve [SHELL32.51]
515  */
516 DWORD WINAPI PathResolve(LPCSTR s,DWORD x2,DWORD x3) {
517         FIXME(shell,"(%s,0x%08lx,0x%08lx),stub!\n",s,x2,x3);
518         return 0;
519 }
520
521 /*************************************************************************
522  * PathGetArgs [SHELL32.52]
523  *
524  * NOTES
525  *     look for next arg in string. handle "quoted" strings
526  *     returns pointer to argument *AFTER* the space. Or to the \0.
527  */
528 LPVOID WINAPI PathGetArgs(LPVOID cmdline) 
529 {       BOOL32  qflag = FALSE;
530         LPWSTR wptr;
531         LPSTR aptr;
532         
533         if (VERSION_OsIsUnicode())
534         { TRACE(shell,"%sL\n",debugstr_w((LPWSTR)cmdline));
535           wptr=(LPWSTR) cmdline;
536           while (*wptr) 
537           { if ((*wptr==' ') && !qflag)
538                 return wptr+1;
539             if (*wptr=='"')
540                 qflag=!qflag;
541             wptr++;
542           }
543           return (LPVOID) wptr;
544         }
545         TRACE(shell,"%s\n",(LPSTR)cmdline);
546         aptr=(LPSTR) cmdline;
547         while (*aptr) 
548         { if ((*aptr==' ') && !qflag)
549             return aptr+1;
550           if (*aptr=='"')
551             qflag=!qflag;
552           aptr++;
553         }
554         return (LPVOID) aptr;
555 }
556 /*************************************************************************
557  * PathQuoteSpaces [SHELL32.55]
558  * 
559  * NOTES
560  *     basename(char *fn);
561  */
562 LPSTR WINAPI PathQuoteSpaces32A(LPCSTR aptr)
563 {       FIXME(shell,"%s\n",aptr);
564         return 0;
565
566 }
567 LPWSTR WINAPI PathQuoteSpaces32W(LPCWSTR wptr)
568 {       FIXME(shell,"L%s\n",debugstr_w(wptr));
569         return 0;       
570 }
571 LPVOID WINAPI PathQuoteSpaces32AW (LPCVOID fn)
572 {       if(VERSION_OsIsUnicode())
573           return PathQuoteSpaces32W(fn);
574         return PathQuoteSpaces32A(fn);
575 }
576
577
578 /*************************************************************************
579  * PathUnquoteSpaces [SHELL32.56]
580  * 
581  * NOTES
582  *     unquote string (remove ")
583  */
584 VOID WINAPI PathUnquoteSpaces(LPSTR str) {
585     DWORD      len = lstrlen32A(str);
586     TRACE(shell,"%s\n",str);
587     if (*str!='"') return;
588     if (str[len-1]!='"') return;
589     str[len-1]='\0';
590     lstrcpy32A(str,str+1);
591     return;
592 }
593
594 /*************************************************************************
595  * PathGetDriveNumber32 [SHELL32.57]
596  *
597  */
598 HRESULT WINAPI PathGetDriveNumber32(LPSTR u)
599 {       FIXME(shell,"%s stub\n",debugstr_a(u));
600         return 0;
601 }
602
603 /*************************************************************************
604  * PathYetAnotherMakeUniqueName [SHELL32.75]
605  * 
606  * NOTES
607  *     exported by ordinal
608  */
609 BOOL32 WINAPI PathYetAnotherMakeUniqueName(LPDWORD x,LPDWORD y) {
610     FIXME(shell,"(%p,%p):stub.\n",x,y);
611     return TRUE;
612 }
613
614 /*************************************************************************
615  * IsLFNDrive [SHELL32.119]
616  * 
617  * NOTES
618  *     exported by ordinal Name
619  */
620 BOOL32 WINAPI IsLFNDrive(LPCSTR path) {
621     DWORD       fnlen;
622
623     if (!GetVolumeInformation32A(path,NULL,0,NULL,&fnlen,NULL,NULL,0))
624         return FALSE;
625     return fnlen>12;
626 }
627 /*************************************************************************
628  * PathFindOnPath [SHELL32.145]
629  */
630 BOOL32 WINAPI PathFindOnPath32A(LPSTR sFile, LPCSTR sOtherDirs)
631 {       FIXME(shell,"%s %s\n",sFile, sOtherDirs);
632         return FALSE;
633 }
634 BOOL32 WINAPI PathFindOnPath32W(LPWSTR sFile, LPCWSTR sOtherDirs)
635 {       FIXME(shell,"%s %s\n",debugstr_w(sFile), debugstr_w(sOtherDirs));
636         return FALSE;
637 }
638 BOOL32 WINAPI PathFindOnPath32AW(LPVOID sFile, LPCVOID sOtherDirs)
639 {       if (VERSION_OsIsUnicode())
640           return PathFindOnPath32W(sFile, sOtherDirs);
641         return PathFindOnPath32A(sFile, sOtherDirs);
642 }
643
644 /*************************************************************************
645  * PathGetExtension [SHELL32.158]
646  *
647  * NOTES
648  *     exported by ordinal
649  */
650 LPCSTR WINAPI PathGetExtension32A(LPCSTR path,DWORD y,DWORD z)
651 {       TRACE(shell,"(%s,%08lx,%08lx)\n",path,y,z);
652         path = PathFindExtension32A(path);
653         return *path?(path+1):path;
654 }
655 LPCWSTR WINAPI PathGetExtension32W(LPCWSTR path,DWORD y,DWORD z)
656 {       TRACE(shell,"(L%s,%08lx,%08lx)\n",debugstr_w(path),y,z);
657         path = PathFindExtension32W(path);
658         return *path?(path+1):path;
659 }
660 LPCVOID WINAPI PathGetExtension32AW(LPCVOID path,DWORD y,DWORD z) 
661 {       if (VERSION_OsIsUnicode())
662           return PathGetExtension32W(path,y,z);
663         return PathGetExtension32A(path,y,z);
664 }
665
666 /*************************************************************************
667  * SheGetDirW [SHELL32.281]
668  *
669  */
670 HRESULT WINAPI SheGetDir32W(LPWSTR u, LPWSTR v)
671 {       FIXME(shell,"%s %s stub\n",debugstr_w(u),debugstr_w(v) );
672         return 0;
673 }
674
675 /*************************************************************************
676  * SheChangeDirW [SHELL32.274]
677  *
678  */
679 HRESULT WINAPI SheChangeDir32W(LPWSTR u)
680 {       FIXME(shell,"(%s),stub\n",debugstr_w(u));
681         return 0;
682 }
683
684 /*************************************************************************
685 *       PathProcessCommand      [SHELL32.653]
686 */
687 HRESULT WINAPI PathProcessCommand (DWORD u, DWORD v, DWORD w, DWORD x)
688 {       FIXME(shell,"0x%04lx 0x%04lx 0x%04lx 0x%04lx stub\n",u,v,w,x);
689         return 0;
690 }