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
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
41 * Near the bottom of this file are the exported DllRegisterServer and
42 * DllUnregisterServer, which make all this worthwhile.
45 /***********************************************************************
46 * interface for self-registering
48 struct regsvr_interface
50 IID const *iid; /* NULL for end of list */
51 LPCSTR name; /* can be NULL to omit */
52 IID const *base_iid; /* can be NULL to omit */
53 int num_methods; /* can be <0 to omit */
54 CLSID const *ps_clsid; /* can be NULL to omit */
55 CLSID const *ps_clsid32; /* can be NULL to omit */
58 static HRESULT register_interfaces(struct regsvr_interface const *list);
59 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
63 CLSID const *clsid; /* NULL for end of list */
64 LPCSTR name; /* can be NULL to omit */
65 LPCSTR ips; /* can be NULL to omit */
66 LPCSTR ips32; /* can be NULL to omit */
67 LPCSTR ips32_tmodel; /* can be NULL to omit */
68 LPCSTR progid; /* can be NULL to omit */
69 LPCSTR viprogid; /* can be NULL to omit */
70 LPCSTR progid_extra; /* can be NULL to omit */
73 static HRESULT register_coclasses(struct regsvr_coclass const *list);
74 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
76 /***********************************************************************
77 * static string constants
79 static WCHAR const interface_keyname[10] = {
80 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
81 static WCHAR const base_ifa_keyname[14] = {
82 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
84 static WCHAR const num_methods_keyname[11] = {
85 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
86 static WCHAR const ps_clsid_keyname[15] = {
87 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
89 static WCHAR const ps_clsid32_keyname[17] = {
90 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
91 'i', 'd', '3', '2', 0 };
92 static WCHAR const clsid_keyname[6] = {
93 'C', 'L', 'S', 'I', 'D', 0 };
94 static WCHAR const curver_keyname[7] = {
95 'C', 'u', 'r', 'V', 'e', 'r', 0 };
96 static WCHAR const ips_keyname[13] = {
97 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
99 static WCHAR const ips32_keyname[15] = {
100 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
102 static WCHAR const progid_keyname[7] = {
103 'P', 'r', 'o', 'g', 'I', 'D', 0 };
104 static WCHAR const viprogid_keyname[25] = {
105 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
106 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
108 static char const tmodel_valuename[] = "ThreadingModel";
110 /***********************************************************************
111 * static helper functions
113 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
114 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
116 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
118 static LONG register_progid(WCHAR const *clsid,
119 char const *progid, char const *curver_progid,
120 char const *name, char const *extra);
121 static LONG recursive_delete_key(HKEY key);
122 static LONG recursive_delete_keyA(HKEY base, char const *name);
123 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
125 /***********************************************************************
126 * register_interfaces
128 static HRESULT register_interfaces(struct regsvr_interface const *list)
130 LONG res = ERROR_SUCCESS;
133 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
134 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
135 if (res != ERROR_SUCCESS) goto error_return;
137 for (; res == ERROR_SUCCESS && list->iid; ++list) {
141 StringFromGUID2(list->iid, buf, 39);
142 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
143 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
144 if (res != ERROR_SUCCESS) goto error_close_interface_key;
147 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
148 (CONST BYTE*)(list->name),
149 strlen(list->name) + 1);
150 if (res != ERROR_SUCCESS) goto error_close_iid_key;
153 if (list->base_iid) {
154 register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
155 if (res != ERROR_SUCCESS) goto error_close_iid_key;
158 if (0 <= list->num_methods) {
159 static WCHAR const fmt[3] = { '%', 'd', 0 };
162 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
163 KEY_READ | KEY_WRITE, NULL, &key, NULL);
164 if (res != ERROR_SUCCESS) goto error_close_iid_key;
166 wsprintfW(buf, fmt, list->num_methods);
167 res = RegSetValueExW(key, NULL, 0, REG_SZ,
169 (lstrlenW(buf) + 1) * sizeof(WCHAR));
172 if (res != ERROR_SUCCESS) goto error_close_iid_key;
175 if (list->ps_clsid) {
176 register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
177 if (res != ERROR_SUCCESS) goto error_close_iid_key;
180 if (list->ps_clsid32) {
181 register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
182 if (res != ERROR_SUCCESS) goto error_close_iid_key;
186 RegCloseKey(iid_key);
189 error_close_interface_key:
190 RegCloseKey(interface_key);
192 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
195 /***********************************************************************
196 * unregister_interfaces
198 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
200 LONG res = ERROR_SUCCESS;
203 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
204 KEY_READ | KEY_WRITE, &interface_key);
205 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
206 if (res != ERROR_SUCCESS) goto error_return;
208 for (; res == ERROR_SUCCESS && list->iid; ++list) {
211 StringFromGUID2(list->iid, buf, 39);
212 res = recursive_delete_keyW(interface_key, buf);
215 RegCloseKey(interface_key);
217 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
220 /***********************************************************************
223 static HRESULT register_coclasses(struct regsvr_coclass const *list)
225 LONG res = ERROR_SUCCESS;
228 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
229 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
230 if (res != ERROR_SUCCESS) goto error_return;
232 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
236 StringFromGUID2(list->clsid, buf, 39);
237 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
238 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
239 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
242 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
243 (CONST BYTE*)(list->name),
244 strlen(list->name) + 1);
245 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
249 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
250 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
256 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
257 KEY_READ | KEY_WRITE, NULL,
259 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
261 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
262 (CONST BYTE*)list->ips32,
263 lstrlenA(list->ips32) + 1);
264 if (res == ERROR_SUCCESS && list->ips32_tmodel)
265 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
266 (CONST BYTE*)list->ips32_tmodel,
267 strlen(list->ips32_tmodel) + 1);
268 RegCloseKey(ips32_key);
269 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
273 res = register_key_defvalueA(clsid_key, progid_keyname,
275 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277 res = register_progid(buf, list->progid, NULL,
278 list->name, list->progid_extra);
279 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
282 if (list->viprogid) {
283 res = register_key_defvalueA(clsid_key, viprogid_keyname,
285 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287 res = register_progid(buf, list->viprogid, list->progid,
288 list->name, list->progid_extra);
289 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
292 error_close_clsid_key:
293 RegCloseKey(clsid_key);
296 error_close_coclass_key:
297 RegCloseKey(coclass_key);
299 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
302 /***********************************************************************
303 * unregister_coclasses
305 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
307 LONG res = ERROR_SUCCESS;
310 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
311 KEY_READ | KEY_WRITE, &coclass_key);
312 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
313 if (res != ERROR_SUCCESS) goto error_return;
315 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
318 StringFromGUID2(list->clsid, buf, 39);
319 res = recursive_delete_keyW(coclass_key, buf);
320 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
323 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
324 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
327 if (list->viprogid) {
328 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
329 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
333 error_close_coclass_key:
334 RegCloseKey(coclass_key);
336 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
339 /***********************************************************************
342 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
346 StringFromGUID2(guid, buf, 39);
347 return register_key_defvalueW(base, name, buf);
350 /***********************************************************************
351 * regsvr_key_defvalueW
353 static LONG register_key_defvalueW(
361 res = RegCreateKeyExW(base, name, 0, NULL, 0,
362 KEY_READ | KEY_WRITE, NULL, &key, NULL);
363 if (res != ERROR_SUCCESS) return res;
364 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
365 (lstrlenW(value) + 1) * sizeof(WCHAR));
370 /***********************************************************************
371 * regsvr_key_defvalueA
373 static LONG register_key_defvalueA(
381 res = RegCreateKeyExW(base, name, 0, NULL, 0,
382 KEY_READ | KEY_WRITE, NULL, &key, NULL);
383 if (res != ERROR_SUCCESS) return res;
384 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
385 lstrlenA(value) + 1);
390 /***********************************************************************
393 static LONG register_progid(
396 char const *curver_progid,
403 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
404 NULL, 0, KEY_READ | KEY_WRITE, NULL,
406 if (res != ERROR_SUCCESS) return res;
409 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
410 (CONST BYTE*)name, strlen(name) + 1);
411 if (res != ERROR_SUCCESS) goto error_close_progid_key;
415 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
416 if (res != ERROR_SUCCESS) goto error_close_progid_key;
420 res = register_key_defvalueA(progid_key, curver_keyname,
422 if (res != ERROR_SUCCESS) goto error_close_progid_key;
428 res = RegCreateKeyExA(progid_key, extra, 0,
429 NULL, 0, KEY_READ | KEY_WRITE, NULL,
431 if (res == ERROR_SUCCESS)
432 RegCloseKey(extra_key);
435 error_close_progid_key:
436 RegCloseKey(progid_key);
440 /***********************************************************************
441 * recursive_delete_key
443 static LONG recursive_delete_key(HKEY key)
446 WCHAR subkey_name[MAX_PATH];
451 cName = sizeof(subkey_name) / sizeof(WCHAR);
452 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
453 NULL, NULL, NULL, NULL);
454 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
455 res = ERROR_SUCCESS; /* presumably we're done enumerating */
458 res = RegOpenKeyExW(key, subkey_name, 0,
459 KEY_READ | KEY_WRITE, &subkey);
460 if (res == ERROR_FILE_NOT_FOUND) continue;
461 if (res != ERROR_SUCCESS) break;
463 res = recursive_delete_key(subkey);
465 if (res != ERROR_SUCCESS) break;
468 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
472 /***********************************************************************
473 * recursive_delete_keyA
475 static LONG recursive_delete_keyA(HKEY base, char const *name)
480 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
481 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
482 if (res != ERROR_SUCCESS) return res;
483 res = recursive_delete_key(key);
488 /***********************************************************************
489 * recursive_delete_keyW
491 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
496 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
497 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
498 if (res != ERROR_SUCCESS) return res;
499 res = recursive_delete_key(key);
504 /***********************************************************************
507 static struct regsvr_coclass const coclass_list[] = {
508 { &CLSID_StdURLMoniker,
514 { NULL } /* list terminator */
517 /***********************************************************************
521 static struct regsvr_interface const interface_list[] = {
522 { NULL } /* list terminator */
525 /***********************************************************************
526 * DllRegisterServer (URLMON.@)
528 HRESULT WINAPI URLMON_DllRegisterServer(void)
534 hr = register_coclasses(coclass_list);
536 hr = register_interfaces(interface_list);
540 /***********************************************************************
541 * DllUnregisterServer (URLMON.@)
543 HRESULT WINAPI URLMON_DllUnregisterServer(void)
549 hr = unregister_coclasses(coclass_list);
551 hr = unregister_interfaces(interface_list);