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