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 */
76 LPCSTR progid; /* can be NULL to omit */
77 LPCSTR viprogid; /* can be NULL to omit */
78 LPCSTR progid_extra; /* can be NULL to omit */
81 /* flags for regsvr_coclass.flags */
82 #define PROGID_CLSID 0x00000010
84 static HRESULT register_coclasses(struct regsvr_coclass const *list);
85 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
87 /***********************************************************************
88 * static string constants
90 static WCHAR const interface_keyname[10] = {
91 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
92 static WCHAR const base_ifa_keyname[14] = {
93 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
95 static WCHAR const num_methods_keyname[11] = {
96 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
97 static WCHAR const ps_clsid_keyname[15] = {
98 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
100 static WCHAR const ps_clsid32_keyname[17] = {
101 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
102 'i', 'd', '3', '2', 0 };
103 static WCHAR const clsid_keyname[6] = {
104 'C', 'L', 'S', 'I', 'D', 0 };
105 static WCHAR const curver_keyname[7] = {
106 'C', 'u', 'r', 'V', 'e', 'r', 0 };
107 static WCHAR const iph32_keyname[] = {
108 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
110 static WCHAR const ips_keyname[13] = {
111 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
113 static WCHAR const ips32_keyname[15] = {
114 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
116 static WCHAR const progid_keyname[7] = {
117 'P', 'r', 'o', 'g', 'I', 'D', 0 };
118 static WCHAR const viprogid_keyname[25] = {
119 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
120 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
122 static char const tmodel_valuename[] = "ThreadingModel";
124 /***********************************************************************
125 * static helper functions
127 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
128 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
130 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
132 static LONG register_progid(WCHAR const *clsid,
133 char const *progid, char const *curver_progid,
134 char const *name, char const *extra);
135 static LONG recursive_delete_key(HKEY key);
136 static LONG recursive_delete_keyA(HKEY base, char const *name);
137 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
139 /***********************************************************************
140 * register_interfaces
142 static HRESULT register_interfaces(struct regsvr_interface const *list) {
143 LONG res = ERROR_SUCCESS;
146 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
147 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
148 if (res != ERROR_SUCCESS) goto error_return;
150 for (; res == ERROR_SUCCESS && list->iid; ++list) {
154 StringFromGUID2(list->iid, buf, 39);
155 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
156 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
157 if (res != ERROR_SUCCESS) goto error_close_interface_key;
160 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
161 (CONST BYTE*)(list->name),
162 strlen(list->name) + 1);
163 if (res != ERROR_SUCCESS) goto error_close_iid_key;
166 if (list->base_iid) {
167 res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
168 if (res != ERROR_SUCCESS) goto error_close_iid_key;
171 if (0 <= list->num_methods) {
172 static WCHAR const fmt[3] = { '%', 'd', 0 };
175 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
176 KEY_READ | KEY_WRITE, NULL, &key, NULL);
177 if (res != ERROR_SUCCESS) goto error_close_iid_key;
179 wsprintfW(buf, fmt, list->num_methods);
180 res = RegSetValueExW(key, NULL, 0, REG_SZ,
182 (lstrlenW(buf) + 1) * sizeof(WCHAR));
185 if (res != ERROR_SUCCESS) goto error_close_iid_key;
188 if (list->ps_clsid) {
189 res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
190 if (res != ERROR_SUCCESS) goto error_close_iid_key;
193 if (list->ps_clsid32) {
194 res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
195 if (res != ERROR_SUCCESS) goto error_close_iid_key;
199 RegCloseKey(iid_key);
202 error_close_interface_key:
203 RegCloseKey(interface_key);
205 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
208 /***********************************************************************
209 * unregister_interfaces
211 static HRESULT unregister_interfaces(struct regsvr_interface const *list) {
212 LONG res = ERROR_SUCCESS;
215 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
216 KEY_READ | KEY_WRITE, &interface_key);
217 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
218 if (res != ERROR_SUCCESS) goto error_return;
220 for (; res == ERROR_SUCCESS && list->iid; ++list) {
223 StringFromGUID2(list->iid, buf, 39);
224 res = recursive_delete_keyW(interface_key, buf);
227 RegCloseKey(interface_key);
229 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
232 /***********************************************************************
235 static HRESULT register_coclasses(struct regsvr_coclass const *list) {
236 LONG res = ERROR_SUCCESS;
239 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
240 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
241 if (res != ERROR_SUCCESS) goto error_return;
243 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
247 StringFromGUID2(list->clsid, buf, 39);
248 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
249 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
250 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
253 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
254 (CONST BYTE*)(list->name),
255 strlen(list->name) + 1);
256 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
262 res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
263 KEY_READ | KEY_WRITE, NULL,
265 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
267 res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
268 (CONST BYTE*)list->iph32,
269 lstrlenA(list->iph32) + 1);
270 RegCloseKey(iph32_key);
271 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
275 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
276 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
282 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
283 KEY_READ | KEY_WRITE, NULL,
285 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
288 (CONST BYTE*)list->ips32,
289 lstrlenA(list->ips32) + 1);
290 if (res == ERROR_SUCCESS && list->ips32_tmodel)
291 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
292 (CONST BYTE*)list->ips32_tmodel,
293 strlen(list->ips32_tmodel) + 1);
294 RegCloseKey(ips32_key);
295 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
299 res = register_key_defvalueA(clsid_key, progid_keyname,
301 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
303 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
305 list->name, list->progid_extra);
306 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
309 if (list->viprogid) {
310 res = register_key_defvalueA(clsid_key, viprogid_keyname,
312 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
314 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
315 list->viprogid, list->progid,
316 list->name, list->progid_extra);
317 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
320 error_close_clsid_key:
321 RegCloseKey(clsid_key);
324 error_close_coclass_key:
325 RegCloseKey(coclass_key);
327 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
330 /***********************************************************************
331 * unregister_coclasses
333 static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
334 LONG res = ERROR_SUCCESS;
337 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
338 KEY_READ | KEY_WRITE, &coclass_key);
339 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
340 if (res != ERROR_SUCCESS) goto error_return;
342 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
345 StringFromGUID2(list->clsid, buf, 39);
346 res = recursive_delete_keyW(coclass_key, buf);
347 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
350 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
351 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
354 if (list->viprogid) {
355 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
356 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
360 error_close_coclass_key:
361 RegCloseKey(coclass_key);
363 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
366 /***********************************************************************
369 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
372 StringFromGUID2(guid, buf, 39);
373 return register_key_defvalueW(base, name, buf);
376 /***********************************************************************
377 * regsvr_key_defvalueW
379 static LONG register_key_defvalueW(
382 WCHAR const *value) {
386 res = RegCreateKeyExW(base, name, 0, NULL, 0,
387 KEY_READ | KEY_WRITE, NULL, &key, NULL);
388 if (res != ERROR_SUCCESS) return res;
389 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
390 (lstrlenW(value) + 1) * sizeof(WCHAR));
395 /***********************************************************************
396 * regsvr_key_defvalueA
398 static LONG register_key_defvalueA(
405 res = RegCreateKeyExW(base, name, 0, NULL, 0,
406 KEY_READ | KEY_WRITE, NULL, &key, NULL);
407 if (res != ERROR_SUCCESS) return res;
408 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
409 lstrlenA(value) + 1);
414 /***********************************************************************
417 static LONG register_progid(
420 char const *curver_progid,
426 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
427 NULL, 0, KEY_READ | KEY_WRITE, NULL,
429 if (res != ERROR_SUCCESS) return res;
432 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
433 (CONST BYTE*)name, strlen(name) + 1);
434 if (res != ERROR_SUCCESS) goto error_close_progid_key;
438 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
439 if (res != ERROR_SUCCESS) goto error_close_progid_key;
443 res = register_key_defvalueA(progid_key, curver_keyname,
445 if (res != ERROR_SUCCESS) goto error_close_progid_key;
451 res = RegCreateKeyExA(progid_key, extra, 0,
452 NULL, 0, KEY_READ | KEY_WRITE, NULL,
454 if (res == ERROR_SUCCESS)
455 RegCloseKey(extra_key);
458 error_close_progid_key:
459 RegCloseKey(progid_key);
463 /***********************************************************************
464 * recursive_delete_key
466 static LONG recursive_delete_key(HKEY key) {
468 WCHAR subkey_name[MAX_PATH];
473 cName = sizeof(subkey_name) / sizeof(WCHAR);
474 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
475 NULL, NULL, NULL, NULL);
476 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
477 res = ERROR_SUCCESS; /* presumably we're done enumerating */
480 res = RegOpenKeyExW(key, subkey_name, 0,
481 KEY_READ | KEY_WRITE, &subkey);
482 if (res == ERROR_FILE_NOT_FOUND) continue;
483 if (res != ERROR_SUCCESS) break;
485 res = recursive_delete_key(subkey);
487 if (res != ERROR_SUCCESS) break;
490 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
494 /***********************************************************************
495 * recursive_delete_keyA
497 static LONG recursive_delete_keyA(HKEY base, char const *name) {
501 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
502 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
503 if (res != ERROR_SUCCESS) return res;
504 res = recursive_delete_key(key);
509 /***********************************************************************
510 * recursive_delete_keyW
512 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) {
516 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
517 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
518 if (res != ERROR_SUCCESS) return res;
519 res = recursive_delete_key(key);
524 /***********************************************************************
527 static struct regsvr_coclass const coclass_list[] = {
530 "Msi install server",
540 &CLSID_IMsiServerMessage,
541 "Wine Installer Message RPC",
547 "WindowsInstaller.Message",
552 "Msi install server",
558 "WindowsInstaller.Installer",
563 "Msi install server",
569 "WindowsInstaller.Installer",
574 "Msi install server",
580 "WindowsInstaller.Installer",
583 { NULL } /* list terminator */
586 /***********************************************************************
590 * we should declare: (@see ole32/regsvr.c for examples)
591 [-HKEY_CLASSES_ROOT\Interface\{000C101C-0000-0000-C000-000000000046}]
592 [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
593 [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
594 [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
595 [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
596 [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
597 [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
598 [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
599 [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
600 [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
601 [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
602 [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
603 [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
605 static struct regsvr_interface const interface_list[] = {
606 { NULL } /* list terminator */
609 static HRESULT register_msiexec(void)
611 static const WCHAR key[] = {
612 'S','o','f','t','w','a','r','e',
613 '\\','M','i','c','r','o','s','o','f','t',
614 '\\','W','i','n','d','o','w','s',
615 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
616 '\\','I','n','s','t','a','l','l','e','r',0 };
617 static const WCHAR val[] = {
618 'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
619 WCHAR path[MAX_PATH];
624 len = GetSystemDirectoryW(path, MAX_PATH);
625 if (!len || len > MAX_PATH)
628 res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0,
629 NULL, 0, KEY_READ | KEY_WRITE, NULL,
631 if (res != ERROR_SUCCESS)
634 res = RegSetValueExW(hkey, val, 0, REG_SZ,
635 (BYTE*)path, (len + 1)*sizeof(WCHAR));
639 return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
642 /***********************************************************************
643 * DllRegisterServer (MSI.@)
645 HRESULT WINAPI DllRegisterServer(void)
651 hr = register_coclasses(coclass_list);
653 hr = register_interfaces(interface_list);
655 hr = register_msiexec();
659 /***********************************************************************
660 * DllUnregisterServer (MSI.@)
662 HRESULT WINAPI DllUnregisterServer(void)
668 hr = unregister_coclasses(coclass_list);
670 hr = unregister_interfaces(interface_list);