Like the AUTORADIOBUTTON, the parent of a RADIOBUTTON style button
[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         TRACE("(%p(%s) %p)\n", clsid, clsid, id);
126         return CLSIDFromString16(clsid, id); 
127 }
128 DWORD WINAPI SHCLSIDFromStringW (LPWSTR clsid, CLSID *id)
129 {
130         TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
131         return CLSIDFromString(clsid, id); 
132 }
133 DWORD WINAPI SHCLSIDFromStringAW (LPVOID clsid, CLSID *id)
134 {
135         if (VERSION_OsIsUnicode())
136           return SHCLSIDFromStringW (clsid, id);
137         return SHCLSIDFromStringA (clsid, id);
138 }
139
140 /*************************************************************************
141  *                       SHGetMalloc                    [SHELL32.220]
142  * returns the interface to shell malloc.
143  *
144  * [SDK header win95/shlobj.h:
145  * equivalent to:  #define SHGetMalloc(ppmem)   CoGetMalloc(MEMCTX_TASK, ppmem)
146  * ]
147  * What we are currently doing is not very wrong, since we always use the same
148  * heap (ProcessHeap).
149  */
150 DWORD WINAPI SHGetMalloc(LPMALLOC *lpmal) 
151 {
152         TRACE("(%p)\n", lpmal);
153         return CoGetMalloc(0,lpmal);
154 }
155
156 /*************************************************************************
157  * SHGetDesktopFolder                   [SHELL32.216]
158  */
159 LPSHELLFOLDER pdesktopfolder=NULL;
160
161 DWORD WINAPI SHGetDesktopFolder(IShellFolder **psf)
162 {
163         HRESULT hres = S_OK;
164         LPCLASSFACTORY lpclf;
165         TRACE("%p->(%p)\n",psf,*psf);
166
167         *psf=NULL;
168
169         if (!pdesktopfolder) 
170         {
171           lpclf = IClassFactory_Constructor(&CLSID_ShellDesktop);
172           if(lpclf) 
173           {
174             hres = IClassFactory_CreateInstance(lpclf,NULL,(REFIID)&IID_IShellFolder, (void*)&pdesktopfolder);
175             IClassFactory_Release(lpclf);
176           }  
177         }
178         
179         if (pdesktopfolder) 
180         {
181           /* even if we create the folder, add a ref so the application canĀ“t destroy the folder*/
182           IShellFolder_AddRef(pdesktopfolder);
183           *psf = pdesktopfolder;
184         }
185
186         TRACE("-- %p->(%p)\n",psf, *psf);
187         return hres;
188 }
189
190 /**************************************************************************
191 *  IClassFactory Implementation
192 */
193
194 typedef struct
195 {
196     /* IUnknown fields */
197     ICOM_VFIELD(IClassFactory);
198     DWORD                       ref;
199     CLSID                       *rclsid;
200 } IClassFactoryImpl;
201
202 static ICOM_VTABLE(IClassFactory) clfvt;
203
204 /**************************************************************************
205  *  IClassFactory_Constructor
206  */
207
208 LPCLASSFACTORY IClassFactory_Constructor(REFCLSID rclsid)
209 {
210         IClassFactoryImpl* lpclf;
211
212         lpclf= (IClassFactoryImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IClassFactoryImpl));
213         lpclf->ref = 1;
214         ICOM_VTBL(lpclf) = &clfvt;
215         lpclf->rclsid = (CLSID*)rclsid;
216
217         TRACE("(%p)->()\n",lpclf);
218         InterlockedIncrement(&shell32_ObjCount);
219         return (LPCLASSFACTORY)lpclf;
220 }
221 /**************************************************************************
222  *  IClassFactory_QueryInterface
223  */
224 static HRESULT WINAPI IClassFactory_fnQueryInterface(
225   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
226 {
227         ICOM_THIS(IClassFactoryImpl,iface);
228         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
229
230         *ppvObj = NULL;
231
232         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
233         { *ppvObj = This; 
234         }
235         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
236         { *ppvObj = (IClassFactory*)This;
237         }   
238
239         if(*ppvObj)
240         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
241           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
242           return S_OK;
243         }
244         TRACE("-- Interface: %s E_NOINTERFACE\n", debugstr_guid(riid));
245         return E_NOINTERFACE;
246 }  
247 /******************************************************************************
248  * IClassFactory_AddRef
249  */
250 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
251 {
252         ICOM_THIS(IClassFactoryImpl,iface);
253         TRACE("(%p)->(count=%lu)\n",This,This->ref);
254
255         InterlockedIncrement(&shell32_ObjCount);
256         return InterlockedIncrement(&This->ref);
257 }
258 /******************************************************************************
259  * IClassFactory_Release
260  */
261 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
262 {
263         ICOM_THIS(IClassFactoryImpl,iface);
264         TRACE("(%p)->(count=%lu)\n",This,This->ref);
265
266         InterlockedDecrement(&shell32_ObjCount);
267         if (!InterlockedDecrement(&This->ref)) 
268         {
269           TRACE("-- destroying IClassFactory(%p)\n",This);
270           HeapFree(GetProcessHeap(),0,This);
271           return 0;
272         }
273         return This->ref;
274 }
275 /******************************************************************************
276  * IClassFactory_CreateInstance
277  */
278 static HRESULT WINAPI IClassFactory_fnCreateInstance(
279   LPCLASSFACTORY iface, LPUNKNOWN pUnknown, REFIID riid, LPVOID *ppObject)
280 {
281         ICOM_THIS(IClassFactoryImpl,iface);
282         IUnknown *pObj = NULL;
283         HRESULT hres;
284
285         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnknown,debugstr_guid(riid),ppObject);
286
287         *ppObject = NULL;
288                 
289         if(pUnknown)
290         {
291           return(CLASS_E_NOAGGREGATION);
292         }
293
294         if (IsEqualCLSID(This->rclsid, &CLSID_ShellDesktop))
295         {
296           pObj = (IUnknown *)ISF_Desktop_Constructor();
297         }
298         else if (IsEqualCLSID(This->rclsid, &CLSID_ShellLink))
299         {
300           pObj = (IUnknown *)IShellLink_Constructor(FALSE);
301         } 
302         else
303         {
304           ERR("unknown IID requested\n\tIID:\t%s\n",debugstr_guid(riid));
305           return(E_NOINTERFACE);
306         }
307         
308         if (!pObj)
309         {
310           return(E_OUTOFMEMORY);
311         }
312          
313         hres = IUnknown_QueryInterface(pObj,riid, ppObject);
314         IUnknown_Release(pObj);
315
316         TRACE("-- Object created: (%p)->%p\n",This,*ppObject);
317
318         return hres;
319 }
320 /******************************************************************************
321  * IClassFactory_LockServer
322  */
323 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
324 {
325         ICOM_THIS(IClassFactoryImpl,iface);
326         TRACE("%p->(0x%x), not implemented\n",This, fLock);
327         return E_NOTIMPL;
328 }
329
330 static ICOM_VTABLE(IClassFactory) clfvt = 
331 {
332     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
333     IClassFactory_fnQueryInterface,
334     IClassFactory_fnAddRef,
335   IClassFactory_fnRelease,
336   IClassFactory_fnCreateInstance,
337   IClassFactory_fnLockServer
338 };
339
340 /**************************************************************************
341  * Default ClassFactory Implementation
342  *
343  * SHCreateDefClassObject
344  *
345  * NOTES
346  *  helper function for dll's without a own classfactory
347  *  a generic classfactory is returned
348  *  when the CreateInstance of the cf is called the callback is executed
349  */
350 typedef HRESULT (CALLBACK * LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
351
352 typedef struct
353 {
354     ICOM_VFIELD(IClassFactory);
355     DWORD                       ref;
356     CLSID                       *rclsid;
357     LPFNCREATEINSTANCE          lpfnCI;
358     const IID *                 riidInst;
359     ULONG *                     pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
360 } IDefClFImpl;
361
362 static ICOM_VTABLE(IClassFactory) dclfvt;
363
364 /**************************************************************************
365  *  IDefClF_fnConstructor
366  */
367
368 IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, REFIID riidInst)
369 {
370         IDefClFImpl* lpclf;
371
372         lpclf = (IDefClFImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl));
373         lpclf->ref = 1;
374         ICOM_VTBL(lpclf) = &dclfvt;
375         lpclf->lpfnCI = lpfnCI;
376         lpclf->pcRefDll = pcRefDll;
377
378         if (pcRefDll) InterlockedIncrement(pcRefDll);
379         lpclf->riidInst = riidInst;
380
381         TRACE("(%p)\n\tIID:\t%s\n",lpclf, debugstr_guid(riidInst));
382         InterlockedIncrement(&shell32_ObjCount);
383         return (LPCLASSFACTORY)lpclf;
384 }
385 /**************************************************************************
386  *  IDefClF_fnQueryInterface
387  */
388 static HRESULT WINAPI IDefClF_fnQueryInterface(
389   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
390 {
391         ICOM_THIS(IDefClFImpl,iface);
392
393         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
394
395         *ppvObj = NULL;
396
397         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
398         { *ppvObj = This; 
399         }
400         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
401         { *ppvObj = (IClassFactory*)This;
402         }   
403
404         if(*ppvObj)
405         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
406           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
407           return S_OK;
408         }
409         TRACE("-- Interface: %s E_NOINTERFACE\n", debugstr_guid(riid));
410         return E_NOINTERFACE;
411 }  
412 /******************************************************************************
413  * IDefClF_fnAddRef
414  */
415 static ULONG WINAPI IDefClF_fnAddRef(LPCLASSFACTORY iface)
416 {
417         ICOM_THIS(IDefClFImpl,iface);
418         TRACE("(%p)->(count=%lu)\n",This,This->ref);
419
420         InterlockedIncrement(&shell32_ObjCount);
421         return InterlockedIncrement(&This->ref);
422 }
423 /******************************************************************************
424  * IDefClF_fnRelease
425  */
426 static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface)
427 {
428         ICOM_THIS(IDefClFImpl,iface);
429         TRACE("(%p)->(count=%lu)\n",This,This->ref);
430
431         InterlockedDecrement(&shell32_ObjCount);
432
433         if (!InterlockedDecrement(&This->ref)) 
434         { 
435           if (This->pcRefDll) InterlockedDecrement(This->pcRefDll);
436
437           TRACE("-- destroying IClassFactory(%p)\n",This);
438           HeapFree(GetProcessHeap(),0,This);
439           return 0;
440         }
441         return This->ref;
442 }
443 /******************************************************************************
444  * IDefClF_fnCreateInstance
445  */
446 static HRESULT WINAPI IDefClF_fnCreateInstance(
447   LPCLASSFACTORY iface, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
448 {
449         ICOM_THIS(IDefClFImpl,iface);
450
451         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnkOuter,debugstr_guid(riid),ppvObject);
452
453         *ppvObject = NULL;
454                 
455         if(pUnkOuter)
456           return(CLASS_E_NOAGGREGATION);
457
458         if ( This->riidInst==NULL ||
459              IsEqualCLSID(riid, This->riidInst) ||
460              IsEqualCLSID(riid, &IID_IUnknown) )
461         {
462           return This->lpfnCI(pUnkOuter, riid, ppvObject);
463         }
464
465         ERR("unknown IID requested\n\tIID:\t%s\n",debugstr_guid(riid));
466         return E_NOINTERFACE;
467 }
468 /******************************************************************************
469  * IDefClF_fnLockServer
470  */
471 static HRESULT WINAPI IDefClF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
472 {
473         ICOM_THIS(IDefClFImpl,iface);
474         TRACE("%p->(0x%x), not implemented\n",This, fLock);
475         return E_NOTIMPL;
476 }
477
478 static ICOM_VTABLE(IClassFactory) dclfvt = 
479 {
480     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
481     IDefClF_fnQueryInterface,
482     IDefClF_fnAddRef,
483   IDefClF_fnRelease,
484   IDefClF_fnCreateInstance,
485   IDefClF_fnLockServer
486 };
487
488 /******************************************************************************
489  * SHCreateDefClassObject                       [SHELL32.70]
490  */
491 HRESULT WINAPI SHCreateDefClassObject(
492         REFIID  riid,                           
493         LPVOID* ppv,    
494         LPFNCREATEINSTANCE lpfnCI,      /* create instance callback entry */
495         PLONG   pcRefDll,               /* ref count of the dll */
496         REFIID  riidInst)               /* optional interface to the instance */
497 {
498         TRACE("\n\tIID:\t%s %p %p %p \n\tIIDIns:\t%s\n",
499               debugstr_guid(riid), ppv, lpfnCI, pcRefDll, debugstr_guid(riidInst));
500
501         if ( IsEqualCLSID(riid, &IID_IClassFactory) )
502         {
503           IClassFactory * pcf = IDefClF_fnConstructor(lpfnCI, pcRefDll, riidInst);
504           if (pcf)
505           {
506             *ppv = pcf;
507             return NOERROR;
508           }
509           return E_OUTOFMEMORY;
510         }
511         return E_NOINTERFACE;
512 }
513
514 /*************************************************************************
515  *  DragAcceptFiles             [SHELL32.54]
516  */
517 void WINAPI DragAcceptFiles(HWND hWnd, BOOL b)
518 {
519         LONG exstyle;
520   
521         if( !IsWindow(hWnd) ) return;
522         exstyle = GetWindowLongA(hWnd,GWL_EXSTYLE);
523         if (b)
524           exstyle |= WS_EX_ACCEPTFILES;
525         else
526           exstyle &= ~WS_EX_ACCEPTFILES;
527         SetWindowLongA(hWnd,GWL_EXSTYLE,exstyle);
528 }
529
530 /*************************************************************************
531  * DragFinish           [SHELL32.80]
532  */
533 void WINAPI DragFinish(HDROP h)
534 {
535         TRACE("\n");
536         GlobalFree((HGLOBAL)h);
537 }
538
539 /*************************************************************************
540  * DragQueryPoint               [SHELL32.135]
541  */
542 BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p)
543 {
544         LPDROPFILESTRUCT lpDropFileStruct;  
545         BOOL bRet;
546
547         TRACE("\n");
548
549         lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop);
550   
551         memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT));
552         bRet = lpDropFileStruct->fInNonClientArea;
553   
554         GlobalUnlock(hDrop);
555         return bRet;
556 }
557
558 /*************************************************************************
559  *  DragQueryFileA              [SHELL32.81] [shell32.82]
560  */
561 UINT WINAPI DragQueryFileA(
562         HDROP hDrop,
563         UINT lFile,
564         LPSTR lpszFile,
565         UINT lLength)
566 {
567         LPSTR lpDrop;
568         UINT i = 0;
569         LPDROPFILESTRUCT lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); 
570     
571         TRACE("(%08x, %x, %p, %u)\n",   hDrop,lFile,lpszFile,lLength);
572     
573         if(!lpDropFileStruct) goto end;
574
575         lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->lSize;
576
577         while (i++ < lFile)
578         {
579           while (*lpDrop++); /* skip filename */
580           if (!*lpDrop) 
581           {
582             i = (lFile == 0xFFFFFFFF) ? i : 0; 
583             goto end;
584           }
585         }
586     
587         i = lstrlenA(lpDrop);
588         i++;
589         if (!lpszFile ) goto end;   /* needed buffer size */
590         i = (lLength > i) ? i : lLength;
591         lstrcpynA (lpszFile,  lpDrop,  i);
592 end:
593         GlobalUnlock(hDrop);
594         return i;
595 }
596
597 /*************************************************************************
598  *  DragQueryFileW              [shell32.133]
599  */
600 UINT WINAPI DragQueryFileW(
601         HDROP hDrop,
602         UINT lFile,
603         LPWSTR lpszwFile,
604         UINT lLength)
605 {
606         LPWSTR lpwDrop;
607         UINT i = 0;
608         LPDROPFILESTRUCT lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock(hDrop); 
609     
610         TRACE("(%08x, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength);
611     
612         if(!lpDropFileStruct) goto end;
613
614         lpwDrop = (LPWSTR) lpDropFileStruct + lpDropFileStruct->lSize;
615
616         i = 0;
617         while (i++ < lFile)
618         {
619           while (*lpwDrop++); /* skip filename */
620           if (!*lpwDrop) 
621           {
622             i = (lFile == 0xFFFFFFFF) ? i : 0; 
623             goto end;
624           }
625         }
626     
627         i = lstrlenW(lpwDrop);
628         i++;
629         if ( !lpszwFile) goto end;   /* needed buffer size */
630
631         i = (lLength > i) ? i : lLength;
632         lstrcpynW (lpszwFile, lpwDrop, i);
633 end:
634         GlobalUnlock(hDrop);
635         return i;
636 }