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