2 * self-registerable dll functions for shdocvw.dll
4 * Copyright (C) 2003 John K. Hohm
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
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
37 * Near the bottom of this file are the exported DllRegisterServer and
38 * DllUnregisterServer, which make all this worthwhile.
41 /***********************************************************************
42 * interface for self-registering
44 struct regsvr_interface
46 IID const *iid; /* NULL for end of list */
47 LPCSTR name; /* can be NULL to omit */
48 IID const *base_iid; /* can be NULL to omit */
49 int num_methods; /* can be <0 to omit */
50 CLSID const *ps_clsid; /* can be NULL to omit */
51 CLSID const *ps_clsid32; /* can be NULL to omit */
54 static HRESULT register_interfaces(struct regsvr_interface const *list);
55 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
59 CLSID const *clsid; /* NULL for end of list */
60 LPCSTR name; /* can be NULL to omit */
61 LPCSTR ips; /* can be NULL to omit */
62 LPCSTR ips32; /* can be NULL to omit */
63 LPCSTR ips32_tmodel; /* can be NULL to omit */
64 LPCSTR progid; /* can be NULL to omit */
65 LPCSTR viprogid; /* can be NULL to omit */
66 LPCSTR progid_extra; /* can be NULL to omit */
69 DWORD dwCallForAttributes;
72 /* flags for regsvr_coclass.flags */
73 #define SHELLEX_MAYCHANGEDEFAULTMENU 0x00000001
74 #define SHELLFOLDER_WANTSFORPARSING 0x00000002
75 #define SHELLFOLDER_ATTRIBUTES 0x00000004
76 #define SHELLFOLDER_CALLFORATTRIBUTES 0x00000008
78 static HRESULT register_coclasses(struct regsvr_coclass const *list);
79 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
81 /***********************************************************************
82 * static string constants
84 static WCHAR const interface_keyname[10] = {
85 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
86 static WCHAR const base_ifa_keyname[14] = {
87 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
89 static WCHAR const num_methods_keyname[11] = {
90 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
91 static WCHAR const ps_clsid_keyname[15] = {
92 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
94 static WCHAR const ps_clsid32_keyname[17] = {
95 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
96 'i', 'd', '3', '2', 0 };
97 static WCHAR const clsid_keyname[6] = {
98 'C', 'L', 'S', 'I', 'D', 0 };
99 static WCHAR const curver_keyname[7] = {
100 'C', 'u', 'r', 'V', 'e', 'r', 0 };
101 static WCHAR const ips_keyname[13] = {
102 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
104 static WCHAR const ips32_keyname[15] = {
105 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
107 static WCHAR const progid_keyname[7] = {
108 'P', 'r', 'o', 'g', 'I', 'D', 0 };
109 static WCHAR const viprogid_keyname[25] = {
110 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
111 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
113 static WCHAR const shellex_keyname[8] = {
114 's', 'h', 'e', 'l', 'l', 'e', 'x', 0 };
115 static WCHAR const shellfolder_keyname[12] = {
116 'S', 'h', 'e', 'l', 'l', 'F', 'o', 'l', 'd', 'e', 'r', 0 };
117 static WCHAR const mcdm_keyname[21] = {
118 'M', 'a', 'y', 'C', 'h', 'a', 'n', 'g', 'e', 'D', 'e', 'f',
119 'a', 'u', 'l', 't', 'M', 'e', 'n', 'u', 0 };
120 static char const tmodel_valuename[] = "ThreadingModel";
121 static char const wfparsing_valuename[] = "WantsFORPARSING";
122 static char const attributes_valuename[] = "Attributes";
123 static char const cfattributes_valuename[] = "CallForAttributes";
124 static WCHAR const lcs32_keyname[] = {
125 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
126 static const WCHAR szIERelPath[] = {
127 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
128 'i','e','x','p','l','o','r','e','.','e','x','e',0 };
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);
141 static LONG recursive_delete_key(HKEY key);
142 static LONG recursive_delete_keyA(HKEY base, char const *name);
143 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
145 /***********************************************************************
146 * register_interfaces
148 static HRESULT register_interfaces(struct regsvr_interface const *list)
150 LONG res = ERROR_SUCCESS;
153 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
154 KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
155 if (res != ERROR_SUCCESS) goto error_return;
157 for (; res == ERROR_SUCCESS && list->iid; ++list) {
161 StringFromGUID2(list->iid, buf, 39);
162 res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
163 KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
164 if (res != ERROR_SUCCESS) goto error_close_interface_key;
167 res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
168 (CONST BYTE*)(list->name),
169 strlen(list->name) + 1);
170 if (res != ERROR_SUCCESS) goto error_close_iid_key;
173 if (list->base_iid) {
174 res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
175 if (res != ERROR_SUCCESS) goto error_close_iid_key;
178 if (0 <= list->num_methods) {
179 static WCHAR const fmt[3] = { '%', 'd', 0 };
182 res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
183 KEY_READ | KEY_WRITE, NULL, &key, NULL);
184 if (res != ERROR_SUCCESS) goto error_close_iid_key;
186 wsprintfW(buf, fmt, list->num_methods);
187 res = RegSetValueExW(key, NULL, 0, REG_SZ,
189 (lstrlenW(buf) + 1) * sizeof(WCHAR));
192 if (res != ERROR_SUCCESS) goto error_close_iid_key;
195 if (list->ps_clsid) {
196 res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
197 if (res != ERROR_SUCCESS) goto error_close_iid_key;
200 if (list->ps_clsid32) {
201 res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
202 if (res != ERROR_SUCCESS) goto error_close_iid_key;
206 RegCloseKey(iid_key);
209 error_close_interface_key:
210 RegCloseKey(interface_key);
212 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
215 /***********************************************************************
216 * unregister_interfaces
218 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
220 LONG res = ERROR_SUCCESS;
223 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
224 KEY_READ | KEY_WRITE, &interface_key);
225 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
226 if (res != ERROR_SUCCESS) goto error_return;
228 for (; res == ERROR_SUCCESS && list->iid; ++list) {
231 StringFromGUID2(list->iid, buf, 39);
232 res = recursive_delete_keyW(interface_key, buf);
235 RegCloseKey(interface_key);
237 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
240 /***********************************************************************
243 static HRESULT register_coclasses(struct regsvr_coclass const *list)
245 LONG res = ERROR_SUCCESS;
248 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
249 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
250 if (res != ERROR_SUCCESS) goto error_return;
252 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
256 StringFromGUID2(list->clsid, buf, 39);
257 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
258 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
259 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
262 res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
263 (CONST BYTE*)(list->name),
264 strlen(list->name) + 1);
265 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
269 res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
270 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
276 res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
277 KEY_READ | KEY_WRITE, NULL,
279 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
281 res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
282 (CONST BYTE*)list->ips32,
283 lstrlenA(list->ips32) + 1);
284 if (res == ERROR_SUCCESS && list->ips32_tmodel)
285 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
286 (CONST BYTE*)list->ips32_tmodel,
287 strlen(list->ips32_tmodel) + 1);
288 RegCloseKey(ips32_key);
289 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
292 if (list->flags & SHELLEX_MAYCHANGEDEFAULTMENU) {
293 HKEY shellex_key, mcdm_key;
295 res = RegCreateKeyExW(clsid_key, shellex_keyname, 0, NULL, 0,
296 KEY_READ | KEY_WRITE, NULL,
298 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
299 res = RegCreateKeyExW(shellex_key, mcdm_keyname, 0, NULL, 0,
300 KEY_READ | KEY_WRITE, NULL,
302 RegCloseKey(shellex_key);
303 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
304 RegCloseKey(mcdm_key);
308 (SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES))
310 HKEY shellfolder_key;
312 res = RegCreateKeyExW(clsid_key, shellfolder_keyname, 0, NULL, 0,
313 KEY_READ | KEY_WRITE, NULL,
314 &shellfolder_key, NULL);
315 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
316 if (list->flags & SHELLFOLDER_WANTSFORPARSING)
317 res = RegSetValueExA(shellfolder_key, wfparsing_valuename, 0, REG_SZ, (const BYTE *)"", 1);
318 if (list->flags & SHELLFOLDER_ATTRIBUTES)
319 res = RegSetValueExA(shellfolder_key, attributes_valuename, 0, REG_DWORD,
320 (const BYTE *)&list->dwAttributes, sizeof(DWORD));
321 if (list->flags & SHELLFOLDER_CALLFORATTRIBUTES)
322 res = RegSetValueExA(shellfolder_key, cfattributes_valuename, 0, REG_DWORD,
323 (const BYTE *)&list->dwCallForAttributes, sizeof(DWORD));
324 RegCloseKey(shellfolder_key);
325 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
329 res = register_key_defvalueA(clsid_key, progid_keyname,
331 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
333 res = register_progid(buf, list->progid, NULL,
334 list->name, list->progid_extra);
335 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
338 if (list->viprogid) {
339 res = register_key_defvalueA(clsid_key, viprogid_keyname,
341 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
343 res = register_progid(buf, list->viprogid, list->progid,
344 list->name, list->progid_extra);
345 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
348 error_close_clsid_key:
349 RegCloseKey(clsid_key);
352 error_close_coclass_key:
353 RegCloseKey(coclass_key);
355 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
358 /***********************************************************************
359 * unregister_coclasses
361 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
363 LONG res = ERROR_SUCCESS;
366 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
367 KEY_READ | KEY_WRITE, &coclass_key);
368 if (res == ERROR_FILE_NOT_FOUND) return S_OK;
369 if (res != ERROR_SUCCESS) goto error_return;
371 for (; res == ERROR_SUCCESS && list->clsid; ++list) {
374 StringFromGUID2(list->clsid, buf, 39);
375 res = recursive_delete_keyW(coclass_key, buf);
376 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
379 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
380 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
383 if (list->viprogid) {
384 res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
385 if (res != ERROR_SUCCESS) goto error_close_coclass_key;
389 error_close_coclass_key:
390 RegCloseKey(coclass_key);
392 return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
395 /***********************************************************************
398 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
402 StringFromGUID2(guid, buf, 39);
403 return register_key_defvalueW(base, name, buf);
406 /***********************************************************************
407 * regsvr_key_defvalueW
409 static LONG register_key_defvalueW(
417 res = RegCreateKeyExW(base, name, 0, NULL, 0,
418 KEY_READ | KEY_WRITE, NULL, &key, NULL);
419 if (res != ERROR_SUCCESS) return res;
420 res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
421 (lstrlenW(value) + 1) * sizeof(WCHAR));
426 /***********************************************************************
427 * regsvr_key_defvalueA
429 static LONG register_key_defvalueA(
437 res = RegCreateKeyExW(base, name, 0, NULL, 0,
438 KEY_READ | KEY_WRITE, NULL, &key, NULL);
439 if (res != ERROR_SUCCESS) return res;
440 res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
441 lstrlenA(value) + 1);
446 /***********************************************************************
449 static LONG register_progid(
452 char const *curver_progid,
459 res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
460 NULL, 0, KEY_READ | KEY_WRITE, NULL,
462 if (res != ERROR_SUCCESS) return res;
465 res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
466 (CONST BYTE*)name, strlen(name) + 1);
467 if (res != ERROR_SUCCESS) goto error_close_progid_key;
471 res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
472 if (res != ERROR_SUCCESS) goto error_close_progid_key;
476 res = register_key_defvalueA(progid_key, curver_keyname,
478 if (res != ERROR_SUCCESS) goto error_close_progid_key;
484 res = RegCreateKeyExA(progid_key, extra, 0,
485 NULL, 0, KEY_READ | KEY_WRITE, NULL,
487 if (res == ERROR_SUCCESS)
488 RegCloseKey(extra_key);
491 error_close_progid_key:
492 RegCloseKey(progid_key);
496 /***********************************************************************
497 * recursive_delete_key
499 static LONG recursive_delete_key(HKEY key)
502 WCHAR subkey_name[MAX_PATH];
507 cName = sizeof(subkey_name) / sizeof(WCHAR);
508 res = RegEnumKeyExW(key, 0, subkey_name, &cName,
509 NULL, NULL, NULL, NULL);
510 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
511 res = ERROR_SUCCESS; /* presumably we're done enumerating */
514 res = RegOpenKeyExW(key, subkey_name, 0,
515 KEY_READ | KEY_WRITE, &subkey);
516 if (res == ERROR_FILE_NOT_FOUND) continue;
517 if (res != ERROR_SUCCESS) break;
519 res = recursive_delete_key(subkey);
521 if (res != ERROR_SUCCESS) break;
524 if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
528 /***********************************************************************
529 * recursive_delete_keyA
531 static LONG recursive_delete_keyA(HKEY base, char const *name)
536 res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
537 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
538 if (res != ERROR_SUCCESS) return res;
539 res = recursive_delete_key(key);
544 /***********************************************************************
545 * recursive_delete_keyW
547 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
552 res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
553 if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
554 if (res != ERROR_SUCCESS) return res;
555 res = recursive_delete_key(key);
561 static const GUID CLSID_MicrosoftBrowserArchitecture =
562 {0xa5e46e3a, 0x8849, 0x11d1, {0x9d, 0x8c, 0x00, 0xc0, 0x4f, 0xc9, 0x9d, 0x61}};
563 static const GUID CLSID_MruLongList =
564 {0x53bd6b4e, 0x3780, 0x4693, {0xaf, 0xc3, 0x71, 0x61, 0xc2, 0xf3, 0xee, 0x9c}};
566 /***********************************************************************
569 static struct regsvr_coclass const coclass_list[] = {
570 { &CLSID_WebBrowser_V1,
571 "Microsoft Web Browser Version 1",
579 "Microsoft Web Browser",
586 { &CLSID_InternetExplorer,
587 "Internet Explorer(Ver 1.0)",
591 "InternetExplorer.Application.1",
592 "InternetExplorer.Application"
594 { &CLSID_ShellSearchAssistantOC,
599 "SearchAssistantOC.SearchAssistantOC.1",
600 "SearchAssistantOC.SearchAssistantOC"
602 { &CLSID_ShellShellNameSpace,
607 "ShellNameSpace.ShellNameSpace.1",
608 "ShellNameSpace.ShellNameSpace"
610 { &CLSID_ShellNameSpace,
615 "ShellNameSpace.ShellNameSpace.1",
616 "ShellNameSpace.ShellNameSpace"
618 { &CLSID_ShellUIHelper,
619 "Microsoft Shell UI Helper",
626 { &CLSID_ShellWindows,
634 { &CLSID_SearchAssistantOC,
639 "SearchAssistantOC.SearchAssistantOC.1",
640 "SearchAssistantOC.SearchAssistantOC"
643 &CLSID_MicrosoftBrowserArchitecture,
644 "Microsoft Browser Architecture",
662 "Microsoft Url History Service",
678 SHELLFOLDER_ATTRIBUTES,
679 SFGAO_CANDELETE|SFGAO_CANLINK
681 { NULL } /* list terminator */
684 /***********************************************************************
688 static struct regsvr_interface const interface_list[] = {
689 { NULL } /* list terminator */
692 static HRESULT register_localserver(void)
694 HKEY coclass_key = 0, clsid_key = 0;
695 WCHAR buf[39], path[MAX_PATH];
699 res = SHGetFolderPathW(NULL, CSIDL_FLAG_CREATE|CSIDL_PROGRAM_FILES,
700 NULL, SHGFP_TYPE_CURRENT, path);
704 len = lstrlenW(path);
705 if ((len + (sizeof szIERelPath/sizeof(WCHAR)) + 1) > MAX_PATH)
709 lstrcpyW(&path[len+1], szIERelPath);
711 res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
712 KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
713 if (res != ERROR_SUCCESS) goto err;
715 StringFromGUID2(&CLSID_InternetExplorer, buf, 39);
716 res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
717 KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
718 if (res != ERROR_SUCCESS) goto err;
720 res = register_key_defvalueW(clsid_key, lcs32_keyname, path);
721 if (res != ERROR_SUCCESS) goto err;
724 if (clsid_key) RegCloseKey(clsid_key);
725 if (coclass_key) RegCloseKey(coclass_key);
726 return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
729 static HRESULT register_typelib(void)
734 static const WCHAR wszSHDocVw[] = {'s','h','d','o','c','v','w','.','d','l','l',0};
736 hres = LoadTypeLibEx(wszSHDocVw, REGKIND_REGISTER, &typelib);
738 ERR("Could not load typelib: %08x\n", hres);
742 ITypeLib_Release(typelib);
747 static HRESULT unregister_typelib(void)
749 return UnRegisterTypeLib(&LIBID_SHDocVw, 1, 1, LOCALE_SYSTEM_DEFAULT, SYS_WIN32);
752 /***********************************************************************
753 * DllRegisterServer (SHDOCVW.@)
755 HRESULT WINAPI DllRegisterServer(void)
761 hr = register_coclasses(coclass_list);
763 hr = register_interfaces(interface_list);
765 hr = register_localserver();
767 hr = register_typelib();
772 /***********************************************************************
773 * DllUnregisterServer (SHDOCVW.@)
775 HRESULT WINAPI DllUnregisterServer(void)
781 hr = unregister_coclasses(coclass_list);
783 hr = unregister_interfaces(interface_list);
785 hr = unregister_typelib();