2 * self-registerable dll functions for msi.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
35 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
44 * Near the bottom of this file are the exported DllRegisterServer and
45 * DllUnregisterServer, which make all this worthwhile.
48 /***********************************************************************
49 * interface for self-registering
51 struct regsvr_interface
{
52 IID
const *iid
; /* NULL for end of list */
53 LPCSTR name
; /* can be NULL to omit */
54 IID
const *base_iid
; /* can be NULL to omit */
55 int num_methods
; /* can be <0 to omit */
56 CLSID
const *ps_clsid
; /* can be NULL to omit */
57 CLSID
const *ps_clsid32
; /* can be NULL to omit */
60 static HRESULT
register_interfaces(struct regsvr_interface
const *list
);
61 static HRESULT
unregister_interfaces(struct regsvr_interface
const *list
);
64 * @todo: maybe adding typelibs support here
65 * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217
66 * @="{000C1092-0000-0000-C000-000000000046}"
68 struct regsvr_coclass
{
69 CLSID
const *clsid
; /* NULL for end of list */
70 LPCSTR name
; /* can be NULL to omit */
71 LPCSTR iph32
; /* can be NULL to omit */
72 LPCSTR ips
; /* can be NULL to omit */
73 LPCSTR ips32
; /* can be NULL to omit */
74 LPCSTR ips32_tmodel
; /* can be NULL to omit, if apartment, iph32 must be set */
75 LPCSTR progid
; /* can be NULL to omit */
76 LPCSTR viprogid
; /* can be NULL to omit */
77 LPCSTR progid_extra
; /* can be NULL to omit */
80 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
);
81 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
);
83 /***********************************************************************
84 * static string constants
86 static WCHAR
const interface_keyname
[10] = {
87 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
88 static WCHAR
const base_ifa_keyname
[14] = {
89 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
91 static WCHAR
const num_methods_keyname
[11] = {
92 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
93 static WCHAR
const ps_clsid_keyname
[15] = {
94 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
96 static WCHAR
const ps_clsid32_keyname
[17] = {
97 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
98 'i', 'd', '3', '2', 0 };
99 static WCHAR
const clsid_keyname
[6] = {
100 'C', 'L', 'S', 'I', 'D', 0 };
101 static WCHAR
const curver_keyname
[7] = {
102 'C', 'u', 'r', 'V', 'e', 'r', 0 };
103 static WCHAR
const iph32_keyname
[] = {
104 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
106 static WCHAR
const ips_keyname
[13] = {
107 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
109 static WCHAR
const ips32_keyname
[15] = {
110 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
112 static WCHAR
const progid_keyname
[7] = {
113 'P', 'r', 'o', 'g', 'I', 'D', 0 };
114 static WCHAR
const viprogid_keyname
[25] = {
115 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
116 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
118 static char const tmodel_valuename
[] = "ThreadingModel";
120 /***********************************************************************
121 * static helper functions
123 static LONG
register_key_guid(HKEY base
, WCHAR
const *name
, GUID
const *guid
);
124 static LONG
register_key_defvalueW(HKEY base
, WCHAR
const *name
,
126 static LONG
register_key_defvalueA(HKEY base
, WCHAR
const *name
,
128 static LONG
register_progid(WCHAR
const *clsid
,
129 char const *progid
, char const *curver_progid
,
130 char const *name
, char const *extra
);
131 static LONG
recursive_delete_key(HKEY key
);
132 static LONG
recursive_delete_keyA(HKEY base
, char const *name
);
133 static LONG
recursive_delete_keyW(HKEY base
, WCHAR
const *name
);
135 /***********************************************************************
136 * register_interfaces
138 static HRESULT
register_interfaces(struct regsvr_interface
const *list
) {
139 LONG res
= ERROR_SUCCESS
;
142 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, interface_keyname
, 0, NULL
, 0,
143 KEY_READ
| KEY_WRITE
, NULL
, &interface_key
, NULL
);
144 if (res
!= ERROR_SUCCESS
) goto error_return
;
146 for (; res
== ERROR_SUCCESS
&& list
->iid
; ++list
) {
150 StringFromGUID2(list
->iid
, buf
, 39);
151 res
= RegCreateKeyExW(interface_key
, buf
, 0, NULL
, 0,
152 KEY_READ
| KEY_WRITE
, NULL
, &iid_key
, NULL
);
153 if (res
!= ERROR_SUCCESS
) goto error_close_interface_key
;
156 res
= RegSetValueExA(iid_key
, NULL
, 0, REG_SZ
,
157 (CONST BYTE
*)(list
->name
),
158 strlen(list
->name
) + 1);
159 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
162 if (list
->base_iid
) {
163 res
= register_key_guid(iid_key
, base_ifa_keyname
, list
->base_iid
);
164 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
167 if (0 <= list
->num_methods
) {
168 static WCHAR
const fmt
[3] = { '%', 'd', 0 };
171 res
= RegCreateKeyExW(iid_key
, num_methods_keyname
, 0, NULL
, 0,
172 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
173 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
175 wsprintfW(buf
, fmt
, list
->num_methods
);
176 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
,
178 (lstrlenW(buf
) + 1) * sizeof(WCHAR
));
181 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
184 if (list
->ps_clsid
) {
185 register_key_guid(iid_key
, ps_clsid_keyname
, list
->ps_clsid
);
186 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
189 if (list
->ps_clsid32
) {
190 register_key_guid(iid_key
, ps_clsid32_keyname
, list
->ps_clsid32
);
191 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
195 RegCloseKey(iid_key
);
198 error_close_interface_key
:
199 RegCloseKey(interface_key
);
201 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
204 /***********************************************************************
205 * unregister_interfaces
207 static HRESULT
unregister_interfaces(struct regsvr_interface
const *list
) {
208 LONG res
= ERROR_SUCCESS
;
211 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, interface_keyname
, 0,
212 KEY_READ
| KEY_WRITE
, &interface_key
);
213 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
214 if (res
!= ERROR_SUCCESS
) goto error_return
;
216 for (; res
== ERROR_SUCCESS
&& list
->iid
; ++list
) {
219 StringFromGUID2(list
->iid
, buf
, 39);
220 res
= recursive_delete_keyW(interface_key
, buf
);
223 RegCloseKey(interface_key
);
225 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
228 /***********************************************************************
231 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
) {
232 LONG res
= ERROR_SUCCESS
;
235 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
236 KEY_READ
| KEY_WRITE
, NULL
, &coclass_key
, NULL
);
237 if (res
!= ERROR_SUCCESS
) goto error_return
;
239 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
243 StringFromGUID2(list
->clsid
, buf
, 39);
244 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
245 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
246 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
249 res
= RegSetValueExA(clsid_key
, NULL
, 0, REG_SZ
,
250 (CONST BYTE
*)(list
->name
),
251 strlen(list
->name
) + 1);
252 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
258 res
= RegCreateKeyExW(clsid_key
, iph32_keyname
, 0, NULL
, 0,
259 KEY_READ
| KEY_WRITE
, NULL
,
261 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
263 res
= RegSetValueExA(iph32_key
, NULL
, 0, REG_SZ
,
264 (CONST BYTE
*)list
->iph32
,
265 lstrlenA(list
->iph32
) + 1);
266 RegCloseKey(iph32_key
);
267 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
271 res
= register_key_defvalueA(clsid_key
, ips_keyname
, list
->ips
);
272 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
278 res
= RegCreateKeyExW(clsid_key
, ips32_keyname
, 0, NULL
, 0,
279 KEY_READ
| KEY_WRITE
, NULL
,
281 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
283 res
= RegSetValueExA(ips32_key
, NULL
, 0, REG_SZ
,
284 (CONST BYTE
*)list
->ips32
,
285 lstrlenA(list
->ips32
) + 1);
286 if (res
== ERROR_SUCCESS
&& list
->ips32_tmodel
)
287 res
= RegSetValueExA(ips32_key
, tmodel_valuename
, 0, REG_SZ
,
288 (CONST BYTE
*)list
->ips32_tmodel
,
289 strlen(list
->ips32_tmodel
) + 1);
290 RegCloseKey(ips32_key
);
291 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
295 res
= register_key_defvalueA(clsid_key
, progid_keyname
,
297 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
299 res
= register_progid(buf
, list
->progid
, NULL
,
300 list
->name
, list
->progid_extra
);
301 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
304 if (list
->viprogid
) {
305 res
= register_key_defvalueA(clsid_key
, viprogid_keyname
,
307 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
309 res
= register_progid(buf
, list
->viprogid
, list
->progid
,
310 list
->name
, list
->progid_extra
);
311 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
314 error_close_clsid_key
:
315 RegCloseKey(clsid_key
);
318 error_close_coclass_key
:
319 RegCloseKey(coclass_key
);
321 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
324 /***********************************************************************
325 * unregister_coclasses
327 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
) {
328 LONG res
= ERROR_SUCCESS
;
331 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0,
332 KEY_READ
| KEY_WRITE
, &coclass_key
);
333 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
334 if (res
!= ERROR_SUCCESS
) goto error_return
;
336 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
339 StringFromGUID2(list
->clsid
, buf
, 39);
340 res
= recursive_delete_keyW(coclass_key
, buf
);
341 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
344 res
= recursive_delete_keyA(HKEY_CLASSES_ROOT
, list
->progid
);
345 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
348 if (list
->viprogid
) {
349 res
= recursive_delete_keyA(HKEY_CLASSES_ROOT
, list
->viprogid
);
350 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
354 error_close_coclass_key
:
355 RegCloseKey(coclass_key
);
357 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
360 /***********************************************************************
363 static LONG
register_key_guid(HKEY base
, WCHAR
const *name
, GUID
const *guid
) {
366 StringFromGUID2(guid
, buf
, 39);
367 return register_key_defvalueW(base
, name
, buf
);
370 /***********************************************************************
371 * regsvr_key_defvalueW
373 static LONG
register_key_defvalueW(
376 WCHAR
const *value
) {
380 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
381 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
382 if (res
!= ERROR_SUCCESS
) return res
;
383 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
384 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
389 /***********************************************************************
390 * regsvr_key_defvalueA
392 static LONG
register_key_defvalueA(
399 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
400 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
401 if (res
!= ERROR_SUCCESS
) return res
;
402 res
= RegSetValueExA(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
403 lstrlenA(value
) + 1);
408 /***********************************************************************
411 static LONG
register_progid(
414 char const *curver_progid
,
420 res
= RegCreateKeyExA(HKEY_CLASSES_ROOT
, progid
, 0,
421 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
423 if (res
!= ERROR_SUCCESS
) return res
;
426 res
= RegSetValueExA(progid_key
, NULL
, 0, REG_SZ
,
427 (CONST BYTE
*)name
, strlen(name
) + 1);
428 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
432 res
= register_key_defvalueW(progid_key
, clsid_keyname
, clsid
);
433 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
437 res
= register_key_defvalueA(progid_key
, curver_keyname
,
439 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
445 res
= RegCreateKeyExA(progid_key
, extra
, 0,
446 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
448 if (res
== ERROR_SUCCESS
)
449 RegCloseKey(extra_key
);
452 error_close_progid_key
:
453 RegCloseKey(progid_key
);
457 /***********************************************************************
458 * recursive_delete_key
460 static LONG
recursive_delete_key(HKEY key
) {
462 WCHAR subkey_name
[MAX_PATH
];
467 cName
= sizeof(subkey_name
) / sizeof(WCHAR
);
468 res
= RegEnumKeyExW(key
, 0, subkey_name
, &cName
,
469 NULL
, NULL
, NULL
, NULL
);
470 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) {
471 res
= ERROR_SUCCESS
; /* presumably we're done enumerating */
474 res
= RegOpenKeyExW(key
, subkey_name
, 0,
475 KEY_READ
| KEY_WRITE
, &subkey
);
476 if (res
== ERROR_FILE_NOT_FOUND
) continue;
477 if (res
!= ERROR_SUCCESS
) break;
479 res
= recursive_delete_key(subkey
);
481 if (res
!= ERROR_SUCCESS
) break;
484 if (res
== ERROR_SUCCESS
) res
= RegDeleteKeyW(key
, 0);
488 /***********************************************************************
489 * recursive_delete_keyA
491 static LONG
recursive_delete_keyA(HKEY base
, char const *name
) {
495 res
= RegOpenKeyExA(base
, name
, 0, KEY_READ
| KEY_WRITE
, &key
);
496 if (res
== ERROR_FILE_NOT_FOUND
) return ERROR_SUCCESS
;
497 if (res
!= ERROR_SUCCESS
) return res
;
498 res
= recursive_delete_key(key
);
503 /***********************************************************************
504 * recursive_delete_keyW
506 static LONG
recursive_delete_keyW(HKEY base
, WCHAR
const *name
) {
510 res
= RegOpenKeyExW(base
, name
, 0, KEY_READ
| KEY_WRITE
, &key
);
511 if (res
== ERROR_FILE_NOT_FOUND
) return ERROR_SUCCESS
;
512 if (res
!= ERROR_SUCCESS
) return res
;
513 res
= recursive_delete_key(key
);
518 /***********************************************************************
521 static struct regsvr_coclass
const coclass_list
[] = {
524 "Msi install server",
529 "WindowsInstaller.Installer",
533 &CLSID_IMsiServerMessage
,
534 "Wine Installer Message RPC",
539 "WindowsInstaller.Message",
544 "Msi install server",
549 "WindowsInstaller.Installer",
554 "Msi install server",
559 "WindowsInstaller.Installer",
564 "Msi install server",
569 "WindowsInstaller.Installer",
572 { NULL
} /* list terminator */
575 /***********************************************************************
579 * we should declare: (@see ole32/regsvr.c for examples)
580 [-HKEY_CLASSES_ROOT\Interface\{000C101C-0000-0000-C000-000000000046}]
581 [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
582 [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
583 [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
584 [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
585 [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
586 [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
587 [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
588 [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
589 [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
590 [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
591 [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
592 [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
594 static struct regsvr_interface
const interface_list
[] = {
595 { NULL
} /* list terminator */
598 static HRESULT
register_msiexec(void)
600 static const WCHAR key
[] = {
601 'S','o','f','t','w','a','r','e',
602 '\\','M','i','c','r','o','s','o','f','t',
603 '\\','W','i','n','d','o','w','s',
604 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
605 '\\','I','n','s','t','a','l','l','e','r',0 };
606 static const WCHAR val
[] = {
607 'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
608 WCHAR path
[MAX_PATH
];
613 len
= GetSystemDirectoryW(path
, MAX_PATH
);
614 if (!len
|| len
> MAX_PATH
)
617 res
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, key
, 0,
618 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
620 if (res
!= ERROR_SUCCESS
)
623 res
= RegSetValueExW(hkey
, val
, 0, REG_SZ
,
624 (BYTE
*)path
, (len
+ 1)*sizeof(WCHAR
));
628 return (res
== ERROR_SUCCESS
) ? S_OK
: E_FAIL
;
631 /***********************************************************************
632 * DllRegisterServer (MSI.@)
634 HRESULT WINAPI
DllRegisterServer(void)
640 hr
= register_coclasses(coclass_list
);
642 hr
= register_interfaces(interface_list
);
644 hr
= register_msiexec();
648 /***********************************************************************
649 * DllUnregisterServer (MSI.@)
651 HRESULT WINAPI
DllUnregisterServer(void)
657 hr
= unregister_coclasses(coclass_list
);
659 hr
= unregister_interfaces(interface_list
);