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