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"
39 #include "wine/unicode.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48 * Near the bottom of this file are the exported DllRegisterServer and
49 * DllUnregisterServer, which make all this worthwhile.
52 /***********************************************************************
53 * interface for self-registering
55 struct regsvr_interface {
56 IID const *iid; /* NULL for end of list */
57 LPCSTR name; /* can be NULL to omit */
58 IID const *base_iid; /* can be NULL to omit */
59 int num_methods; /* can be <0 to omit */
60 CLSID const *ps_clsid; /* can be NULL to omit */
61 CLSID const *ps_clsid32; /* can be NULL to omit */
64 static HRESULT register_interfaces(struct regsvr_interface const *list);
65 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
68 * @todo: maybe adding typelibs support here
69 * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217
70 * @="{000C1092-0000-0000-C000-000000000046}"
72 struct regsvr_coclass {
73 CLSID const *clsid; /* NULL for end of list */
74 LPCSTR name; /* can be NULL to omit */
75 LPCSTR iph32; /* can be NULL to omit */
76 LPCSTR ips; /* can be NULL to omit */
77 LPCSTR ips32; /* can be NULL to omit */
78 LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */
80 LPCSTR progid; /* can be NULL to omit */
81 LPCSTR viprogid; /* can be NULL to omit */
82 LPCSTR progid_extra; /* can be NULL to omit */
83 LPCSTR dllversion; /* can be NULL to omit */
86 /* flags for regsvr_coclass.flags */
87 #define PROGID_CLSID 0x00000010
89 static HRESULT register_coclasses(struct regsvr_coclass const *list);
90 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
92 /***********************************************************************
93 * static string constants
95 static WCHAR const interface_keyname[10] = {
96 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
97 static WCHAR const base_ifa_keyname[14] = {
98 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
100 static WCHAR const num_methods_keyname[11] = {
101 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
102 static WCHAR const ps_clsid_keyname[15] = {
103 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
105 static WCHAR const ps_clsid32_keyname[17] = {
106 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
107 'i', 'd', '3', '2', 0 };
108 static WCHAR const clsid_keyname[6] = {
109 'C', 'L', 'S', 'I', 'D', 0 };
110 static WCHAR const curver_keyname[7] = {
111 'C', 'u', 'r', 'V', 'e', 'r', 0 };
112 static WCHAR const iph32_keyname[] = {
113 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
115 static WCHAR const ips_keyname[13] = {
116 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
118 static WCHAR const ips32_keyname[15] = {
119 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
121 static WCHAR const progid_keyname[7] = {
122 'P', 'r', 'o', 'g', 'I', 'D', 0 };
123 static WCHAR const viprogid_keyname[25] = {
124 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
125 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
127 static WCHAR const dllversion_keyname[11] = {
128 'D', 'l', 'l', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 };
129 static char const tmodel_valuename[] = "ThreadingModel";
131 /***********************************************************************
132 * static helper functions
134 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
135 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
137 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
139 static LONG register_progid(WCHAR const *clsid,
140 char const *progid, char const *curver_progid,
141 char const *name, char const *extra);
143 /***********************************************************************
144 * register_interfaces
146 static HRESULT register_interfaces(struct regsvr_interface const *list) {
147 LONG res = ERROR_SUCCESS;
150 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
151 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
152 if (res != ERROR_SUCCESS) goto error_return;
154 for (; res == ERROR_SUCCESS && list->iid; ++list) {
158 StringFromGUID2(list->iid, buf, 39);
159 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
160 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
161 if (res != ERROR_SUCCESS) goto error_close_interface_key;
164 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
165 (CONST BYTE*)(list->name),
166 strlen(list->name) + 1);
167 if (res != ERROR_SUCCESS) goto error_close_iid_key;
170 if (list->base_iid) {
171 res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
172 if (res != ERROR_SUCCESS) goto error_close_iid_key;
175 if (0 <= list->num_methods) {
176 static WCHAR const fmt[3] = { '%', 'd', 0 };
179 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
180 KEY_READ | KEY_WRITE, NULL, &key, NULL);
181 if (res != ERROR_SUCCESS) goto error_close_iid_key;
183 sprintfW(buf, fmt, list->num_methods);
184 res = RegSetValueExW(key, NULL, 0, REG_SZ,
186 (lstrlenW(buf) + 1) * sizeof(WCHAR));
189 if (res != ERROR_SUCCESS) goto error_close_iid_key;
192 if (list->ps_clsid) {
193 res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
194 if (res != ERROR_SUCCESS) goto error_close_iid_key;
197 if (list->ps_clsid32) {
198 res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
199 if (res != ERROR_SUCCESS) goto error_close_iid_key;
203 RegCloseKey(iid_key);
206 error_close_interface_key:
207 RegCloseKey(interface_key);
209 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
212 /***********************************************************************
213 * unregister_interfaces
215 static HRESULT unregister_interfaces(struct regsvr_interface const *list) {
216 LONG res = ERROR_SUCCESS;
219 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
220 KEY_READ | KEY_WRITE, &interface_key);
221 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
222 if (res != ERROR_SUCCESS) goto error_return;
224 for (; res == ERROR_SUCCESS && list->iid; ++list) {
227 StringFromGUID2(list->iid, buf, 39);
228 res = RegDeleteTreeW(interface_key, buf);
229 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
232 RegCloseKey(interface_key);
234 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
237 /***********************************************************************
240 static HRESULT register_coclasses(struct regsvr_coclass const *list) {
241 LONG res = ERROR_SUCCESS;
244 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
245 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
246 if (res != ERROR_SUCCESS) goto error_return;
248 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
252 StringFromGUID2(list->clsid, buf, 39);
253 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
254 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
255 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
258 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
259 (CONST BYTE*)(list->name),
260 strlen(list->name) + 1);
261 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
267 res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
268 KEY_READ | KEY_WRITE, NULL,
270 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
272 res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
273 (CONST BYTE*)list->iph32,
274 lstrlenA(list->iph32) + 1);
275 RegCloseKey(iph32_key);
276 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
280 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
281 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
288 KEY_READ | KEY_WRITE, NULL,
290 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
292 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
293 (CONST BYTE*)list->ips32,
294 lstrlenA(list->ips32) + 1);
295 if (res == ERROR_SUCCESS && list->ips32_tmodel)
296 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
297 (CONST BYTE*)list->ips32_tmodel,
298 strlen(list->ips32_tmodel) + 1);
299 RegCloseKey(ips32_key);
300 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
304 res = register_key_defvalueA(clsid_key, progid_keyname,
306 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
308 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
310 list->name, list->progid_extra);
311 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
314 if (list->viprogid) {
315 res = register_key_defvalueA(clsid_key, viprogid_keyname,
317 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
319 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
320 list->viprogid, list->progid,
321 list->name, list->progid_extra);
322 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
325 if (list->dllversion) {
328 res = RegCreateKeyExW(clsid_key, dllversion_keyname, 0, NULL, 0,
329 KEY_READ | KEY_WRITE, NULL,
331 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
333 res = RegSetValueExA(dllver_key, NULL, 0, REG_SZ,
334 (CONST BYTE*)list->dllversion,
335 lstrlenA(list->dllversion) + 1);
336 RegCloseKey(dllver_key);
337 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
341 error_close_clsid_key:
342 RegCloseKey(clsid_key);
345 error_close_coclass_key:
346 RegCloseKey(coclass_key);
348 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
351 /***********************************************************************
352 * unregister_coclasses
354 static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
355 LONG res = ERROR_SUCCESS;
358 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
359 KEY_READ | KEY_WRITE, &coclass_key);
360 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
361 if (res != ERROR_SUCCESS) goto error_return;
363 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
366 StringFromGUID2(list->clsid, buf, 39);
367 res = RegDeleteTreeW(coclass_key, buf);
368 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
369 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
372 res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
373 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
374 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
377 if (list->viprogid) {
378 res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
379 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
380 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
384 error_close_coclass_key:
385 RegCloseKey(coclass_key);
387 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
390 /***********************************************************************
393 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
396 StringFromGUID2(guid, buf, 39);
397 return register_key_defvalueW(base, name, buf);
400 /***********************************************************************
401 * regsvr_key_defvalueW
403 static LONG register_key_defvalueW(
406 WCHAR const *value) {
410 res = RegCreateKeyExW(base, name, 0, NULL, 0,
411 KEY_READ | KEY_WRITE, NULL, &key, NULL);
412 if (res != ERROR_SUCCESS) return res;
413 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
414 (lstrlenW(value) + 1) * sizeof(WCHAR));
419 /***********************************************************************
420 * regsvr_key_defvalueA
422 static LONG register_key_defvalueA(
429 res = RegCreateKeyExW(base, name, 0, NULL, 0,
430 KEY_READ | KEY_WRITE, NULL, &key, NULL);
431 if (res != ERROR_SUCCESS) return res;
432 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
433 lstrlenA(value) + 1);
438 /***********************************************************************
441 static LONG register_progid(
444 char const *curver_progid,
450 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
451 NULL, 0, KEY_READ | KEY_WRITE, NULL,
453 if (res != ERROR_SUCCESS) return res;
456 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
457 (CONST BYTE*)name, strlen(name) + 1);
458 if (res != ERROR_SUCCESS) goto error_close_progid_key;
462 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
463 if (res != ERROR_SUCCESS) goto error_close_progid_key;
467 res = register_key_defvalueA(progid_key, curver_keyname,
469 if (res != ERROR_SUCCESS) goto error_close_progid_key;
475 res = RegCreateKeyExA(progid_key, extra, 0,
476 NULL, 0, KEY_READ | KEY_WRITE, NULL,
478 if (res == ERROR_SUCCESS)
479 RegCloseKey(extra_key);
482 error_close_progid_key:
483 RegCloseKey(progid_key);
487 /***********************************************************************
490 static struct regsvr_coclass const coclass_list[] = {
493 "Msi install server",
505 &CLSID_IMsiServerMessage,
506 "Wine Installer Message RPC",
512 "WindowsInstaller.Message",
519 "Msi install server",
525 "WindowsInstaller.Installer",
532 "Msi install server",
538 "WindowsInstaller.Installer",
545 "Msi install server",
551 "WindowsInstaller.Installer",
556 { NULL } /* list terminator */
559 /***********************************************************************
563 * we should declare: (@see ole32/regsvr.c for examples)
564 [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
565 [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
566 [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
567 [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
568 [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
569 [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
570 [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
571 [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
572 [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
573 [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
574 [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
575 [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
578 static struct regsvr_interface const interface_list[] = {
585 { NULL } /* list terminator */
588 static HRESULT register_msiexec(void)
590 static const WCHAR key[] = {
591 'S','o','f','t','w','a','r','e',
592 '\\','M','i','c','r','o','s','o','f','t',
593 '\\','W','i','n','d','o','w','s',
594 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
595 '\\','I','n','s','t','a','l','l','e','r',0 };
596 static const WCHAR val[] = {
597 'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
598 WCHAR path[MAX_PATH];
603 len = GetSystemDirectoryW(path, MAX_PATH);
604 if (!len || len > MAX_PATH)
607 res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0,
608 NULL, 0, KEY_READ | KEY_WRITE, NULL,
610 if (res != ERROR_SUCCESS)
613 res = RegSetValueExW(hkey, val, 0, REG_SZ,
614 (BYTE*)path, (len + 1)*sizeof(WCHAR));
618 return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
621 /***********************************************************************
622 * DllRegisterServer (MSI.@)
624 HRESULT WINAPI DllRegisterServer(void)
632 hr = register_coclasses(coclass_list);
634 hr = register_interfaces(interface_list);
636 hr = register_msiexec();
638 tl = get_msi_typelib( &path );
641 hr = RegisterTypeLib( tl, path, NULL );
642 ITypeLib_Release( tl );
650 /***********************************************************************
651 * DllUnregisterServer (MSI.@)
653 HRESULT WINAPI DllUnregisterServer(void)
659 hr = unregister_coclasses(coclass_list);
661 hr = unregister_interfaces(interface_list);