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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define COM_NO_WINDOWS_H
38 #include "wine/debug.h"
41 #include "urlmon_main.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
46 * Near the bottom of this file are the exported DllRegisterServer and
47 * DllUnregisterServer, which make all this worthwhile.
50 /***********************************************************************
51 * interface for self-registering
53 struct regsvr_interface
55 IID const *iid; /* NULL for end of list */
56 LPCSTR name; /* can be NULL to omit */
57 IID const *base_iid; /* can be NULL to omit */
58 int num_methods; /* can be <0 to omit */
59 CLSID const *ps_clsid; /* can be NULL to omit */
60 CLSID const *ps_clsid32; /* can be NULL to omit */
63 static HRESULT register_interfaces(struct regsvr_interface const *list);
64 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
68 CLSID const *clsid; /* NULL for end of list */
69 LPCSTR name; /* can be NULL to omit */
70 LPCSTR ips; /* can be NULL to omit */
71 LPCSTR ips32; /* can be NULL to omit */
72 LPCSTR ips32_tmodel; /* can be NULL to omit */
73 LPCSTR progid; /* can be NULL to omit */
74 LPCSTR viprogid; /* can be NULL to omit */
75 LPCSTR progid_extra; /* can be NULL to omit */
78 static HRESULT register_coclasses(struct regsvr_coclass const *list);
79 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
81 /***********************************************************************
82 * static string constants
84 static WCHAR const interface_keyname[10] = {
85 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
86 static WCHAR const base_ifa_keyname[14] = {
87 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
89 static WCHAR const num_methods_keyname[11] = {
90 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
91 static WCHAR const ps_clsid_keyname[15] = {
92 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
94 static WCHAR const ps_clsid32_keyname[17] = {
95 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
96 'i', 'd', '3', '2', 0 };
97 static WCHAR const clsid_keyname[6] = {
98 'C', 'L', 'S', 'I', 'D', 0 };
99 static WCHAR const curver_keyname[7] = {
100 'C', 'u', 'r', 'V', 'e', 'r', 0 };
101 static WCHAR const ips_keyname[13] = {
102 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
104 static WCHAR const ips32_keyname[15] = {
105 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
107 static WCHAR const progid_keyname[7] = {
108 'P', 'r', 'o', 'g', 'I', 'D', 0 };
109 static WCHAR const viprogid_keyname[25] = {
110 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
111 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
113 static char const tmodel_valuename[] = "ThreadingModel";
115 /***********************************************************************
116 * static helper functions
118 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
119 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
121 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
123 static LONG register_progid(WCHAR const *clsid,
124 char const *progid, char const *curver_progid,
125 char const *name, char const *extra);
126 static LONG recursive_delete_key(HKEY key);
127 static LONG recursive_delete_keyA(HKEY base, char const *name);
128 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
130 /***********************************************************************
131 * register_interfaces
133 static HRESULT register_interfaces(struct regsvr_interface const *list)
135 LONG res = ERROR_SUCCESS;
138 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
139 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
140 if (res != ERROR_SUCCESS) goto error_return;
142 for (; res == ERROR_SUCCESS && list->iid; ++list) {
146 StringFromGUID2(list->iid, buf, 39);
147 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
148 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
149 if (res != ERROR_SUCCESS) goto error_close_interface_key;
152 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
153 (CONST BYTE*)(list->name),
154 strlen(list->name) + 1);
155 if (res != ERROR_SUCCESS) goto error_close_iid_key;
158 if (list->base_iid) {
159 register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
160 if (res != ERROR_SUCCESS) goto error_close_iid_key;
163 if (0 <= list->num_methods) {
164 static WCHAR const fmt[3] = { '%', 'd', 0 };
167 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
168 KEY_READ | KEY_WRITE, NULL, &key, NULL);
169 if (res != ERROR_SUCCESS) goto error_close_iid_key;
171 wsprintfW(buf, fmt, list->num_methods);
172 res = RegSetValueExW(key, NULL, 0, REG_SZ,
174 (lstrlenW(buf) + 1) * sizeof(WCHAR));
177 if (res != ERROR_SUCCESS) goto error_close_iid_key;
180 if (list->ps_clsid) {
181 register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
182 if (res != ERROR_SUCCESS) goto error_close_iid_key;
185 if (list->ps_clsid32) {
186 register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
187 if (res != ERROR_SUCCESS) goto error_close_iid_key;
191 RegCloseKey(iid_key);
194 error_close_interface_key:
195 RegCloseKey(interface_key);
197 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
200 /***********************************************************************
201 * unregister_interfaces
203 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
205 LONG res = ERROR_SUCCESS;
208 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
209 KEY_READ | KEY_WRITE, &interface_key);
210 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
211 if (res != ERROR_SUCCESS) goto error_return;
213 for (; res == ERROR_SUCCESS && list->iid; ++list) {
216 StringFromGUID2(list->iid, buf, 39);
217 res = recursive_delete_keyW(interface_key, buf);
220 RegCloseKey(interface_key);
222 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
225 /***********************************************************************
228 static HRESULT register_coclasses(struct regsvr_coclass const *list)
230 LONG res = ERROR_SUCCESS;
233 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
234 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
235 if (res != ERROR_SUCCESS) goto error_return;
237 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
241 StringFromGUID2(list->clsid, buf, 39);
242 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
243 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
244 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
247 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
248 (CONST BYTE*)(list->name),
249 strlen(list->name) + 1);
250 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
254 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
255 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
261 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
262 KEY_READ | KEY_WRITE, NULL,
264 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
266 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
267 (CONST BYTE*)list->ips32,
268 lstrlenA(list->ips32) + 1);
269 if (res == ERROR_SUCCESS && list->ips32_tmodel)
270 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
271 (CONST BYTE*)list->ips32_tmodel,
272 strlen(list->ips32_tmodel) + 1);
273 RegCloseKey(ips32_key);
274 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
278 res = register_key_defvalueA(clsid_key, progid_keyname,
280 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
282 res = register_progid(buf, list->progid, NULL,
283 list->name, list->progid_extra);
284 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287 if (list->viprogid) {
288 res = register_key_defvalueA(clsid_key, viprogid_keyname,
290 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
292 res = register_progid(buf, list->viprogid, list->progid,
293 list->name, list->progid_extra);
294 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
297 error_close_clsid_key:
298 RegCloseKey(clsid_key);
301 error_close_coclass_key:
302 RegCloseKey(coclass_key);
304 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
307 /***********************************************************************
308 * unregister_coclasses
310 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
312 LONG res = ERROR_SUCCESS;
315 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
316 KEY_READ | KEY_WRITE, &coclass_key);
317 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
318 if (res != ERROR_SUCCESS) goto error_return;
320 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
323 StringFromGUID2(list->clsid, buf, 39);
324 res = recursive_delete_keyW(coclass_key, buf);
325 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
328 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
329 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
332 if (list->viprogid) {
333 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
334 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
338 error_close_coclass_key:
339 RegCloseKey(coclass_key);
341 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
344 /***********************************************************************
347 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
351 StringFromGUID2(guid, buf, 39);
352 return register_key_defvalueW(base, name, buf);
355 /***********************************************************************
356 * regsvr_key_defvalueW
358 static LONG register_key_defvalueW(
366 res = RegCreateKeyExW(base, name, 0, NULL, 0,
367 KEY_READ | KEY_WRITE, NULL, &key, NULL);
368 if (res != ERROR_SUCCESS) return res;
369 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
370 (lstrlenW(value) + 1) * sizeof(WCHAR));
375 /***********************************************************************
376 * regsvr_key_defvalueA
378 static LONG register_key_defvalueA(
386 res = RegCreateKeyExW(base, name, 0, NULL, 0,
387 KEY_READ | KEY_WRITE, NULL, &key, NULL);
388 if (res != ERROR_SUCCESS) return res;
389 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
390 lstrlenA(value) + 1);
395 /***********************************************************************
398 static LONG register_progid(
401 char const *curver_progid,
408 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
409 NULL, 0, KEY_READ | KEY_WRITE, NULL,
411 if (res != ERROR_SUCCESS) return res;
414 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
415 (CONST BYTE*)name, strlen(name) + 1);
416 if (res != ERROR_SUCCESS) goto error_close_progid_key;
420 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
421 if (res != ERROR_SUCCESS) goto error_close_progid_key;
425 res = register_key_defvalueA(progid_key, curver_keyname,
427 if (res != ERROR_SUCCESS) goto error_close_progid_key;
433 res = RegCreateKeyExA(progid_key, extra, 0,
434 NULL, 0, KEY_READ | KEY_WRITE, NULL,
436 if (res == ERROR_SUCCESS)
437 RegCloseKey(extra_key);
440 error_close_progid_key:
441 RegCloseKey(progid_key);
445 /***********************************************************************
446 * recursive_delete_key
448 static LONG recursive_delete_key(HKEY key)
451 WCHAR subkey_name[MAX_PATH];
456 cName = sizeof(subkey_name) / sizeof(WCHAR);
457 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
458 NULL, NULL, NULL, NULL);
459 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
460 res = ERROR_SUCCESS; /* presumably we're done enumerating */
463 res = RegOpenKeyExW(key, subkey_name, 0,
464 KEY_READ | KEY_WRITE, &subkey);
465 if (res == ERROR_FILE_NOT_FOUND) continue;
466 if (res != ERROR_SUCCESS) break;
468 res = recursive_delete_key(subkey);
470 if (res != ERROR_SUCCESS) break;
473 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
477 /***********************************************************************
478 * recursive_delete_keyA
480 static LONG recursive_delete_keyA(HKEY base, char const *name)
485 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
486 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
487 if (res != ERROR_SUCCESS) return res;
488 res = recursive_delete_key(key);
493 /***********************************************************************
494 * recursive_delete_keyW
496 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
501 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
502 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
503 if (res != ERROR_SUCCESS) return res;
504 res = recursive_delete_key(key);
509 /***********************************************************************
512 static struct regsvr_coclass const coclass_list[] = {
513 { &CLSID_StdURLMoniker,
519 { &CLSID_CdlProtocol,
520 "CDL: Asynchronous Pluggable Protocol Handler",
525 { &CLSID_FileProtocol,
526 "file:, local: Asynchronous Pluggable Protocol Handler",
531 { &CLSID_FtpProtocol,
532 "ftp: Asynchronous Pluggable Protocol Handler",
537 { &CLSID_GopherProtocol,
538 "gopher: Asynchronous Pluggable Protocol Handler",
543 { &CLSID_HttpProtocol,
544 "http: Asynchronous Pluggable Protocol Handler",
549 { &CLSID_HttpsProtocol,
550 "https: Asynchronous Pluggable Protocol Handler",
556 "mk: Asynchronous Pluggable Protocol Handler",
561 { NULL } /* list terminator */
564 /***********************************************************************
568 static struct regsvr_interface const interface_list[] = {
569 { NULL } /* list terminator */
572 /***********************************************************************
576 #define INF_SET_CLSID(clsid) \
577 pse[i].pszName = "CLSID_" #clsid; \
578 clsids[i++] = &CLSID_ ## clsid;
580 static HRESULT register_inf(BOOL doregister)
584 typeof(RegInstall) *pRegInstall;
587 static CLSID const *clsids[34];
590 static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
592 INF_SET_CLSID(CdlProtocol);
593 INF_SET_CLSID(FileProtocol);
594 INF_SET_CLSID(FtpProtocol);
595 INF_SET_CLSID(GopherProtocol);
596 INF_SET_CLSID(HttpProtocol);
597 INF_SET_CLSID(HttpsProtocol);
598 INF_SET_CLSID(MkProtocol);
600 for(i = 0; i < sizeof(pse)/sizeof(pse[0]); i++) {
601 pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39);
602 sprintf(pse[i].pszValue, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
603 clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0],
604 clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4],
605 clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]);
608 strtable.cEntries = sizeof(pse)/sizeof(pse[0]);
611 hAdvpack = LoadLibraryW(wszAdvpack);
612 pRegInstall = (typeof(RegInstall)*)GetProcAddress(hAdvpack, "RegInstall");
614 hres = pRegInstall(URLMON_hInstance, doregister ? "RegisterDll" : "UnregisterDll", &strtable);
616 for(i=0; i < sizeof(pse)/sizeof(pse[0]); i++)
617 HeapFree(GetProcessHeap(), 0, pse[i].pszValue);
624 /***********************************************************************
625 * DllRegisterServer (URLMON.@)
627 HRESULT WINAPI URLMON_DllRegisterServer(void)
633 hr = register_coclasses(coclass_list);
635 hr = register_interfaces(interface_list);
638 return register_inf(TRUE);
641 /***********************************************************************
642 * DllUnregisterServer (URLMON.@)
644 HRESULT WINAPI URLMON_DllUnregisterServer(void)
650 hr = unregister_coclasses(coclass_list);
652 hr = unregister_interfaces(interface_list);
655 return register_inf(FALSE);