Buffer overflows and strncpy fixes.
[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         char    xclsid[48], xiid[48];
53         DWORD   hres;
54         IID     iid;
55         CLSID * myclsid = (CLSID*)clsid;
56         
57         WINE_StringFromCLSID(refiid,xiid);
58
59         if (!clsid)
60         {
61           if (!aclsid) return REGDB_E_CLASSNOTREG;
62           SHCLSIDFromStringA(aclsid, &iid);
63           myclsid = &iid;
64         }
65
66         WINE_StringFromCLSID(myclsid,xclsid);
67         WINE_StringFromCLSID(refiid,xiid);
68           
69         TRACE("(%p,\n\tCLSID:\t%s, unk:%p\n\tIID:\t%s,%p)\n",
70                 aclsid,xclsid,unknownouter,xiid,ppv);
71
72         if IsEqualCLSID(myclsid, &CLSID_ShellFSFolder)
73         {
74           hres = IFSFolder_Constructor(unknownouter, refiid, ppv);
75         }
76         else
77         {
78           hres = CoCreateInstance(myclsid, unknownouter, CLSCTX_INPROC_SERVER, refiid, ppv);
79         }
80         
81         if(hres!=S_OK)
82         {
83           ERR("failed (0x%08lx) to create \n\tCLSID:\t%s\n\tIID:\t%s\n", hres, xclsid, xiid);
84           ERR("class not found in registry\n");
85         }
86
87         TRACE("-- instance: %p\n",*ppv);
88         return hres;
89 }
90
91 /*************************************************************************
92  * SHELL32_DllGetClassObject   [SHELL32.128]
93  */
94 HRESULT WINAPI SHELL32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
95 {       HRESULT hres = E_OUTOFMEMORY;
96         LPCLASSFACTORY lpclf;
97
98         char xclsid[50],xiid[50];
99         WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
100         WINE_StringFromCLSID((LPCLSID)iid,xiid);
101         TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n",xclsid,xiid);
102         
103         *ppv = NULL;
104
105         if(IsEqualCLSID(rclsid, &CLSID_ShellDesktop)|| 
106            IsEqualCLSID(rclsid, &CLSID_ShellLink))
107         {
108           lpclf = IClassFactory_Constructor( rclsid );
109
110           if(lpclf) 
111           {
112             hres = IClassFactory_QueryInterface(lpclf,iid, ppv);
113             IClassFactory_Release(lpclf);
114           }
115         }
116         else
117         {
118           WARN("-- CLSID not found\n");
119           hres = CLASS_E_CLASSNOTAVAILABLE;
120         }
121         TRACE("-- pointer to class factory: %p\n",*ppv);
122         return hres;
123 }
124
125 /*************************************************************************
126  * SHCLSIDFromString                            [SHELL32.147]
127  *
128  * NOTES
129  *     exported by ordinal
130  */
131 DWORD WINAPI SHCLSIDFromStringA (LPSTR clsid, CLSID *id)
132 {
133         TRACE("(%p(%s) %p)\n", clsid, clsid, id);
134         return CLSIDFromString16(clsid, id); 
135 }
136 DWORD WINAPI SHCLSIDFromStringW (LPWSTR clsid, CLSID *id)
137 {
138         TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id);
139         return CLSIDFromString(clsid, id); 
140 }
141 DWORD WINAPI SHCLSIDFromStringAW (LPVOID clsid, CLSID *id)
142 {
143         if (VERSION_OsIsUnicode())
144           return SHCLSIDFromStringW (clsid, id);
145         return SHCLSIDFromStringA (clsid, id);
146 }
147
148 /*************************************************************************
149  *                       SHGetMalloc                    [SHELL32.220]
150  * returns the interface to shell malloc.
151  *
152  * [SDK header win95/shlobj.h:
153  * equivalent to:  #define SHGetMalloc(ppmem)   CoGetMalloc(MEMCTX_TASK, ppmem)
154  * ]
155  * What we are currently doing is not very wrong, since we always use the same
156  * heap (ProcessHeap).
157  */
158 DWORD WINAPI SHGetMalloc(LPMALLOC *lpmal) 
159 {
160         TRACE("(%p)\n", lpmal);
161         return CoGetMalloc(0,lpmal);
162 }
163
164 /*************************************************************************
165  * SHGetDesktopFolder                   [SHELL32.216]
166  */
167 LPSHELLFOLDER pdesktopfolder=NULL;
168
169 DWORD WINAPI SHGetDesktopFolder(IShellFolder **psf)
170 {
171         HRESULT hres = S_OK;
172         LPCLASSFACTORY lpclf;
173         TRACE("%p->(%p)\n",psf,*psf);
174
175         *psf=NULL;
176
177         if (!pdesktopfolder) 
178         {
179           lpclf = IClassFactory_Constructor(&CLSID_ShellDesktop);
180           if(lpclf) 
181           {
182             hres = IClassFactory_CreateInstance(lpclf,NULL,(REFIID)&IID_IShellFolder, (void*)&pdesktopfolder);
183             IClassFactory_Release(lpclf);
184           }  
185         }
186         
187         if (pdesktopfolder) 
188         {
189           /* even if we create the folder, add a ref so the application canĀ“t destroy the folder*/
190           IShellFolder_AddRef(pdesktopfolder);
191           *psf = pdesktopfolder;
192         }
193
194         TRACE("-- %p->(%p)\n",psf, *psf);
195         return hres;
196 }
197
198 /**************************************************************************
199 *  IClassFactory Implementation
200 */
201
202 typedef struct
203 {
204     /* IUnknown fields */
205     ICOM_VFIELD(IClassFactory);
206     DWORD                       ref;
207     CLSID                       *rclsid;
208 } IClassFactoryImpl;
209
210 static ICOM_VTABLE(IClassFactory) clfvt;
211
212 /**************************************************************************
213  *  IClassFactory_Constructor
214  */
215
216 LPCLASSFACTORY IClassFactory_Constructor(REFCLSID rclsid)
217 {
218         IClassFactoryImpl* lpclf;
219
220         lpclf= (IClassFactoryImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IClassFactoryImpl));
221         lpclf->ref = 1;
222         ICOM_VTBL(lpclf) = &clfvt;
223         lpclf->rclsid = (CLSID*)rclsid;
224
225         TRACE("(%p)->()\n",lpclf);
226         shell32_ObjCount++;
227         return (LPCLASSFACTORY)lpclf;
228 }
229 /**************************************************************************
230  *  IClassFactory_QueryInterface
231  */
232 static HRESULT WINAPI IClassFactory_fnQueryInterface(
233   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
234 {
235         ICOM_THIS(IClassFactoryImpl,iface);
236         char    xriid[50];
237         WINE_StringFromCLSID((LPCLSID)riid,xriid);
238         TRACE("(%p)->(\n\tIID:\t%s)\n",This,xriid);
239
240         *ppvObj = NULL;
241
242         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
243         { *ppvObj = This; 
244         }
245         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
246         { *ppvObj = (IClassFactory*)This;
247         }   
248
249         if(*ppvObj)
250         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
251           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
252           return S_OK;
253         }
254         TRACE("-- Interface: %s E_NOINTERFACE\n", xriid);
255         return E_NOINTERFACE;
256 }  
257 /******************************************************************************
258  * IClassFactory_AddRef
259  */
260 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
261 {
262         ICOM_THIS(IClassFactoryImpl,iface);
263         TRACE("(%p)->(count=%lu)\n",This,This->ref);
264
265         shell32_ObjCount++;
266         return ++(This->ref);
267 }
268 /******************************************************************************
269  * IClassFactory_Release
270  */
271 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
272 {
273         ICOM_THIS(IClassFactoryImpl,iface);
274         TRACE("(%p)->(count=%lu)\n",This,This->ref);
275
276         shell32_ObjCount--;
277         if (!--(This->ref)) 
278         { TRACE("-- destroying IClassFactory(%p)\n",This);
279                 HeapFree(GetProcessHeap(),0,This);
280                 return 0;
281         }
282         return This->ref;
283 }
284 /******************************************************************************
285  * IClassFactory_CreateInstance
286  */
287 static HRESULT WINAPI IClassFactory_fnCreateInstance(
288   LPCLASSFACTORY iface, LPUNKNOWN pUnknown, REFIID riid, LPVOID *ppObject)
289 {
290         ICOM_THIS(IClassFactoryImpl,iface);
291         IUnknown *pObj = NULL;
292         HRESULT hres;
293         char    xriid[50];
294
295         WINE_StringFromCLSID((LPCLSID)riid,xriid);
296         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnknown,xriid,ppObject);
297
298         *ppObject = NULL;
299                 
300         if(pUnknown)
301         {
302           return(CLASS_E_NOAGGREGATION);
303         }
304
305         if (IsEqualCLSID(This->rclsid, &CLSID_ShellDesktop))
306         {
307           pObj = (IUnknown *)ISF_Desktop_Constructor();
308         }
309         else if (IsEqualCLSID(This->rclsid, &CLSID_ShellLink))
310         {
311           pObj = (IUnknown *)IShellLink_Constructor(FALSE);
312         } 
313         else
314         {
315           ERR("unknown IID requested\n\tIID:\t%s\n",xriid);
316           return(E_NOINTERFACE);
317         }
318         
319         if (!pObj)
320         {
321           return(E_OUTOFMEMORY);
322         }
323          
324         hres = IUnknown_QueryInterface(pObj,riid, ppObject);
325         IUnknown_Release(pObj);
326
327         TRACE("-- Object created: (%p)->%p\n",This,*ppObject);
328
329         return hres;
330 }
331 /******************************************************************************
332  * IClassFactory_LockServer
333  */
334 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
335 {
336         ICOM_THIS(IClassFactoryImpl,iface);
337         TRACE("%p->(0x%x), not implemented\n",This, fLock);
338         return E_NOTIMPL;
339 }
340
341 static ICOM_VTABLE(IClassFactory) clfvt = 
342 {
343     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
344     IClassFactory_fnQueryInterface,
345     IClassFactory_fnAddRef,
346   IClassFactory_fnRelease,
347   IClassFactory_fnCreateInstance,
348   IClassFactory_fnLockServer
349 };
350
351 /**************************************************************************
352  * Default ClassFactory Implementation
353  *
354  * SHCreateDefClassObject
355  *
356  * NOTES
357  *  helper function for dll's without a own classfactory
358  *  a generic classfactory is returned
359  *  when the CreateInstance of the cf is called the callback is executed
360  */
361 typedef HRESULT (CALLBACK * LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject);
362
363 typedef struct
364 {
365     ICOM_VFIELD(IClassFactory);
366     DWORD                       ref;
367     CLSID                       *rclsid;
368     LPFNCREATEINSTANCE          lpfnCI;
369     const IID *                 riidInst;
370     UINT *                      pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */
371 } IDefClFImpl;
372
373 static ICOM_VTABLE(IClassFactory) dclfvt;
374
375 /**************************************************************************
376  *  IDefClF_fnConstructor
377  */
378
379 IClassFactory * IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, UINT * pcRefDll, REFIID riidInst)
380 {
381         IDefClFImpl* lpclf;
382         char    xriidInst[50];
383
384         WINE_StringFromCLSID((LPCLSID)riidInst,xriidInst);
385
386         lpclf = (IDefClFImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDefClFImpl));
387         lpclf->ref = 1;
388         ICOM_VTBL(lpclf) = &dclfvt;
389         lpclf->lpfnCI = lpfnCI;
390         lpclf->pcRefDll = pcRefDll;
391
392         if (pcRefDll) 
393           (*pcRefDll)++;
394
395         lpclf->riidInst = riidInst;
396
397         TRACE("(%p)\n\tIID:\t%s\n",lpclf, xriidInst);
398         shell32_ObjCount++;
399         return (LPCLASSFACTORY)lpclf;
400 }
401 /**************************************************************************
402  *  IDefClF_fnQueryInterface
403  */
404 static HRESULT WINAPI IDefClF_fnQueryInterface(
405   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
406 {
407         ICOM_THIS(IDefClFImpl,iface);
408         char    xriid[50];
409         WINE_StringFromCLSID((LPCLSID)riid,xriid);
410         TRACE("(%p)->(\n\tIID:\t%s)\n",This,xriid);
411
412         *ppvObj = NULL;
413
414         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
415         { *ppvObj = This; 
416         }
417         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
418         { *ppvObj = (IClassFactory*)This;
419         }   
420
421         if(*ppvObj)
422         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
423           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
424           return S_OK;
425         }
426         TRACE("-- Interface: %s E_NOINTERFACE\n", xriid);
427         return E_NOINTERFACE;
428 }  
429 /******************************************************************************
430  * IDefClF_fnAddRef
431  */
432 static ULONG WINAPI IDefClF_fnAddRef(LPCLASSFACTORY iface)
433 {
434         ICOM_THIS(IDefClFImpl,iface);
435         TRACE("(%p)->(count=%lu)\n",This,This->ref);
436
437         shell32_ObjCount++;
438
439         return ++(This->ref);
440 }
441 /******************************************************************************
442  * IDefClF_fnRelease
443  */
444 static ULONG WINAPI IDefClF_fnRelease(LPCLASSFACTORY iface)
445 {
446         ICOM_THIS(IDefClFImpl,iface);
447         TRACE("(%p)->(count=%lu)\n",This,This->ref);
448
449         shell32_ObjCount--;
450
451         if (!--(This->ref)) 
452         { 
453           if (This->pcRefDll) 
454             (*This->pcRefDll)--;
455
456           TRACE("-- destroying IClassFactory(%p)\n",This);
457           HeapFree(GetProcessHeap(),0,This);
458           return 0;
459         }
460         return This->ref;
461 }
462 /******************************************************************************
463  * IDefClF_fnCreateInstance
464  */
465 static HRESULT WINAPI IDefClF_fnCreateInstance(
466   LPCLASSFACTORY iface, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
467 {
468         ICOM_THIS(IDefClFImpl,iface);
469         char    xriid[50];
470
471         WINE_StringFromCLSID((LPCLSID)riid,xriid);
472         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnkOuter,xriid,ppvObject);
473
474         *ppvObject = NULL;
475                 
476         if(pUnkOuter)
477           return(CLASS_E_NOAGGREGATION);
478
479         if ( This->riidInst==NULL ||
480              IsEqualCLSID(riid, This->riidInst) ||
481              IsEqualCLSID(riid, &IID_IUnknown) )
482         {
483           return This->lpfnCI(pUnkOuter, riid, ppvObject);
484         }
485
486         ERR("unknown IID requested\n\tIID:\t%s\n",xriid);
487         return E_NOINTERFACE;
488 }
489 /******************************************************************************
490  * IDefClF_fnLockServer
491  */
492 static HRESULT WINAPI IDefClF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
493 {
494         ICOM_THIS(IDefClFImpl,iface);
495         TRACE("%p->(0x%x), not implemented\n",This, fLock);
496         return E_NOTIMPL;
497 }
498
499 static ICOM_VTABLE(IClassFactory) dclfvt = 
500 {
501     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
502     IDefClF_fnQueryInterface,
503     IDefClF_fnAddRef,
504   IDefClF_fnRelease,
505   IDefClF_fnCreateInstance,
506   IDefClF_fnLockServer
507 };
508
509 /******************************************************************************
510  * SHCreateDefClassObject                       [SHELL32.70]
511  */
512 HRESULT WINAPI SHCreateDefClassObject(
513         REFIID  riid,                           
514         LPVOID* ppv,    
515         LPFNCREATEINSTANCE lpfnCI,      /* create instance callback entry */
516         UINT    *pcRefDll,              /* ref count of the dll */
517         REFIID  riidInst)               /* optional interface to the instance */
518 {
519
520         char xriid[50],xriidInst[50];
521         WINE_StringFromCLSID((LPCLSID)riid,xriid);
522         WINE_StringFromCLSID((LPCLSID)riidInst,xriidInst);
523
524         TRACE("\n\tIID:\t%s %p %p %p \n\tIIDIns:\t%s\n",
525         xriid, ppv, lpfnCI, pcRefDll, xriidInst);
526
527         if ( IsEqualCLSID(riid, &IID_IClassFactory) )
528         {
529           IClassFactory * pcf = IDefClF_fnConstructor(lpfnCI, pcRefDll, riidInst);
530           if (pcf)
531           {
532             *ppv = pcf;
533             return NOERROR;
534           }
535           return E_OUTOFMEMORY;
536         }
537         return E_NOINTERFACE;
538 }
539