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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 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 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 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
);