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