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