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 */
84 /* flags for regsvr_coclass.flags */
85 #define PROGID_CLSID 0x00000010
87 static HRESULT register_coclasses(struct regsvr_coclass const *list);
88 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
90 /***********************************************************************
91 * static string constants
93 static WCHAR const interface_keyname[10] = {
94 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
95 static WCHAR const base_ifa_keyname[14] = {
96 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
98 static WCHAR const num_methods_keyname[11] = {
99 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
100 static WCHAR const ps_clsid_keyname[15] = {
101 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
103 static WCHAR const ps_clsid32_keyname[17] = {
104 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
105 'i', 'd', '3', '2', 0 };
106 static WCHAR const clsid_keyname[6] = {
107 'C', 'L', 'S', 'I', 'D', 0 };
108 static WCHAR const curver_keyname[7] = {
109 'C', 'u', 'r', 'V', 'e', 'r', 0 };
110 static WCHAR const iph32_keyname[] = {
111 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
113 static WCHAR const ips_keyname[13] = {
114 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
116 static WCHAR const ips32_keyname[15] = {
117 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
119 static WCHAR const progid_keyname[7] = {
120 'P', 'r', 'o', 'g', 'I', 'D', 0 };
121 static WCHAR const viprogid_keyname[25] = {
122 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
123 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
125 static char const tmodel_valuename[] = "ThreadingModel";
127 /***********************************************************************
128 * static helper functions
130 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
131 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
133 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
135 static LONG register_progid(WCHAR const *clsid,
136 char const *progid, char const *curver_progid,
137 char const *name, char const *extra);
138 static LONG recursive_delete_key(HKEY key);
139 static LONG recursive_delete_keyA(HKEY base, char const *name);
140 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
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 = recursive_delete_keyW(interface_key, buf);
230 RegCloseKey(interface_key);
232 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
235 /***********************************************************************
238 static HRESULT register_coclasses(struct regsvr_coclass const *list) {
239 LONG res = ERROR_SUCCESS;
242 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
243 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
244 if (res != ERROR_SUCCESS) goto error_return;
246 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
250 StringFromGUID2(list->clsid, buf, 39);
251 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
252 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
253 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
256 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
257 (CONST BYTE*)(list->name),
258 strlen(list->name) + 1);
259 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
265 res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
266 KEY_READ | KEY_WRITE, NULL,
268 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
270 res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
271 (CONST BYTE*)list->iph32,
272 lstrlenA(list->iph32) + 1);
273 RegCloseKey(iph32_key);
274 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
278 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
279 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
285 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
286 KEY_READ | KEY_WRITE, NULL,
288 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
290 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
291 (CONST BYTE*)list->ips32,
292 lstrlenA(list->ips32) + 1);
293 if (res == ERROR_SUCCESS && list->ips32_tmodel)
294 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
295 (CONST BYTE*)list->ips32_tmodel,
296 strlen(list->ips32_tmodel) + 1);
297 RegCloseKey(ips32_key);
298 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
302 res = register_key_defvalueA(clsid_key, progid_keyname,
304 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
306 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
308 list->name, list->progid_extra);
309 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
312 if (list->viprogid) {
313 res = register_key_defvalueA(clsid_key, viprogid_keyname,
315 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
317 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
318 list->viprogid, list->progid,
319 list->name, list->progid_extra);
320 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
323 error_close_clsid_key:
324 RegCloseKey(clsid_key);
327 error_close_coclass_key:
328 RegCloseKey(coclass_key);
330 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
333 /***********************************************************************
334 * unregister_coclasses
336 static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
337 LONG res = ERROR_SUCCESS;
340 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
341 KEY_READ | KEY_WRITE, &coclass_key);
342 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
343 if (res != ERROR_SUCCESS) goto error_return;
345 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
348 StringFromGUID2(list->clsid, buf, 39);
349 res = recursive_delete_keyW(coclass_key, buf);
350 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
353 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
354 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
357 if (list->viprogid) {
358 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
359 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
363 error_close_coclass_key:
364 RegCloseKey(coclass_key);
366 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
369 /***********************************************************************
372 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
375 StringFromGUID2(guid, buf, 39);
376 return register_key_defvalueW(base, name, buf);
379 /***********************************************************************
380 * regsvr_key_defvalueW
382 static LONG register_key_defvalueW(
385 WCHAR const *value) {
389 res = RegCreateKeyExW(base, name, 0, NULL, 0,
390 KEY_READ | KEY_WRITE, NULL, &key, NULL);
391 if (res != ERROR_SUCCESS) return res;
392 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
393 (lstrlenW(value) + 1) * sizeof(WCHAR));
398 /***********************************************************************
399 * regsvr_key_defvalueA
401 static LONG register_key_defvalueA(
408 res = RegCreateKeyExW(base, name, 0, NULL, 0,
409 KEY_READ | KEY_WRITE, NULL, &key, NULL);
410 if (res != ERROR_SUCCESS) return res;
411 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
412 lstrlenA(value) + 1);
417 /***********************************************************************
420 static LONG register_progid(
423 char const *curver_progid,
429 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
430 NULL, 0, KEY_READ | KEY_WRITE, NULL,
432 if (res != ERROR_SUCCESS) return res;
435 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
436 (CONST BYTE*)name, strlen(name) + 1);
437 if (res != ERROR_SUCCESS) goto error_close_progid_key;
441 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
442 if (res != ERROR_SUCCESS) goto error_close_progid_key;
446 res = register_key_defvalueA(progid_key, curver_keyname,
448 if (res != ERROR_SUCCESS) goto error_close_progid_key;
454 res = RegCreateKeyExA(progid_key, extra, 0,
455 NULL, 0, KEY_READ | KEY_WRITE, NULL,
457 if (res == ERROR_SUCCESS)
458 RegCloseKey(extra_key);
461 error_close_progid_key:
462 RegCloseKey(progid_key);
466 /***********************************************************************
467 * recursive_delete_key
469 static LONG recursive_delete_key(HKEY key) {
471 WCHAR subkey_name[MAX_PATH];
476 cName = sizeof(subkey_name) / sizeof(WCHAR);
477 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
478 NULL, NULL, NULL, NULL);
479 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
480 res = ERROR_SUCCESS; /* presumably we're done enumerating */
483 res = RegOpenKeyExW(key, subkey_name, 0,
484 KEY_READ | KEY_WRITE, &subkey);
485 if (res == ERROR_FILE_NOT_FOUND) continue;
486 if (res != ERROR_SUCCESS) break;
488 res = recursive_delete_key(subkey);
490 if (res != ERROR_SUCCESS) break;
493 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
497 /***********************************************************************
498 * recursive_delete_keyA
500 static LONG recursive_delete_keyA(HKEY base, char const *name) {
504 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
505 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
506 if (res != ERROR_SUCCESS) return res;
507 res = recursive_delete_key(key);
512 /***********************************************************************
513 * recursive_delete_keyW
515 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) {
519 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
520 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
521 if (res != ERROR_SUCCESS) return res;
522 res = recursive_delete_key(key);
527 /***********************************************************************
530 static struct regsvr_coclass const coclass_list[] = {
533 "Msi install server",
543 &CLSID_IMsiServerMessage,
544 "Wine Installer Message RPC",
550 "WindowsInstaller.Message",
555 "Msi install server",
561 "WindowsInstaller.Installer",
566 "Msi install server",
572 "WindowsInstaller.Installer",
577 "Msi install server",
583 "WindowsInstaller.Installer",
586 { NULL } /* list terminator */
589 /***********************************************************************
593 * we should declare: (@see ole32/regsvr.c for examples)
594 [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
595 [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
596 [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
597 [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
598 [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
599 [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
600 [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
601 [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
602 [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
603 [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
604 [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
605 [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
608 static struct regsvr_interface const interface_list[] = {
615 { NULL } /* list terminator */
618 static HRESULT register_msiexec(void)
620 static const WCHAR key[] = {
621 'S','o','f','t','w','a','r','e',
622 '\\','M','i','c','r','o','s','o','f','t',
623 '\\','W','i','n','d','o','w','s',
624 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
625 '\\','I','n','s','t','a','l','l','e','r',0 };
626 static const WCHAR val[] = {
627 'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
628 WCHAR path[MAX_PATH];
633 len = GetSystemDirectoryW(path, MAX_PATH);
634 if (!len || len > MAX_PATH)
637 res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0,
638 NULL, 0, KEY_READ | KEY_WRITE, NULL,
640 if (res != ERROR_SUCCESS)
643 res = RegSetValueExW(hkey, val, 0, REG_SZ,
644 (BYTE*)path, (len + 1)*sizeof(WCHAR));
648 return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
651 /***********************************************************************
652 * DllRegisterServer (MSI.@)
654 HRESULT WINAPI DllRegisterServer(void)
662 hr = register_coclasses(coclass_list);
664 hr = register_interfaces(interface_list);
666 hr = register_msiexec();
668 tl = get_msi_typelib( &path );
671 hr = RegisterTypeLib( tl, path, NULL );
672 ITypeLib_Release( tl );
680 /***********************************************************************
681 * DllUnregisterServer (MSI.@)
683 HRESULT WINAPI DllUnregisterServer(void)
689 hr = unregister_coclasses(coclass_list);
691 hr = unregister_interfaces(interface_list);