Put FOR_EACH_COCLASS macro into its own file and export it
[WebKit-https.git] / WebKit / win / WebKitDLL.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "WebKitDLL.h"
28
29 #include "ForEachCoClass.h"
30 #include "IWebURLResponse.h"
31 #include "ProgIDMacros.h"
32 #include "WebKit.h"
33 #include "WebKitClassFactory.h"
34 #include "resource.h"
35 #pragma warning( push, 0 )
36 #include <WebCore/COMPtr.h>
37 #include <WebCore/IconDatabase.h>
38 #include <WebCore/Page.h>
39 #include <WebCore/SharedBuffer.h>
40 #include <WebCore/Widget.h>
41 #include <wtf/Vector.h>
42 #pragma warning(pop)
43 #include <tchar.h>
44 #include <olectl.h>
45
46 ULONG gLockCount;
47 ULONG gClassCount;
48 HINSTANCE gInstance;
49
50 #define CLSID_FOR_CLASS(cls) CLSID_##cls,
51 static CLSID gRegCLSIDs[] = {
52     FOR_EACH_COCLASS(CLSID_FOR_CLASS)
53 };
54 #undef CLSID_FOR_CLASS
55
56 void shutDownWebKit()
57 {
58     WebCore::iconDatabase()->close();
59 }
60
61 STDAPI_(BOOL) DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID /*lpReserved*/)
62 {
63     switch (ul_reason_for_call) {
64         case DLL_PROCESS_ATTACH:
65             gLockCount = gClassCount = 0;
66             gInstance = hModule;
67             WebCore::Page::setInstanceHandle(hModule);
68             return TRUE;
69
70         case DLL_PROCESS_DETACH:
71             shutDownWebKit();
72             break;
73
74         case DLL_THREAD_ATTACH:
75         case DLL_THREAD_DETACH:
76             break;
77     }
78     return FALSE;
79 }
80
81 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
82 {
83     bool found = false;
84     for (int i = 0; i < ARRAYSIZE(gRegCLSIDs); i++) {
85         if (IsEqualGUID(rclsid, gRegCLSIDs[i])) {
86             found = true;
87             break;
88         }
89     }
90     if (!found)
91         return E_FAIL;
92
93     if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IClassFactory))
94         return E_NOINTERFACE;
95
96     WebKitClassFactory* factory = new WebKitClassFactory(rclsid);
97     *ppv = reinterpret_cast<LPVOID>(factory);
98     if (!factory)
99         return E_OUTOFMEMORY;
100
101     factory->AddRef();
102     return S_OK;
103 }
104
105 STDAPI DllCanUnloadNow(void)
106 {
107     if (!gClassCount && !gLockCount)
108         return S_OK;
109     
110     return S_FALSE;
111 }
112
113 #if __BUILDBOT__
114 #define VERSION_INDEPENDENT_PROGID(className) VERSION_INDEPENDENT_PRODUCTION_PROGID(className)
115 #else
116 #define VERSION_INDEPENDENT_PROGID(className) VERSION_INDEPENDENT_OPENSOURCE_PROGID(className)
117 #endif
118 #define CURRENT_VERSIONED_PROGID(className) VERSIONED_PROGID(VERSION_INDEPENDENT_PROGID(className), CURRENT_PROGID_VERSION)
119 #define VERSIONED_303_PROGID(className) VERSIONED_PROGID(VERSION_INDEPENDENT_PROGID(className), 3)
120
121 // FIXME: The last line of this macro only here for the benefit of Safari 3.0.3. Once a newer version
122 // is released, the last line should be removed and gSlotsPerEntry should be decremented by 1.
123 //key                                                                                       value name              value }
124 #define KEYS_FOR_CLASS(cls) \
125 { TEXT("CLSID\\{########-####-####-####-############}"),                                    0,                      TEXT(#cls) }, \
126 { TEXT("CLSID\\{########-####-####-####-############}\\InprocServer32"),                    0,                      (LPCTSTR)-1 }, \
127 { TEXT("CLSID\\{########-####-####-####-############}\\InprocServer32"),                    TEXT("ThreadingModel"), TEXT("Apartment") }, \
128 { TEXT("CLSID\\{########-####-####-####-############}\\ProgID"),                            0,                      CURRENT_VERSIONED_PROGID(cls) }, \
129 { CURRENT_VERSIONED_PROGID(cls),                                                            0,                      TEXT(#cls) }, \
130 { CURRENT_VERSIONED_PROGID(cls) TEXT("\\CLSID"),                                            0,                      TEXT("{########-####-####-####-############}") }, \
131 { TEXT("CLSID\\{########-####-####-####-############}\\VersionIndependentProgID"),          0,                      VERSION_INDEPENDENT_PROGID(cls) }, \
132 { VERSION_INDEPENDENT_PROGID(cls),                                                          0,                      TEXT(#cls) }, \
133 { VERSION_INDEPENDENT_PROGID(cls) TEXT("\\CLSID"),                                          0,                      TEXT("{########-####-####-####-############}") }, \
134 { VERSION_INDEPENDENT_PROGID(cls) TEXT("\\CurVer"),                                         0,                      STRINGIFIED_VERSION(CURRENT_PROGID_VERSION) }, \
135 { VERSIONED_303_PROGID(cls),                                                                0,                      TEXT(#cls) }, \
136 { VERSIONED_303_PROGID(cls) TEXT("\\CLSID"),                                                0,                      TEXT("{########-####-####-####-############}") }, \
137 // end of macro
138
139 static const int gSlotsPerEntry = 12;
140 static LPCTSTR gRegTable[][3] = {
141     FOR_EACH_COCLASS(KEYS_FOR_CLASS)
142 };
143 #undef KEYS_FOR_CLASS
144
145 static void substituteGUID(LPTSTR str, const UUID* guid)
146 {
147     if (!guid || !str)
148         return;
149
150     TCHAR uuidString[40];
151     _stprintf_s(uuidString, ARRAYSIZE(uuidString), TEXT("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"), guid->Data1, guid->Data2, guid->Data3,
152         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
153
154     LPCTSTR guidPattern = TEXT("########-####-####-####-############");
155     size_t patternLength = _tcslen(guidPattern);
156     size_t strLength = _tcslen(str);
157     LPTSTR guidSubStr = str;
158     while (strLength) {
159         guidSubStr = _tcsstr(guidSubStr, guidPattern);
160         if (!guidSubStr)
161             break;
162         _tcsncpy(guidSubStr, uuidString, patternLength);
163         guidSubStr += patternLength;
164         strLength -= (guidSubStr - str);
165     }
166 }
167
168 STDAPI DllUnregisterServer(void)
169 {
170     HRESULT hr = S_OK;
171     HKEY userClasses;
172
173 #if __BUILDBOT__
174     UnRegisterTypeLib(LIBID_WebKit, 3, 0, 0, SYS_WIN32);
175 #else
176     UnRegisterTypeLib(LIBID_OpenSourceWebKit, 3, 0, 0, SYS_WIN32);
177 #endif
178
179     if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\CLASSES"), 0, KEY_WRITE, &userClasses) != ERROR_SUCCESS)
180         userClasses = 0;
181
182     int nEntries = ARRAYSIZE(gRegTable);
183     for (int i = nEntries - 1; i >= 0; i--) {
184         LPTSTR pszKeyName = _tcsdup(gRegTable[i][0]);
185         if (pszKeyName) {
186             substituteGUID(pszKeyName, &gRegCLSIDs[i/gSlotsPerEntry]);
187             RegDeleteKey(HKEY_CLASSES_ROOT, pszKeyName);
188             if (userClasses)
189                 RegDeleteKey(userClasses, pszKeyName);
190             free(pszKeyName);
191         } else
192             hr = E_OUTOFMEMORY;
193     }
194
195     if (userClasses)
196         RegCloseKey(userClasses);
197     return hr;
198 }
199
200 STDAPI DllRegisterServer(void)
201 {
202     HRESULT hr = S_OK;
203
204     // look up server's file name
205     TCHAR szFileName[MAX_PATH];
206     GetModuleFileName(gInstance, szFileName, MAX_PATH);
207
208     COMPtr<ITypeLib> typeLib;
209     LoadTypeLibEx(szFileName, REGKIND_REGISTER, &typeLib);
210
211     HKEY userClasses;
212     if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\CLASSES"), 0, KEY_WRITE, &userClasses) != ERROR_SUCCESS)
213         userClasses = 0;
214
215     // register entries from table
216     int nEntries = ARRAYSIZE(gRegTable);
217     for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {
218         LPTSTR pszKeyName   = _tcsdup(gRegTable[i][0]);
219         LPTSTR pszValueName = gRegTable[i][1] ? _tcsdup(gRegTable[i][1]) : 0;
220         LPTSTR allocatedValue   = (gRegTable[i][2] != (LPTSTR)-1) ? _tcsdup(gRegTable[i][2]) : (LPTSTR)-1;
221         LPTSTR pszValue     = allocatedValue;
222
223         if (pszKeyName && pszValue) {
224
225             int clsidIndex = i/gSlotsPerEntry;
226             substituteGUID(pszKeyName, &gRegCLSIDs[clsidIndex]);
227             substituteGUID(pszValueName, &gRegCLSIDs[clsidIndex]);
228
229             // map rogue value to module file name
230             if (pszValue == (LPTSTR)-1)
231                 pszValue = szFileName;
232             else
233                 substituteGUID(pszValue, &gRegCLSIDs[clsidIndex]);
234
235             // create the key
236             HKEY hkey;
237             LONG err = RegCreateKey(HKEY_CLASSES_ROOT, pszKeyName, &hkey);
238             if (err != ERROR_SUCCESS && userClasses)
239                 err = RegCreateKey(userClasses, pszKeyName, &hkey);
240             if (err == ERROR_SUCCESS) {
241                 // set the value
242                 err = RegSetValueEx(hkey, pszValueName, 0, REG_SZ, (const BYTE*)pszValue, (DWORD) sizeof(pszValue[0])*(_tcslen(pszValue) + 1));
243                 RegCloseKey(hkey);
244             }
245         }
246         if (pszKeyName)
247             free(pszKeyName);
248         if (pszValueName)
249             free(pszValueName);
250         if (allocatedValue && allocatedValue != (LPTSTR)-1)
251             free(allocatedValue);
252     }
253
254     if (userClasses)
255         RegCloseKey(userClasses);
256
257     return hr;
258 }
259
260 STDAPI RunAsLocalServer(void)
261 {
262     DWORD reg;
263     COMPtr<IUnknown> classFactory;
264     DllGetClassObject(CLSID_WebDebugProgram, IID_IUnknown, (void**)&classFactory);
265     CoRegisterClassObject(CLSID_WebDebugProgram, classFactory.get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &reg);
266     return 0;
267 }
268
269 //FIXME: We should consider moving this to a new file for cross-project functionality
270 PassRefPtr<WebCore::SharedBuffer> loadResourceIntoBuffer(const char* name)
271 {
272     int idr;
273     // temporary hack to get resource id
274     if (!strcmp(name, "textAreaResizeCorner"))
275         idr = IDR_RESIZE_CORNER;
276     else if (!strcmp(name, "missingImage"))
277         idr = IDR_MISSING_IMAGE;
278     else if (!strcmp(name, "urlIcon"))
279         idr = IDR_URL_ICON;
280     else if (!strcmp(name, "nullPlugin"))
281         idr = IDR_NULL_PLUGIN;
282     else if (!strcmp(name, "zoomInCursor"))
283         idr = IDR_ZOOM_IN_CURSOR;
284     else if (!strcmp(name, "zoomOutCursor"))
285         idr = IDR_ZOOM_OUT_CURSOR;
286     else if (!strcmp(name, "verticalTextCursor"))
287         idr = IDR_VERTICAL_TEXT_CURSOR;
288     else
289         return 0;
290
291     HRSRC resInfo = FindResource(gInstance, MAKEINTRESOURCE(idr), L"PNG");
292     if (!resInfo)
293         return 0;
294     HANDLE res = LoadResource(gInstance, resInfo);
295     if (!res)
296         return 0;
297     void* resource = LockResource(res);
298     if (!resource)
299         return 0;
300     int size = SizeofResource(gInstance, resInfo);
301
302     return new WebCore::SharedBuffer(reinterpret_cast<const char*>(resource), size);
303 }