2 * self-registerable dll functions for objsel.dll
4 * Copyright (C) 2004 Raphael Junqueira
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
36 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(objsel);
43 * Near the bottom of this file are the exported DllRegisterServer and
44 * DllUnregisterServer, which make all this worthwhile.
47 /***********************************************************************
48 * interface for self-registering
50 struct regsvr_interface {
51 IID const *iid; /* NULL for end of list */
52 LPCSTR name; /* can be NULL to omit */
53 IID const *base_iid; /* can be NULL to omit */
54 int num_methods; /* can be <0 to omit */
55 CLSID const *ps_clsid; /* can be NULL to omit */
56 CLSID const *ps_clsid32; /* can be NULL to omit */
59 static HRESULT register_interfaces(struct regsvr_interface const *list);
60 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
63 * @todo: maybe adding typelibs support here
64 * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217
65 * @="{000C1092-0000-0000-C000-000000000046}"
67 struct regsvr_coclass {
68 CLSID const *clsid; /* NULL for end of list */
69 LPCSTR name; /* can be NULL to omit */
70 LPCSTR iph32; /* can be NULL to omit */
71 LPCSTR ips; /* can be NULL to omit */
72 LPCSTR ips32; /* can be NULL to omit */
73 LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */
74 LPCSTR progid; /* can be NULL to omit */
75 LPCSTR viprogid; /* can be NULL to omit */
76 LPCSTR progid_extra; /* can be NULL to omit */
79 static HRESULT register_coclasses(struct regsvr_coclass const *list);
80 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
82 /***********************************************************************
83 * static string constants
85 static WCHAR const interface_keyname[10] = {
86 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
87 static WCHAR const base_ifa_keyname[14] = {
88 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
90 static WCHAR const num_methods_keyname[11] = {
91 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
92 static WCHAR const ps_clsid_keyname[15] = {
93 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
95 static WCHAR const ps_clsid32_keyname[17] = {
96 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
97 'i', 'd', '3', '2', 0 };
98 static WCHAR const clsid_keyname[6] = {
99 'C', 'L', 'S', 'I', 'D', 0 };
100 static WCHAR const curver_keyname[7] = {
101 'C', 'u', 'r', 'V', 'e', 'r', 0 };
102 static WCHAR const iph32_keyname[] = {
103 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
105 static WCHAR const ips_keyname[13] = {
106 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
108 static WCHAR const ips32_keyname[15] = {
109 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
111 static WCHAR const progid_keyname[7] = {
112 'P', 'r', 'o', 'g', 'I', 'D', 0 };
113 static WCHAR const viprogid_keyname[25] = {
114 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
115 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
117 static char const tmodel_valuename[] = "ThreadingModel";
119 /***********************************************************************
120 * static helper functions
122 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
123 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
125 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
127 static LONG register_progid(WCHAR const *clsid,
128 char const *progid, char const *curver_progid,
129 char const *name, char const *extra);
130 static LONG recursive_delete_key(HKEY key);
131 static LONG recursive_delete_keyA(HKEY base, char const *name);
132 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
134 /***********************************************************************
135 * register_interfaces
137 static HRESULT register_interfaces(struct regsvr_interface const *list) {
138 LONG res = ERROR_SUCCESS;
141 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
142 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
143 if (res != ERROR_SUCCESS) goto error_return;
145 for (; res == ERROR_SUCCESS && list->iid; ++list) {
149 StringFromGUID2(list->iid, buf, 39);
150 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
151 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
152 if (res != ERROR_SUCCESS) goto error_close_interface_key;
155 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
156 (CONST BYTE*)(list->name),
157 strlen(list->name) + 1);
158 if (res != ERROR_SUCCESS) goto error_close_iid_key;
161 if (list->base_iid) {
162 res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
163 if (res != ERROR_SUCCESS) goto error_close_iid_key;
166 if (0 <= list->num_methods) {
167 static WCHAR const fmt[3] = { '%', 'd', 0 };
170 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
171 KEY_READ | KEY_WRITE, NULL, &key, NULL);
172 if (res != ERROR_SUCCESS) goto error_close_iid_key;
174 wsprintfW(buf, fmt, list->num_methods);
175 res = RegSetValueExW(key, NULL, 0, REG_SZ,
177 (lstrlenW(buf) + 1) * sizeof(WCHAR));
180 if (res != ERROR_SUCCESS) goto error_close_iid_key;
183 if (list->ps_clsid) {
184 res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
185 if (res != ERROR_SUCCESS) goto error_close_iid_key;
188 if (list->ps_clsid32) {
189 res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
190 if (res != ERROR_SUCCESS) goto error_close_iid_key;
194 RegCloseKey(iid_key);
197 error_close_interface_key:
198 RegCloseKey(interface_key);
200 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
203 /***********************************************************************
204 * unregister_interfaces
206 static HRESULT unregister_interfaces(struct regsvr_interface const *list) {
207 LONG res = ERROR_SUCCESS;
210 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
211 KEY_READ | KEY_WRITE, &interface_key);
212 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
213 if (res != ERROR_SUCCESS) goto error_return;
215 for (; res == ERROR_SUCCESS && list->iid; ++list) {
218 StringFromGUID2(list->iid, buf, 39);
219 res = recursive_delete_keyW(interface_key, buf);
222 RegCloseKey(interface_key);
224 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
227 /***********************************************************************
230 static HRESULT register_coclasses(struct regsvr_coclass const *list) {
231 LONG res = ERROR_SUCCESS;
234 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
235 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
236 if (res != ERROR_SUCCESS) goto error_return;
238 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
242 StringFromGUID2(list->clsid, buf, 39);
243 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
244 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
245 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
248 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
249 (CONST BYTE*)(list->name),
250 strlen(list->name) + 1);
251 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
257 res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
258 KEY_READ | KEY_WRITE, NULL,
260 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
262 res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
263 (CONST BYTE*)list->iph32,
264 lstrlenA(list->iph32) + 1);
265 RegCloseKey(iph32_key);
266 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
270 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
271 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
278 KEY_READ | KEY_WRITE, NULL,
280 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
282 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
283 (CONST BYTE*)list->ips32,
284 lstrlenA(list->ips32) + 1);
285 if (res == ERROR_SUCCESS && list->ips32_tmodel)
286 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
287 (CONST BYTE*)list->ips32_tmodel,
288 strlen(list->ips32_tmodel) + 1);
289 RegCloseKey(ips32_key);
290 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
294 res = register_key_defvalueA(clsid_key, progid_keyname,
296 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
298 res = register_progid(buf, list->progid, NULL,
299 list->name, list->progid_extra);
300 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
303 if (list->viprogid) {
304 res = register_key_defvalueA(clsid_key, viprogid_keyname,
306 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
308 res = register_progid(buf, list->viprogid, list->progid,
309 list->name, list->progid_extra);
310 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
313 error_close_clsid_key:
314 RegCloseKey(clsid_key);
317 error_close_coclass_key:
318 RegCloseKey(coclass_key);
320 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
323 /***********************************************************************
324 * unregister_coclasses
326 static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
327 LONG res = ERROR_SUCCESS;
330 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
331 KEY_READ | KEY_WRITE, &coclass_key);
332 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
333 if (res != ERROR_SUCCESS) goto error_return;
335 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
338 StringFromGUID2(list->clsid, buf, 39);
339 res = recursive_delete_keyW(coclass_key, buf);
340 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
343 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
344 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
347 if (list->viprogid) {
348 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
349 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
353 error_close_coclass_key:
354 RegCloseKey(coclass_key);
356 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
359 /***********************************************************************
362 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
365 StringFromGUID2(guid, buf, 39);
366 return register_key_defvalueW(base, name, buf);
369 /***********************************************************************
370 * regsvr_key_defvalueW
372 static LONG register_key_defvalueW(
375 WCHAR const *value) {
379 res = RegCreateKeyExW(base, name, 0, NULL, 0,
380 KEY_READ | KEY_WRITE, NULL, &key, NULL);
381 if (res != ERROR_SUCCESS) return res;
382 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
383 (lstrlenW(value) + 1) * sizeof(WCHAR));
388 /***********************************************************************
389 * regsvr_key_defvalueA
391 static LONG register_key_defvalueA(
398 res = RegCreateKeyExW(base, name, 0, NULL, 0,
399 KEY_READ | KEY_WRITE, NULL, &key, NULL);
400 if (res != ERROR_SUCCESS) return res;
401 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
402 lstrlenA(value) + 1);
407 /***********************************************************************
410 static LONG register_progid(
413 char const *curver_progid,
419 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
420 NULL, 0, KEY_READ | KEY_WRITE, NULL,
422 if (res != ERROR_SUCCESS) return res;
425 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
426 (CONST BYTE*)name, strlen(name) + 1);
427 if (res != ERROR_SUCCESS) goto error_close_progid_key;
431 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
432 if (res != ERROR_SUCCESS) goto error_close_progid_key;
436 res = register_key_defvalueA(progid_key, curver_keyname,
438 if (res != ERROR_SUCCESS) goto error_close_progid_key;
444 res = RegCreateKeyExA(progid_key, extra, 0,
445 NULL, 0, KEY_READ | KEY_WRITE, NULL,
447 if (res == ERROR_SUCCESS)
448 RegCloseKey(extra_key);
451 error_close_progid_key:
452 RegCloseKey(progid_key);
456 /***********************************************************************
457 * recursive_delete_key
459 static LONG recursive_delete_key(HKEY key) {
461 WCHAR subkey_name[MAX_PATH];
466 cName = sizeof(subkey_name) / sizeof(WCHAR);
467 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
468 NULL, NULL, NULL, NULL);
469 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
470 res = ERROR_SUCCESS; /* presumably we're done enumerating */
473 res = RegOpenKeyExW(key, subkey_name, 0,
474 KEY_READ | KEY_WRITE, &subkey);
475 if (res == ERROR_FILE_NOT_FOUND) continue;
476 if (res != ERROR_SUCCESS) break;
478 res = recursive_delete_key(subkey);
480 if (res != ERROR_SUCCESS) break;
483 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
487 /***********************************************************************
488 * recursive_delete_keyA
490 static LONG recursive_delete_keyA(HKEY base, char const *name) {
494 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
495 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
496 if (res != ERROR_SUCCESS) return res;
497 res = recursive_delete_key(key);
502 /***********************************************************************
503 * recursive_delete_keyW
505 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) {
509 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
510 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
511 if (res != ERROR_SUCCESS) return res;
512 res = recursive_delete_key(key);
517 /***********************************************************************
520 static struct regsvr_coclass const coclass_list[] = {
522 &CLSID_DsObjectPicker,
531 { NULL } /* list terminator */
534 /***********************************************************************
537 static struct regsvr_interface const interface_list[] = {
538 { NULL } /* list terminator */
541 /***********************************************************************
544 HRESULT WINAPI DllRegisterServer(void) {
549 hr = register_coclasses(coclass_list);
551 hr = register_interfaces(interface_list);
555 /***********************************************************************
556 * DllUnregisterServer
558 HRESULT WINAPI DllUnregisterServer(void) {
563 hr = unregister_coclasses(coclass_list);
565 hr = unregister_interfaces(interface_list);