With some apps a fault was possible in ExtractAssociatedIcon.
[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  */
8
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "wine/obj_base.h"
13 #include "wine/obj_shelllink.h"
14 #include "wine/obj_shellfolder.h"
15 #include "wine/obj_shellbrowser.h"
16 #include "wine/obj_contextmenu.h"
17 #include "wine/obj_shellextinit.h"
18 #include "wine/obj_extracticon.h"
19
20 #include "shlguid.h"
21 #include "winversion.h"
22 #include "winreg.h"
23 #include "winerror.h"
24 #include "debugtools.h"
25
26 #include "shell32_main.h"
27
28 DEFAULT_DEBUG_CHANNEL(shell)
29
30 DWORD WINAPI SHCLSIDFromStringA (LPSTR clsid, CLSID *id);
31 extern IShellFolder * IShellFolder_Constructor(
32         IShellFolder * psf,
33         LPITEMIDLIST pidl);
34 extern HRESULT IFSFolder_Constructor(
35         IUnknown * pUnkOuter,
36         REFIID riid,
37         LPVOID * ppv);
38
39 /*************************************************************************
40  * SHCoCreateInstance [SHELL32.102]
41  * 
42  * NOTES
43  *     exported by ordinal
44  */
45 LRESULT WINAPI SHCoCreateInstance(
46         LPSTR aclsid,
47         REFCLSID clsid,
48         IUnknown * unknownouter,
49         REFIID refiid,
50         LPVOID *ppv)
51 {
52         DWORD   hres;
53         IID     iid;
54         CLSID * myclsid = (CLSID*)clsid;
55         
56         if (!clsid)
57         {
58           if (!aclsid) return REGDB_E_CLASSNOTREG;
59           SHCLSIDFromStringA(aclsid, &iid);
60           myclsid = &iid;
61         }
62
63         TRACE("(%p,\n\tCLSID:\t%s, unk:%p\n\tIID:\t%s,%p)\n",
64                 aclsid,debugstr_guid(myclsid),unknownouter,debugstr_guid(refiid),ppv);
65
66         if IsEqualCLSID(myclsid, &CLSID_ShellFSFolder)
67         {
68           hres = IFSFolder_Constructor(unknownouter, refiid, ppv);
69         }
70         else
71         {
72           hres = CoCreateInstance(myclsid, unknownouter, CLSCTX_INPROC_SERVER, refiid, ppv);
73         }
74         
75         if(hres!=S_OK)
76         {
77           ERR("failed (0x%08lx) to create \n\tCLSID:\t%s\n\tIID:\t%s\n",
78               hres, debugstr_guid(myclsid), debugstr_guid(refiid));
79           ERR("class not found in registry\n");
80         }
81
82         TRACE("-- instance: %p\n",*ppv);
83         return hres;
84 }
85
86 /*************************************************************************
87  * SHELL32_DllGetClassObject   [SHELL32.128]
88  */
89 HRESULT WINAPI SHELL32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
90 {       HRESULT hres = E_OUTOFMEMORY;
91         LPCLASSFACTORY lpclf;
92
93         TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
94         
95         *ppv = NULL;
96
97         if(IsEqualCLSID(rclsid, &CLSID_ShellDesktop)|| 
98            IsEqualCLSID(rclsid, &CLSID_ShellLink))
99         {
100           lpclf = IClassFactory_Constructor( rclsid );
101
102           if(lpclf) 
103           {
104             hres = IClassFactory_QueryInterface(lpclf,iid, ppv);
105             IClassFactory_Release(lpclf);
106           }
107         }
108         else
109         {
110           WARN("-- CLSID not found\n");
111           hres = CLASS_E_CLASSNOTAVAILABLE;
112         }
113         TRACE("-- pointer to class factory: %p\n",*ppv);
114         return hres;
115 }
116
117 /*************************************************************************
118  * SHCLSIDFromString                            [SHELL32.147]
119  *
120  * NOTES
121  *     exported by ordinal
122  */
123 DWORD WINAPI SHCLSIDFromStringA (LPSTR clsid, CLSID *id)
124 {
125     WCHAR buffer[40];
126     TRACE("(%p(%s) %p)\n", clsid, clsid, id);
127     if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) ))
128         return CO_E_CLASSSTRING;
129     return CLSIDFromString( buffer, id );
130 }
131 DWORD WINAPI SHCLSIDFromStringW (LPWSTR clsid, CLSID *id)
132 {
133         TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
134         return CLSIDFromString(clsid, id); 
135 }
136 DWORD WINAPI SHCLSIDFromStringAW (LPVOID clsid, CLSID *id)
137 {
138         if (VERSION_OsIsUnicode())
139           return SHCLSIDFromStringW (clsid, id);
140         return SHCLSIDFromStringA (clsid, id);
141 }
142
143 /*************************************************************************
144  *                       SHGetMalloc                    [SHELL32.220]
145  * returns the interface to shell malloc.
146  *
147  * [SDK header win95/shlobj.h:
148  * equivalent to:  #define SHGetMalloc(ppmem)   CoGetMalloc(MEMCTX_TASK, ppmem)
149  * ]
150  * What we are currently doing is not very wrong, since we always use the same
151  * heap (ProcessHeap).
152  */
153 DWORD WINAPI SHGetMalloc(LPMALLOC *lpmal) 
154 {
155         TRACE("(%p)\n", lpmal);
156         return CoGetMalloc(0,lpmal);
157 }
158
159 /*************************************************************************
160  * SHGetDesktopFolder                   [SHELL32.216]
161  */
162 LPSHELLFOLDER pdesktopfolder=NULL;
163
164 DWORD WINAPI SHGetDesktopFolder(IShellFolder **psf)
165 {
166         HRESULT hres = S_OK;
167         LPCLASSFACTORY lpclf;
168         TRACE("%p->(%p)\n",psf,*psf);
169
170         *psf=NULL;
171
172         if (!pdesktopfolder) 
173         {
174           lpclf = IClassFactory_Constructor(&CLSID_ShellDesktop);
175           if(lpclf) 
176           {
177             hres = IClassFactory_CreateInstance(lpclf,NULL,(REFIID)&IID_IShellFolder, (void*)&pdesktopfolder);
178             IClassFactory_Release(lpclf);
179           }  
180         }
181         
182         if (pdesktopfolder) 
183         {
184           /* even if we create the folder, add a ref so the application can´t destroy the folder*/
185           IShellFolder_AddRef(pdesktopfolder);
186           *psf = pdesktopfolder;
187         }
188
189         TRACE("-- %p->(%p)\n",psf, *psf);
190         return hres;
191 }
192
193 /**************************************************************************
194 *  IClassFactory Implementation
195 */
196
197 typedef struct
198 {
199     /* IUnknown fields */
200     ICOM_VFIELD(IClassFactory);
201     DWORD                       ref;
202     CLSID                       *rclsid;
203 } IClassFactoryImpl;
204
205 static ICOM_VTABLE(IClassFactory) clfvt;
206
207 /**************************************************************************
208  *  IClassFactory_Constructor
209  */
210
211 LPCLASSFACTORY IClassFactory_Constructor(REFCLSID rclsid)
212 {
213         IClassFactoryImpl* lpclf;
214
215         lpclf= (IClassFactoryImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IClassFactoryImpl));
216         lpclf->ref = 1;
217         ICOM_VTBL(lpclf) = &clfvt;
218         lpclf->rclsid = (CLSID*)rclsid;
219
220         TRACE("(%p)->()\n",lpclf);
221         InterlockedIncrement(&shell32_ObjCount);
222         return (LPCLASSFACTORY)lpclf;
223 }
224 /**************************************************************************
225  *  IClassFactory_QueryInterface
226  */
227 static HRESULT WINAPI IClassFactory_fnQueryInterface(
228   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
229 {
230         ICOM_THIS(IClassFactoryImpl,iface);
231         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
232
233         *ppvObj = NULL;
234
235         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
236         { *ppvObj = This; 
237         }
238         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
239         { *ppvObj = (IClassFactory*)This;
240         }   
241
242         if(*ppvObj)
243         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
244           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
245           return S_OK;
246         }
247         TRACE("-- Interface: %s E_NOINTERFACE\n", debugstr_guid(riid));
248         return E_NOINTERFACE;
249 }  
250 /******************************************************************************
251  * IClassFactory_AddRef
252  */
253 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
254 {
255         ICOM_THIS(IClassFactoryImpl,iface);
256         TRACE("(%p)->(count=%lu)\n",This,This->ref);
257
258         InterlockedIncrement(&shell32_ObjCount);
259         return InterlockedIncrement(&This->ref);
260 }
261 /******************************************************************************
262  * IClassFactory_Release
263  */
264 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
265 {
266         ICOM_THIS(IClassFactoryImpl,iface);
267         TRACE("(%p)->(count=%lu)\n",This,This->ref);
268
269         InterlockedDecrement(&shell32_ObjCount);
270         if (!InterlockedDecrement(&This->ref)) 
271         {
272           TRACE("-- destroying IClassFactory(%p)\n",This);
273           HeapFree(GetProcessHeap(),0,This);
274           return 0;
275         }
276         return This->ref;
277 }
278 /******************************************************************************
279  * IClassFactory_CreateInstance
280  */
281 static HRESULT WINAPI IClassFactory_fnCreateInstance(
282   LPCLASSFACTORY iface, LPUNKNOWN pUnknown, REFIID riid, LPVOID *ppObject)
283 {
284         ICOM_THIS(IClassFactoryImpl,iface);
285         IUnknown *pObj = NULL;
286         HRESULT hres;
287
288         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnknown,debugstr_guid(riid),ppObject);
289
290         *ppObject = NULL;
291                 
292         if(pUnknown)
293         {
294           return(CLASS_E_NOAGGREGATION);
295         }
296
297         if (IsEqualCLSID(This->rclsid, &CLSID_ShellDesktop))
298         {
299           pObj = (IUnknown *)ISF_Desktop_Constructor();
300         }
301         else if (IsEqualCLSID(This->rclsid, &CLSID_ShellLink))
302         {
303           pObj = (IUnknown *)IShellLink_Constructor(FALSE);
304         } 
305         else
306         {
307           ERR("unknown IID requested\n\tIID:\t%s\n",debugstr_guid(riid));
308           return(E_NOINTERFACE);
309         }
310         
311         if (!pObj)
312         {
313           return(E_OUTOFMEMORY);
314         }
315          
316         hres = IUnknown_QueryInterface(pObj,riid, ppObject);
317         IUnknown_Release(pObj);
318
319         TRACE("-- Object created: (%p)->%p\n",This,*ppObject);
320
321         return hres;
322 }
323 /******************************************************************************
324  * IClassFactory_LockServer
325  */
326 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
327 {
328         ICOM_THIS(IClassFactoryImpl,iface);
329         TRACE("%p->(0x%x), not implemented\n",This, fLock);
330         return E_NOTIMPL;
331 }
332
333 static ICOM_VTABLE(IClassFactory) clfvt = 
334 {
335     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
336     IClassFactory_fnQueryInterface,
337     IClassFactory_fnAddRef,
338   IClassFactory_fnRelease,
339   IClassFactory_fnCreateInstance,
340   IClassFactory_fnLockServer
341 };
342
343 /**************************************************************************
344  * Default ClassFactory Implementation
345  *
346  * SHCreateDefClassObject
347  *
348  * NOTES
349  *  helper function for dll's without a own classfactory
350  *  a generic classfactory is returned
351  *  when the CreateInstance of the cf is called the callback is executed
352  */
353 typedef HRESULT (CALLBACK * LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
354
355 typedef struct
356 {
357     ICOM_VFIELD(IClassFactory);
358     DWORD                       ref;
359     CLSID                       *rclsid;
360     LPFNCREATEINSTANCE          lpfnCI;
361     const IID *                 riidInst;
362     ULONG *                     pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
363 } IDefClFImpl;
364
365 static ICOM_VTABLE(IClassFactory) dclfvt;
366
367 /**************************************************************************
368  *  IDefClF_fnConstructor
369  */
370
371 IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst)
372 {
373         IDefClFImpl* lpclf;
374
375         lpclf = (IDefClFImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl));
376         lpclf->ref = 1;
377         ICOM_VTBL(lpclf) = &dclfvt;
378         lpclf->lpfnCI = lpfnCI;
379         lpclf->pcRefDll = pcRefDll;
380
381         if (pcRefDll) InterlockedIncrement(pcRefDll);
382         lpclf->riidInst = riidInst;
383
384         TRACE("(%p)\n\tIID:\t%s\n",lpclf, debugstr_guid(riidInst));
385         InterlockedIncrement(&shell32_ObjCount);
386         return (LPCLASSFACTORY)lpclf;
387 }
388 /**************************************************************************
389  *  IDefClF_fnQueryInterface
390  */
391 static HRESULT WINAPI IDefClF_fnQueryInterface(
392   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
393 {
394         ICOM_THIS(IDefClFImpl,iface);
395
396         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
397
398         *ppvObj = NULL;
399
400         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
401         { *ppvObj = This; 
402         }
403         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
404         { *ppvObj = (IClassFactory*)This;
405         }   
406
407         if(*ppvObj)
408         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
409           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
410           return S_OK;
411         }
412         TRACE("-- Interface: %s E_NOINTERFACE\n", debugstr_guid(riid));
413         return E_NOINTERFACE;
414 }  
415 /******************************************************************************
416  * IDefClF_fnAddRef
417  */
418 static ULONG WINAPI IDefClF_fnAddRef(LPCLASSFACTORY iface)
419 {
420         ICOM_THIS(IDefClFImpl,iface);
421         TRACE("(%p)->(count=%lu)\n",This,This->ref);
422
423         InterlockedIncrement(&shell32_ObjCount);
424         return InterlockedIncrement(&This->ref);
425 }
426 /******************************************************************************
427  * IDefClF_fnRelease
428  */
429 static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface)
430 {
431         ICOM_THIS(IDefClFImpl,iface);
432         TRACE("(%p)->(count=%lu)\n",This,This->ref);
433
434         InterlockedDecrement(&shell32_ObjCount);
435
436         if (!InterlockedDecrement(&This->ref)) 
437         { 
438           if (This->pcRefDll) InterlockedDecrement(This->pcRefDll);
439
440           TRACE("-- destroying IClassFactory(%p)\n",This);
441           HeapFree(GetProcessHeap(),0,This);
442           return 0;
443         }
444         return This->ref;
445 }
446 /******************************************************************************
447  * IDefClF_fnCreateInstance
448  */
449 static HRESULT WINAPI IDefClF_fnCreateInstance(
450   LPCLASSFACTORY iface, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
451 {
452         ICOM_THIS(IDefClFImpl,iface);
453
454         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnkOuter,debugstr_guid(riid),ppvObject);
455
456         *ppvObject = NULL;
457                 
458         if(pUnkOuter)
459           return(CLASS_E_NOAGGREGATION);
460
461         if ( This->riidInst==NULL ||
462              IsEqualCLSID(riid, This->riidInst) ||
463              IsEqualCLSID(riid, &IID_IUnknown) )
464         {
465           return This->lpfnCI(pUnkOuter, riid, ppvObject);
466         }
467
468         ERR("unknown IID requested\n\tIID:\t%s\n",debugstr_guid(riid));
469         return E_NOINTERFACE;
470 }
471 /******************************************************************************
472  * IDefClF_fnLockServer
473  */
474 static HRESULT WINAPI IDefClF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
475 {
476         ICOM_THIS(IDefClFImpl,iface);
477         TRACE("%p->(0x%x), not implemented\n",This, fLock);
478         return E_NOTIMPL;
479 }
480
481 static ICOM_VTABLE(IClassFactory) dclfvt = 
482 {
483     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
484     IDefClF_fnQueryInterface,
485     IDefClF_fnAddRef,
486   IDefClF_fnRelease,
487   IDefClF_fnCreateInstance,
488   IDefClF_fnLockServer
489 };
490
491 /******************************************************************************
492  * SHCreateDefClassObject                       [SHELL32.70]
493  */
494 HRESULT WINAPI SHCreateDefClassObject(
495         REFIID  riid,                           
496         LPVOID* ppv,    
497         LPFNCREATEINSTANCE lpfnCI,      /* create instance callback entry */
498         PLONG   pcRefDll,               /* ref count of the dll */
499         REFIID  riidInst)               /* optional interface to the instance */
500 {
501         TRACE("\n\tIID:\t%s %p %p %p \n\tIIDIns:\t%s\n",
502               debugstr_guid(riid), ppv, lpfnCI, pcRefDll, debugstr_guid(riidInst));
503
504         if ( IsEqualCLSID(riid, &IID_IClassFactory) )
505         {
506           IClassFactory * pcf = IDefClF_fnConstructor(lpfnCI, pcRefDll, riidInst);
507           if (pcf)
508           {
509             *ppv = pcf;
510             return NOERROR;
511           }
512           return E_OUTOFMEMORY;
513         }
514         return E_NOINTERFACE;
515 }
516
517 /*************************************************************************
518  *  DragAcceptFiles             [SHELL32.54]
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.80]
535  */
536 void WINAPI DragFinish(HDROP h)
537 {
538         TRACE("\n");
539         GlobalFree((HGLOBAL)h);
540 }
541
542 /*************************************************************************
543  * DragQueryPoint               [SHELL32.135]
544  */
545 BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
546 {
547         LPDROPFILESTRUCT lpDropFileStruct;  
548         BOOL bRet;
549
550         TRACE("\n");
551
552         lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop);
553   
554         memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT));
555         bRet = lpDropFileStruct->fInNonClientArea;
556   
557         GlobalUnlock(hDrop);
558         return bRet;
559 }
560
561 /*************************************************************************
562  *  DragQueryFileA              [SHELL32.81] [shell32.82]
563  */
564 UINT WINAPI DragQueryFileA(
565         HDROP hDrop,
566         UINT lFile,
567         LPSTR lpszFile,
568         UINT lLength)
569 {
570         LPSTR lpDrop;
571         UINT i = 0;
572         LPDROPFILESTRUCT lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); 
573     
574         TRACE("(%08x, %x, %p, %u)\n",   hDrop,lFile,lpszFile,lLength);
575     
576         if(!lpDropFileStruct) goto end;
577
578         lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->lSize;
579
580         while (i++ < lFile)
581         {
582           while (*lpDrop++); /* skip filename */
583           if (!*lpDrop) 
584           {
585             i = (lFile == 0xFFFFFFFF) ? i : 0; 
586             goto end;
587           }
588         }
589     
590         i = lstrlenA(lpDrop);
591         i++;
592         if (!lpszFile ) goto end;   /* needed buffer size */
593         i = (lLength > i) ? i : lLength;
594         lstrcpynA (lpszFile,  lpDrop,  i);
595 end:
596         GlobalUnlock(hDrop);
597         return i;
598 }
599
600 /*************************************************************************
601  *  DragQueryFileW              [shell32.133]
602  */
603 UINT WINAPI DragQueryFileW(
604         HDROP hDrop,
605         UINT lFile,
606         LPWSTR lpszwFile,
607         UINT lLength)
608 {
609         LPWSTR lpwDrop;
610         UINT i = 0;
611         LPDROPFILESTRUCT lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); 
612     
613         TRACE("(%08x, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
614     
615         if(!lpDropFileStruct) goto end;
616
617         lpwDrop = (LPWSTR) lpDropFileStruct + lpDropFileStruct->lSize;
618
619         i = 0;
620         while (i++ < lFile)
621         {
622           while (*lpwDrop++); /* skip filename */
623           if (!*lpwDrop) 
624           {
625             i = (lFile == 0xFFFFFFFF) ? i : 0; 
626             goto end;
627           }
628         }
629     
630         i = lstrlenW(lpwDrop);
631         i++;
632         if ( !lpszwFile) goto end;   /* needed buffer size */
633
634         i = (lLength > i) ? i : lLength;
635         lstrcpynW (lpszwFile, lpwDrop, i);
636 end:
637         GlobalUnlock(hDrop);
638         return i;
639 }