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