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);
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 = RegDeleteTreeW(interface_key, buf);
225 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
228 RegCloseKey(interface_key);
230 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
233 /***********************************************************************
236 static HRESULT register_coclasses(struct regsvr_coclass const *list) {
237 LONG res = ERROR_SUCCESS;
240 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
241 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
242 if (res != ERROR_SUCCESS) goto error_return;
244 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
248 StringFromGUID2(list->clsid, buf, 39);
249 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
250 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
251 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
254 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
255 (CONST BYTE*)(list->name),
256 strlen(list->name) + 1);
257 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
263 res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
264 KEY_READ | KEY_WRITE, NULL,
266 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
268 res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
269 (CONST BYTE*)list->iph32,
270 lstrlenA(list->iph32) + 1);
271 RegCloseKey(iph32_key);
272 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
276 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
277 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
283 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
284 KEY_READ | KEY_WRITE, NULL,
286 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
288 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
289 (CONST BYTE*)list->ips32,
290 lstrlenA(list->ips32) + 1);
291 if (res == ERROR_SUCCESS && list->ips32_tmodel)
292 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
293 (CONST BYTE*)list->ips32_tmodel,
294 strlen(list->ips32_tmodel) + 1);
295 RegCloseKey(ips32_key);
296 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
300 res = register_key_defvalueA(clsid_key, progid_keyname,
302 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
304 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
306 list->name, list->progid_extra);
307 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
310 if (list->viprogid) {
311 res = register_key_defvalueA(clsid_key, viprogid_keyname,
313 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
315 res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
316 list->viprogid, list->progid,
317 list->name, list->progid_extra);
318 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
321 error_close_clsid_key:
322 RegCloseKey(clsid_key);
325 error_close_coclass_key:
326 RegCloseKey(coclass_key);
328 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
331 /***********************************************************************
332 * unregister_coclasses
334 static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
335 LONG res = ERROR_SUCCESS;
338 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
339 KEY_READ | KEY_WRITE, &coclass_key);
340 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
341 if (res != ERROR_SUCCESS) goto error_return;
343 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
346 StringFromGUID2(list->clsid, buf, 39);
347 res = RegDeleteTreeW(coclass_key, buf);
348 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
349 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
352 res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
353 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
354 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
357 if (list->viprogid) {
358 res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
359 if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
360 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
364 error_close_coclass_key:
365 RegCloseKey(coclass_key);
367 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
370 /***********************************************************************
373 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
376 StringFromGUID2(guid, buf, 39);
377 return register_key_defvalueW(base, name, buf);
380 /***********************************************************************
381 * regsvr_key_defvalueW
383 static LONG register_key_defvalueW(
386 WCHAR const *value) {
390 res = RegCreateKeyExW(base, name, 0, NULL, 0,
391 KEY_READ | KEY_WRITE, NULL, &key, NULL);
392 if (res != ERROR_SUCCESS) return res;
393 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
394 (lstrlenW(value) + 1) * sizeof(WCHAR));
399 /***********************************************************************
400 * regsvr_key_defvalueA
402 static LONG register_key_defvalueA(
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 = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
413 lstrlenA(value) + 1);
418 /***********************************************************************
421 static LONG register_progid(
424 char const *curver_progid,
430 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
431 NULL, 0, KEY_READ | KEY_WRITE, NULL,
433 if (res != ERROR_SUCCESS) return res;
436 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
437 (CONST BYTE*)name, strlen(name) + 1);
438 if (res != ERROR_SUCCESS) goto error_close_progid_key;
442 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
443 if (res != ERROR_SUCCESS) goto error_close_progid_key;
447 res = register_key_defvalueA(progid_key, curver_keyname,
449 if (res != ERROR_SUCCESS) goto error_close_progid_key;
455 res = RegCreateKeyExA(progid_key, extra, 0,
456 NULL, 0, KEY_READ | KEY_WRITE, NULL,
458 if (res == ERROR_SUCCESS)
459 RegCloseKey(extra_key);
462 error_close_progid_key:
463 RegCloseKey(progid_key);
467 /***********************************************************************
470 static struct regsvr_coclass const coclass_list[] = {
473 "Msi install server",
483 &CLSID_IMsiServerMessage,
484 "Wine Installer Message RPC",
490 "WindowsInstaller.Message",
495 "Msi install server",
501 "WindowsInstaller.Installer",
506 "Msi install server",
512 "WindowsInstaller.Installer",
517 "Msi install server",
523 "WindowsInstaller.Installer",
526 { NULL } /* list terminator */
529 /***********************************************************************
533 * we should declare: (@see ole32/regsvr.c for examples)
534 [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
535 [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
536 [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
537 [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
538 [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
539 [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
540 [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
541 [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
542 [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
543 [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
544 [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
545 [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
548 static struct regsvr_interface const interface_list[] = {
555 { NULL } /* list terminator */
558 static HRESULT register_msiexec(void)
560 static const WCHAR key[] = {
561 'S','o','f','t','w','a','r','e',
562 '\\','M','i','c','r','o','s','o','f','t',
563 '\\','W','i','n','d','o','w','s',
564 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
565 '\\','I','n','s','t','a','l','l','e','r',0 };
566 static const WCHAR val[] = {
567 'I','n','s','t','a','l','l','e','r','L','o','c','a','t','i','o','n',0 };
568 WCHAR path[MAX_PATH];
573 len = GetSystemDirectoryW(path, MAX_PATH);
574 if (!len || len > MAX_PATH)
577 res = RegCreateKeyExW(HKEY_LOCAL_MACHINE, key, 0,
578 NULL, 0, KEY_READ | KEY_WRITE, NULL,
580 if (res != ERROR_SUCCESS)
583 res = RegSetValueExW(hkey, val, 0, REG_SZ,
584 (BYTE*)path, (len + 1)*sizeof(WCHAR));
588 return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
591 /***********************************************************************
592 * DllRegisterServer (MSI.@)
594 HRESULT WINAPI DllRegisterServer(void)
602 hr = register_coclasses(coclass_list);
604 hr = register_interfaces(interface_list);
606 hr = register_msiexec();
608 tl = get_msi_typelib( &path );
611 hr = RegisterTypeLib( tl, path, NULL );
612 ITypeLib_Release( tl );
620 /***********************************************************************
621 * DllUnregisterServer (MSI.@)
623 HRESULT WINAPI DllUnregisterServer(void)
629 hr = unregister_coclasses(coclass_list);
631 hr = unregister_interfaces(interface_list);