shellole.c 22.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2
 *	handling of SHELL32.DLL OLE-Objects
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4 5 6
 *
 *	Copyright 1997	Marcus Meissner
 *	Copyright 1998	Juergen Schmied  <juergen.schmied@metronet.de>
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

22 23
#include "config.h"

24
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26
#include <stdlib.h>
#include <string.h>
27

28
#define COBJMACROS
29
#define NONAMELESSUNION
30

31 32
#include "windef.h"
#include "winbase.h"
33
#include "shellapi.h"
34 35
#include "wingdi.h"
#include "winuser.h"
36
#include "shlobj.h"
37
#include "shlguid.h"
38
#include "shldisp.h"
39 40
#include "winreg.h"
#include "winerror.h"
41

42
#include "undocshell.h"
43
#include "wine/unicode.h"
44 45
#include "shell32_main.h"

46
#include "wine/debug.h"
47
#include "shlwapi.h"
48
#include "debughlp.h"
49

50
WINE_DEFAULT_DEBUG_CHANNEL(shell);
51

52
extern INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax);  /* shlwapi.24 */
53 54 55 56 57

/**************************************************************************
 * Default ClassFactory types
 */
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 CLSIDs of shell32 objects */
61
static const struct {
62 63
	REFIID			riid;
	LPFNCREATEINSTANCE	lpfnCI;
64
} InterfaceTable[] = {
65

66
	{&CLSID_ApplicationAssociationRegistration, ApplicationAssociationRegistration_Constructor},
67 68 69 70
	{&CLSID_AutoComplete,   IAutoComplete_Constructor},
	{&CLSID_ControlPanel,	IControlPanel_Constructor},
	{&CLSID_DragDropHelper, IDropTargetHelper_Constructor},
	{&CLSID_FolderShortcut, FolderShortcut_Constructor},
71
	{&CLSID_MyComputer,	ISF_MyComputer_Constructor},
72
	{&CLSID_MyDocuments,    MyDocuments_Constructor},
73
	{&CLSID_NetworkPlaces,  ISF_NetworkPlaces_Constructor},
74 75 76
	{&CLSID_Printers,       Printers_Constructor},
	{&CLSID_QueryAssociations, QueryAssociations_Constructor},
	{&CLSID_RecycleBin,     RecycleBin_Constructor},
77
	{&CLSID_ShellDesktop,	ISF_Desktop_Constructor},
78
	{&CLSID_ShellFSFolder,	IFSFolder_Constructor},
79
	{&CLSID_ShellItem,	IShellItem_Constructor},
80 81
	{&CLSID_ShellLink,	IShellLink_Constructor},
	{&CLSID_UnixDosFolder,  UnixDosFolder_Constructor},
82
	{&CLSID_UnixFolder,     UnixFolder_Constructor},
83
	{&CLSID_ExplorerBrowser,ExplorerBrowser_Constructor},
84
	{&CLSID_KnownFolderManager, KnownFolderManager_Constructor},
85
	{&CLSID_Shell,          IShellDispatch_Constructor},
86
	{NULL, NULL}
87 88
};

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/*************************************************************************
 * SHCoCreateInstance [SHELL32.102]
 *
 * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes
 * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see
 * SHLoadOLE for details.
 *
 * Under wine if a "LoadWithoutCOM" value is present or the object resides in
 * shell32.dll the function will load the object manually without the help of ole32
 *
 * NOTES
 *     exported by ordinal
 *
 * SEE ALSO
 *     CoCreateInstace, SHLoadOLE
 */
105
HRESULT WINAPI SHCoCreateInstance(
106 107
	LPCWSTR aclsid,
	const CLSID *clsid,
108
	LPUNKNOWN pUnkOuter,
109 110 111
	REFIID refiid,
	LPVOID *ppv)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
112
	DWORD	hres;
113
	IID	iid;
114
	const	CLSID * myclsid = clsid;
115
	WCHAR	sKeyName[MAX_PATH];
116
	static const WCHAR sCLSID[] = {'C','L','S','I','D','\\','\0'};
117
	WCHAR	sClassID[60];
118 119
	static const WCHAR sInProcServer32[] = {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'};
	static const WCHAR sLoadWithoutCOM[] = {'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'};
120
	WCHAR	sDllPath[MAX_PATH];
121
	HKEY	hKey = 0;
122 123 124
	DWORD	dwSize;
	IClassFactory * pcf = NULL;

125 126 127
	if(!ppv) return E_POINTER;
	*ppv=NULL;

128
	/* if the clsid is a string, convert it */
129 130 131
	if (!clsid)
	{
	  if (!aclsid) return REGDB_E_CLASSNOTREG;
132
	  SHCLSIDFromStringW(aclsid, &iid);
133
	  myclsid = &iid;
Alexandre Julliard's avatar
Alexandre Julliard committed
134 135
	}

136 137
	TRACE("(%p,%s,unk:%p,%s,%p)\n",
		aclsid,shdebugstr_guid(myclsid),pUnkOuter,shdebugstr_guid(refiid),ppv);
Alexandre Julliard's avatar
Alexandre Julliard committed
138

139 140 141 142 143 144 145
        if (SUCCEEDED(DllGetClassObject(myclsid, &IID_IClassFactory,(LPVOID*)&pcf)))
        {
            hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv);
            IClassFactory_Release(pcf);
            goto end;
        }

146
	/* we look up the dll path in the registry */
147
        SHStringFromGUIDW(myclsid, sClassID, sizeof(sClassID)/sizeof(WCHAR));
148 149 150 151
	lstrcpyW(sKeyName, sCLSID);
	lstrcatW(sKeyName, sClassID);
	lstrcatW(sKeyName, sInProcServer32);

152 153
	if (RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey))
            return E_ACCESSDENIED;
154

155 156 157
        /* if a special registry key is set, we load a shell extension without help of OLE32 */
        if (!SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0))
        {
158
	    /* load an external dll without ole32 */
159 160 161 162
	    HANDLE hLibrary;
	    typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
	    DllGetClassObjectFunc DllGetClassObject;

163 164 165
            dwSize = sizeof(sDllPath);
            SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize );

166 167 168 169 170 171 172 173 174
	    if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
	        ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath));
		hres = E_ACCESSDENIED;
	        goto end;
	    } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
	        ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath));
	        FreeLibrary( hLibrary );
		hres = E_ACCESSDENIED;
	        goto end;
175
            } else if (FAILED(hres = DllGetClassObject(myclsid, &IID_IClassFactory, (LPVOID*)&pcf))) {
176
		    TRACE("GetClassObject failed 0x%08x\n", hres);
177 178 179
		    goto end;
	    }

180 181
            hres = IClassFactory_CreateInstance(pcf, pUnkOuter, refiid, ppv);
            IClassFactory_Release(pcf);
182 183
	} else {

184
	    /* load an external dll in the usual way */
185
	    hres = CoCreateInstance(myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv);
186
	}
187

188
end:
189
        if (hKey) RegCloseKey(hKey);
190 191
	if(hres!=S_OK)
	{
192
	  ERR("failed (0x%08x) to create CLSID:%s IID:%s\n",
193
              hres, shdebugstr_guid(myclsid), shdebugstr_guid(refiid));
194
	  ERR("class not found in registry\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
195
	}
196

197
	TRACE("-- instance: %p\n",*ppv);
Alexandre Julliard's avatar
Alexandre Julliard committed
198 199 200 201
	return hres;
}

/*************************************************************************
202 203
 * DllGetClassObject     [SHELL32.@]
 * SHDllGetClassObject   [SHELL32.128]
Alexandre Julliard's avatar
Alexandre Julliard committed
204
 */
205
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
206 207 208 209
{
	HRESULT	hres = E_OUTOFMEMORY;
	IClassFactory * pcf = NULL;
	int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
210

211
	TRACE("CLSID:%s,IID:%s\n",shdebugstr_guid(rclsid),shdebugstr_guid(iid));
212

213
	if (!ppv) return E_INVALIDARG;
Alexandre Julliard's avatar
Alexandre Julliard committed
214
	*ppv = NULL;
215

216 217 218 219
	/* search our internal interface table */
	for(i=0;InterfaceTable[i].riid;i++) {
	    if(IsEqualIID(InterfaceTable[i].riid, rclsid)) {
	        TRACE("index[%u]\n", i);
220
	        pcf = IDefClF_fnConstructor(InterfaceTable[i].lpfnCI, NULL, NULL);
221
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
222
	}
223 224

        if (!pcf) {
225
	    FIXME("failed for CLSID=%s\n", shdebugstr_guid(rclsid));
226
	    return CLASS_E_CLASSNOTAVAILABLE;
Alexandre Julliard's avatar
Alexandre Julliard committed
227
	}
228 229 230 231

	hres = IClassFactory_QueryInterface(pcf, iid, ppv);
	IClassFactory_Release(pcf);

232
	TRACE("-- pointer to class factory: %p\n",*ppv);
Alexandre Julliard's avatar
Alexandre Julliard committed
233 234 235
	return hres;
}

236 237 238
/*************************************************************************
 * SHCLSIDFromString				[SHELL32.147]
 *
239 240 241 242 243
 * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed
 * to avoid dependency on ole32.dll (see SHLoadOLE for details).
 *
 * Under Windows NT/2000/XP this is equivalent to CLSIDFromString
 *
244 245
 * NOTES
 *     exported by ordinal
246 247 248
 *
 * SEE ALSO
 *     CLSIDFromString, SHLoadOLE
249
 */
250
DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id)
251
{
252 253 254 255 256
    WCHAR buffer[40];
    TRACE("(%p(%s) %p)\n", clsid, clsid, id);
    if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) ))
        return CO_E_CLASSSTRING;
    return CLSIDFromString( buffer, id );
257
}
258
DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id)
259 260
{
	TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
261
	return CLSIDFromString(clsid, id);
262
}
263
DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id)
264
{
265
	if (SHELL_OsIsUnicode())
266 267 268
	  return SHCLSIDFromStringW (clsid, id);
	return SHCLSIDFromStringA (clsid, id);
}
269

270 271
/*************************************************************************
 *			 SHGetMalloc			[SHELL32.@]
Jon Griffiths's avatar
Jon Griffiths committed
272
 *
273 274 275
 * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function
 * could use the shell32 built-in "mini-COM" without the need to load ole32.dll -
 * see SHLoadOLE for details. 
Jon Griffiths's avatar
Jon Griffiths committed
276 277 278 279 280 281 282
 *
 * PARAMS
 *  lpmal [O] Destination for IMalloc interface.
 *
 * RETURNS
 *  Success: S_OK. lpmal contains the shells IMalloc interface.
 *  Failure. An HRESULT error code.
283
 *
284 285
 * SEE ALSO
 *  CoGetMalloc, SHLoadOLE
286
 */
287
HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal)
288 289
{
	TRACE("(%p)\n", lpmal);
290
	return CoGetMalloc(MEMCTX_TASK, lpmal);
291
}
292

293 294 295
/*************************************************************************
 * SHAlloc					[SHELL32.196]
 *
296 297 298 299
 * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use
 * the shell32 built-in "mini-COM" without the need to load ole32.dll -
 * see SHLoadOLE for details. 
 *
300 301
 * NOTES
 *     exported by ordinal
302 303 304
 *
 * SEE ALSO
 *     CoTaskMemAlloc, SHLoadOLE
305 306 307
 */
LPVOID WINAPI SHAlloc(DWORD len)
{
308
	LPVOID ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
309

310
	ret = CoTaskMemAlloc(len);
311
	TRACE("%u bytes at %p\n",len, ret);
312
	return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
313
}
314 315 316 317

/*************************************************************************
 * SHFree					[SHELL32.195]
 *
318 319 320 321
 * Equivalent to CoTaskMemFree. Under Windows 9x this function could use
 * the shell32 built-in "mini-COM" without the need to load ole32.dll -
 * see SHLoadOLE for details. 
 *
322 323
 * NOTES
 *     exported by ordinal
324 325 326
 *
 * SEE ALSO
 *     CoTaskMemFree, SHLoadOLE
Alexandre Julliard's avatar
Alexandre Julliard committed
327
 */
328
void WINAPI SHFree(LPVOID pv)
329
{
330
	TRACE("%p\n",pv);
331
	CoTaskMemFree(pv);
Alexandre Julliard's avatar
Alexandre Julliard committed
332
}
333

334 335 336
/*************************************************************************
 * SHGetDesktopFolder			[SHELL32.@]
 */
337
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
338
{
339 340 341
	HRESULT	hres;

	TRACE("(%p)\n", psf);
342 343

	if(!psf) return E_INVALIDARG;
344

345
	*psf = NULL;
346
	hres = ISF_Desktop_Constructor(NULL, &IID_IShellFolder, (LPVOID*)psf);
347

348
	TRACE("-- %p->(%p) 0x%08x\n", psf, *psf, hres);
349 350
	return hres;
}
351 352 353 354 355 356
/**************************************************************************
 * Default ClassFactory Implementation
 *
 * SHCreateDefClassObject
 *
 * NOTES
357 358 359
 *  Helper function for dlls without their own classfactory.
 *  A generic classfactory is returned.
 *  When the CreateInstance of the cf is called the callback is executed.
360 361 362 363
 */

typedef struct
{
364
    IClassFactory               IClassFactory_iface;
Mike McCormack's avatar
Mike McCormack committed
365
    LONG                        ref;
366 367 368
    CLSID			*rclsid;
    LPFNCREATEINSTANCE		lpfnCI;
    const IID *			riidInst;
Mike McCormack's avatar
Mike McCormack committed
369
    LONG *			pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
370 371
} IDefClFImpl;

372 373 374 375 376
static inline IDefClFImpl *impl_from_IClassFactory(IClassFactory *iface)
{
	return CONTAINING_RECORD(iface, IDefClFImpl, IClassFactory_iface);
}

377
static const IClassFactoryVtbl dclfvt;
378 379 380 381 382

/**************************************************************************
 *  IDefClF_fnConstructor
 */

383
static IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst)
384 385 386
{
	IDefClFImpl* lpclf;

387
	lpclf = HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl));
388
	lpclf->ref = 1;
389
	lpclf->IClassFactory_iface.lpVtbl = &dclfvt;
390 391 392
	lpclf->lpfnCI = lpfnCI;
	lpclf->pcRefDll = pcRefDll;

393
	if (pcRefDll) InterlockedIncrement(pcRefDll);
394 395
	lpclf->riidInst = riidInst;

396
	TRACE("(%p)%s\n",lpclf, shdebugstr_guid(riidInst));
397 398 399 400 401 402 403 404
	return (LPCLASSFACTORY)lpclf;
}
/**************************************************************************
 *  IDefClF_fnQueryInterface
 */
static HRESULT WINAPI IDefClF_fnQueryInterface(
  LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
{
405
	IDefClFImpl *This = impl_from_IClassFactory(iface);
406

407
	TRACE("(%p)->(%s)\n",This,shdebugstr_guid(riid));
408 409 410

	*ppvObj = NULL;

411 412 413
	if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) {
	  *ppvObj = This;
	  InterlockedIncrement(&This->ref);
414 415
	  return S_OK;
	}
416 417

	TRACE("-- E_NOINTERFACE\n");
418
	return E_NOINTERFACE;
419
}
420 421 422 423 424
/******************************************************************************
 * IDefClF_fnAddRef
 */
static ULONG WINAPI IDefClF_fnAddRef(LPCLASSFACTORY iface)
{
425
	IDefClFImpl *This = impl_from_IClassFactory(iface);
426
	ULONG refCount = InterlockedIncrement(&This->ref);
427

428
	TRACE("(%p)->(count=%u)\n", This, refCount - 1);
429 430

	return refCount;
431 432 433 434 435 436
}
/******************************************************************************
 * IDefClF_fnRelease
 */
static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface)
{
437
	IDefClFImpl *This = impl_from_IClassFactory(iface);
438
	ULONG refCount = InterlockedDecrement(&This->ref);
439

440
	TRACE("(%p)->(count=%u)\n", This, refCount + 1);
441

442
	if (!refCount)
443
	{
444
	  if (This->pcRefDll) InterlockedDecrement(This->pcRefDll);
445 446 447 448 449

	  TRACE("-- destroying IClassFactory(%p)\n",This);
	  HeapFree(GetProcessHeap(),0,This);
	  return 0;
	}
450
	return refCount;
451 452 453 454 455 456 457
}
/******************************************************************************
 * IDefClF_fnCreateInstance
 */
static HRESULT WINAPI IDefClF_fnCreateInstance(
  LPCLASSFACTORY iface, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
{
458
	IDefClFImpl *This = impl_from_IClassFactory(iface);
459

460
	TRACE("%p->(%p,%s,%p)\n",This,pUnkOuter,shdebugstr_guid(riid),ppvObject);
461 462

	*ppvObject = NULL;
463

464 465 466 467 468 469 470
	if ( This->riidInst==NULL ||
	     IsEqualCLSID(riid, This->riidInst) ||
	     IsEqualCLSID(riid, &IID_IUnknown) )
	{
	  return This->lpfnCI(pUnkOuter, riid, ppvObject);
	}

471
	ERR("unknown IID requested %s\n",shdebugstr_guid(riid));
472 473 474 475 476 477 478
	return E_NOINTERFACE;
}
/******************************************************************************
 * IDefClF_fnLockServer
 */
static HRESULT WINAPI IDefClF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
{
479
	IDefClFImpl *This = impl_from_IClassFactory(iface);
480 481 482 483
	TRACE("%p->(0x%x), not implemented\n",This, fLock);
	return E_NOTIMPL;
}

484
static const IClassFactoryVtbl dclfvt =
485 486 487 488 489 490 491 492 493 494 495 496
{
    IDefClF_fnQueryInterface,
    IDefClF_fnAddRef,
  IDefClF_fnRelease,
  IDefClF_fnCreateInstance,
  IDefClF_fnLockServer
};

/******************************************************************************
 * SHCreateDefClassObject			[SHELL32.70]
 */
HRESULT WINAPI SHCreateDefClassObject(
497 498
	REFIID	riid,
	LPVOID*	ppv,
499
	LPFNCREATEINSTANCE lpfnCI,	/* [in] create instance callback entry */
500
	LPDWORD	pcRefDll,		/* [in/out] ref count of the dll */
501
	REFIID	riidInst)		/* [in] optional interface to the instance */
502
{
503 504
	IClassFactory * pcf;

505 506
	TRACE("%s %p %p %p %s\n",
              shdebugstr_guid(riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(riidInst));
507

508
	if (! IsEqualCLSID(riid, &IID_IClassFactory) ) return E_NOINTERFACE;
509
	if (! (pcf = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, riidInst))) return E_OUTOFMEMORY;
510
	*ppv = pcf;
511
	return S_OK;
512 513
}

514
/*************************************************************************
515
 *  DragAcceptFiles		[SHELL32.@]
516 517 518 519
 */
void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
{
	LONG exstyle;
520

521 522 523 524 525 526 527 528 529 530
	if( !IsWindow(hWnd) ) return;
	exstyle = GetWindowLongA(hWnd,GWL_EXSTYLE);
	if (b)
	  exstyle |= WS_EX_ACCEPTFILES;
	else
	  exstyle &= ~WS_EX_ACCEPTFILES;
	SetWindowLongA(hWnd,GWL_EXSTYLE,exstyle);
}

/*************************************************************************
531
 * DragFinish		[SHELL32.@]
532 533 534 535
 */
void WINAPI DragFinish(HDROP h)
{
	TRACE("\n");
536
	GlobalFree(h);
537 538 539
}

/*************************************************************************
540
 * DragQueryPoint		[SHELL32.@]
541 542 543
 */
BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
{
544
        DROPFILES *lpDropFileStruct;
545 546 547 548
	BOOL bRet;

	TRACE("\n");

549
	lpDropFileStruct = GlobalLock(hDrop);
550 551 552

        *p = lpDropFileStruct->pt;
	bRet = lpDropFileStruct->fNC;
553

554 555 556 557 558
	GlobalUnlock(hDrop);
	return bRet;
}

/*************************************************************************
559
 *  DragQueryFileA		[SHELL32.@]
560
 *  DragQueryFile 		[SHELL32.@]
561 562 563 564 565 566 567 568 569
 */
UINT WINAPI DragQueryFileA(
	HDROP hDrop,
	UINT lFile,
	LPSTR lpszFile,
	UINT lLength)
{
	LPSTR lpDrop;
	UINT i = 0;
570
	DROPFILES *lpDropFileStruct = GlobalLock(hDrop);
571

572
	TRACE("(%p, %x, %p, %u)\n",	hDrop,lFile,lpszFile,lLength);
573

574 575
	if(!lpDropFileStruct) goto end;

576
	lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles;
577

578
        if(lpDropFileStruct->fWide) {
579 580 581
            LPWSTR lpszFileW = NULL;

            if(lpszFile) {
582
                lpszFileW = HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR));
583 584 585 586 587 588 589 590 591 592 593 594 595
                if(lpszFileW == NULL) {
                    goto end;
                }
            }
            i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength);

            if(lpszFileW) {
                WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL);
                HeapFree(GetProcessHeap(), 0, lpszFileW);
            }
            goto end;
        }

596 597 598
	while (i++ < lFile)
	{
	  while (*lpDrop++); /* skip filename */
599
	  if (!*lpDrop)
600
	  {
601
	    i = (lFile == 0xFFFFFFFF) ? i : 0;
602 603 604
	    goto end;
	  }
	}
605

606
	i = strlen(lpDrop);
607
	if (!lpszFile ) goto end;   /* needed buffer size */
608
	lstrcpynA (lpszFile, lpDrop, lLength);
609 610 611 612 613 614
end:
	GlobalUnlock(hDrop);
	return i;
}

/*************************************************************************
615
 *  DragQueryFileW		[SHELL32.@]
616 617 618 619 620 621 622 623 624
 */
UINT WINAPI DragQueryFileW(
	HDROP hDrop,
	UINT lFile,
	LPWSTR lpszwFile,
	UINT lLength)
{
	LPWSTR lpwDrop;
	UINT i = 0;
625
	DROPFILES *lpDropFileStruct = GlobalLock(hDrop);
626

627
	TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
628

629 630
	if(!lpDropFileStruct) goto end;

631
	lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles);
632

633 634
        if(lpDropFileStruct->fWide == FALSE) {
            LPSTR lpszFileA = NULL;
635

636
            if(lpszwFile) {
637
                lpszFileA = HeapAlloc(GetProcessHeap(), 0, lLength);
638 639 640 641 642 643 644 645 646 647 648 649 650
                if(lpszFileA == NULL) {
                    goto end;
                }
            }
            i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength);

            if(lpszFileA) {
                MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength);
                HeapFree(GetProcessHeap(), 0, lpszFileA);
            }
            goto end;
        }

651 652 653 654
	i = 0;
	while (i++ < lFile)
	{
	  while (*lpwDrop++); /* skip filename */
655
	  if (!*lpwDrop)
656
	  {
657
	    i = (lFile == 0xFFFFFFFF) ? i : 0;
658 659 660
	    goto end;
	  }
	}
661

662
	i = strlenW(lpwDrop);
663
	if ( !lpszwFile) goto end;   /* needed buffer size */
664
	lstrcpynW (lpszwFile, lpwDrop, lLength);
665 666 667 668
end:
	GlobalUnlock(hDrop);
	return i;
}
669 670 671 672 673 674 675 676

/*************************************************************************
 *  SHPropStgCreate             [SHELL32.685]
 */
HRESULT WINAPI SHPropStgCreate(IPropertySetStorage *psstg, REFFMTID fmtid,
        const CLSID *pclsid, DWORD grfFlags, DWORD grfMode,
        DWORD dwDisposition, IPropertyStorage **ppstg, UINT *puCodePage)
{
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
    PROPSPEC prop;
    PROPVARIANT ret;
    HRESULT hres;

    TRACE("%p %s %s %x %x %x %p %p\n", psstg, debugstr_guid(fmtid), debugstr_guid(pclsid),
            grfFlags, grfMode, dwDisposition, ppstg, puCodePage);

    hres = IPropertySetStorage_Open(psstg, fmtid, grfMode, ppstg);

    switch(dwDisposition) {
    case CREATE_ALWAYS:
        if(SUCCEEDED(hres)) {
            IPropertyStorage_Release(*ppstg);
            hres = IPropertySetStorage_Delete(psstg, fmtid);
            if(FAILED(hres))
                return hres;
            hres = E_FAIL;
        }

    case OPEN_ALWAYS:
    case CREATE_NEW:
        if(FAILED(hres))
            hres = IPropertySetStorage_Create(psstg, fmtid, pclsid,
                    grfFlags, grfMode, ppstg);

    case OPEN_EXISTING:
        if(FAILED(hres))
            return hres;

        if(puCodePage) {
            prop.ulKind = PRSPEC_PROPID;
            prop.u.propid = PID_CODEPAGE;
            hres = IPropertyStorage_ReadMultiple(*ppstg, 1, &prop, &ret);
            if(FAILED(hres) || ret.vt!=VT_I2)
                *puCodePage = 0;
            else
                *puCodePage = ret.u.iVal;
        }
    }

    return S_OK;
718 719 720 721 722 723 724 725
}

/*************************************************************************
 *  SHPropStgReadMultiple       [SHELL32.688]
 */
HRESULT WINAPI SHPropStgReadMultiple(IPropertyStorage *pps, UINT uCodePage,
        ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar)
{
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
    STATPROPSETSTG stat;
    HRESULT hres;

    FIXME("%p %u %u %p %p\n", pps, uCodePage, cpspec, rgpspec, rgvar);

    memset(rgvar, 0, cpspec*sizeof(PROPVARIANT));
    hres = IPropertyStorage_ReadMultiple(pps, cpspec, rgpspec, rgvar);
    if(FAILED(hres))
        return hres;

    if(!uCodePage) {
        PROPSPEC prop;
        PROPVARIANT ret;

        prop.ulKind = PRSPEC_PROPID;
        prop.u.propid = PID_CODEPAGE;
        hres = IPropertyStorage_ReadMultiple(pps, 1, &prop, &ret);
        if(FAILED(hres) || ret.vt!=VT_I2)
            return S_OK;

        uCodePage = ret.u.iVal;
    }

    hres = IPropertyStorage_Stat(pps, &stat);
    if(FAILED(hres))
        return S_OK;

    /* TODO: do something with codepage and stat */
    return S_OK;
755 756 757 758 759 760 761 762
}

/*************************************************************************
 *  SHPropStgWriteMultiple      [SHELL32.689]
 */
HRESULT WINAPI SHPropStgWriteMultiple(IPropertyStorage *pps, UINT *uCodePage,
        ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar, PROPID propidNameFirst)
{
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
    STATPROPSETSTG stat;
    UINT codepage;
    HRESULT hres;

    FIXME("%p %p %u %p %p %d\n", pps, uCodePage, cpspec, rgpspec, rgvar, propidNameFirst);

    hres = IPropertyStorage_Stat(pps, &stat);
    if(FAILED(hres))
        return hres;

    if(uCodePage && *uCodePage)
        codepage = *uCodePage;
    else {
        PROPSPEC prop;
        PROPVARIANT ret;

        prop.ulKind = PRSPEC_PROPID;
        prop.u.propid = PID_CODEPAGE;
        hres = IPropertyStorage_ReadMultiple(pps, 1, &prop, &ret);
        if(FAILED(hres))
            return hres;
        if(ret.vt!=VT_I2 || !ret.u.iVal)
            return E_FAIL;

        codepage = ret.u.iVal;
        if(uCodePage)
            *uCodePage = codepage;
    }

    /* TODO: do something with codepage and stat */

    hres = IPropertyStorage_WriteMultiple(pps, cpspec, rgpspec, rgvar, propidNameFirst);
    return hres;
796
}