2 * self-registerable dll functions for urlmon.dll
4 * Copyright (C) 2003 John K. Hohm
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.
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.
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
21 #define COM_NO_WINDOWS_H
38 #include "wine/debug.h"
40 #include "urlmon_main.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
45 * Near the bottom of this file are the exported DllRegisterServer and
46 * DllUnregisterServer, which make all this worthwhile.
49 /***********************************************************************
50 * interface for self-registering
52 struct regsvr_interface
54 IID const *iid; /* NULL for end of list */
55 LPCSTR name; /* can be NULL to omit */
56 IID const *base_iid; /* can be NULL to omit */
57 int num_methods; /* can be <0 to omit */
58 CLSID const *ps_clsid; /* can be NULL to omit */
59 CLSID const *ps_clsid32; /* can be NULL to omit */
62 static HRESULT register_interfaces(struct regsvr_interface const *list);
63 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
67 CLSID const *clsid; /* NULL for end of list */
68 LPCSTR name; /* can be NULL to omit */
69 LPCSTR ips; /* can be NULL to omit */
70 LPCSTR ips32; /* can be NULL to omit */
71 LPCSTR ips32_tmodel; /* can be NULL to omit */
72 LPCSTR progid; /* can be NULL to omit */
73 LPCSTR viprogid; /* can be NULL to omit */
74 LPCSTR progid_extra; /* can be NULL to omit */
77 static HRESULT register_coclasses(struct regsvr_coclass const *list);
78 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
80 /***********************************************************************
81 * static string constants
83 static WCHAR const interface_keyname[10] = {
84 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
85 static WCHAR const base_ifa_keyname[14] = {
86 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
88 static WCHAR const num_methods_keyname[11] = {
89 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
90 static WCHAR const ps_clsid_keyname[15] = {
91 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
93 static WCHAR const ps_clsid32_keyname[17] = {
94 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
95 'i', 'd', '3', '2', 0 };
96 static WCHAR const clsid_keyname[6] = {
97 'C', 'L', 'S', 'I', 'D', 0 };
98 static WCHAR const curver_keyname[7] = {
99 'C', 'u', 'r', 'V', 'e', 'r', 0 };
100 static WCHAR const ips_keyname[13] = {
101 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
103 static WCHAR const ips32_keyname[15] = {
104 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
106 static WCHAR const progid_keyname[7] = {
107 'P', 'r', 'o', 'g', 'I', 'D', 0 };
108 static WCHAR const viprogid_keyname[25] = {
109 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
110 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
112 static char const tmodel_valuename[] = "ThreadingModel";
114 /***********************************************************************
115 * static helper functions
117 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
118 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
120 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
122 static LONG register_progid(WCHAR const *clsid,
123 char const *progid, char const *curver_progid,
124 char const *name, char const *extra);
125 static LONG recursive_delete_key(HKEY key);
126 static LONG recursive_delete_keyA(HKEY base, char const *name);
127 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
129 /***********************************************************************
130 * register_interfaces
132 static HRESULT register_interfaces(struct regsvr_interface const *list)
134 LONG res = ERROR_SUCCESS;
137 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
138 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
139 if (res != ERROR_SUCCESS) goto error_return;
141 for (; res == ERROR_SUCCESS && list->iid; ++list) {
145 StringFromGUID2(list->iid, buf, 39);
146 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
147 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
148 if (res != ERROR_SUCCESS) goto error_close_interface_key;
151 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
152 (CONST BYTE*)(list->name),
153 strlen(list->name) + 1);
154 if (res != ERROR_SUCCESS) goto error_close_iid_key;
157 if (list->base_iid) {
158 res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
159 if (res != ERROR_SUCCESS) goto error_close_iid_key;
162 if (0 <= list->num_methods) {
163 static WCHAR const fmt[3] = { '%', 'd', 0 };
166 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
167 KEY_READ | KEY_WRITE, NULL, &key, NULL);
168 if (res != ERROR_SUCCESS) goto error_close_iid_key;
170 wsprintfW(buf, fmt, list->num_methods);
171 res = RegSetValueExW(key, NULL, 0, REG_SZ,
173 (lstrlenW(buf) + 1) * sizeof(WCHAR));
176 if (res != ERROR_SUCCESS) goto error_close_iid_key;
179 if (list->ps_clsid) {
180 res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
181 if (res != ERROR_SUCCESS) goto error_close_iid_key;
184 if (list->ps_clsid32) {
185 res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
186 if (res != ERROR_SUCCESS) goto error_close_iid_key;
190 RegCloseKey(iid_key);
193 error_close_interface_key:
194 RegCloseKey(interface_key);
196 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
199 /***********************************************************************
200 * unregister_interfaces
202 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
204 LONG res = ERROR_SUCCESS;
207 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
208 KEY_READ | KEY_WRITE, &interface_key);
209 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
210 if (res != ERROR_SUCCESS) goto error_return;
212 for (; res == ERROR_SUCCESS && list->iid; ++list) {
215 StringFromGUID2(list->iid, buf, 39);
216 res = recursive_delete_keyW(interface_key, buf);
219 RegCloseKey(interface_key);
221 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
224 /***********************************************************************
227 static HRESULT register_coclasses(struct regsvr_coclass const *list)
229 LONG res = ERROR_SUCCESS;
232 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
233 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
234 if (res != ERROR_SUCCESS) goto error_return;
236 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
240 StringFromGUID2(list->clsid, buf, 39);
241 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
242 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
243 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
246 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
247 (CONST BYTE*)(list->name),
248 strlen(list->name) + 1);
249 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
253 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
254 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
260 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
261 KEY_READ | KEY_WRITE, NULL,
263 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
265 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
266 (CONST BYTE*)list->ips32,
267 lstrlenA(list->ips32) + 1);
268 if (res == ERROR_SUCCESS && list->ips32_tmodel)
269 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
270 (CONST BYTE*)list->ips32_tmodel,
271 strlen(list->ips32_tmodel) + 1);
272 RegCloseKey(ips32_key);
273 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277 res = register_key_defvalueA(clsid_key, progid_keyname,
279 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
281 res = register_progid(buf, list->progid, NULL,
282 list->name, list->progid_extra);
283 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
286 if (list->viprogid) {
287 res = register_key_defvalueA(clsid_key, viprogid_keyname,
289 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
291 res = register_progid(buf, list->viprogid, list->progid,
292 list->name, list->progid_extra);
293 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
296 error_close_clsid_key:
297 RegCloseKey(clsid_key);
300 error_close_coclass_key:
301 RegCloseKey(coclass_key);
303 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
306 /***********************************************************************
307 * unregister_coclasses
309 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
311 LONG res = ERROR_SUCCESS;
314 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
315 KEY_READ | KEY_WRITE, &coclass_key);
316 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
317 if (res != ERROR_SUCCESS) goto error_return;
319 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
322 StringFromGUID2(list->clsid, buf, 39);
323 res = recursive_delete_keyW(coclass_key, buf);
324 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
327 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
328 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
331 if (list->viprogid) {
332 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
333 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
337 error_close_coclass_key:
338 RegCloseKey(coclass_key);
340 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
343 /***********************************************************************
346 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
350 StringFromGUID2(guid, buf, 39);
351 return register_key_defvalueW(base, name, buf);
354 /***********************************************************************
355 * regsvr_key_defvalueW
357 static LONG register_key_defvalueW(
365 res = RegCreateKeyExW(base, name, 0, NULL, 0,
366 KEY_READ | KEY_WRITE, NULL, &key, NULL);
367 if (res != ERROR_SUCCESS) return res;
368 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
369 (lstrlenW(value) + 1) * sizeof(WCHAR));
374 /***********************************************************************
375 * regsvr_key_defvalueA
377 static LONG register_key_defvalueA(
385 res = RegCreateKeyExW(base, name, 0, NULL, 0,
386 KEY_READ | KEY_WRITE, NULL, &key, NULL);
387 if (res != ERROR_SUCCESS) return res;
388 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
389 lstrlenA(value) + 1);
394 /***********************************************************************
397 static LONG register_progid(
400 char const *curver_progid,
407 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
408 NULL, 0, KEY_READ | KEY_WRITE, NULL,
410 if (res != ERROR_SUCCESS) return res;
413 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
414 (CONST BYTE*)name, strlen(name) + 1);
415 if (res != ERROR_SUCCESS) goto error_close_progid_key;
419 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
420 if (res != ERROR_SUCCESS) goto error_close_progid_key;
424 res = register_key_defvalueA(progid_key, curver_keyname,
426 if (res != ERROR_SUCCESS) goto error_close_progid_key;
432 res = RegCreateKeyExA(progid_key, extra, 0,
433 NULL, 0, KEY_READ | KEY_WRITE, NULL,
435 if (res == ERROR_SUCCESS)
436 RegCloseKey(extra_key);
439 error_close_progid_key:
440 RegCloseKey(progid_key);
444 /***********************************************************************
445 * recursive_delete_key
447 static LONG recursive_delete_key(HKEY key)
450 WCHAR subkey_name[MAX_PATH];
455 cName = sizeof(subkey_name) / sizeof(WCHAR);
456 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
457 NULL, NULL, NULL, NULL);
458 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
459 res = ERROR_SUCCESS; /* presumably we're done enumerating */
462 res = RegOpenKeyExW(key, subkey_name, 0,
463 KEY_READ | KEY_WRITE, &subkey);
464 if (res == ERROR_FILE_NOT_FOUND) continue;
465 if (res != ERROR_SUCCESS) break;
467 res = recursive_delete_key(subkey);
469 if (res != ERROR_SUCCESS) break;
472 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
476 /***********************************************************************
477 * recursive_delete_keyA
479 static LONG recursive_delete_keyA(HKEY base, char const *name)
484 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
485 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
486 if (res != ERROR_SUCCESS) return res;
487 res = recursive_delete_key(key);
492 /***********************************************************************
493 * recursive_delete_keyW
495 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
500 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
501 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
502 if (res != ERROR_SUCCESS) return res;
503 res = recursive_delete_key(key);
508 /***********************************************************************
511 static struct regsvr_coclass const coclass_list[] = {
512 { &CLSID_StdURLMoniker,
518 { &CLSID_CdlProtocol,
519 "CDL: Asynchronous Pluggable Protocol Handler",
524 { &CLSID_FileProtocol,
525 "file:, local: Asynchronous Pluggable Protocol Handler",
530 { &CLSID_FtpProtocol,
531 "ftp: Asynchronous Pluggable Protocol Handler",
536 { &CLSID_GopherProtocol,
537 "gopher: Asynchronous Pluggable Protocol Handler",
542 { &CLSID_HttpProtocol,
543 "http: Asynchronous Pluggable Protocol Handler",
548 { &CLSID_HttpSProtocol,
549 "https: Asynchronous Pluggable Protocol Handler",
555 "mk: Asynchronous Pluggable Protocol Handler",
560 { &CLSID_InternetSecurityManager,
566 { &CLSID_InternetZoneManager,
572 { NULL } /* list terminator */
575 /***********************************************************************
579 static struct regsvr_interface const interface_list[] = {
580 { NULL } /* list terminator */
583 /***********************************************************************
587 #define INF_SET_CLSID(clsid) \
590 static CHAR name[] = "CLSID_" #clsid; \
592 pse[i].pszName = name; \
593 clsids[i++] = &CLSID_ ## clsid; \
596 static HRESULT register_inf(BOOL doregister)
600 typeof(RegInstallA) *pRegInstall;
603 static CLSID const *clsids[34];
606 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
608 INF_SET_CLSID(CdlProtocol);
609 INF_SET_CLSID(FileProtocol);
610 INF_SET_CLSID(FtpProtocol);
611 INF_SET_CLSID(GopherProtocol);
612 INF_SET_CLSID(HttpProtocol);
613 INF_SET_CLSID(HttpSProtocol);
614 INF_SET_CLSID(MkProtocol);
616 for(i = 0; i < sizeof(pse)/sizeof(pse[0]); i++) {
617 pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39);
618 sprintf(pse[i].pszValue, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
619 clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0],
620 clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4],
621 clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]);
624 strtable.cEntries = sizeof(pse)/sizeof(pse[0]);
627 hAdvpack = LoadLibraryW(wszAdvpack);
628 pRegInstall = (typeof(RegInstallA)*)GetProcAddress(hAdvpack, "RegInstall");
630 hres = pRegInstall(URLMON_hInstance, doregister ? "RegisterDll" : "UnregisterDll", &strtable);
632 for(i=0; i < sizeof(pse)/sizeof(pse[0]); i++)
633 HeapFree(GetProcessHeap(), 0, pse[i].pszValue);
640 /***********************************************************************
641 * DllRegisterServer (URLMON.@)
643 HRESULT WINAPI DllRegisterServer(void)
649 hr = register_coclasses(coclass_list);
651 hr = register_interfaces(interface_list);
654 return register_inf(TRUE);
657 /***********************************************************************
658 * DllUnregisterServer (URLMON.@)
660 HRESULT WINAPI DllUnregisterServer(void)
666 hr = unregister_coclasses(coclass_list);
668 hr = unregister_interfaces(interface_list);
671 return register_inf(FALSE);