shdocvw: Use an iface instead of an vtbl pointer in IClassFactoryImpl.
[wine] / dlls / shdocvw / factory.c
1 /*
2  * Implementation of class factory for IE Web Browser
3  *
4  * Copyright 2001 John R. Sheets (for CodeWeavers)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <string.h>
22 #include <stdio.h>
23
24 #include "shdocvw.h"
25 #include "winreg.h"
26 #include "advpub.h"
27 #include "isguids.h"
28
29 #include "winver.h"
30
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
34
35 /**********************************************************************
36  * Implement the WebBrowser class factory
37  */
38
39 typedef struct
40 {
41     /* IUnknown fields */
42     IClassFactory IClassFactory_iface;
43     HRESULT (*cf)(LPUNKNOWN, REFIID, LPVOID *);
44     LONG ref;
45 } IClassFactoryImpl;
46
47 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
48 {
49     return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
50 }
51
52
53 /**********************************************************************
54  * WBCF_QueryInterface (IUnknown)
55  */
56 static HRESULT WINAPI WBCF_QueryInterface(LPCLASSFACTORY iface,
57                                           REFIID riid, LPVOID *ppobj)
58 {
59     TRACE("(%s %p)\n", debugstr_guid(riid), ppobj);
60
61     if (!ppobj)
62         return E_POINTER;
63
64     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
65         *ppobj = iface;
66         IClassFactory_AddRef(iface);
67         return S_OK;
68     }
69
70     WARN("Not supported interface %s\n", debugstr_guid(riid));
71
72     *ppobj = NULL;
73     return E_NOINTERFACE;
74 }
75
76 /************************************************************************
77  * WBCF_AddRef (IUnknown)
78  */
79 static ULONG WINAPI WBCF_AddRef(LPCLASSFACTORY iface)
80 {
81     SHDOCVW_LockModule();
82
83     return 2; /* non-heap based object */
84 }
85
86 /************************************************************************
87  * WBCF_Release (IUnknown)
88  */
89 static ULONG WINAPI WBCF_Release(LPCLASSFACTORY iface)
90 {
91     SHDOCVW_UnlockModule();
92
93     return 1; /* non-heap based object */
94 }
95
96 /************************************************************************
97  * WBCF_CreateInstance (IClassFactory)
98  */
99 static HRESULT WINAPI WBCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
100                                           REFIID riid, LPVOID *ppobj)
101 {
102     IClassFactoryImpl *This = (IClassFactoryImpl *) iface;
103     return This->cf(pOuter, riid, ppobj);
104 }
105
106 /************************************************************************
107  * WBCF_LockServer (IClassFactory)
108  */
109 static HRESULT WINAPI WBCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
110 {
111     TRACE("(%d)\n", dolock);
112
113     if (dolock)
114         SHDOCVW_LockModule();
115     else
116         SHDOCVW_UnlockModule();
117     
118     return S_OK;
119 }
120
121 static const IClassFactoryVtbl WBCF_Vtbl =
122 {
123     WBCF_QueryInterface,
124     WBCF_AddRef,
125     WBCF_Release,
126     WBCF_CreateInstance,
127     WBCF_LockServer
128 };
129
130 /*************************************************************************
131  *              DllGetClassObject (SHDOCVW.@)
132  */
133 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
134 {
135     static IClassFactoryImpl WB1ClassFactory = {{&WBCF_Vtbl}, WebBrowserV1_Create};
136     static IClassFactoryImpl WB2ClassFactory = {{&WBCF_Vtbl}, WebBrowserV2_Create};
137     static IClassFactoryImpl CUHClassFactory = {{&WBCF_Vtbl}, CUrlHistory_Create};
138     static IClassFactoryImpl ISCClassFactory = {{&WBCF_Vtbl}, InternetShortcut_Create};
139     static IClassFactoryImpl TBLClassFactory = {{&WBCF_Vtbl}, TaskbarList_Create};
140
141     TRACE("\n");
142
143     if(IsEqualGUID(&CLSID_WebBrowser, rclsid))
144         return IClassFactory_QueryInterface(&WB2ClassFactory.IClassFactory_iface, riid, ppv);
145
146     if(IsEqualGUID(&CLSID_WebBrowser_V1, rclsid))
147         return IClassFactory_QueryInterface(&WB1ClassFactory.IClassFactory_iface, riid, ppv);
148
149     if(IsEqualGUID(&CLSID_CUrlHistory, rclsid))
150         return IClassFactory_QueryInterface(&CUHClassFactory.IClassFactory_iface, riid, ppv);
151
152     if(IsEqualGUID(&CLSID_InternetShortcut, rclsid))
153         return IClassFactory_QueryInterface(&ISCClassFactory.IClassFactory_iface, riid, ppv);
154
155     if(IsEqualGUID(&CLSID_TaskbarList, rclsid))
156         return IClassFactory_QueryInterface(&TBLClassFactory.IClassFactory_iface, riid, ppv);
157
158     /* As a last resort, figure if the CLSID belongs to a 'Shell Instance Object' */
159     return SHDOCVW_GetShellInstanceObjectClassObject(rclsid, riid, ppv);
160 }
161
162 HRESULT register_class_object(BOOL do_reg)
163 {
164     HRESULT hres;
165
166     static DWORD cookie;
167     static IClassFactoryImpl IEClassFactory = {{&WBCF_Vtbl}, InternetExplorer_Create};
168
169     if(do_reg) {
170         hres = CoRegisterClassObject(&CLSID_InternetExplorer,
171                                      (IUnknown*)&IEClassFactory.IClassFactory_iface, CLSCTX_SERVER,
172                                      REGCLS_MULTIPLEUSE|REGCLS_SUSPENDED, &cookie);
173         if (FAILED(hres)) {
174             ERR("failed to register object %08x\n", hres);
175             return hres;
176         }
177
178         hres = CoResumeClassObjects();
179         if(SUCCEEDED(hres))
180             return hres;
181
182         ERR("failed to resume object %08x\n", hres);
183     }
184
185     return CoRevokeClassObject(cookie);
186 }
187
188 static HRESULT reg_install(LPCSTR section, STRTABLEA *strtable)
189 {
190     HRESULT (WINAPI *pRegInstall)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
191     HMODULE hadvpack;
192     HRESULT hres;
193
194     static const WCHAR advpackW[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
195
196     hadvpack = LoadLibraryW(advpackW);
197     pRegInstall = (void *)GetProcAddress(hadvpack, "RegInstall");
198
199     hres = pRegInstall(shdocvw_hinstance, section, strtable);
200
201     FreeLibrary(hadvpack);
202     return hres;
203 }
204
205 static const GUID CLSID_MicrosoftBrowserArchitecture =
206     {0xa5e46e3a, 0x8849, 0x11d1, {0x9d, 0x8c, 0x00, 0xc0, 0x4f, 0xc9, 0x9d, 0x61}};
207 static const GUID CLSID_MruLongList =
208     {0x53bd6b4e, 0x3780, 0x4693, {0xaf, 0xc3, 0x71, 0x61, 0xc2, 0xf3, 0xee, 0x9c}};
209
210 #define INF_SET_CLSID(clsid)                  \
211     do                                        \
212     {                                         \
213         static CHAR name[] = "CLSID_" #clsid; \
214                                               \
215         pse[i].pszName = name;                \
216         clsids[i++] = &CLSID_ ## clsid;       \
217     } while (0)
218
219 static HRESULT register_server(BOOL doregister)
220 {
221     STRTABLEA strtable;
222     STRENTRYA pse[15];
223     static CLSID const *clsids[15];
224     unsigned int i = 0;
225     HRESULT hres;
226
227     INF_SET_CLSID(CUrlHistory);
228     INF_SET_CLSID(Internet);
229     INF_SET_CLSID(InternetExplorer);
230     INF_SET_CLSID(InternetShortcut);
231     INF_SET_CLSID(MicrosoftBrowserArchitecture);
232     INF_SET_CLSID(MruLongList);
233     INF_SET_CLSID(SearchAssistantOC);
234     INF_SET_CLSID(ShellNameSpace);
235     INF_SET_CLSID(ShellSearchAssistantOC);
236     INF_SET_CLSID(ShellShellNameSpace);
237     INF_SET_CLSID(ShellUIHelper);
238     INF_SET_CLSID(ShellWindows);
239     INF_SET_CLSID(TaskbarList);
240     INF_SET_CLSID(WebBrowser);
241     INF_SET_CLSID(WebBrowser_V1);
242
243     for(i = 0; i < sizeof(pse)/sizeof(pse[0]); i++) {
244         pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39);
245         sprintf(pse[i].pszValue, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
246                 clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0],
247                 clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4],
248                 clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]);
249     }
250
251     strtable.cEntries = sizeof(pse)/sizeof(pse[0]);
252     strtable.pse = pse;
253
254     hres = reg_install(doregister ? "RegisterDll" : "UnregisterDll", &strtable);
255
256     for(i=0; i < sizeof(pse)/sizeof(pse[0]); i++)
257         HeapFree(GetProcessHeap(), 0, pse[i].pszValue);
258
259     return hres;
260 }
261
262 #undef INF_SET_CLSID
263
264 /***********************************************************************
265  *          DllRegisterServer (shdocvw.@)
266  */
267 HRESULT WINAPI DllRegisterServer(void)
268 {
269     ITypeLib *typelib;
270     HRESULT hres;
271
272     static const WCHAR shdocvwW[] = {'s','h','d','o','c','v','w','.','d','l','l',0};
273
274     hres = register_server(TRUE);
275     if(FAILED(hres))
276         return hres;
277
278     hres = LoadTypeLibEx(shdocvwW, REGKIND_REGISTER, &typelib);
279     if(FAILED(hres)) {
280         ERR("Could not load typelib: %08x\n", hres);
281         return hres;
282     }
283
284     ITypeLib_Release(typelib);
285
286     return hres;
287 }
288
289 /***********************************************************************
290  *          DllUnregisterServer (shdocvw.@)
291  */
292 HRESULT WINAPI DllUnregisterServer(void)
293 {
294     HRESULT hres;
295
296     hres = register_server(FALSE);
297     if(FAILED(hres))
298         return hres;
299
300     return UnRegisterTypeLib(&LIBID_SHDocVw, 1, 1, LOCALE_SYSTEM_DEFAULT, SYS_WIN32);
301 }
302
303 static BOOL check_native_ie(void)
304 {
305     static const WCHAR cszPath[] = {'b','r','o','w','s','e','u','i','.','d','l','l',0};
306     DWORD handle,size;
307     BOOL ret = TRUE;
308
309     size = GetFileVersionInfoSizeW(cszPath,&handle);
310     if (size)
311     {
312         LPVOID buf;
313         LPWSTR lpFileDescription;
314         UINT dwBytes;
315         static const WCHAR cszFD[] = {'\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o','\\','0','4','0','9','0','4','e','4','\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0};
316         static const WCHAR cszWine[] = {'W','i','n','e',0};
317
318         buf = HeapAlloc(GetProcessHeap(),0,size);
319         GetFileVersionInfoW(cszPath,0,size,buf);
320
321         if (VerQueryValueW(buf, cszFD, (LPVOID*)&lpFileDescription, &dwBytes) &&
322             strstrW(lpFileDescription,cszWine))
323                 ret = FALSE;
324
325         HeapFree(GetProcessHeap(), 0, buf);
326     }
327
328     return ret;
329 }
330
331 DWORD register_iexplore(BOOL doregister)
332 {
333     HRESULT hres;
334     if (check_native_ie())
335     {
336         TRACE("Native IE detected, not doing registration\n");
337         return S_OK;
338     }
339     hres = reg_install(doregister ? "RegisterIE" : "UnregisterIE", NULL);
340     return FAILED(hres);
341 }