Synchronize up to trunk's revision r57784.
[reactos.git] / dll / win32 / shell32 / shellole.cpp
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 <precomp.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL(shell);
25
26 extern HRESULT WINAPI IFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv);
27
28 static const WCHAR sShell32[12] = {'S','H','E','L','L','3','2','.','D','L','L','\0'};
29
30 /**************************************************************************
31 * Default ClassFactory types
32 */
33 typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
34 HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory);
35
36 /* FIXME: this should be SHLWAPI.24 since we can't yet import by ordinal */
37
38 DWORD WINAPI __SHGUIDToStringW (REFGUID guid, LPWSTR str)
39 {
40 WCHAR sFormat[52] = {'{','%','0','8','l','x','-','%','0','4',
41 'x','-','%','0','4','x','-','%','0','2',
42 'x','%','0','2','x','-','%','0','2','x',
43 '%','0','2','x','%','0','2','x','%','0',
44 '2','x','%','0','2','x','%','0','2','x',
45 '}','\0'};
46
47 return swprintf ( str, sFormat,
48 guid.Data1, guid.Data2, guid.Data3,
49 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
50 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
51
52 }
53
54 /*************************************************************************
55 * SHCoCreateInstance [SHELL32.102]
56 *
57 * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes
58 * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see
59 * SHLoadOLE for details.
60 *
61 * Under wine if a "LoadWithoutCOM" value is present or the object resides in
62 * shell32.dll the function will load the object manually without the help of ole32
63 *
64 * NOTES
65 * exported by ordinal
66 *
67 * SEE ALSO
68 * CoCreateInstace, SHLoadOLE
69 */
70 HRESULT WINAPI SHCoCreateInstance(
71 LPCWSTR aclsid,
72 const CLSID *clsid,
73 LPUNKNOWN pUnkOuter,
74 REFIID refiid,
75 LPVOID *ppv)
76 {
77 DWORD hres;
78 CLSID iid;
79 const CLSID * myclsid = clsid;
80 WCHAR sKeyName[MAX_PATH];
81 const WCHAR sCLSID[7] = {'C','L','S','I','D','\\','\0'};
82 WCHAR sClassID[60];
83 const WCHAR sInProcServer32[16] ={'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'};
84 const WCHAR sLoadWithoutCOM[15] ={'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'};
85 WCHAR sDllPath[MAX_PATH];
86 HKEY hKey;
87 DWORD dwSize;
88 BOOLEAN bLoadFromShell32 = FALSE;
89 BOOLEAN bLoadWithoutCOM = FALSE;
90 CComPtr<IClassFactory> pcf;
91
92 if(!ppv) return E_POINTER;
93 *ppv=NULL;
94
95 /* if the clsid is a string, convert it */
96 if (!clsid)
97 {
98 if (!aclsid) return REGDB_E_CLASSNOTREG;
99 CLSIDFromString((LPOLESTR)aclsid, &iid);
100 myclsid = &iid;
101 }
102
103 TRACE("(%p,%s,unk:%p,%s,%p)\n",
104 aclsid, shdebugstr_guid(myclsid), pUnkOuter, shdebugstr_guid(&refiid), ppv);
105
106 /* we look up the dll path in the registry */
107 __SHGUIDToStringW(*myclsid, sClassID);
108 wcscpy(sKeyName, sCLSID);
109 wcscat(sKeyName, sClassID);
110 wcscat(sKeyName, sInProcServer32);
111
112 if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey)) {
113 dwSize = sizeof(sDllPath);
114 SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize );
115
116 /* if a special registry key is set, we load a shell extension without help of OLE32 */
117 bLoadWithoutCOM = (ERROR_SUCCESS == SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0));
118
119 /* if the com object is inside shell32, omit use of ole32 */
120 bLoadFromShell32 = (0==lstrcmpiW( PathFindFileNameW(sDllPath), sShell32));
121
122 RegCloseKey (hKey);
123 } else {
124 /* since we can't find it in the registry we try internally */
125 bLoadFromShell32 = TRUE;
126 }
127
128 TRACE("WithoutCom=%u FromShell=%u\n", bLoadWithoutCOM, bLoadFromShell32);
129
130 /* now we create an instance */
131 if (bLoadFromShell32) {
132 if (! SUCCEEDED(DllGetClassObject(*myclsid, IID_IClassFactory, (LPVOID*)&pcf))) {
133 ERR("LoadFromShell failed for CLSID=%s\n", shdebugstr_guid(myclsid));
134 }
135 } else if (bLoadWithoutCOM) {
136
137 /* load an external dll without ole32 */
138 HINSTANCE hLibrary;
139 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
140 DllGetClassObjectFunc DllGetClassObject;
141
142 if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
143 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath));
144 hres = E_ACCESSDENIED;
145 goto end;
146 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
147 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath));
148 FreeLibrary( hLibrary );
149 hres = E_ACCESSDENIED;
150 goto end;
151 } else if (! SUCCEEDED(hres = DllGetClassObject(*myclsid, IID_IClassFactory, (LPVOID*)&pcf))) {
152 TRACE("GetClassObject failed 0x%08x\n", hres);
153 goto end;
154 }
155
156 } else {
157
158 /* load an external dll in the usual way */
159 hres = CoCreateInstance(*myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv);
160 goto end;
161 }
162
163 /* here we should have a ClassFactory */
164 if (!pcf) return E_ACCESSDENIED;
165
166 hres = pcf->CreateInstance(pUnkOuter, refiid, ppv);
167 end:
168 if(hres!=S_OK)
169 {
170 ERR("failed (0x%08x) to create CLSID:%s IID:%s\n",
171 hres, shdebugstr_guid(myclsid), shdebugstr_guid(&refiid));
172 ERR("class not found in registry\n");
173 }
174
175 TRACE("-- instance: %p\n",*ppv);
176 return hres;
177 }
178
179 /*************************************************************************
180 * SHCLSIDFromString [SHELL32.147]
181 *
182 * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed
183 * to avoid dependency on ole32.dll (see SHLoadOLE for details).
184 *
185 * Under Windows NT/2000/XP this is equivalent to CLSIDFromString
186 *
187 * NOTES
188 * exported by ordinal
189 *
190 * SEE ALSO
191 * CLSIDFromString, SHLoadOLE
192 */
193 DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id)
194 {
195 WCHAR buffer[40];
196 TRACE("(%p(%s) %p)\n", clsid, clsid, id);
197 if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) ))
198 return CO_E_CLASSSTRING;
199 return CLSIDFromString( buffer, id );
200 }
201
202 DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id)
203 {
204 TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
205 return CLSIDFromString((LPWSTR)clsid, id);
206 }
207
208 EXTERN_C DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id)
209 {
210 if (SHELL_OsIsUnicode())
211 return SHCLSIDFromStringW ((LPCWSTR)clsid, id);
212 return SHCLSIDFromStringA ((LPCSTR)clsid, id);
213 }
214
215 /*************************************************************************
216 * SHGetMalloc [SHELL32.@]
217 *
218 * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function
219 * could use the shell32 built-in "mini-COM" without the need to load ole32.dll -
220 * see SHLoadOLE for details.
221 *
222 * PARAMS
223 * lpmal [O] Destination for IMalloc interface.
224 *
225 * RETURNS
226 * Success: S_OK. lpmal contains the shells IMalloc interface.
227 * Failure. An HRESULT error code.
228 *
229 * SEE ALSO
230 * CoGetMalloc, SHLoadOLE
231 */
232 HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal)
233 {
234 TRACE("(%p)\n", lpmal);
235 return CoGetMalloc(MEMCTX_TASK, lpmal);
236 }
237
238 /*************************************************************************
239 * SHAlloc [SHELL32.196]
240 *
241 * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use
242 * the shell32 built-in "mini-COM" without the need to load ole32.dll -
243 * see SHLoadOLE for details.
244 *
245 * NOTES
246 * exported by ordinal
247 *
248 * SEE ALSO
249 * CoTaskMemAlloc, SHLoadOLE
250 */
251 LPVOID WINAPI SHAlloc(SIZE_T len)
252 {
253 LPVOID ret;
254
255 ret = CoTaskMemAlloc(len);
256 TRACE("%u bytes at %p\n",len, ret);
257 return ret;
258 }
259
260 /*************************************************************************
261 * SHFree [SHELL32.195]
262 *
263 * Equivalent to CoTaskMemFree. Under Windows 9x this function could use
264 * the shell32 built-in "mini-COM" without the need to load ole32.dll -
265 * see SHLoadOLE for details.
266 *
267 * NOTES
268 * exported by ordinal
269 *
270 * SEE ALSO
271 * CoTaskMemFree, SHLoadOLE
272 */
273 void WINAPI SHFree(LPVOID pv)
274 {
275 TRACE("%p\n",pv);
276 CoTaskMemFree(pv);
277 }
278
279 /*************************************************************************
280 * SHGetDesktopFolder [SHELL32.@]
281 */
282 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
283 {
284 HRESULT hres = S_OK;
285 TRACE("\n");
286
287 if(!psf) return E_INVALIDARG;
288 *psf = NULL;
289 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_IShellFolder, (void**)psf);
290
291 TRACE("-- %p->(%p)\n",psf, *psf);
292 return hres;
293 }
294 /**************************************************************************
295 * Default ClassFactory Implementation
296 *
297 * SHCreateDefClassObject
298 *
299 * NOTES
300 * Helper function for dlls without their own classfactory.
301 * A generic classfactory is returned.
302 * When the CreateInstance of the cf is called the callback is executed.
303 */
304
305 class IDefClFImpl :
306 public CComObjectRootEx<CComMultiThreadModelNoCS>,
307 public IClassFactory
308 {
309 private:
310 CLSID *rclsid;
311 LPFNCREATEINSTANCE lpfnCI;
312 const IID *riidInst;
313 LONG *pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
314 public:
315 IDefClFImpl();
316 HRESULT Initialize(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInstx);
317
318 // IClassFactory
319 virtual HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject);
320 virtual HRESULT WINAPI LockServer(BOOL fLock);
321
322 BEGIN_COM_MAP(IDefClFImpl)
323 COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
324 END_COM_MAP()
325 };
326
327 IDefClFImpl::IDefClFImpl()
328 {
329 lpfnCI = NULL;
330 riidInst = NULL;
331 pcRefDll = NULL;
332 rclsid = NULL;
333 }
334
335 HRESULT IDefClFImpl::Initialize(LPFNCREATEINSTANCE lpfnCIx, PLONG pcRefDllx, const IID *riidInstx)
336 {
337 lpfnCI = lpfnCIx;
338 riidInst = riidInstx;
339 pcRefDll = pcRefDllx;
340
341 if (pcRefDll)
342 InterlockedIncrement(pcRefDll);
343
344 TRACE("(%p)%s\n", this, shdebugstr_guid(riidInst));
345 return S_OK;
346 }
347
348 /******************************************************************************
349 * IDefClF_fnCreateInstance
350 */
351 HRESULT WINAPI IDefClFImpl::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
352 {
353 TRACE("%p->(%p,%s,%p)\n", this, pUnkOuter, shdebugstr_guid(&riid), ppvObject);
354
355 *ppvObject = NULL;
356
357 if (riidInst == NULL || IsEqualCLSID(riid, *riidInst) || IsEqualCLSID(riid, IID_IUnknown))
358 {
359 return lpfnCI(pUnkOuter, riid, ppvObject);
360 }
361
362 ERR("unknown IID requested %s\n", shdebugstr_guid(&riid));
363 return E_NOINTERFACE;
364 }
365
366 /******************************************************************************
367 * IDefClF_fnLockServer
368 */
369 HRESULT WINAPI IDefClFImpl::LockServer(BOOL fLock)
370 {
371 TRACE("%p->(0x%x), not implemented\n", this, fLock);
372 return E_NOTIMPL;
373 }
374
375 /**************************************************************************
376 * IDefClF_fnConstructor
377 */
378
379 HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory)
380 {
381 CComObject<IDefClFImpl> *theClassObject;
382 CComPtr<IClassFactory> result;
383 HRESULT hResult;
384
385 if (theFactory == NULL)
386 return E_POINTER;
387 *theFactory = NULL;
388 ATLTRY (theClassObject = new CComObject<IDefClFImpl>);
389 if (theClassObject == NULL)
390 return E_OUTOFMEMORY;
391 hResult = theClassObject->QueryInterface (IID_IClassFactory, (void **)&result);
392 if (FAILED (hResult))
393 {
394 delete theClassObject;
395 return hResult;
396 }
397 hResult = theClassObject->Initialize (lpfnCI, pcRefDll, riidInst);
398 if (FAILED (hResult))
399 return hResult;
400 *theFactory = result.Detach ();
401 return S_OK;
402 }
403
404 /******************************************************************************
405 * SHCreateDefClassObject [SHELL32.70]
406 */
407 HRESULT WINAPI SHCreateDefClassObject(
408 REFIID riid,
409 LPVOID* ppv,
410 LPFNCREATEINSTANCE lpfnCI, /* [in] create instance callback entry */
411 LPDWORD pcRefDll, /* [in/out] ref count of the dll */
412 REFIID riidInst) /* [in] optional interface to the instance */
413 {
414 IClassFactory *pcf;
415 HRESULT hResult;
416
417 TRACE("%s %p %p %p %s\n", shdebugstr_guid(&riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(&riidInst));
418
419 if (!IsEqualCLSID(riid, IID_IClassFactory))
420 return E_NOINTERFACE;
421 hResult = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, &riidInst, &pcf);
422 if (FAILED(hResult))
423 return hResult;
424 *ppv = pcf;
425 return NOERROR;
426 }
427
428 /*************************************************************************
429 * DragAcceptFiles [SHELL32.@]
430 */
431 void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
432 {
433 LONG exstyle;
434
435 if( !IsWindow(hWnd) ) return;
436 exstyle = GetWindowLongPtrA(hWnd,GWL_EXSTYLE);
437 if (b)
438 exstyle |= WS_EX_ACCEPTFILES;
439 else
440 exstyle &= ~WS_EX_ACCEPTFILES;
441 SetWindowLongPtrA(hWnd,GWL_EXSTYLE,exstyle);
442 }
443
444 /*************************************************************************
445 * DragFinish [SHELL32.@]
446 */
447 void WINAPI DragFinish(HDROP h)
448 {
449 TRACE("\n");
450 GlobalFree((HGLOBAL)h);
451 }
452
453 /*************************************************************************
454 * DragQueryPoint [SHELL32.@]
455 */
456 BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
457 {
458 DROPFILES *lpDropFileStruct;
459 BOOL bRet;
460
461 TRACE("\n");
462
463 lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
464
465 *p = lpDropFileStruct->pt;
466 bRet = lpDropFileStruct->fNC;
467
468 GlobalUnlock(hDrop);
469 return bRet;
470 }
471
472 /*************************************************************************
473 * DragQueryFileA [SHELL32.@]
474 * DragQueryFile [SHELL32.@]
475 */
476 UINT WINAPI DragQueryFileA(
477 HDROP hDrop,
478 UINT lFile,
479 LPSTR lpszFile,
480 UINT lLength)
481 {
482 LPSTR lpDrop;
483 UINT i = 0;
484 DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
485
486 TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszFile,lLength);
487
488 if(!lpDropFileStruct) goto end;
489
490 lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles;
491
492 if(lpDropFileStruct->fWide) {
493 LPWSTR lpszFileW = NULL;
494
495 if(lpszFile) {
496 lpszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR));
497 if(lpszFileW == NULL) {
498 goto end;
499 }
500 }
501 i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength);
502
503 if(lpszFileW) {
504 WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL);
505 HeapFree(GetProcessHeap(), 0, lpszFileW);
506 }
507 goto end;
508 }
509
510 while (i++ < lFile)
511 {
512 while (*lpDrop++); /* skip filename */
513 if (!*lpDrop)
514 {
515 i = (lFile == 0xFFFFFFFF) ? i : 0;
516 goto end;
517 }
518 }
519
520 i = strlen(lpDrop);
521 if (!lpszFile ) goto end; /* needed buffer size */
522 lstrcpynA (lpszFile, lpDrop, lLength);
523 end:
524 GlobalUnlock(hDrop);
525 return i;
526 }
527
528 /*************************************************************************
529 * DragQueryFileW [SHELL32.@]
530 */
531 UINT WINAPI DragQueryFileW(
532 HDROP hDrop,
533 UINT lFile,
534 LPWSTR lpszwFile,
535 UINT lLength)
536 {
537 LPWSTR lpwDrop;
538 UINT i = 0;
539 DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
540
541 TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
542
543 if(!lpDropFileStruct) goto end;
544
545 lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles);
546
547 if(lpDropFileStruct->fWide == FALSE) {
548 LPSTR lpszFileA = NULL;
549
550 if(lpszwFile) {
551 lpszFileA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, lLength);
552 if(lpszFileA == NULL) {
553 goto end;
554 }
555 }
556 i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength);
557
558 if(lpszFileA) {
559 MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength);
560 HeapFree(GetProcessHeap(), 0, lpszFileA);
561 }
562 goto end;
563 }
564
565 i = 0;
566 while (i++ < lFile)
567 {
568 while (*lpwDrop++); /* skip filename */
569 if (!*lpwDrop)
570 {
571 i = (lFile == 0xFFFFFFFF) ? i : 0;
572 goto end;
573 }
574 }
575
576 i = wcslen(lpwDrop);
577 if ( !lpszwFile) goto end; /* needed buffer size */
578 lstrcpynW (lpszwFile, lpwDrop, lLength);
579 end:
580 GlobalUnlock(hDrop);
581 return i;
582 }
583
584 /*************************************************************************
585 * SHPropStgCreate [SHELL32.685]
586 */
587 EXTERN_C HRESULT WINAPI SHPropStgCreate(IPropertySetStorage *psstg, REFFMTID fmtid,
588 const CLSID *pclsid, DWORD grfFlags, DWORD grfMode,
589 DWORD dwDisposition, IPropertyStorage **ppstg, UINT *puCodePage)
590 {
591 PROPSPEC prop;
592 PROPVARIANT ret;
593 HRESULT hres;
594
595 TRACE("%p %s %s %x %x %x %p %p\n", psstg, debugstr_guid(&fmtid), debugstr_guid(pclsid),
596 grfFlags, grfMode, dwDisposition, ppstg, puCodePage);
597
598 hres = psstg->Open(fmtid, grfMode, ppstg);
599
600 switch (dwDisposition)
601 {
602 case CREATE_ALWAYS:
603 if (SUCCEEDED(hres))
604 {
605 reinterpret_cast<IPropertyStorage*>(*ppstg)->Release();
606 hres = psstg->Delete(fmtid);
607 if(FAILED(hres))
608 return hres;
609 hres = E_FAIL;
610 }
611
612 case OPEN_ALWAYS:
613 case CREATE_NEW:
614 if (FAILED(hres))
615 hres = psstg->Create(fmtid, pclsid, grfFlags, grfMode, ppstg);
616
617 case OPEN_EXISTING:
618 if (FAILED(hres))
619 return hres;
620
621 if (puCodePage)
622 {
623 prop.ulKind = PRSPEC_PROPID;
624 prop.propid = PID_CODEPAGE;
625 hres = reinterpret_cast<IPropertyStorage*>(*ppstg)->ReadMultiple(1, &prop, &ret);
626 if (FAILED(hres) || ret.vt!=VT_I2)
627 *puCodePage = 0;
628 else
629 *puCodePage = ret.iVal;
630 }
631 }
632
633 return S_OK;
634 }
635
636 /*************************************************************************
637 * SHPropStgReadMultiple [SHELL32.688]
638 */
639 EXTERN_C HRESULT WINAPI SHPropStgReadMultiple(IPropertyStorage *pps, UINT uCodePage,
640 ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar)
641 {
642 STATPROPSETSTG stat;
643 HRESULT hres;
644
645 FIXME("%p %u %u %p %p\n", pps, uCodePage, cpspec, rgpspec, rgvar);
646
647 memset(rgvar, 0, cpspec*sizeof(PROPVARIANT));
648 hres = pps->ReadMultiple(cpspec, rgpspec, rgvar);
649 if (FAILED(hres))
650 return hres;
651
652 if (!uCodePage)
653 {
654 PROPSPEC prop;
655 PROPVARIANT ret;
656
657 prop.ulKind = PRSPEC_PROPID;
658 prop.propid = PID_CODEPAGE;
659 hres = pps->ReadMultiple(1, &prop, &ret);
660 if(FAILED(hres) || ret.vt!=VT_I2)
661 return S_OK;
662
663 uCodePage = ret.iVal;
664 }
665
666 hres = pps->Stat(&stat);
667 if (FAILED(hres))
668 return S_OK;
669
670 /* TODO: do something with codepage and stat */
671 return S_OK;
672 }
673
674 /*************************************************************************
675 * SHPropStgWriteMultiple [SHELL32.689]
676 */
677 EXTERN_C HRESULT WINAPI SHPropStgWriteMultiple(IPropertyStorage *pps, UINT *uCodePage,
678 ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar, PROPID propidNameFirst)
679 {
680 STATPROPSETSTG stat;
681 UINT codepage;
682 HRESULT hres;
683
684 FIXME("%p %p %u %p %p %d\n", pps, uCodePage, cpspec, rgpspec, rgvar, propidNameFirst);
685
686 hres = pps->Stat(&stat);
687 if (FAILED(hres))
688 return hres;
689
690 if (uCodePage && *uCodePage)
691 codepage = *uCodePage;
692 else
693 {
694 PROPSPEC prop;
695 PROPVARIANT ret;
696
697 prop.ulKind = PRSPEC_PROPID;
698 prop.propid = PID_CODEPAGE;
699 hres = pps->ReadMultiple(1, &prop, &ret);
700 if (FAILED(hres))
701 return hres;
702 if (ret.vt!=VT_I2 || !ret.iVal)
703 return E_FAIL;
704
705 codepage = ret.iVal;
706 if (uCodePage)
707 *uCodePage = codepage;
708 }
709
710 /* TODO: do something with codepage and stat */
711
712 hres = pps->WriteMultiple(cpspec, rgpspec, rgvar, propidNameFirst);
713 return hres;
714 }