urlmon: Use flag to store protocol lock state.
[wine] / dlls / shell32 / shellole.c
1 /*
2  *      handling of SHELL32.DLL OLE-Objects
3  *
4  *      Copyright 1997  Marcus Meissner
5  *      Copyright 1998  Juergen Schmied  <juergen.schmied@metronet.de>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "shellapi.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36 #include "shlguid.h"
37 #include "winreg.h"
38 #include "winerror.h"
39
40 #include "undocshell.h"
41 #include "wine/unicode.h"
42 #include "shell32_main.h"
43
44 #include "wine/debug.h"
45 #include "shlwapi.h"
46 #include "debughlp.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49
50 extern HRESULT WINAPI IFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv);
51
52 static const WCHAR sShell32[12] = {'S','H','E','L','L','3','2','.','D','L','L','\0'};
53
54 /**************************************************************************
55  * Default ClassFactory types
56  */
57 typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
58 static IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst);
59
60 /* this table contains all CLSID's of shell32 objects */
61 static const struct {
62         REFIID                  riid;
63         LPFNCREATEINSTANCE      lpfnCI;
64 } InterfaceTable[] = {
65         {&CLSID_ShellFSFolder,  &IFSFolder_Constructor},
66         {&CLSID_MyComputer,     &ISF_MyComputer_Constructor},
67         {&CLSID_ShellDesktop,   &ISF_Desktop_Constructor},
68         {&CLSID_ShellLink,      &IShellLink_Constructor},
69         {&CLSID_DragDropHelper, &IDropTargetHelper_Constructor},
70         {&CLSID_ControlPanel,   &IControlPanel_Constructor},
71         {&CLSID_AutoComplete,   &IAutoComplete_Constructor},
72         {&CLSID_UnixFolder,     &UnixFolder_Constructor},
73         {&CLSID_UnixDosFolder,  &UnixDosFolder_Constructor},
74         {&CLSID_FolderShortcut, &FolderShortcut_Constructor},
75         {&CLSID_MyDocuments,    &MyDocuments_Constructor},
76         {&CLSID_RecycleBin,     &RecycleBin_Constructor},
77         {NULL,NULL}
78 };
79
80
81 /* FIXME: this should be SHLWAPI.24 since we can't yet import by ordinal */
82
83 DWORD WINAPI __SHGUIDToStringW (REFGUID guid, LPWSTR str)
84 {
85     WCHAR sFormat[52] = {'{','%','0','8','l','x','-','%','0','4',
86                          'x','-','%','0','4','x','-','%','0','2',
87                          'x','%','0','2','x','-','%','0','2','x',
88                          '%','0','2','x','%','0','2','x','%','0',
89                          '2','x','%','0','2','x','%','0','2','x',
90                          '}','\0'};
91
92     return wsprintfW ( str, sFormat,
93              guid->Data1, guid->Data2, guid->Data3,
94              guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
95              guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] );
96
97 }
98
99 /*************************************************************************
100  * SHCoCreateInstance [SHELL32.102]
101  *
102  * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes
103  * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see
104  * SHLoadOLE for details.
105  *
106  * Under wine if a "LoadWithoutCOM" value is present or the object resides in
107  * shell32.dll the function will load the object manually without the help of ole32
108  *
109  * NOTES
110  *     exported by ordinal
111  *
112  * SEE ALSO
113  *     CoCreateInstace, SHLoadOLE
114  */
115 HRESULT WINAPI SHCoCreateInstance(
116         LPCWSTR aclsid,
117         const CLSID *clsid,
118         LPUNKNOWN pUnkOuter,
119         REFIID refiid,
120         LPVOID *ppv)
121 {
122         DWORD   hres;
123         IID     iid;
124         const   CLSID * myclsid = clsid;
125         WCHAR   sKeyName[MAX_PATH];
126         const   WCHAR sCLSID[7] = {'C','L','S','I','D','\\','\0'};
127         WCHAR   sClassID[60];
128         const WCHAR sInProcServer32[16] ={'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'};
129         const WCHAR sLoadWithoutCOM[15] ={'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'};
130         WCHAR   sDllPath[MAX_PATH];
131         HKEY    hKey = 0;
132         DWORD   dwSize;
133         IClassFactory * pcf = NULL;
134
135         if(!ppv) return E_POINTER;
136         *ppv=NULL;
137
138         /* if the clsid is a string, convert it */
139         if (!clsid)
140         {
141           if (!aclsid) return REGDB_E_CLASSNOTREG;
142           SHCLSIDFromStringW(aclsid, &iid);
143           myclsid = &iid;
144         }
145
146         TRACE("(%p,%s,unk:%p,%s,%p)\n",
147                 aclsid,shdebugstr_guid(myclsid),pUnkOuter,shdebugstr_guid(refiid),ppv);
148
149         if (SUCCEEDED(DllGetClassObject(myclsid, &IID_IClassFactory,(LPVOID*)&pcf)))
150         {
151             hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv);
152             IClassFactory_Release(pcf);
153             goto end;
154         }
155
156         /* we look up the dll path in the registry */
157         __SHGUIDToStringW(myclsid, sClassID);
158         lstrcpyW(sKeyName, sCLSID);
159         lstrcatW(sKeyName, sClassID);
160         lstrcatW(sKeyName, sInProcServer32);
161
162         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey))
163             return E_ACCESSDENIED;
164
165         /* if a special registry key is set, we load a shell extension without help of OLE32 */
166         if (!SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0))
167         {
168             /* load an external dll without ole32 */
169             HANDLE hLibrary;
170             typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
171             DllGetClassObjectFunc DllGetClassObject;
172
173             dwSize = sizeof(sDllPath);
174             SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize );
175
176             if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
177                 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath));
178                 hres = E_ACCESSDENIED;
179                 goto end;
180             } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
181                 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath));
182                 FreeLibrary( hLibrary );
183                 hres = E_ACCESSDENIED;
184                 goto end;
185             } else if (! SUCCEEDED(hres = DllGetClassObject(myclsid, &IID_IClassFactory, (LPVOID*)&pcf))) {
186                     TRACE("GetClassObject failed 0x%08x\n", hres);
187                     goto end;
188             }
189
190             hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv);
191             IClassFactory_Release(pcf);
192         } else {
193
194             /* load an external dll in the usual way */
195             hres = CoCreateInstance(myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv);
196         }
197
198 end:
199         if (hKey) RegCloseKey(hKey);
200         if(hres!=S_OK)
201         {
202           ERR("failed (0x%08x) to create CLSID:%s IID:%s\n",
203               hres, shdebugstr_guid(myclsid), shdebugstr_guid(refiid));
204           ERR("class not found in registry\n");
205         }
206
207         TRACE("-- instance: %p\n",*ppv);
208         return hres;
209 }
210
211 /*************************************************************************
212  * DllGetClassObject     [SHELL32.@]
213  * SHDllGetClassObject   [SHELL32.128]
214  */
215 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
216 {
217         HRESULT hres = E_OUTOFMEMORY;
218         IClassFactory * pcf = NULL;
219         int i;
220
221         TRACE("CLSID:%s,IID:%s\n",shdebugstr_guid(rclsid),shdebugstr_guid(iid));
222
223         if (!ppv) return E_INVALIDARG;
224         *ppv = NULL;
225
226         /* search our internal interface table */
227         for(i=0;InterfaceTable[i].riid;i++) {
228             if(IsEqualIID(InterfaceTable[i].riid, rclsid)) {
229                 TRACE("index[%u]\n", i);
230                 pcf = IDefClF_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL);
231             }
232         }
233
234         if (!pcf) {
235             FIXME("failed for CLSID=%s\n", shdebugstr_guid(rclsid));
236             return CLASS_E_CLASSNOTAVAILABLE;
237         }
238
239         hres = IClassFactory_QueryInterface(pcf, iid, ppv);
240         IClassFactory_Release(pcf);
241
242         TRACE("-- pointer to class factory: %p\n",*ppv);
243         return hres;
244 }
245
246 /*************************************************************************
247  * SHCLSIDFromString                            [SHELL32.147]
248  *
249  * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed
250  * to avoid dependency on ole32.dll (see SHLoadOLE for details).
251  *
252  * Under Windows NT/2000/XP this is equivalent to CLSIDFromString
253  *
254  * NOTES
255  *     exported by ordinal
256  *
257  * SEE ALSO
258  *     CLSIDFromString, SHLoadOLE
259  */
260 DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id)
261 {
262     WCHAR buffer[40];
263     TRACE("(%p(%s) %p)\n", clsid, clsid, id);
264     if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) ))
265         return CO_E_CLASSSTRING;
266     return CLSIDFromString( buffer, id );
267 }
268 DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id)
269 {
270         TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
271         return CLSIDFromString((LPWSTR)clsid, id);
272 }
273 DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id)
274 {
275         if (SHELL_OsIsUnicode())
276           return SHCLSIDFromStringW (clsid, id);
277         return SHCLSIDFromStringA (clsid, id);
278 }
279
280 /*************************************************************************
281  *                       SHGetMalloc                    [SHELL32.@]
282  *
283  * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function
284  * could use the shell32 built-in "mini-COM" without the need to load ole32.dll -
285  * see SHLoadOLE for details. 
286  *
287  * PARAMS
288  *  lpmal [O] Destination for IMalloc interface.
289  *
290  * RETURNS
291  *  Success: S_OK. lpmal contains the shells IMalloc interface.
292  *  Failure. An HRESULT error code.
293  *
294  * SEE ALSO
295  *  CoGetMalloc, SHLoadOLE
296  */
297 HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal)
298 {
299         TRACE("(%p)\n", lpmal);
300         return CoGetMalloc(MEMCTX_TASK, lpmal);
301 }
302
303 /*************************************************************************
304  * SHAlloc                                      [SHELL32.196]
305  *
306  * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use
307  * the shell32 built-in "mini-COM" without the need to load ole32.dll -
308  * see SHLoadOLE for details. 
309  *
310  * NOTES
311  *     exported by ordinal
312  *
313  * SEE ALSO
314  *     CoTaskMemAlloc, SHLoadOLE
315  */
316 LPVOID WINAPI SHAlloc(DWORD len)
317 {
318         LPVOID ret;
319
320         ret = CoTaskMemAlloc(len);
321         TRACE("%u bytes at %p\n",len, ret);
322         return ret;
323 }
324
325 /*************************************************************************
326  * SHFree                                       [SHELL32.195]
327  *
328  * Equivalent to CoTaskMemFree. Under Windows 9x this function could use
329  * the shell32 built-in "mini-COM" without the need to load ole32.dll -
330  * see SHLoadOLE for details. 
331  *
332  * NOTES
333  *     exported by ordinal
334  *
335  * SEE ALSO
336  *     CoTaskMemFree, SHLoadOLE
337  */
338 void WINAPI SHFree(LPVOID pv)
339 {
340         TRACE("%p\n",pv);
341         CoTaskMemFree(pv);
342 }
343
344 /*************************************************************************
345  * SHGetDesktopFolder                   [SHELL32.@]
346  */
347 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
348 {
349         HRESULT hres = S_OK;
350         TRACE("\n");
351
352         if(!psf) return E_INVALIDARG;
353         *psf = NULL;
354         hres = ISF_Desktop_Constructor(NULL, &IID_IShellFolder,(LPVOID*)psf);
355
356         TRACE("-- %p->(%p)\n",psf, *psf);
357         return hres;
358 }
359 /**************************************************************************
360  * Default ClassFactory Implementation
361  *
362  * SHCreateDefClassObject
363  *
364  * NOTES
365  *  Helper function for dlls without their own classfactory.
366  *  A generic classfactory is returned.
367  *  When the CreateInstance of the cf is called the callback is executed.
368  */
369
370 typedef struct
371 {
372     const IClassFactoryVtbl    *lpVtbl;
373     LONG                        ref;
374     CLSID                       *rclsid;
375     LPFNCREATEINSTANCE          lpfnCI;
376     const IID *                 riidInst;
377     LONG *                      pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
378 } IDefClFImpl;
379
380 static const IClassFactoryVtbl dclfvt;
381
382 /**************************************************************************
383  *  IDefClF_fnConstructor
384  */
385
386 static IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst)
387 {
388         IDefClFImpl* lpclf;
389
390         lpclf = HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl));
391         lpclf->ref = 1;
392         lpclf->lpVtbl = &dclfvt;
393         lpclf->lpfnCI = lpfnCI;
394         lpclf->pcRefDll = pcRefDll;
395
396         if (pcRefDll) InterlockedIncrement(pcRefDll);
397         lpclf->riidInst = riidInst;
398
399         TRACE("(%p)%s\n",lpclf, shdebugstr_guid(riidInst));
400         return (LPCLASSFACTORY)lpclf;
401 }
402 /**************************************************************************
403  *  IDefClF_fnQueryInterface
404  */
405 static HRESULT WINAPI IDefClF_fnQueryInterface(
406   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
407 {
408         IDefClFImpl *This = (IDefClFImpl *)iface;
409
410         TRACE("(%p)->(%s)\n",This,shdebugstr_guid(riid));
411
412         *ppvObj = NULL;
413
414         if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) {
415           *ppvObj = This;
416           InterlockedIncrement(&This->ref);
417           return S_OK;
418         }
419
420         TRACE("-- E_NOINTERFACE\n");
421         return E_NOINTERFACE;
422 }
423 /******************************************************************************
424  * IDefClF_fnAddRef
425  */
426 static ULONG WINAPI IDefClF_fnAddRef(LPCLASSFACTORY iface)
427 {
428         IDefClFImpl *This = (IDefClFImpl *)iface;
429         ULONG refCount = InterlockedIncrement(&This->ref);
430
431         TRACE("(%p)->(count=%u)\n", This, refCount - 1);
432
433         return refCount;
434 }
435 /******************************************************************************
436  * IDefClF_fnRelease
437  */
438 static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface)
439 {
440         IDefClFImpl *This = (IDefClFImpl *)iface;
441         ULONG refCount = InterlockedDecrement(&This->ref);
442         
443         TRACE("(%p)->(count=%u)\n", This, refCount + 1);
444
445         if (!refCount)
446         {
447           if (This->pcRefDll) InterlockedDecrement(This->pcRefDll);
448
449           TRACE("-- destroying IClassFactory(%p)\n",This);
450           HeapFree(GetProcessHeap(),0,This);
451           return 0;
452         }
453         return refCount;
454 }
455 /******************************************************************************
456  * IDefClF_fnCreateInstance
457  */
458 static HRESULT WINAPI IDefClF_fnCreateInstance(
459   LPCLASSFACTORY iface, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
460 {
461         IDefClFImpl *This = (IDefClFImpl *)iface;
462
463         TRACE("%p->(%p,%s,%p)\n",This,pUnkOuter,shdebugstr_guid(riid),ppvObject);
464
465         *ppvObject = NULL;
466
467         if ( This->riidInst==NULL ||
468              IsEqualCLSID(riid, This->riidInst) ||
469              IsEqualCLSID(riid, &IID_IUnknown) )
470         {
471           return This->lpfnCI(pUnkOuter, riid, ppvObject);
472         }
473
474         ERR("unknown IID requested %s\n",shdebugstr_guid(riid));
475         return E_NOINTERFACE;
476 }
477 /******************************************************************************
478  * IDefClF_fnLockServer
479  */
480 static HRESULT WINAPI IDefClF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
481 {
482         IDefClFImpl *This = (IDefClFImpl *)iface;
483         TRACE("%p->(0x%x), not implemented\n",This, fLock);
484         return E_NOTIMPL;
485 }
486
487 static const IClassFactoryVtbl dclfvt =
488 {
489     IDefClF_fnQueryInterface,
490     IDefClF_fnAddRef,
491   IDefClF_fnRelease,
492   IDefClF_fnCreateInstance,
493   IDefClF_fnLockServer
494 };
495
496 /******************************************************************************
497  * SHCreateDefClassObject                       [SHELL32.70]
498  */
499 HRESULT WINAPI SHCreateDefClassObject(
500         REFIID  riid,
501         LPVOID* ppv,
502         LPFNCREATEINSTANCE lpfnCI,      /* [in] create instance callback entry */
503         LPDWORD pcRefDll,               /* [in/out] ref count of the dll */
504         REFIID  riidInst)               /* [in] optional interface to the instance */
505 {
506         IClassFactory * pcf;
507
508         TRACE("%s %p %p %p %s\n",
509               shdebugstr_guid(riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(riidInst));
510
511         if (! IsEqualCLSID(riid, &IID_IClassFactory) ) return E_NOINTERFACE;
512         if (! (pcf = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, riidInst))) return E_OUTOFMEMORY;
513         *ppv = pcf;
514         return NOERROR;
515 }
516
517 /*************************************************************************
518  *  DragAcceptFiles             [SHELL32.@]
519  */
520 void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
521 {
522         LONG exstyle;
523
524         if( !IsWindow(hWnd) ) return;
525         exstyle = GetWindowLongA(hWnd,GWL_EXSTYLE);
526         if (b)
527           exstyle |= WS_EX_ACCEPTFILES;
528         else
529           exstyle &= ~WS_EX_ACCEPTFILES;
530         SetWindowLongA(hWnd,GWL_EXSTYLE,exstyle);
531 }
532
533 /*************************************************************************
534  * DragFinish           [SHELL32.@]
535  */
536 void WINAPI DragFinish(HDROP h)
537 {
538         TRACE("\n");
539         GlobalFree((HGLOBAL)h);
540 }
541
542 /*************************************************************************
543  * DragQueryPoint               [SHELL32.@]
544  */
545 BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
546 {
547         DROPFILES *lpDropFileStruct;
548         BOOL bRet;
549
550         TRACE("\n");
551
552         lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
553
554         *p = lpDropFileStruct->pt;
555         bRet = lpDropFileStruct->fNC;
556
557         GlobalUnlock(hDrop);
558         return bRet;
559 }
560
561 /*************************************************************************
562  *  DragQueryFileA              [SHELL32.@]
563  *  DragQueryFile               [SHELL32.@]
564  */
565 UINT WINAPI DragQueryFileA(
566         HDROP hDrop,
567         UINT lFile,
568         LPSTR lpszFile,
569         UINT lLength)
570 {
571         LPSTR lpDrop;
572         UINT i = 0;
573         DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
574
575         TRACE("(%p, %x, %p, %u)\n",     hDrop,lFile,lpszFile,lLength);
576
577         if(!lpDropFileStruct) goto end;
578
579         lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles;
580
581         if(lpDropFileStruct->fWide) {
582             LPWSTR lpszFileW = NULL;
583
584             if(lpszFile) {
585                 lpszFileW = HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR));
586                 if(lpszFileW == NULL) {
587                     goto end;
588                 }
589             }
590             i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength);
591
592             if(lpszFileW) {
593                 WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL);
594                 HeapFree(GetProcessHeap(), 0, lpszFileW);
595             }
596             goto end;
597         }
598
599         while (i++ < lFile)
600         {
601           while (*lpDrop++); /* skip filename */
602           if (!*lpDrop)
603           {
604             i = (lFile == 0xFFFFFFFF) ? i : 0;
605             goto end;
606           }
607         }
608
609         i = strlen(lpDrop);
610         if (!lpszFile ) goto end;   /* needed buffer size */
611         lstrcpynA (lpszFile, lpDrop, lLength);
612 end:
613         GlobalUnlock(hDrop);
614         return i;
615 }
616
617 /*************************************************************************
618  *  DragQueryFileW              [SHELL32.@]
619  */
620 UINT WINAPI DragQueryFileW(
621         HDROP hDrop,
622         UINT lFile,
623         LPWSTR lpszwFile,
624         UINT lLength)
625 {
626         LPWSTR lpwDrop;
627         UINT i = 0;
628         DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
629
630         TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
631
632         if(!lpDropFileStruct) goto end;
633
634         lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles);
635
636         if(lpDropFileStruct->fWide == FALSE) {
637             LPSTR lpszFileA = NULL;
638
639             if(lpszwFile) {
640                 lpszFileA = HeapAlloc(GetProcessHeap(), 0, lLength);
641                 if(lpszFileA == NULL) {
642                     goto end;
643                 }
644             }
645             i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength);
646
647             if(lpszFileA) {
648                 MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength);
649                 HeapFree(GetProcessHeap(), 0, lpszFileA);
650             }
651             goto end;
652         }
653
654         i = 0;
655         while (i++ < lFile)
656         {
657           while (*lpwDrop++); /* skip filename */
658           if (!*lpwDrop)
659           {
660             i = (lFile == 0xFFFFFFFF) ? i : 0;
661             goto end;
662           }
663         }
664
665         i = strlenW(lpwDrop);
666         if ( !lpszwFile) goto end;   /* needed buffer size */
667         lstrcpynW (lpszwFile, lpwDrop, lLength);
668 end:
669         GlobalUnlock(hDrop);
670         return i;
671 }