3efc94f9433a37022364859d01448e1d1d5bc987
[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 "autoversion.h"
30 #include "ForEachCoClass.h"
31 #include "ProgIDMacros.h"
32 #include "resource.h"
33 #include "WebKit.h"
34 #include "WebKitClassFactory.h"
35 #include "WebScriptDebugServer.h"
36 #pragma warning( push, 0 )
37 #include <WebCore/COMPtr.h>
38 #include <WebCore/IconDatabase.h>
39 #include <WebCore/Page.h>
40 #include <WebCore/SharedBuffer.h>
41 #include <WebCore/Widget.h>
42 #include <wtf/Vector.h>
43 #pragma warning(pop)
44 #include <tchar.h>
45 #include <olectl.h>
46
47 ULONG gLockCount;
48 ULONG gClassCount;
49 HINSTANCE gInstance;
50
51 #define CLSID_FOR_CLASS(cls) CLSID_##cls,
52 static CLSID gRegCLSIDs[] = {
53     FOR_EACH_COCLASS(CLSID_FOR_CLASS)
54 };
55 #undef CLSID_FOR_CLASS
56
57 void shutDownWebKit()
58 {
59     WebCore::iconDatabase()->close();
60 }
61
62 STDAPI_(BOOL) DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID /*lpReserved*/)
63 {
64     switch (ul_reason_for_call) {
65         case DLL_PROCESS_ATTACH:
66             gLockCount = gClassCount = 0;
67             gInstance = hModule;
68             WebCore::Page::setInstanceHandle(hModule);
69             return TRUE;
70
71         case DLL_PROCESS_DETACH:
72             shutDownWebKit();
73             break;
74
75         case DLL_THREAD_ATTACH:
76         case DLL_THREAD_DETACH:
77             break;
78     }
79     return FALSE;
80 }
81
82 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
83 {
84     bool found = false;
85     for (int i = 0; i < ARRAYSIZE(gRegCLSIDs); i++) {
86         if (IsEqualGUID(rclsid, gRegCLSIDs[i])) {
87             found = true;
88             break;
89         }
90     }
91     if (!found)
92         return E_FAIL;
93
94     if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IClassFactory))
95         return E_NOINTERFACE;
96
97     WebKitClassFactory* factory = new WebKitClassFactory(rclsid);
98     *ppv = reinterpret_cast<LPVOID>(factory);
99     if (!factory)
100         return E_OUTOFMEMORY;
101
102     factory->AddRef();
103     return S_OK;
104 }
105
106 STDAPI DllCanUnloadNow(void)
107 {
108     if (!gClassCount && !gLockCount)
109         return S_OK;
110     
111     return S_FALSE;
112 }
113
114 #if __PRODUCTION__
115 #define VERSION_INDEPENDENT_PROGID(className) VERSION_INDEPENDENT_PRODUCTION_PROGID(className)
116 #else
117 #define VERSION_INDEPENDENT_PROGID(className) VERSION_INDEPENDENT_OPENSOURCE_PROGID(className)
118 #endif
119 #define CURRENT_VERSIONED_PROGID(className) VERSIONED_PROGID(VERSION_INDEPENDENT_PROGID(className), CURRENT_PROGID_VERSION)
120 #define VERSIONED_303_PROGID(className) VERSIONED_PROGID(VERSION_INDEPENDENT_PROGID(className), 3)
121
122 // FIXME: The last line of this macro only here for the benefit of Safari 3.0.3. Once a newer version
123 // is released, the last line should be removed and gSlotsPerEntry should be decremented by 1.
124 //key                                                                                       value name              value }
125 #define KEYS_FOR_CLASS(cls) \
126 { TEXT("CLSID\\{########-####-####-####-############}"),                                    0,                      TEXT(#cls) }, \
127 { TEXT("CLSID\\{########-####-####-####-############}\\InprocServer32"),                    0,                      (LPCTSTR)-1 }, \
128 { TEXT("CLSID\\{########-####-####-####-############}\\InprocServer32"),                    TEXT("ThreadingModel"), TEXT("Apartment") }, \
129 { TEXT("CLSID\\{########-####-####-####-############}\\ProgID"),                            0,                      CURRENT_VERSIONED_PROGID(cls) }, \
130 { CURRENT_VERSIONED_PROGID(cls),                                                            0,                      TEXT(#cls) }, \
131 { CURRENT_VERSIONED_PROGID(cls) TEXT("\\CLSID"),                                            0,                      TEXT("{########-####-####-####-############}") }, \
132 { TEXT("CLSID\\{########-####-####-####-############}\\VersionIndependentProgID"),          0,                      VERSION_INDEPENDENT_PROGID(cls) }, \
133 { VERSION_INDEPENDENT_PROGID(cls),                                                          0,                      TEXT(#cls) }, \
134 { VERSION_INDEPENDENT_PROGID(cls) TEXT("\\CLSID"),                                          0,                      TEXT("{########-####-####-####-############}") }, \
135 { VERSION_INDEPENDENT_PROGID(cls) TEXT("\\CurVer"),                                         0,                      STRINGIFIED_VERSION(CURRENT_PROGID_VERSION) }, \
136 { VERSIONED_303_PROGID(cls),                                                                0,                      TEXT(#cls) }, \
137 { VERSIONED_303_PROGID(cls) TEXT("\\CLSID"),                                                0,                      TEXT("{########-####-####-####-############}") }, \
138 // end of macro
139
140 static const int gSlotsPerEntry = 12;
141 static LPCTSTR gRegTable[][3] = {
142     FOR_EACH_COCLASS(KEYS_FOR_CLASS)
143 };
144 #undef KEYS_FOR_CLASS
145
146 static void substituteGUID(LPTSTR str, const UUID* guid)
147 {
148     if (!guid || !str)
149         return;
150
151     TCHAR uuidString[40];
152     _stprintf_s(uuidString, ARRAYSIZE(uuidString), TEXT("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"), guid->Data1, guid->Data2, guid->Data3,
153         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
154
155     LPCTSTR guidPattern = TEXT("########-####-####-####-############");
156     size_t patternLength = _tcslen(guidPattern);
157     size_t strLength = _tcslen(str);
158     LPTSTR guidSubStr = str;
159     while (strLength) {
160         guidSubStr = _tcsstr(guidSubStr, guidPattern);
161         if (!guidSubStr)
162             break;
163         _tcsncpy(guidSubStr, uuidString, patternLength);
164         guidSubStr += patternLength;
165         strLength -= (guidSubStr - str);
166     }
167 }
168
169 STDAPI DllUnregisterServer(void)
170 {
171     HRESULT hr = S_OK;
172     HKEY userClasses;
173
174 #if __PRODUCTION__
175     const GUID libID = LIBID_WebKit;
176 #else
177     const GUID libID = LIBID_OpenSourceWebKit;
178 #endif
179
180     typedef HRESULT (WINAPI *UnRegisterTypeLibForUserPtr)(REFGUID, unsigned short, unsigned short, LCID, SYSKIND);
181     if (UnRegisterTypeLibForUserPtr unRegisterTypeLibForUser = reinterpret_cast<UnRegisterTypeLibForUserPtr>(GetProcAddress(GetModuleHandle(TEXT("oleaut32.dll")), "UnRegisterTypeLibForUser")))
182         unRegisterTypeLibForUser(libID, __BUILD_NUMBER_MAJOR__, __BUILD_NUMBER_MINOR__, 0, SYS_WIN32);
183     else
184         UnRegisterTypeLib(libID, __BUILD_NUMBER_MAJOR__, __BUILD_NUMBER_MINOR__, 0, SYS_WIN32);
185
186     if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\CLASSES"), 0, KEY_WRITE, &userClasses) != ERROR_SUCCESS)
187         userClasses = 0;
188
189     int nEntries = ARRAYSIZE(gRegTable);
190     for (int i = nEntries - 1; i >= 0; i--) {
191         LPTSTR pszKeyName = _tcsdup(gRegTable[i][0]);
192         if (pszKeyName) {
193             substituteGUID(pszKeyName, &gRegCLSIDs[i/gSlotsPerEntry]);
194             RegDeleteKey(HKEY_CLASSES_ROOT, pszKeyName);
195             if (userClasses)
196                 RegDeleteKey(userClasses, pszKeyName);
197             free(pszKeyName);
198         } else
199             hr = E_OUTOFMEMORY;
200     }
201
202     if (userClasses)
203         RegCloseKey(userClasses);
204     return hr;
205 }
206
207 STDAPI DllRegisterServer(void)
208 {
209     HRESULT hr = S_OK;
210
211     // look up server's file name
212     TCHAR szFileName[MAX_PATH];
213     GetModuleFileName(gInstance, szFileName, MAX_PATH);
214
215     typedef HRESULT (WINAPI *RegisterTypeLibForUserPtr)(ITypeLib*, OLECHAR*, OLECHAR*);
216     COMPtr<ITypeLib> typeLib;
217     LoadTypeLibEx(szFileName, REGKIND_NONE, &typeLib);
218     if (RegisterTypeLibForUserPtr registerTypeLibForUser = reinterpret_cast<RegisterTypeLibForUserPtr>(GetProcAddress(GetModuleHandle(TEXT("oleaut32.dll")), "RegisterTypeLibForUser")))
219         registerTypeLibForUser(typeLib.get(), szFileName, 0);
220     else
221         RegisterTypeLib(typeLib.get(), szFileName, 0);
222
223     HKEY userClasses;
224     if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\CLASSES"), 0, KEY_WRITE, &userClasses) != ERROR_SUCCESS)
225         userClasses = 0;
226
227     // register entries from table
228     int nEntries = ARRAYSIZE(gRegTable);
229     for (int i = 0; SUCCEEDED(hr) && i < nEntries; i++) {
230         LPTSTR pszKeyName   = _tcsdup(gRegTable[i][0]);
231         LPTSTR pszValueName = gRegTable[i][1] ? _tcsdup(gRegTable[i][1]) : 0;
232         LPTSTR allocatedValue   = (gRegTable[i][2] != (LPTSTR)-1) ? _tcsdup(gRegTable[i][2]) : (LPTSTR)-1;
233         LPTSTR pszValue     = allocatedValue;
234
235         if (pszKeyName && pszValue) {
236
237             int clsidIndex = i/gSlotsPerEntry;
238             substituteGUID(pszKeyName, &gRegCLSIDs[clsidIndex]);
239             substituteGUID(pszValueName, &gRegCLSIDs[clsidIndex]);
240
241             // map rogue value to module file name
242             if (pszValue == (LPTSTR)-1)
243                 pszValue = szFileName;
244             else
245                 substituteGUID(pszValue, &gRegCLSIDs[clsidIndex]);
246
247             // create the key
248             HKEY hkey;
249             LONG err = RegCreateKey(HKEY_CLASSES_ROOT, pszKeyName, &hkey);
250             if (err != ERROR_SUCCESS && userClasses)
251                 err = RegCreateKey(userClasses, pszKeyName, &hkey);
252             if (err == ERROR_SUCCESS) {
253                 // set the value
254                 err = RegSetValueEx(hkey, pszValueName, 0, REG_SZ, (const BYTE*)pszValue, (DWORD) sizeof(pszValue[0])*(_tcslen(pszValue) + 1));
255                 RegCloseKey(hkey);
256             }
257         }
258         if (pszKeyName)
259             free(pszKeyName);
260         if (pszValueName)
261             free(pszValueName);
262         if (allocatedValue && allocatedValue != (LPTSTR)-1)
263             free(allocatedValue);
264     }
265
266     if (userClasses)
267         RegCloseKey(userClasses);
268
269     return hr;
270 }
271
272 STDAPI RunAsLocalServer()
273 {
274     DWORD reg;
275     COMPtr<IUnknown> classFactory;
276     DllGetClassObject(CLSID_WebScriptDebugServer, IID_IUnknown, (void**)&classFactory);
277     CoRegisterClassObject(CLSID_WebScriptDebugServer, classFactory.get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &reg);
278     return 0;
279 }
280
281 STDAPI LocalServerDidDie()
282 {
283     WebScriptDebugServer::sharedWebScriptDebugServer()->serverDidDie();
284     return 0;
285 }
286
287 //FIXME: We should consider moving this to a new file for cross-project functionality
288 PassRefPtr<WebCore::SharedBuffer> loadResourceIntoBuffer(const char* name)
289 {
290     int idr;
291     // temporary hack to get resource id
292     if (!strcmp(name, "textAreaResizeCorner"))
293         idr = IDR_RESIZE_CORNER;
294     else if (!strcmp(name, "missingImage"))
295         idr = IDR_MISSING_IMAGE;
296     else if (!strcmp(name, "urlIcon"))
297         idr = IDR_URL_ICON;
298     else if (!strcmp(name, "nullPlugin"))
299         idr = IDR_NULL_PLUGIN;
300     else if (!strcmp(name, "zoomInCursor"))
301         idr = IDR_ZOOM_IN_CURSOR;
302     else if (!strcmp(name, "zoomOutCursor"))
303         idr = IDR_ZOOM_OUT_CURSOR;
304     else if (!strcmp(name, "verticalTextCursor"))
305         idr = IDR_VERTICAL_TEXT_CURSOR;
306     else
307         return 0;
308
309     HRSRC resInfo = FindResource(gInstance, MAKEINTRESOURCE(idr), L"PNG");
310     if (!resInfo)
311         return 0;
312     HANDLE res = LoadResource(gInstance, resInfo);
313     if (!res)
314         return 0;
315     void* resource = LockResource(res);
316     if (!resource)
317         return 0;
318     int size = SizeofResource(gInstance, resInfo);
319
320     return WebCore::SharedBuffer::create(reinterpret_cast<const char*>(resource), size);
321 }