xref: /reactos/dll/win32/shell32/wine/shellole.c (revision 9d3c3a75)
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 <wine/config.h>
23 
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #define WIN32_NO_STATUS
29 #define _INC_WINDOWS
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 
33 #include <windef.h>
34 #include <winbase.h>
35 #include <shellapi.h>
36 #include <shlobj.h>
37 #include <shlwapi.h>
38 #include <debughlp.h>
39 
40 #include <wine/debug.h>
41 #include <wine/unicode.h>
42 
43 #include "shell32_main.h"
44 
45 WINE_DEFAULT_DEBUG_CHANNEL(shell);
46 
47 extern INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax);  /* shlwapi.24 */
48 
49 /**************************************************************************
50  * Default ClassFactory types
51  */
52 typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
53 
54 #ifndef __REACTOS__
55 
56 static IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst);
57 
58 /* this table contains all CLSIDs of shell32 objects */
59 static const struct {
60 	REFIID			clsid;
61 	LPFNCREATEINSTANCE	lpfnCI;
62 } InterfaceTable[] = {
63 
64 	{&CLSID_ApplicationAssociationRegistration, ApplicationAssociationRegistration_Constructor},
65 	{&CLSID_AutoComplete,   IAutoComplete_Constructor},
66 	{&CLSID_ControlPanel,	IControlPanel_Constructor},
67 	{&CLSID_DragDropHelper, IDropTargetHelper_Constructor},
68 	{&CLSID_FolderShortcut, FolderShortcut_Constructor},
69 	{&CLSID_MyComputer,	ISF_MyComputer_Constructor},
70 	{&CLSID_MyDocuments,    MyDocuments_Constructor},
71 	{&CLSID_NetworkPlaces,  ISF_NetworkPlaces_Constructor},
72 	{&CLSID_Printers,       Printers_Constructor},
73 	{&CLSID_QueryAssociations, QueryAssociations_Constructor},
74 	{&CLSID_RecycleBin,     RecycleBin_Constructor},
75 	{&CLSID_ShellDesktop,	ISF_Desktop_Constructor},
76 	{&CLSID_ShellFSFolder,	IFSFolder_Constructor},
77 	{&CLSID_ShellItem,	IShellItem_Constructor},
78 	{&CLSID_ShellLink,	IShellLink_Constructor},
79 	{&CLSID_UnixDosFolder,  UnixDosFolder_Constructor},
80 	{&CLSID_UnixFolder,     UnixFolder_Constructor},
81 	{&CLSID_ExplorerBrowser,ExplorerBrowser_Constructor},
82 	{&CLSID_KnownFolderManager, KnownFolderManager_Constructor},
83 	{&CLSID_Shell,          IShellDispatch_Constructor},
84 	{NULL, NULL}
85 };
86 
87 #endif /* !__REACTOS__ */
88 
89 /*************************************************************************
90  * SHCoCreateInstance [SHELL32.102]
91  *
92  * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes
93  * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see
94  * SHLoadOLE for details.
95  *
96  * Under wine if a "LoadWithoutCOM" value is present or the object resides in
97  * shell32.dll the function will load the object manually without the help of ole32
98  *
99  * NOTES
100  *     exported by ordinal
101  *
102  * SEE ALSO
103  *     CoCreateInstance, SHLoadOLE
104  */
105 HRESULT WINAPI SHCoCreateInstance(
106 	LPCWSTR aclsid,
107 	const CLSID *clsid,
108 	LPUNKNOWN pUnkOuter,
109 	REFIID refiid,
110 	LPVOID *ppv)
111 {
112 	DWORD	hres;
113 	CLSID	iid;
114 	const	CLSID * myclsid = clsid;
115 	WCHAR	sKeyName[MAX_PATH];
116 	WCHAR	sClassID[60];
117 	WCHAR	sDllPath[MAX_PATH];
118 	HKEY	hKey = 0;
119 	DWORD	dwSize;
120 	IClassFactory * pcf = NULL;
121 
122 	if(!ppv) return E_POINTER;
123 	*ppv=NULL;
124 
125 	/* if the clsid is a string, convert it */
126 	if (!clsid)
127 	{
128 	  if (!aclsid) return REGDB_E_CLASSNOTREG;
129 	  SHCLSIDFromStringW(aclsid, &iid);
130 	  myclsid = &iid;
131 	}
132 
133 	TRACE("(%p,%s,unk:%p,%s,%p)\n",
134 		aclsid,shdebugstr_guid(myclsid),pUnkOuter,shdebugstr_guid(refiid),ppv);
135 
136         if (SUCCEEDED(DllGetClassObject(myclsid, &IID_IClassFactory,(LPVOID*)&pcf)))
137         {
138             hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv);
139             IClassFactory_Release(pcf);
140             goto end;
141         }
142 
143 	/* we look up the dll path in the registry */
144 	SHStringFromGUIDW(myclsid, sClassID, ARRAY_SIZE(sClassID));
145 	swprintf(sKeyName, L"CLSID\\%s\\InprocServer32", sClassID);
146 
147 	if (RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey))
148             return E_ACCESSDENIED;
149 
150         /* if a special registry key is set, we load a shell extension without help of OLE32 */
151         if (!SHQueryValueExW(hKey, L"LoadWithoutCOM", 0, 0, 0, 0))
152         {
153 	    /* load an external dll without ole32 */
154 	    HANDLE hLibrary;
155 	    typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
156 	    DllGetClassObjectFunc DllGetClassObject;
157 
158             dwSize = sizeof(sDllPath);
159             SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize );
160 
161 	    if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
162 	        ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath));
163 		hres = E_ACCESSDENIED;
164 	        goto end;
165 	    } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
166 	        ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath));
167 	        FreeLibrary( hLibrary );
168 		hres = E_ACCESSDENIED;
169 	        goto end;
170             } else if (FAILED(hres = DllGetClassObject(myclsid, &IID_IClassFactory, (LPVOID*)&pcf))) {
171 		    TRACE("GetClassObject failed 0x%08x\n", hres);
172 		    goto end;
173 	    }
174 
175             hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv);
176             IClassFactory_Release(pcf);
177 	} else {
178 
179 	    /* load an external dll in the usual way */
180 	    hres = CoCreateInstance(myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv);
181 	}
182 
183 end:
184         if (hKey) RegCloseKey(hKey);
185 	if(hres!=S_OK)
186 	{
187 	  ERR("failed (0x%08x) to create CLSID:%s IID:%s\n",
188               hres, shdebugstr_guid(myclsid), shdebugstr_guid(refiid));
189 	  ERR("class not found in registry\n");
190 	}
191 
192 	TRACE("-- instance: %p\n",*ppv);
193 	return hres;
194 }
195 
196 #ifndef __REACTOS__
197 /*************************************************************************
198  * DllGetClassObject     [SHELL32.@]
199  * SHDllGetClassObject   [SHELL32.128]
200  */
201 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
202 {
203 	IClassFactory * pcf = NULL;
204 	HRESULT	hres;
205 	int i;
206 
207 	TRACE("CLSID:%s,IID:%s\n",shdebugstr_guid(rclsid),shdebugstr_guid(iid));
208 
209 	if (!ppv) return E_INVALIDARG;
210 	*ppv = NULL;
211 
212 	/* search our internal interface table */
213 	for(i=0;InterfaceTable[i].clsid;i++) {
214 	    if(IsEqualIID(InterfaceTable[i].clsid, rclsid)) {
215 	        TRACE("index[%u]\n", i);
216 	        pcf = IDefClF_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL);
217 	        break;
218 	    }
219 	}
220 
221         if (!pcf) {
222 	    FIXME("failed for CLSID=%s\n", shdebugstr_guid(rclsid));
223 	    return CLASS_E_CLASSNOTAVAILABLE;
224 	}
225 
226 	hres = IClassFactory_QueryInterface(pcf, iid, ppv);
227 	IClassFactory_Release(pcf);
228 
229 	TRACE("-- pointer to class factory: %p\n",*ppv);
230 	return hres;
231 }
232 #endif
233 
234 /*************************************************************************
235  * SHCLSIDFromString				[SHELL32.147]
236  *
237  * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed
238  * to avoid dependency on ole32.dll (see SHLoadOLE for details).
239  *
240  * Under Windows NT/2000/XP this is equivalent to CLSIDFromString
241  *
242  * NOTES
243  *     exported by ordinal
244  *
245  * SEE ALSO
246  *     CLSIDFromString, SHLoadOLE
247  */
248 DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id)
249 {
250     WCHAR buffer[40];
251     TRACE("(%p(%s) %p)\n", clsid, clsid, id);
252     if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) ))
253         return CO_E_CLASSSTRING;
254     return CLSIDFromString( buffer, id );
255 }
256 DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id)
257 {
258 	TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
259 	return CLSIDFromString(clsid, id);
260 }
261 DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id)
262 {
263 	if (SHELL_OsIsUnicode())
264 	  return SHCLSIDFromStringW (clsid, id);
265 	return SHCLSIDFromStringA (clsid, id);
266 }
267 
268 /*************************************************************************
269  *			 SHGetMalloc			[SHELL32.@]
270  *
271  * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function
272  * could use the shell32 built-in "mini-COM" without the need to load ole32.dll -
273  * see SHLoadOLE for details.
274  *
275  * PARAMS
276  *  lpmal [O] Destination for IMalloc interface.
277  *
278  * RETURNS
279  *  Success: S_OK. lpmal contains the shells IMalloc interface.
280  *  Failure. An HRESULT error code.
281  *
282  * SEE ALSO
283  *  CoGetMalloc, SHLoadOLE
284  */
285 HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal)
286 {
287 	TRACE("(%p)\n", lpmal);
288 	return CoGetMalloc(MEMCTX_TASK, lpmal);
289 }
290 
291 /*************************************************************************
292  * SHAlloc					[SHELL32.196]
293  *
294  * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use
295  * the shell32 built-in "mini-COM" without the need to load ole32.dll -
296  * see SHLoadOLE for details.
297  *
298  * NOTES
299  *     exported by ordinal
300  *
301  * SEE ALSO
302  *     CoTaskMemAlloc, SHLoadOLE
303  */
304 LPVOID WINAPI SHAlloc(SIZE_T len)
305 {
306 	LPVOID ret;
307 
308 	ret = CoTaskMemAlloc(len);
309 	TRACE("%u bytes at %p\n",len, ret);
310 	return ret;
311 }
312 
313 /*************************************************************************
314  * SHFree					[SHELL32.195]
315  *
316  * Equivalent to CoTaskMemFree. Under Windows 9x this function could use
317  * the shell32 built-in "mini-COM" without the need to load ole32.dll -
318  * see SHLoadOLE for details.
319  *
320  * NOTES
321  *     exported by ordinal
322  *
323  * SEE ALSO
324  *     CoTaskMemFree, SHLoadOLE
325  */
326 void WINAPI SHFree(LPVOID pv)
327 {
328 	TRACE("%p\n",pv);
329 	CoTaskMemFree(pv);
330 }
331 
332 #ifndef __REACTOS__
333 /*************************************************************************
334  * SHGetDesktopFolder			[SHELL32.@]
335  */
336 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
337 {
338 	HRESULT	hres;
339 
340 	TRACE("(%p)\n", psf);
341 
342 	if(!psf) return E_INVALIDARG;
343 
344 	*psf = NULL;
345 	hres = ISF_Desktop_Constructor(NULL, &IID_IShellFolder, (LPVOID*)psf);
346 
347 	TRACE("-- %p->(%p) 0x%08x\n", psf, *psf, hres);
348 	return hres;
349 }
350 #endif
351 
352 /**************************************************************************
353  * Default ClassFactory Implementation
354  *
355  * SHCreateDefClassObject
356  *
357  * NOTES
358  *  Helper function for dlls without their own classfactory.
359  *  A generic classfactory is returned.
360  *  When the CreateInstance of the cf is called the callback is executed.
361  */
362 
363 #ifndef __REACTOS__
364 
365 typedef struct
366 {
367     IClassFactory               IClassFactory_iface;
368     LONG                        ref;
369     CLSID			*rclsid;
370     LPFNCREATEINSTANCE		lpfnCI;
371     const IID *			riidInst;
372     LONG *			pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
373 } IDefClFImpl;
374 
375 static inline IDefClFImpl *impl_from_IClassFactory(IClassFactory *iface)
376 {
377 	return CONTAINING_RECORD(iface, IDefClFImpl, IClassFactory_iface);
378 }
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->IClassFactory_iface.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 = impl_from_IClassFactory(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 = impl_from_IClassFactory(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 = impl_from_IClassFactory(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 = impl_from_IClassFactory(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 = impl_from_IClassFactory(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 S_OK;
515 }
516 
517 #endif /* !__REACTOS__ */
518 
519 /*************************************************************************
520  *  DragAcceptFiles		[SHELL32.@]
521  */
522 void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
523 {
524 	LONG exstyle;
525 
526 	if( !IsWindow(hWnd) ) return;
527 	exstyle = GetWindowLongPtrA(hWnd,GWL_EXSTYLE);
528 	if (b)
529 	  exstyle |= WS_EX_ACCEPTFILES;
530 	else
531 	  exstyle &= ~WS_EX_ACCEPTFILES;
532 	SetWindowLongPtrA(hWnd,GWL_EXSTYLE,exstyle);
533 }
534 
535 /*************************************************************************
536  * DragFinish		[SHELL32.@]
537  */
538 void WINAPI DragFinish(HDROP h)
539 {
540 	TRACE("\n");
541 	GlobalFree(h);
542 }
543 
544 /*************************************************************************
545  * DragQueryPoint		[SHELL32.@]
546  */
547 BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
548 {
549         DROPFILES *lpDropFileStruct;
550 	BOOL bRet;
551 
552 	TRACE("\n");
553 
554 	lpDropFileStruct = GlobalLock(hDrop);
555 
556         *p = lpDropFileStruct->pt;
557 	bRet = lpDropFileStruct->fNC;
558 
559 	GlobalUnlock(hDrop);
560 	return bRet;
561 }
562 
563 /*************************************************************************
564  *  DragQueryFileA		[SHELL32.@]
565  *  DragQueryFile 		[SHELL32.@]
566  */
567 UINT WINAPI DragQueryFileA(
568 	HDROP hDrop,
569 	UINT lFile,
570 	LPSTR lpszFile,
571 	UINT lLength)
572 {
573 	LPSTR lpDrop;
574 	UINT i = 0;
575 	DROPFILES *lpDropFileStruct = GlobalLock(hDrop);
576 
577 	TRACE("(%p, %x, %p, %u)\n",	hDrop,lFile,lpszFile,lLength);
578 
579 	if(!lpDropFileStruct) goto end;
580 
581 	lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles;
582 
583         if(lpDropFileStruct->fWide) {
584             LPWSTR lpszFileW = NULL;
585 
586             if(lpszFile && lFile != 0xFFFFFFFF) {
587                 lpszFileW = HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR));
588                 if(lpszFileW == NULL) {
589                     goto end;
590                 }
591             }
592             i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength);
593 
594             if(lpszFileW) {
595                 WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL);
596                 HeapFree(GetProcessHeap(), 0, lpszFileW);
597             }
598             goto end;
599         }
600 
601 	while (i++ < lFile)
602 	{
603 	  while (*lpDrop++); /* skip filename */
604 	  if (!*lpDrop)
605 	  {
606 	    i = (lFile == 0xFFFFFFFF) ? i : 0;
607 	    goto end;
608 	  }
609 	}
610 
611 	i = strlen(lpDrop);
612 	if (!lpszFile ) goto end;   /* needed buffer size */
613 	lstrcpynA (lpszFile, lpDrop, lLength);
614 end:
615 	GlobalUnlock(hDrop);
616 	return i;
617 }
618 
619 /*************************************************************************
620  *  DragQueryFileW		[SHELL32.@]
621  */
622 UINT WINAPI DragQueryFileW(
623 	HDROP hDrop,
624 	UINT lFile,
625 	LPWSTR lpszwFile,
626 	UINT lLength)
627 {
628 	LPWSTR lpwDrop;
629 	UINT i = 0;
630 	DROPFILES *lpDropFileStruct = GlobalLock(hDrop);
631 
632 	TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
633 
634 	if(!lpDropFileStruct) goto end;
635 
636 	lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles);
637 
638         if(lpDropFileStruct->fWide == FALSE) {
639             LPSTR lpszFileA = NULL;
640 
641             if(lpszwFile && lFile != 0xFFFFFFFF) {
642                 lpszFileA = HeapAlloc(GetProcessHeap(), 0, lLength);
643                 if(lpszFileA == NULL) {
644                     goto end;
645                 }
646             }
647             i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength);
648 
649             if(lpszFileA) {
650                 MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength);
651                 HeapFree(GetProcessHeap(), 0, lpszFileA);
652             }
653             goto end;
654         }
655 
656 	i = 0;
657 	while (i++ < lFile)
658 	{
659 	  while (*lpwDrop++); /* skip filename */
660 	  if (!*lpwDrop)
661 	  {
662 	    i = (lFile == 0xFFFFFFFF) ? i : 0;
663 	    goto end;
664 	  }
665 	}
666 
667 	i = strlenW(lpwDrop);
668 	if ( !lpszwFile) goto end;   /* needed buffer size */
669 	lstrcpynW (lpszwFile, lpwDrop, lLength);
670 end:
671 	GlobalUnlock(hDrop);
672 	return i;
673 }
674 
675 /*************************************************************************
676  *  SHPropStgCreate             [SHELL32.685]
677  */
678 HRESULT WINAPI SHPropStgCreate(IPropertySetStorage *psstg, REFFMTID fmtid,
679         const CLSID *pclsid, DWORD grfFlags, DWORD grfMode,
680         DWORD dwDisposition, IPropertyStorage **ppstg, UINT *puCodePage)
681 {
682     PROPSPEC prop;
683     PROPVARIANT ret;
684     HRESULT hres;
685 
686     TRACE("%p %s %s %x %x %x %p %p\n", psstg, debugstr_guid(fmtid), debugstr_guid(pclsid),
687             grfFlags, grfMode, dwDisposition, ppstg, puCodePage);
688 
689     hres = IPropertySetStorage_Open(psstg, fmtid, grfMode, ppstg);
690 
691     switch(dwDisposition) {
692     case CREATE_ALWAYS:
693         if(SUCCEEDED(hres)) {
694             IPropertyStorage_Release(*ppstg);
695             hres = IPropertySetStorage_Delete(psstg, fmtid);
696             if(FAILED(hres))
697                 return hres;
698             hres = E_FAIL;
699         }
700 
701     case OPEN_ALWAYS:
702     case CREATE_NEW:
703         if(FAILED(hres))
704             hres = IPropertySetStorage_Create(psstg, fmtid, pclsid,
705                     grfFlags, grfMode, ppstg);
706 
707     case OPEN_EXISTING:
708         if(FAILED(hres))
709             return hres;
710 
711         if(puCodePage) {
712             prop.ulKind = PRSPEC_PROPID;
713             prop.u.propid = PID_CODEPAGE;
714             hres = IPropertyStorage_ReadMultiple(*ppstg, 1, &prop, &ret);
715             if(FAILED(hres) || ret.vt!=VT_I2)
716                 *puCodePage = 0;
717             else
718                 *puCodePage = ret.u.iVal;
719         }
720     }
721 
722     return S_OK;
723 }
724 
725 /*************************************************************************
726  *  SHPropStgReadMultiple       [SHELL32.688]
727  */
728 HRESULT WINAPI SHPropStgReadMultiple(IPropertyStorage *pps, UINT uCodePage,
729         ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar)
730 {
731     STATPROPSETSTG stat;
732     HRESULT hres;
733 
734     FIXME("%p %u %u %p %p\n", pps, uCodePage, cpspec, rgpspec, rgvar);
735 
736     memset(rgvar, 0, cpspec*sizeof(PROPVARIANT));
737     hres = IPropertyStorage_ReadMultiple(pps, cpspec, rgpspec, rgvar);
738     if(FAILED(hres))
739         return hres;
740 
741     if(!uCodePage) {
742         PROPSPEC prop;
743         PROPVARIANT ret;
744 
745         prop.ulKind = PRSPEC_PROPID;
746         prop.u.propid = PID_CODEPAGE;
747         hres = IPropertyStorage_ReadMultiple(pps, 1, &prop, &ret);
748         if(FAILED(hres) || ret.vt!=VT_I2)
749             return S_OK;
750 
751         uCodePage = ret.u.iVal;
752     }
753 
754     hres = IPropertyStorage_Stat(pps, &stat);
755     if(FAILED(hres))
756         return S_OK;
757 
758     /* TODO: do something with codepage and stat */
759     return S_OK;
760 }
761 
762 /*************************************************************************
763  *  SHPropStgWriteMultiple      [SHELL32.689]
764  */
765 HRESULT WINAPI SHPropStgWriteMultiple(IPropertyStorage *pps, UINT *uCodePage,
766         ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar, PROPID propidNameFirst)
767 {
768     STATPROPSETSTG stat;
769     UINT codepage;
770     HRESULT hres;
771 
772     FIXME("%p %p %u %p %p %d\n", pps, uCodePage, cpspec, rgpspec, rgvar, propidNameFirst);
773 
774     hres = IPropertyStorage_Stat(pps, &stat);
775     if(FAILED(hres))
776         return hres;
777 
778     if(uCodePage && *uCodePage)
779         codepage = *uCodePage;
780     else {
781         PROPSPEC prop;
782         PROPVARIANT ret;
783 
784         prop.ulKind = PRSPEC_PROPID;
785         prop.u.propid = PID_CODEPAGE;
786         hres = IPropertyStorage_ReadMultiple(pps, 1, &prop, &ret);
787         if(FAILED(hres))
788             return hres;
789         if(ret.vt!=VT_I2 || !ret.u.iVal)
790             return E_FAIL;
791 
792         codepage = ret.u.iVal;
793         if(uCodePage)
794             *uCodePage = codepage;
795     }
796 
797     /* TODO: do something with codepage and stat */
798 
799     hres = IPropertyStorage_WriteMultiple(pps, cpspec, rgpspec, rgvar, propidNameFirst);
800     return hres;
801 }
802 
803 /*************************************************************************
804  *  SHCreateQueryCancelAutoPlayMoniker [SHELL32.@]
805  */
806 HRESULT WINAPI SHCreateQueryCancelAutoPlayMoniker(IMoniker **moniker)
807 {
808     TRACE("%p\n", moniker);
809 
810     if (!moniker) return E_INVALIDARG;
811     return CreateClassMoniker(&CLSID_QueryCancelAutoPlay, moniker);
812 }
813