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
38 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
47 * Near the bottom of this file are the exported DllRegisterServer and
48 * DllUnregisterServer, which make all this worthwhile.
51 /***********************************************************************
52 * interface for self-registering
54 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
);
67 * @todo: maybe adding typelibs support here
68 * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217
69 * @="{000C1092-0000-0000-C000-000000000046}"
71 struct regsvr_coclass
{
72 CLSID
const *clsid
; /* NULL for end of list */
73 LPCSTR name
; /* can be NULL to omit */
74 LPCSTR iph32
; /* can be NULL to omit */
75 LPCSTR ips
; /* can be NULL to omit */
76 LPCSTR ips32
; /* can be NULL to omit */
77 LPCSTR ips32_tmodel
; /* can be NULL to omit, if apartment, iph32 must be set */
79 LPCSTR progid
; /* can be NULL to omit */
80 LPCSTR viprogid
; /* can be NULL to omit */
81 LPCSTR progid_extra
; /* can be NULL to omit */
82 LPCSTR dllversion
; /* can be NULL to omit */
85 /* flags for regsvr_coclass.flags */
86 #define PROGID_CLSID 0x00000010
88 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
);
89 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
);
91 /***********************************************************************
92 * static string constants
94 static WCHAR
const interface_keyname
[10] = {
95 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
96 static WCHAR
const base_ifa_keyname
[14] = {
97 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
99 static WCHAR
const num_methods_keyname
[11] = {
100 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
101 static WCHAR
const ps_clsid_keyname
[15] = {
102 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
104 static WCHAR
const ps_clsid32_keyname
[17] = {
105 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
106 'i', 'd', '3', '2', 0 };
107 static WCHAR
const clsid_keyname
[6] = {
108 'C', 'L', 'S', 'I', 'D', 0 };
109 static WCHAR
const curver_keyname
[7] = {
110 'C', 'u', 'r', 'V', 'e', 'r', 0 };
111 static WCHAR
const iph32_keyname
[] = {
112 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
114 static WCHAR
const ips_keyname
[13] = {
115 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
117 static WCHAR
const ips32_keyname
[15] = {
118 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
120 static WCHAR
const progid_keyname
[7] = {
121 'P', 'r', 'o', 'g', 'I', 'D', 0 };
122 static WCHAR
const viprogid_keyname
[25] = {
123 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
124 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
126 static WCHAR
const dllversion_keyname
[11] = {
127 'D', 'l', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 };
128 static char const tmodel_valuename
[] = "ThreadingModel";
130 /***********************************************************************
131 * static helper functions
133 static LONG
register_key_guid(HKEY base
, WCHAR
const *name
, GUID
const *guid
);
134 static LONG
register_key_defvalueW(HKEY base
, WCHAR
const *name
,
136 static LONG
register_key_defvalueA(HKEY base
, WCHAR
const *name
,
138 static LONG
register_progid(WCHAR
const *clsid
,
139 char const *progid
, char const *curver_progid
,
140 char const *name
, char const *extra
);
142 /***********************************************************************
143 * register_interfaces
145 static HRESULT
register_interfaces(struct regsvr_interface
const *list
) {
146 LONG res
= ERROR_SUCCESS
;
149 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, interface_keyname
, 0, NULL
, 0,
150 KEY_READ
| KEY_WRITE
, NULL
, &interface_key
, NULL
);
151 if (res
!= ERROR_SUCCESS
) goto error_return
;
153 for (; res
== ERROR_SUCCESS
&& list
->iid
; ++list
) {
157 StringFromGUID2(list
->iid
, buf
, 39);
158 res
= RegCreateKeyExW(interface_key
, buf
, 0, NULL
, 0,
159 KEY_READ
| KEY_WRITE
, NULL
, &iid_key
, NULL
);
160 if (res
!= ERROR_SUCCESS
) goto error_close_interface_key
;
163 res
= RegSetValueExA(iid_key
, NULL
, 0, REG_SZ
,
164 (CONST BYTE
*)(list
->name
),
165 strlen(list
->name
) + 1);
166 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
169 if (list
->base_iid
) {
170 res
= register_key_guid(iid_key
, base_ifa_keyname
, list
->base_iid
);
171 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
174 if (0 <= list
->num_methods
) {
175 static WCHAR
const fmt
[3] = { '%', 'd', 0 };
178 res
= RegCreateKeyExW(iid_key
, num_methods_keyname
, 0, NULL
, 0,
179 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
180 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
182 wsprintfW(buf
, fmt
, list
->num_methods
);
183 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
,
185 (lstrlenW(buf
) + 1) * sizeof(WCHAR
));
188 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
191 if (list
->ps_clsid
) {
192 res
= register_key_guid(iid_key
, ps_clsid_keyname
, list
->ps_clsid
);
193 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
196 if (list
->ps_clsid32
) {
197 res
= register_key_guid(iid_key
, ps_clsid32_keyname
, list
->ps_clsid32
);
198 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
202 RegCloseKey(iid_key
);
205 error_close_interface_key
:
206 RegCloseKey(interface_key
);
208 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
211 /***********************************************************************
212 * unregister_interfaces
214 static HRESULT
unregister_interfaces(struct regsvr_interface
const *list
) {
215 LONG res
= ERROR_SUCCESS
;
218 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, interface_keyname
, 0,
219 KEY_READ
| KEY_WRITE
, &interface_key
);
220 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
221 if (res
!= ERROR_SUCCESS
) goto error_return
;
223 for (; res
== ERROR_SUCCESS
&& list
->iid
; ++list
) {
226 StringFromGUID2(list
->iid
, buf
, 39);
227 res
= RegDeleteTreeW(interface_key
, buf
);
228 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
231 RegCloseKey(interface_key
);
233 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
236 /***********************************************************************
239 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
) {
240 LONG res
= ERROR_SUCCESS
;
243 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
244 KEY_READ
| KEY_WRITE
, NULL
, &coclass_key
, NULL
);
245 if (res
!= ERROR_SUCCESS
) goto error_return
;
247 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
251 StringFromGUID2(list
->clsid
, buf
, 39);
252 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
253 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
254 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
257 res
= RegSetValueExA(clsid_key
, NULL
, 0, REG_SZ
,
258 (CONST BYTE
*)(list
->name
),
259 strlen(list
->name
) + 1);
260 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
266 res
= RegCreateKeyExW(clsid_key
, iph32_keyname
, 0, NULL
, 0,
267 KEY_READ
| KEY_WRITE
, NULL
,
269 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
271 res
= RegSetValueExA(iph32_key
, NULL
, 0, REG_SZ
,
272 (CONST BYTE
*)list
->iph32
,
273 lstrlenA(list
->iph32
) + 1);
274 RegCloseKey(iph32_key
);
275 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
279 res
= register_key_defvalueA(clsid_key
, ips_keyname
, list
->ips
);
280 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
286 res
= RegCreateKeyExW(clsid_key
, ips32_keyname
, 0, NULL
, 0,
287 KEY_READ
| KEY_WRITE
, NULL
,
289 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
291 res
= RegSetValueExA(ips32_key
, NULL
, 0, REG_SZ
,
292 (CONST BYTE
*)list
->ips32
,
293 lstrlenA(list
->ips32
) + 1);
294 if (res
== ERROR_SUCCESS
&& list
->ips32_tmodel
)
295 res
= RegSetValueExA(ips32_key
, tmodel_valuename
, 0, REG_SZ
,
296 (CONST BYTE
*)list
->ips32_tmodel
,
297 strlen(list
->ips32_tmodel
) + 1);
298 RegCloseKey(ips32_key
);
299 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
303 res
= register_key_defvalueA(clsid_key
, progid_keyname
,
305 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
307 res
= register_progid(list
->flags
& PROGID_CLSID
? buf
: NULL
,
309 list
->name
, list
->progid_extra
);
310 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
313 if (list
->viprogid
) {
314 res
= register_key_defvalueA(clsid_key
, viprogid_keyname
,
316 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
318 res
= register_progid(list
->flags
& PROGID_CLSID
? buf
: NULL
,
319 list
->viprogid
, list
->progid
,
320 list
->name
, list
->progid_extra
);
321 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
324 if (list
->dllversion
) {
327 res
= RegCreateKeyExW(clsid_key
, dllversion_keyname
, 0, NULL
, 0,
328 KEY_READ
| KEY_WRITE
, NULL
,
330 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
332 res
= RegSetValueExA(dllver_key
, NULL
, 0, REG_SZ
,
333 (CONST BYTE
*)list
->dllversion
,
334 lstrlenA(list
->dllversion
) + 1);
335 RegCloseKey(dllver_key
);
336 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
340 error_close_clsid_key
:
341 RegCloseKey(clsid_key
);
344 error_close_coclass_key
:
345 RegCloseKey(coclass_key
);
347 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
350 /***********************************************************************
351 * unregister_coclasses
353 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
) {
354 LONG res
= ERROR_SUCCESS
;
357 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0,
358 KEY_READ
| KEY_WRITE
, &coclass_key
);
359 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
360 if (res
!= ERROR_SUCCESS
) goto error_return
;
362 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
365 StringFromGUID2(list
->clsid
, buf
, 39);
366 res
= RegDeleteTreeW(coclass_key
, buf
);
367 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
368 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
371 res
= RegDeleteTreeA(HKEY_CLASSES_ROOT
, list
->progid
);
372 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
373 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
376 if (list
->viprogid
) {
377 res
= RegDeleteTreeA(HKEY_CLASSES_ROOT
, list
->viprogid
);
378 if (res
== ERROR_FILE_NOT_FOUND
) res
= ERROR_SUCCESS
;
379 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
383 error_close_coclass_key
:
384 RegCloseKey(coclass_key
);
386 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
389 /***********************************************************************
392 static LONG
register_key_guid(HKEY base
, WCHAR
const *name
, GUID
const *guid
) {
395 StringFromGUID2(guid
, buf
, 39);
396 return register_key_defvalueW(base
, name
, buf
);
399 /***********************************************************************
400 * regsvr_key_defvalueW
402 static LONG
register_key_defvalueW(
405 WCHAR
const *value
) {
409 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
410 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
411 if (res
!= ERROR_SUCCESS
) return res
;
412 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
413 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
418 /***********************************************************************
419 * regsvr_key_defvalueA
421 static LONG
register_key_defvalueA(
428 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
429 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
430 if (res
!= ERROR_SUCCESS
) return res
;
431 res
= RegSetValueExA(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
432 lstrlenA(value
) + 1);
437 /***********************************************************************
440 static LONG
register_progid(
443 char const *curver_progid
,
449 res
= RegCreateKeyExA(HKEY_CLASSES_ROOT
, progid
, 0,
450 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
452 if (res
!= ERROR_SUCCESS
) return res
;
455 res
= RegSetValueExA(progid_key
, NULL
, 0, REG_SZ
,
456 (CONST BYTE
*)name
, strlen(name
) + 1);
457 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
461 res
= register_key_defvalueW(progid_key
, clsid_keyname
, clsid
);
462 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
466 res
= register_key_defvalueA(progid_key
, curver_keyname
,
468 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
474 res
= RegCreateKeyExA(progid_key
, extra
, 0,
475 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
477 if (res
== ERROR_SUCCESS
)
478 RegCloseKey(extra_key
);
481 error_close_progid_key
:
482 RegCloseKey(progid_key
);
486 /***********************************************************************
489 static struct regsvr_coclass
const coclass_list
[] = {
492 "Msi install server",
504 &CLSID_IMsiServerMessage
,
505 "Wine Installer Message RPC",
511 "WindowsInstaller.Message",
518 "Msi install server",
524 "WindowsInstaller.Installer",
531 "Msi install server",
537 "WindowsInstaller.Installer",
544 "Msi install server",
550 "WindowsInstaller.Installer",
555 { NULL
} /* list terminator */
558 /***********************************************************************
562 * we should declare: (@see ole32/regsvr.c for examples)
563 [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
564 [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
565 [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
566 [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
567 [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
568 [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
569 [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
570 [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
571 [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
572 [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
573 [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
574 [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
577 static struct regsvr_interface
const interface_list
[] = {
584 { NULL
} /* list terminator */
587 static HRESULT
register_msiexec(void)
589 static const WCHAR key
[] = {
590 'S','o','f','t','w','a','r','e',
591 '\\','M','i','c','r','o','s','o','f','t',
592 '\\','W','i','n','d','o','w','s',
593 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
594 '\\','I','n','s','t','a','l','l','e','r',0 };
595 static const WCHAR val
[] = {
596 'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
597 WCHAR path
[MAX_PATH
];
602 len
= GetSystemDirectoryW(path
, MAX_PATH
);
603 if (!len
|| len
> MAX_PATH
)
606 res
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, key
, 0,
607 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
609 if (res
!= ERROR_SUCCESS
)
612 res
= RegSetValueExW(hkey
, val
, 0, REG_SZ
,
613 (BYTE
*)path
, (len
+ 1)*sizeof(WCHAR
));
617 return (res
== ERROR_SUCCESS
) ? S_OK
: E_FAIL
;
620 /***********************************************************************
621 * DllRegisterServer (MSI.@)
623 HRESULT WINAPI
DllRegisterServer(void)
631 hr
= register_coclasses(coclass_list
);
633 hr
= register_interfaces(interface_list
);
635 hr
= register_msiexec();
637 tl
= get_msi_typelib( &path
);
640 hr
= RegisterTypeLib( tl
, path
, NULL
);
641 ITypeLib_Release( tl
);
649 /***********************************************************************
650 * DllUnregisterServer (MSI.@)
652 HRESULT WINAPI
DllUnregisterServer(void)
658 hr
= unregister_coclasses(coclass_list
);
660 hr
= unregister_interfaces(interface_list
);