be2ed6af5ec2fa09ecd2725520568f89591aa9b5
[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 static const WCHAR sShell32[12] = {'S','H','E','L','L','3','2','.','D','L','L','\0'};
27
28 /* FIXME: this should be SHLWAPI.24 since we can't yet import by ordinal */
29
30 DWORD WINAPI __SHGUIDToStringW (REFGUID guid, LPWSTR str)
31 {
32 WCHAR sFormat[52] = {'{','%','0','8','l','x','-','%','0','4',
33 'x','-','%','0','4','x','-','%','0','2',
34 'x','%','0','2','x','-','%','0','2','x',
35 '%','0','2','x','%','0','2','x','%','0',
36 '2','x','%','0','2','x','%','0','2','x',
37 '}','\0'};
38
39 return swprintf ( str, sFormat,
40 guid.Data1, guid.Data2, guid.Data3,
41 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
42 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] );
43
44 }
45
46 /*************************************************************************
47 * SHCoCreateInstance [SHELL32.102]
48 *
49 * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes
50 * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see
51 * SHLoadOLE for details.
52 *
53 * Under wine if a "LoadWithoutCOM" value is present or the object resides in
54 * shell32.dll the function will load the object manually without the help of ole32
55 *
56 * NOTES
57 * exported by ordinal
58 *
59 * SEE ALSO
60 * CoCreateInstace, SHLoadOLE
61 */
62 HRESULT WINAPI SHCoCreateInstance(
63 LPCWSTR aclsid,
64 const CLSID *clsid,
65 IUnknown * pUnkOuter,
66 REFIID refiid,
67 LPVOID *ppv)
68 {
69 DWORD hres;
70 CLSID iid;
71 const CLSID * myclsid = clsid;
72 WCHAR sKeyName[MAX_PATH];
73 const WCHAR sCLSID[7] = {'C','L','S','I','D','\\','\0'};
74 WCHAR sClassID[60];
75 const WCHAR sInProcServer32[16] ={'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'};
76 const WCHAR sLoadWithoutCOM[15] ={'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'};
77 WCHAR sDllPath[MAX_PATH];
78 HKEY hKey;
79 DWORD dwSize;
80 BOOLEAN bLoadFromShell32 = FALSE;
81 BOOLEAN bLoadWithoutCOM = FALSE;
82 CComPtr<IClassFactory> pcf;
83
84 if(!ppv) return E_POINTER;
85 *ppv=NULL;
86
87 /* if the clsid is a string, convert it */
88 if (!clsid)
89 {
90 if (!aclsid) return REGDB_E_CLASSNOTREG;
91 CLSIDFromString((LPOLESTR)aclsid, &iid);
92 myclsid = &iid;
93 }
94
95 TRACE("(%p,%s,unk:%p,%s,%p)\n",
96 aclsid, shdebugstr_guid(myclsid), pUnkOuter, shdebugstr_guid(&refiid), ppv);
97
98 /* we look up the dll path in the registry */
99 __SHGUIDToStringW(*myclsid, sClassID);
100 wcscpy(sKeyName, sCLSID);
101 wcscat(sKeyName, sClassID);
102 wcscat(sKeyName, sInProcServer32);
103
104 if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey)) {
105 dwSize = sizeof(sDllPath);
106 SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize );
107
108 /* if a special registry key is set, we load a shell extension without help of OLE32 */
109 bLoadWithoutCOM = (ERROR_SUCCESS == SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0));
110
111 /* if the com object is inside shell32, omit use of ole32 */
112 bLoadFromShell32 = (0==lstrcmpiW( PathFindFileNameW(sDllPath), sShell32));
113
114 RegCloseKey (hKey);
115 } else {
116 /* since we can't find it in the registry we try internally */
117 bLoadFromShell32 = TRUE;
118 }
119
120 TRACE("WithoutCom=%u FromShell=%u\n", bLoadWithoutCOM, bLoadFromShell32);
121
122 /* now we create an instance */
123 if (bLoadFromShell32) {
124 if (! SUCCEEDED(DllGetClassObject(*myclsid, IID_PPV_ARG(IClassFactory, &pcf)))) {
125 ERR("LoadFromShell failed for CLSID=%s\n", shdebugstr_guid(myclsid));
126 }
127 } else if (bLoadWithoutCOM) {
128
129 /* load an external dll without ole32 */
130 HINSTANCE hLibrary;
131 typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
132 DllGetClassObjectFunc DllGetClassObject;
133
134 if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) {
135 ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath));
136 hres = E_ACCESSDENIED;
137 goto end;
138 } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) {
139 ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath));
140 FreeLibrary( hLibrary );
141 hres = E_ACCESSDENIED;
142 goto end;
143 } else if (! SUCCEEDED(hres = DllGetClassObject(*myclsid, IID_PPV_ARG(IClassFactory, &pcf)))) {
144 TRACE("GetClassObject failed 0x%08x\n", hres);
145 goto end;
146 }
147
148 } else {
149
150 /* load an external dll in the usual way */
151 hres = CoCreateInstance(*myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv);
152 goto end;
153 }
154
155 /* here we should have a ClassFactory */
156 if (!pcf) return E_ACCESSDENIED;
157
158 hres = pcf->CreateInstance(pUnkOuter, refiid, ppv);
159 end:
160 if(hres!=S_OK)
161 {
162 ERR("failed (0x%08x) to create CLSID:%s IID:%s\n",
163 hres, shdebugstr_guid(myclsid), shdebugstr_guid(&refiid));
164 ERR("class not found in registry\n");
165 }
166
167 TRACE("-- instance: %p\n",*ppv);
168 return hres;
169 }
170
171 /*************************************************************************
172 * SHCLSIDFromString [SHELL32.147]
173 *
174 * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed
175 * to avoid dependency on ole32.dll (see SHLoadOLE for details).
176 *
177 * Under Windows NT/2000/XP this is equivalent to CLSIDFromString
178 *
179 * NOTES
180 * exported by ordinal
181 *
182 * SEE ALSO
183 * CLSIDFromString, SHLoadOLE
184 */
185 DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id)
186 {
187 WCHAR buffer[40];
188 TRACE("(%p(%s) %p)\n", clsid, clsid, id);
189 if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) ))
190 return CO_E_CLASSSTRING;
191 return CLSIDFromString( buffer, id );
192 }
193
194 DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id)
195 {
196 TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
197 return CLSIDFromString((LPWSTR)clsid, id);
198 }
199
200 EXTERN_C DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id)
201 {
202 if (SHELL_OsIsUnicode())
203 return SHCLSIDFromStringW ((LPCWSTR)clsid, id);
204 return SHCLSIDFromStringA ((LPCSTR)clsid, id);
205 }
206
207 /*************************************************************************
208 * SHGetMalloc [SHELL32.@]
209 *
210 * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function
211 * could use the shell32 built-in "mini-COM" without the need to load ole32.dll -
212 * see SHLoadOLE for details.
213 *
214 * PARAMS
215 * lpmal [O] Destination for IMalloc interface.
216 *
217 * RETURNS
218 * Success: S_OK. lpmal contains the shells IMalloc interface.
219 * Failure. An HRESULT error code.
220 *
221 * SEE ALSO
222 * CoGetMalloc, SHLoadOLE
223 */
224 HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal)
225 {
226 TRACE("(%p)\n", lpmal);
227 return CoGetMalloc(MEMCTX_TASK, lpmal);
228 }
229
230 /*************************************************************************
231 * SHAlloc [SHELL32.196]
232 *
233 * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use
234 * the shell32 built-in "mini-COM" without the need to load ole32.dll -
235 * see SHLoadOLE for details.
236 *
237 * NOTES
238 * exported by ordinal
239 *
240 * SEE ALSO
241 * CoTaskMemAlloc, SHLoadOLE
242 */
243 LPVOID WINAPI SHAlloc(SIZE_T len)
244 {
245 LPVOID ret;
246
247 ret = CoTaskMemAlloc(len);
248 TRACE("%u bytes at %p\n",len, ret);
249 return ret;
250 }
251
252 /*************************************************************************
253 * SHFree [SHELL32.195]
254 *
255 * Equivalent to CoTaskMemFree. Under Windows 9x this function could use
256 * the shell32 built-in "mini-COM" without the need to load ole32.dll -
257 * see SHLoadOLE for details.
258 *
259 * NOTES
260 * exported by ordinal
261 *
262 * SEE ALSO
263 * CoTaskMemFree, SHLoadOLE
264 */
265 void WINAPI SHFree(LPVOID pv)
266 {
267 TRACE("%p\n",pv);
268 CoTaskMemFree(pv);
269 }
270
271 /*************************************************************************
272 * DragAcceptFiles [SHELL32.@]
273 */
274 void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
275 {
276 LONG exstyle;
277
278 if( !IsWindow(hWnd) ) return;
279 exstyle = GetWindowLongPtrA(hWnd,GWL_EXSTYLE);
280 if (b)
281 exstyle |= WS_EX_ACCEPTFILES;
282 else
283 exstyle &= ~WS_EX_ACCEPTFILES;
284 SetWindowLongPtrA(hWnd,GWL_EXSTYLE,exstyle);
285 }
286
287 /*************************************************************************
288 * DragFinish [SHELL32.@]
289 */
290 void WINAPI DragFinish(HDROP h)
291 {
292 TRACE("\n");
293 GlobalFree((HGLOBAL)h);
294 }
295
296 /*************************************************************************
297 * DragQueryPoint [SHELL32.@]
298 */
299 BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
300 {
301 DROPFILES *lpDropFileStruct;
302 BOOL bRet;
303
304 TRACE("\n");
305
306 lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
307
308 *p = lpDropFileStruct->pt;
309 bRet = lpDropFileStruct->fNC;
310
311 GlobalUnlock(hDrop);
312 return bRet;
313 }
314
315 /*************************************************************************
316 * DragQueryFileA [SHELL32.@]
317 * DragQueryFile [SHELL32.@]
318 */
319 UINT WINAPI DragQueryFileA(
320 HDROP hDrop,
321 UINT lFile,
322 LPSTR lpszFile,
323 UINT lLength)
324 {
325 LPSTR lpDrop;
326 UINT i = 0;
327 DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
328
329 TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszFile,lLength);
330
331 if(!lpDropFileStruct) goto end;
332
333 lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles;
334
335 if(lpDropFileStruct->fWide) {
336 LPWSTR lpszFileW = NULL;
337
338 if(lpszFile) {
339 lpszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR));
340 if(lpszFileW == NULL) {
341 goto end;
342 }
343 }
344 i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength);
345
346 if(lpszFileW) {
347 WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL);
348 HeapFree(GetProcessHeap(), 0, lpszFileW);
349 }
350 goto end;
351 }
352
353 while (i++ < lFile)
354 {
355 while (*lpDrop++); /* skip filename */
356 if (!*lpDrop)
357 {
358 i = (lFile == 0xFFFFFFFF) ? i : 0;
359 goto end;
360 }
361 }
362
363 i = strlen(lpDrop);
364 if (!lpszFile ) goto end; /* needed buffer size */
365 lstrcpynA (lpszFile, lpDrop, lLength);
366 end:
367 GlobalUnlock(hDrop);
368 return i;
369 }
370
371 /*************************************************************************
372 * DragQueryFileW [SHELL32.@]
373 */
374 UINT WINAPI DragQueryFileW(
375 HDROP hDrop,
376 UINT lFile,
377 LPWSTR lpszwFile,
378 UINT lLength)
379 {
380 LPWSTR lpwDrop;
381 UINT i = 0;
382 DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop);
383
384 TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
385
386 if(!lpDropFileStruct) goto end;
387
388 lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles);
389
390 if(lpDropFileStruct->fWide == FALSE) {
391 LPSTR lpszFileA = NULL;
392
393 if(lpszwFile) {
394 lpszFileA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, lLength);
395 if(lpszFileA == NULL) {
396 goto end;
397 }
398 }
399 i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength);
400
401 if(lpszFileA) {
402 MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength);
403 HeapFree(GetProcessHeap(), 0, lpszFileA);
404 }
405 goto end;
406 }
407
408 i = 0;
409 while (i++ < lFile)
410 {
411 while (*lpwDrop++); /* skip filename */
412 if (!*lpwDrop)
413 {
414 i = (lFile == 0xFFFFFFFF) ? i : 0;
415 goto end;
416 }
417 }
418
419 i = wcslen(lpwDrop);
420 if ( !lpszwFile) goto end; /* needed buffer size */
421 lstrcpynW (lpszwFile, lpwDrop, lLength);
422 end:
423 GlobalUnlock(hDrop);
424 return i;
425 }
426
427 /*************************************************************************
428 * SHPropStgCreate [SHELL32.685]
429 */
430 EXTERN_C HRESULT WINAPI SHPropStgCreate(IPropertySetStorage *psstg, REFFMTID fmtid,
431 const CLSID *pclsid, DWORD grfFlags, DWORD grfMode,
432 DWORD dwDisposition, IPropertyStorage **ppstg, UINT *puCodePage)
433 {
434 PROPSPEC prop;
435 PROPVARIANT ret;
436 HRESULT hres;
437
438 TRACE("%p %s %s %x %x %x %p %p\n", psstg, debugstr_guid(&fmtid), debugstr_guid(pclsid),
439 grfFlags, grfMode, dwDisposition, ppstg, puCodePage);
440
441 hres = psstg->Open(fmtid, grfMode, ppstg);
442
443 switch (dwDisposition)
444 {
445 case CREATE_ALWAYS:
446 if (SUCCEEDED(hres))
447 {
448 (*ppstg)->Release();
449 hres = psstg->Delete(fmtid);
450 if(FAILED(hres))
451 return hres;
452 hres = E_FAIL;
453 }
454
455 case OPEN_ALWAYS:
456 case CREATE_NEW:
457 if (FAILED(hres))
458 hres = psstg->Create(fmtid, pclsid, grfFlags, grfMode, ppstg);
459
460 case OPEN_EXISTING:
461 if (FAILED(hres))
462 return hres;
463
464 if (puCodePage)
465 {
466 prop.ulKind = PRSPEC_PROPID;
467 prop.propid = PID_CODEPAGE;
468 hres = (*ppstg)->ReadMultiple(1, &prop, &ret);
469 if (FAILED(hres) || ret.vt!=VT_I2)
470 *puCodePage = 0;
471 else
472 *puCodePage = ret.iVal;
473 }
474 }
475
476 return S_OK;
477 }
478
479 /*************************************************************************
480 * SHPropStgReadMultiple [SHELL32.688]
481 */
482 EXTERN_C HRESULT WINAPI SHPropStgReadMultiple(IPropertyStorage *pps, UINT uCodePage,
483 ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar)
484 {
485 STATPROPSETSTG stat;
486 HRESULT hres;
487
488 FIXME("%p %u %u %p %p\n", pps, uCodePage, cpspec, rgpspec, rgvar);
489
490 memset(rgvar, 0, cpspec*sizeof(PROPVARIANT));
491 hres = pps->ReadMultiple(cpspec, rgpspec, rgvar);
492 if (FAILED(hres))
493 return hres;
494
495 if (!uCodePage)
496 {
497 PROPSPEC prop;
498 PROPVARIANT ret;
499
500 prop.ulKind = PRSPEC_PROPID;
501 prop.propid = PID_CODEPAGE;
502 hres = pps->ReadMultiple(1, &prop, &ret);
503 if(FAILED(hres) || ret.vt!=VT_I2)
504 return S_OK;
505
506 uCodePage = ret.iVal;
507 }
508
509 hres = pps->Stat(&stat);
510 if (FAILED(hres))
511 return S_OK;
512
513 /* TODO: do something with codepage and stat */
514 return S_OK;
515 }
516
517 /*************************************************************************
518 * SHPropStgWriteMultiple [SHELL32.689]
519 */
520 EXTERN_C HRESULT WINAPI SHPropStgWriteMultiple(IPropertyStorage *pps, UINT *uCodePage,
521 ULONG cpspec, const PROPSPEC *rgpspec, PROPVARIANT *rgvar, PROPID propidNameFirst)
522 {
523 STATPROPSETSTG stat;
524 UINT codepage;
525 HRESULT hres;
526
527 FIXME("%p %p %u %p %p %d\n", pps, uCodePage, cpspec, rgpspec, rgvar, propidNameFirst);
528
529 hres = pps->Stat(&stat);
530 if (FAILED(hres))
531 return hres;
532
533 if (uCodePage && *uCodePage)
534 codepage = *uCodePage;
535 else
536 {
537 PROPSPEC prop;
538 PROPVARIANT ret;
539
540 prop.ulKind = PRSPEC_PROPID;
541 prop.propid = PID_CODEPAGE;
542 hres = pps->ReadMultiple(1, &prop, &ret);
543 if (FAILED(hres))
544 return hres;
545 if (ret.vt!=VT_I2 || !ret.iVal)
546 return E_FAIL;
547
548 codepage = ret.iVal;
549 if (uCodePage)
550 *uCodePage = codepage;
551 }
552
553 /* TODO: do something with codepage and stat */
554
555 hres = pps->WriteMultiple(cpspec, rgpspec, rgvar, propidNameFirst);
556 return hres;
557 }
558
559 /*************************************************************************
560 * SHCreateQueryCancelAutoPlayMoniker [SHELL32.@]
561 */
562 HRESULT WINAPI SHCreateQueryCancelAutoPlayMoniker(IMoniker **moniker)
563 {
564 TRACE("%p\n", moniker);
565
566 if (!moniker) return E_INVALIDARG;
567 return CreateClassMoniker(CLSID_QueryCancelAutoPlay, moniker);
568 }