Added DebugBreak.
[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 /*************************************************************************
31  *
32  */
33 typedef DWORD (* WINAPI GetClassPtr)(REFCLSID,REFIID,LPVOID);
34
35 static GetClassPtr SH_find_moduleproc(LPSTR dllname,HMODULE *xhmod,LPSTR name)
36 {       HMODULE hmod;
37         FARPROC dllunload,nameproc;
38
39         TRACE("dll=%s, hmodule=%p, name=%s\n",dllname, xhmod, name);
40         if (xhmod)
41         { *xhmod = 0;
42         }
43         if (!strcasecmp(PathFindFilenameA(dllname),"shell32.dll"))
44         { return (GetClassPtr)SHELL32_DllGetClassObject;
45         }
46
47         hmod = LoadLibraryExA(dllname,0,LOAD_WITH_ALTERED_SEARCH_PATH);
48         if (!hmod)
49         { return NULL;
50         }
51         dllunload = GetProcAddress(hmod,"DllCanUnloadNow");
52         if (!dllunload)
53         { if (xhmod)
54           { *xhmod = hmod;
55           }
56         }
57         nameproc = GetProcAddress(hmod,name);
58         if (!nameproc)
59         { FreeLibrary(hmod);
60           return NULL;
61         }
62         /* register unloadable dll with unloadproc ... */
63         return (GetClassPtr)nameproc;
64 }
65 /*************************************************************************
66  *
67  */
68 static DWORD SH_get_instance(REFCLSID clsid,LPSTR dllname,LPVOID unknownouter,REFIID refiid,LPVOID inst) 
69 {       GetClassPtr     dllgetclassob;
70         DWORD           hres;
71         LPCLASSFACTORY  classfac;
72
73         char    xclsid[50],xrefiid[50];
74         WINE_StringFromCLSID((LPCLSID)clsid,xclsid);
75         WINE_StringFromCLSID((LPCLSID)refiid,xrefiid);
76         TRACE("\n\tCLSID:%s,%s,%p,\n\tIID:%s,%p\n",xclsid, dllname,unknownouter,xrefiid,inst);
77         
78         dllgetclassob = SH_find_moduleproc(dllname,NULL,"DllGetClassObject");
79         if (!dllgetclassob)
80         { return 0x80070000|GetLastError();
81         }
82
83         hres = (*dllgetclassob)(clsid,(REFIID)&IID_IClassFactory,&classfac);
84         if ((hres<0) || (hres>=0x80000000))
85             return hres;
86         if (!classfac)
87         { FIXME("no classfactory, but hres is 0x%ld!\n",hres);
88           return E_FAIL;
89         }
90         IClassFactory_CreateInstance(classfac,unknownouter,refiid,inst);
91         IClassFactory_Release(classfac);
92         return 0;
93 }
94
95 /*************************************************************************
96  * SHCoCreateInstance [SHELL32.102]
97  * 
98  * NOTES
99  *     exported by ordinal
100  */
101 LRESULT WINAPI SHCoCreateInstance(LPSTR aclsid,CLSID *clsid,LPUNKNOWN unknownouter,REFIID refiid,LPVOID inst)
102 {       char    buffer[256],xclsid[48],xiid[48],path[260],tmodel[100];
103         HKEY    inprockey;
104         DWORD   pathlen,type,tmodellen;
105         DWORD   hres;
106         
107         WINE_StringFromCLSID(refiid,xiid);
108
109         if (clsid)
110         { WINE_StringFromCLSID(clsid,xclsid);
111         }
112         else
113         { if (!aclsid)
114           {     return 0x80040154;
115           }
116           strcpy(xclsid,aclsid);
117         }
118         TRACE("(%p,\n\tSID:\t%s,%p,\n\tIID:\t%s,%p)\n",aclsid,xclsid,unknownouter,xiid,inst);
119
120         sprintf(buffer,"CLSID\\%s\\InProcServer32",xclsid);
121
122         if (RegOpenKeyExA(HKEY_CLASSES_ROOT,buffer,0,0x02000000,&inprockey))
123         { return SH_get_instance(clsid,"shell32.dll",unknownouter,refiid,inst);
124         }
125         pathlen=sizeof(path);
126
127         if (RegQueryValueA(inprockey,NULL,path,&pathlen))
128         { RegCloseKey(inprockey);
129           return SH_get_instance(clsid,"shell32.dll",unknownouter,refiid,inst);
130         }
131
132         TRACE("Server dll is %s\n",path);
133         tmodellen=sizeof(tmodel);
134         type=REG_SZ;
135         if (RegQueryValueExA(inprockey,"ThreadingModel",NULL,&type,tmodel,&tmodellen))
136         { RegCloseKey(inprockey);
137           return SH_get_instance(clsid,"shell32.dll",unknownouter,refiid,inst);
138         }
139
140         TRACE("Threading model is %s\n",tmodel);
141
142         hres=SH_get_instance(clsid,path,unknownouter,refiid,inst);
143         if (hres<0 || (hres>0x80000000))
144         { hres=SH_get_instance(clsid,"shell32.dll",unknownouter,refiid,inst);
145         }
146         RegCloseKey(inprockey);
147         return hres;
148 }
149
150
151 /*************************************************************************
152  * SHELL32_DllGetClassObject   [SHELL32.128]
153  *
154  * [Standart OLE/COM Interface Method]
155  * This Function retrives the pointer to a specified interface (iid) of
156  * a given class (rclsid).
157  * With this pointer it's possible to call the IClassFactory_CreateInstance
158  * method to get a instance of the requested Class.
159  * This function does NOT instantiate the Class!!!
160  *
161  */
162 HRESULT WINAPI SHELL32_DllGetClassObject(REFCLSID rclsid,REFIID iid,LPVOID *ppv)
163 {       HRESULT hres = E_OUTOFMEMORY;
164         LPCLASSFACTORY lpclf;
165
166         char xclsid[50],xiid[50];
167         WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
168         WINE_StringFromCLSID((LPCLSID)iid,xiid);
169         TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n",xclsid,xiid);
170         
171         *ppv = NULL;
172         if(IsEqualCLSID(rclsid, &CLSID_ShellDesktop)|| 
173            IsEqualCLSID(rclsid, &CLSID_ShellLink))
174         { if(IsEqualCLSID(rclsid, &CLSID_ShellDesktop))      /*debug*/
175           { TRACE("-- requested CLSID_ShellDesktop\n");
176           }
177
178           if (IsEqualCLSID(rclsid, &CLSID_ShellLink))
179           { if (VERSION_OsIsUnicode ())
180               lpclf = IShellLinkW_CF_Constructor();
181             else  
182               lpclf = IShellLink_CF_Constructor();
183           }
184           else
185           { lpclf = IClassFactory_Constructor();
186           }
187
188           if(lpclf) {
189             hres = IClassFactory_QueryInterface(lpclf,iid, ppv);
190             IClassFactory_Release(lpclf);
191           }
192         }
193         else
194         { WARN("-- CLSID not found\n");
195           hres = CLASS_E_CLASSNOTAVAILABLE;
196         }
197         TRACE("-- pointer to class factory: %p\n",*ppv);
198         return hres;
199 }
200
201 /*************************************************************************
202  * SHCLSIDFromString                            [SHELL32.147]
203  *
204  * NOTES
205  *     exported by ordinal
206  */
207 DWORD WINAPI SHCLSIDFromString (LPSTR clsid, CLSID *id)
208 {
209         TRACE("(%p(%s) %p)\n", clsid, clsid, id);
210         return CLSIDFromString16(clsid, id); 
211 }
212
213 /*************************************************************************
214  *                       SHGetMalloc                    [SHELL32.220]
215  * returns the interface to shell malloc.
216  *
217  * [SDK header win95/shlobj.h:
218  * equivalent to:  #define SHGetMalloc(ppmem)   CoGetMalloc(MEMCTX_TASK, ppmem)
219  * ]
220  * What we are currently doing is not very wrong, since we always use the same
221  * heap (ProcessHeap).
222  */
223 DWORD WINAPI SHGetMalloc(LPMALLOC *lpmal) 
224 {       TRACE("(%p)\n", lpmal);
225         return CoGetMalloc(0,lpmal);
226 }
227
228 /**************************************************************************
229 *  IClassFactory Implementation
230 */
231
232 typedef struct
233 {
234     /* IUnknown fields */
235     ICOM_VTABLE(IClassFactory)* lpvtbl;
236     DWORD                       ref;
237 } IClassFactoryImpl;
238
239 static ICOM_VTABLE(IClassFactory) clfvt;
240
241 /**************************************************************************
242  *  IClassFactory_Constructor
243  */
244
245 LPCLASSFACTORY IClassFactory_Constructor(void)
246 {
247         IClassFactoryImpl* lpclf;
248
249         lpclf= (IClassFactoryImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IClassFactoryImpl));
250         lpclf->ref = 1;
251         lpclf->lpvtbl = &clfvt;
252
253         TRACE("(%p)->()\n",lpclf);
254         shell32_ObjCount++;
255         return (LPCLASSFACTORY)lpclf;
256 }
257 /**************************************************************************
258  *  IClassFactory_QueryInterface
259  */
260 static HRESULT WINAPI IClassFactory_fnQueryInterface(
261   LPCLASSFACTORY iface, REFIID riid, LPVOID *ppvObj)
262 {
263         ICOM_THIS(IClassFactoryImpl,iface);
264         char    xriid[50];
265         WINE_StringFromCLSID((LPCLSID)riid,xriid);
266         TRACE("(%p)->(\n\tIID:\t%s)\n",This,xriid);
267
268         *ppvObj = NULL;
269
270         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
271         { *ppvObj = This; 
272         }
273         else if(IsEqualIID(riid, &IID_IClassFactory))  /*IClassFactory*/
274         { *ppvObj = (IClassFactory*)This;
275         }   
276
277         if(*ppvObj)
278         { IUnknown_AddRef((LPUNKNOWN)*ppvObj);          
279           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
280           return S_OK;
281         }
282         TRACE("-- Interface: E_NOINTERFACE\n");
283         return E_NOINTERFACE;
284 }  
285 /******************************************************************************
286  * IClassFactory_AddRef
287  */
288 static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
289 {
290         ICOM_THIS(IClassFactoryImpl,iface);
291         TRACE("(%p)->(count=%lu)\n",This,This->ref);
292
293         shell32_ObjCount++;
294         return ++(This->ref);
295 }
296 /******************************************************************************
297  * IClassFactory_Release
298  */
299 static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
300 {
301         ICOM_THIS(IClassFactoryImpl,iface);
302         TRACE("(%p)->(count=%lu)\n",This,This->ref);
303
304         shell32_ObjCount--;
305         if (!--(This->ref)) 
306         { TRACE("-- destroying IClassFactory(%p)\n",This);
307                 HeapFree(GetProcessHeap(),0,This);
308                 return 0;
309         }
310         return This->ref;
311 }
312 /******************************************************************************
313  * IClassFactory_CreateInstance
314  */
315 static HRESULT WINAPI IClassFactory_fnCreateInstance(
316   LPCLASSFACTORY iface, LPUNKNOWN pUnknown, REFIID riid, LPVOID *ppObject)
317 {
318         ICOM_THIS(IClassFactoryImpl,iface);
319         IUnknown *pObj = NULL;
320         HRESULT hres;
321         char    xriid[50];
322
323         WINE_StringFromCLSID((LPCLSID)riid,xriid);
324         TRACE("%p->(%p,\n\tIID:\t%s,%p)\n",This,pUnknown,xriid,ppObject);
325
326         *ppObject = NULL;
327                 
328         if(pUnknown)
329         {       return(CLASS_E_NOAGGREGATION);
330         }
331
332         if (IsEqualIID(riid, &IID_IShellFolder))
333         { pObj = (IUnknown *)IShellFolder_Constructor(NULL,NULL);
334         } 
335         else if (IsEqualIID(riid, &IID_IShellView))
336         { pObj = (IUnknown *)IShellView_Constructor(NULL,NULL);
337         } 
338         else if (IsEqualIID(riid, &IID_IExtractIconA))
339         { pObj = (IUnknown *)IExtractIconA_Constructor(NULL);
340         } 
341         else if (IsEqualIID(riid, &IID_IContextMenu))
342         { pObj = (IUnknown *)IContextMenu_Constructor(NULL, NULL, 0);
343         } 
344         else if (IsEqualIID(riid, &IID_IDataObject))
345         { pObj = (IUnknown *)IDataObject_Constructor(0,NULL,NULL,0);
346         } 
347         else
348         { ERR("unknown IID requested\n\tIID:\t%s\n",xriid);
349           return(E_NOINTERFACE);
350         }
351         
352         if (!pObj)
353         { return(E_OUTOFMEMORY);
354         }
355          
356         hres = pObj->lpvtbl->fnQueryInterface(pObj,riid, ppObject);
357         pObj->lpvtbl->fnRelease(pObj);
358         TRACE("-- Object created: (%p)->%p\n",This,*ppObject);
359
360         return hres;
361 }
362 /******************************************************************************
363  * IClassFactory_LockServer
364  */
365 static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
366 {
367         ICOM_THIS(IClassFactoryImpl,iface);
368         TRACE("%p->(0x%x), not implemented\n",This, fLock);
369         return E_NOTIMPL;
370 }
371
372 static ICOM_VTABLE(IClassFactory) clfvt = 
373 {
374     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
375     IClassFactory_fnQueryInterface,
376     IClassFactory_fnAddRef,
377   IClassFactory_fnRelease,
378   IClassFactory_fnCreateInstance,
379   IClassFactory_fnLockServer
380 };
381