2 * self-registerable dll functions for urlmon.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
37 #include "wine/debug.h"
39 #include "urlmon_main.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
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
53 IID
const *iid
; /* NULL for end of list */
54 LPCSTR name
; /* can be NULL to omit */
55 IID
const *base_iid
; /* can be NULL to omit */
56 int num_methods
; /* can be <0 to omit */
57 CLSID
const *ps_clsid
; /* can be NULL to omit */
58 CLSID
const *ps_clsid32
; /* can be NULL to omit */
61 static HRESULT
register_interfaces(struct regsvr_interface
const *list
);
62 static HRESULT
unregister_interfaces(struct regsvr_interface
const *list
);
66 CLSID
const *clsid
; /* NULL for end of list */
67 LPCSTR name
; /* can be NULL to omit */
68 LPCSTR ips
; /* can be NULL to omit */
69 LPCSTR ips32
; /* can be NULL to omit */
70 LPCSTR ips32_tmodel
; /* can be NULL to omit */
71 LPCSTR progid
; /* can be NULL to omit */
72 LPCSTR viprogid
; /* can be NULL to omit */
73 LPCSTR progid_extra
; /* can be NULL to omit */
76 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
);
77 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
);
79 /***********************************************************************
80 * static string constants
82 static WCHAR
const interface_keyname
[10] = {
83 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
84 static WCHAR
const base_ifa_keyname
[14] = {
85 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
87 static WCHAR
const num_methods_keyname
[11] = {
88 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
89 static WCHAR
const ps_clsid_keyname
[15] = {
90 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
92 static WCHAR
const ps_clsid32_keyname
[17] = {
93 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
94 'i', 'd', '3', '2', 0 };
95 static WCHAR
const clsid_keyname
[6] = {
96 'C', 'L', 'S', 'I', 'D', 0 };
97 static WCHAR
const curver_keyname
[7] = {
98 'C', 'u', 'r', 'V', 'e', 'r', 0 };
99 static WCHAR
const ips_keyname
[13] = {
100 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
102 static WCHAR
const ips32_keyname
[15] = {
103 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
105 static WCHAR
const progid_keyname
[7] = {
106 'P', 'r', 'o', 'g', 'I', 'D', 0 };
107 static WCHAR
const viprogid_keyname
[25] = {
108 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
109 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
111 static char const tmodel_valuename
[] = "ThreadingModel";
113 /***********************************************************************
114 * static helper functions
116 static LONG
register_key_guid(HKEY base
, WCHAR
const *name
, GUID
const *guid
);
117 static LONG
register_key_defvalueW(HKEY base
, WCHAR
const *name
,
119 static LONG
register_key_defvalueA(HKEY base
, WCHAR
const *name
,
121 static LONG
register_progid(WCHAR
const *clsid
,
122 char const *progid
, char const *curver_progid
,
123 char const *name
, char const *extra
);
124 static LONG
recursive_delete_key(HKEY key
);
125 static LONG
recursive_delete_keyA(HKEY base
, char const *name
);
126 static LONG
recursive_delete_keyW(HKEY base
, WCHAR
const *name
);
128 /***********************************************************************
129 * register_interfaces
131 static HRESULT
register_interfaces(struct regsvr_interface
const *list
)
133 LONG res
= ERROR_SUCCESS
;
136 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, interface_keyname
, 0, NULL
, 0,
137 KEY_READ
| KEY_WRITE
, NULL
, &interface_key
, NULL
);
138 if (res
!= ERROR_SUCCESS
) goto error_return
;
140 for (; res
== ERROR_SUCCESS
&& list
->iid
; ++list
) {
144 StringFromGUID2(list
->iid
, buf
, 39);
145 res
= RegCreateKeyExW(interface_key
, buf
, 0, NULL
, 0,
146 KEY_READ
| KEY_WRITE
, NULL
, &iid_key
, NULL
);
147 if (res
!= ERROR_SUCCESS
) goto error_close_interface_key
;
150 res
= RegSetValueExA(iid_key
, NULL
, 0, REG_SZ
,
151 (CONST BYTE
*)(list
->name
),
152 strlen(list
->name
) + 1);
153 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
156 if (list
->base_iid
) {
157 res
= register_key_guid(iid_key
, base_ifa_keyname
, list
->base_iid
);
158 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
161 if (0 <= list
->num_methods
) {
162 static WCHAR
const fmt
[3] = { '%', 'd', 0 };
165 res
= RegCreateKeyExW(iid_key
, num_methods_keyname
, 0, NULL
, 0,
166 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
167 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
169 wsprintfW(buf
, fmt
, list
->num_methods
);
170 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
,
172 (lstrlenW(buf
) + 1) * sizeof(WCHAR
));
175 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
178 if (list
->ps_clsid
) {
179 res
= register_key_guid(iid_key
, ps_clsid_keyname
, list
->ps_clsid
);
180 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
183 if (list
->ps_clsid32
) {
184 res
= register_key_guid(iid_key
, ps_clsid32_keyname
, list
->ps_clsid32
);
185 if (res
!= ERROR_SUCCESS
) goto error_close_iid_key
;
189 RegCloseKey(iid_key
);
192 error_close_interface_key
:
193 RegCloseKey(interface_key
);
195 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
198 /***********************************************************************
199 * unregister_interfaces
201 static HRESULT
unregister_interfaces(struct regsvr_interface
const *list
)
203 LONG res
= ERROR_SUCCESS
;
206 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, interface_keyname
, 0,
207 KEY_READ
| KEY_WRITE
, &interface_key
);
208 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
209 if (res
!= ERROR_SUCCESS
) goto error_return
;
211 for (; res
== ERROR_SUCCESS
&& list
->iid
; ++list
) {
214 StringFromGUID2(list
->iid
, buf
, 39);
215 res
= recursive_delete_keyW(interface_key
, buf
);
218 RegCloseKey(interface_key
);
220 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
223 /***********************************************************************
226 static HRESULT
register_coclasses(struct regsvr_coclass
const *list
)
228 LONG res
= ERROR_SUCCESS
;
231 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
232 KEY_READ
| KEY_WRITE
, NULL
, &coclass_key
, NULL
);
233 if (res
!= ERROR_SUCCESS
) goto error_return
;
235 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
239 StringFromGUID2(list
->clsid
, buf
, 39);
240 res
= RegCreateKeyExW(coclass_key
, buf
, 0, NULL
, 0,
241 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
242 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
245 res
= RegSetValueExA(clsid_key
, NULL
, 0, REG_SZ
,
246 (CONST BYTE
*)(list
->name
),
247 strlen(list
->name
) + 1);
248 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
252 res
= register_key_defvalueA(clsid_key
, ips_keyname
, list
->ips
);
253 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
259 res
= RegCreateKeyExW(clsid_key
, ips32_keyname
, 0, NULL
, 0,
260 KEY_READ
| KEY_WRITE
, NULL
,
262 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
264 res
= RegSetValueExA(ips32_key
, NULL
, 0, REG_SZ
,
265 (CONST BYTE
*)list
->ips32
,
266 lstrlenA(list
->ips32
) + 1);
267 if (res
== ERROR_SUCCESS
&& list
->ips32_tmodel
)
268 res
= RegSetValueExA(ips32_key
, tmodel_valuename
, 0, REG_SZ
,
269 (CONST BYTE
*)list
->ips32_tmodel
,
270 strlen(list
->ips32_tmodel
) + 1);
271 RegCloseKey(ips32_key
);
272 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
276 res
= register_key_defvalueA(clsid_key
, progid_keyname
,
278 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
280 res
= register_progid(buf
, list
->progid
, NULL
,
281 list
->name
, list
->progid_extra
);
282 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
285 if (list
->viprogid
) {
286 res
= register_key_defvalueA(clsid_key
, viprogid_keyname
,
288 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
290 res
= register_progid(buf
, list
->viprogid
, list
->progid
,
291 list
->name
, list
->progid_extra
);
292 if (res
!= ERROR_SUCCESS
) goto error_close_clsid_key
;
295 error_close_clsid_key
:
296 RegCloseKey(clsid_key
);
299 error_close_coclass_key
:
300 RegCloseKey(coclass_key
);
302 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
305 /***********************************************************************
306 * unregister_coclasses
308 static HRESULT
unregister_coclasses(struct regsvr_coclass
const *list
)
310 LONG res
= ERROR_SUCCESS
;
313 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0,
314 KEY_READ
| KEY_WRITE
, &coclass_key
);
315 if (res
== ERROR_FILE_NOT_FOUND
) return S_OK
;
316 if (res
!= ERROR_SUCCESS
) goto error_return
;
318 for (; res
== ERROR_SUCCESS
&& list
->clsid
; ++list
) {
321 StringFromGUID2(list
->clsid
, buf
, 39);
322 res
= recursive_delete_keyW(coclass_key
, buf
);
323 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
326 res
= recursive_delete_keyA(HKEY_CLASSES_ROOT
, list
->progid
);
327 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
330 if (list
->viprogid
) {
331 res
= recursive_delete_keyA(HKEY_CLASSES_ROOT
, list
->viprogid
);
332 if (res
!= ERROR_SUCCESS
) goto error_close_coclass_key
;
336 error_close_coclass_key
:
337 RegCloseKey(coclass_key
);
339 return res
!= ERROR_SUCCESS
? HRESULT_FROM_WIN32(res
) : S_OK
;
342 /***********************************************************************
345 static LONG
register_key_guid(HKEY base
, WCHAR
const *name
, GUID
const *guid
)
349 StringFromGUID2(guid
, buf
, 39);
350 return register_key_defvalueW(base
, name
, buf
);
353 /***********************************************************************
354 * regsvr_key_defvalueW
356 static LONG
register_key_defvalueW(
364 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
365 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
366 if (res
!= ERROR_SUCCESS
) return res
;
367 res
= RegSetValueExW(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
368 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
373 /***********************************************************************
374 * regsvr_key_defvalueA
376 static LONG
register_key_defvalueA(
384 res
= RegCreateKeyExW(base
, name
, 0, NULL
, 0,
385 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
386 if (res
!= ERROR_SUCCESS
) return res
;
387 res
= RegSetValueExA(key
, NULL
, 0, REG_SZ
, (CONST BYTE
*)value
,
388 lstrlenA(value
) + 1);
393 /***********************************************************************
396 static LONG
register_progid(
399 char const *curver_progid
,
406 res
= RegCreateKeyExA(HKEY_CLASSES_ROOT
, progid
, 0,
407 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
409 if (res
!= ERROR_SUCCESS
) return res
;
412 res
= RegSetValueExA(progid_key
, NULL
, 0, REG_SZ
,
413 (CONST BYTE
*)name
, strlen(name
) + 1);
414 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
418 res
= register_key_defvalueW(progid_key
, clsid_keyname
, clsid
);
419 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
423 res
= register_key_defvalueA(progid_key
, curver_keyname
,
425 if (res
!= ERROR_SUCCESS
) goto error_close_progid_key
;
431 res
= RegCreateKeyExA(progid_key
, extra
, 0,
432 NULL
, 0, KEY_READ
| KEY_WRITE
, NULL
,
434 if (res
== ERROR_SUCCESS
)
435 RegCloseKey(extra_key
);
438 error_close_progid_key
:
439 RegCloseKey(progid_key
);
443 /***********************************************************************
444 * recursive_delete_key
446 static LONG
recursive_delete_key(HKEY key
)
449 WCHAR subkey_name
[MAX_PATH
];
454 cName
= sizeof(subkey_name
) / sizeof(WCHAR
);
455 res
= RegEnumKeyExW(key
, 0, subkey_name
, &cName
,
456 NULL
, NULL
, NULL
, NULL
);
457 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) {
458 res
= ERROR_SUCCESS
; /* presumably we're done enumerating */
461 res
= RegOpenKeyExW(key
, subkey_name
, 0,
462 KEY_READ
| KEY_WRITE
, &subkey
);
463 if (res
== ERROR_FILE_NOT_FOUND
) continue;
464 if (res
!= ERROR_SUCCESS
) break;
466 res
= recursive_delete_key(subkey
);
468 if (res
!= ERROR_SUCCESS
) break;
471 if (res
== ERROR_SUCCESS
) res
= RegDeleteKeyW(key
, 0);
475 /***********************************************************************
476 * recursive_delete_keyA
478 static LONG
recursive_delete_keyA(HKEY base
, char const *name
)
483 res
= RegOpenKeyExA(base
, name
, 0, KEY_READ
| KEY_WRITE
, &key
);
484 if (res
== ERROR_FILE_NOT_FOUND
) return ERROR_SUCCESS
;
485 if (res
!= ERROR_SUCCESS
) return res
;
486 res
= recursive_delete_key(key
);
491 /***********************************************************************
492 * recursive_delete_keyW
494 static LONG
recursive_delete_keyW(HKEY base
, WCHAR
const *name
)
499 res
= RegOpenKeyExW(base
, name
, 0, KEY_READ
| KEY_WRITE
, &key
);
500 if (res
== ERROR_FILE_NOT_FOUND
) return ERROR_SUCCESS
;
501 if (res
!= ERROR_SUCCESS
) return res
;
502 res
= recursive_delete_key(key
);
507 /***********************************************************************
510 static struct regsvr_coclass
const coclass_list
[] = {
511 { &CLSID_StdURLMoniker
,
517 { &CLSID_CdlProtocol
,
518 "CDL: Asynchronous Pluggable Protocol Handler",
523 { &CLSID_FileProtocol
,
524 "file:, local: Asynchronous Pluggable Protocol Handler",
529 { &CLSID_FtpProtocol
,
530 "ftp: Asynchronous Pluggable Protocol Handler",
535 { &CLSID_GopherProtocol
,
536 "gopher: Asynchronous Pluggable Protocol Handler",
541 { &CLSID_HttpProtocol
,
542 "http: Asynchronous Pluggable Protocol Handler",
547 { &CLSID_HttpSProtocol
,
548 "https: Asynchronous Pluggable Protocol Handler",
554 "mk: Asynchronous Pluggable Protocol Handler",
559 { &CLSID_InternetSecurityManager
,
565 { &CLSID_InternetZoneManager
,
571 { NULL
} /* list terminator */
574 /***********************************************************************
578 static struct regsvr_interface
const interface_list
[] = {
579 { NULL
} /* list terminator */
582 /***********************************************************************
586 #define INF_SET_CLSID(clsid) \
589 static CHAR name[] = "CLSID_" #clsid; \
591 pse[i].pszName = name; \
592 clsids[i++] = &CLSID_ ## clsid; \
595 static HRESULT
register_inf(BOOL doregister
)
599 typeof(RegInstallA
) *pRegInstall
;
602 static CLSID
const *clsids
[34];
605 static const WCHAR wszAdvpack
[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
607 INF_SET_CLSID(CdlProtocol
);
608 INF_SET_CLSID(FileProtocol
);
609 INF_SET_CLSID(FtpProtocol
);
610 INF_SET_CLSID(GopherProtocol
);
611 INF_SET_CLSID(HttpProtocol
);
612 INF_SET_CLSID(HttpSProtocol
);
613 INF_SET_CLSID(MkProtocol
);
615 for(i
= 0; i
< sizeof(pse
)/sizeof(pse
[0]); i
++) {
616 pse
[i
].pszValue
= HeapAlloc(GetProcessHeap(), 0, 39);
617 sprintf(pse
[i
].pszValue
, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
618 clsids
[i
]->Data1
, clsids
[i
]->Data2
, clsids
[i
]->Data3
, clsids
[i
]->Data4
[0],
619 clsids
[i
]->Data4
[1], clsids
[i
]->Data4
[2], clsids
[i
]->Data4
[3], clsids
[i
]->Data4
[4],
620 clsids
[i
]->Data4
[5], clsids
[i
]->Data4
[6], clsids
[i
]->Data4
[7]);
623 strtable
.cEntries
= sizeof(pse
)/sizeof(pse
[0]);
626 hAdvpack
= LoadLibraryW(wszAdvpack
);
627 pRegInstall
= (typeof(RegInstallA
)*)GetProcAddress(hAdvpack
, "RegInstall");
629 hres
= pRegInstall(URLMON_hInstance
, doregister
? "RegisterDll" : "UnregisterDll", &strtable
);
631 for(i
=0; i
< sizeof(pse
)/sizeof(pse
[0]); i
++)
632 HeapFree(GetProcessHeap(), 0, pse
[i
].pszValue
);
639 /***********************************************************************
640 * DllRegisterServer (URLMON.@)
642 HRESULT WINAPI
DllRegisterServer(void)
648 hr
= register_coclasses(coclass_list
);
650 hr
= register_interfaces(interface_list
);
653 return register_inf(TRUE
);
656 /***********************************************************************
657 * DllUnregisterServer (URLMON.@)
659 HRESULT WINAPI
DllUnregisterServer(void)
665 hr
= unregister_coclasses(coclass_list
);
667 hr
= unregister_interfaces(interface_list
);
670 return register_inf(FALSE
);