urlmon: Add tests for BindToObject for URL monikers based on the existing tests for...
[wine] / dlls / urlmon / regsvr.c
1 /*
2  *      self-registerable dll functions for urlmon.dll
3  *
4  * Copyright (C) 2003 John K. Hohm
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winerror.h"
31 #include "advpub.h"
32
33 #include "objbase.h"
34
35 #include "urlmon.h"
36
37 #include "wine/debug.h"
38
39 #include "urlmon_main.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
42
43 /*
44  * Near the bottom of this file are the exported DllRegisterServer and
45  * DllUnregisterServer, which make all this worthwhile.
46  */
47
48 /***********************************************************************
49  *              interface for self-registering
50  */
51 struct regsvr_interface
52 {
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 */
59 };
60
61 static HRESULT register_interfaces(struct regsvr_interface const *list);
62 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
63
64 struct regsvr_coclass
65 {
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 */
74 };
75
76 static HRESULT register_coclasses(struct regsvr_coclass const *list);
77 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
78
79 /***********************************************************************
80  *              static string constants
81  */
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',
86     'e', 0 };
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',
91     'i', 'd', 0 };
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',
101     0 };
102 static WCHAR const ips32_keyname[15] = {
103     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
104     '3', '2', 0 };
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',
110     0 };
111 static char const tmodel_valuename[] = "ThreadingModel";
112
113 /***********************************************************************
114  *              static helper functions
115  */
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,
118                                    WCHAR const *value);
119 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
120                                    char const *value);
121 static LONG register_progid(WCHAR const *clsid,
122                             char const *progid, char const *curver_progid,
123                             char const *name, char const *extra);
124
125 /***********************************************************************
126  *              register_interfaces
127  */
128 static HRESULT register_interfaces(struct regsvr_interface const *list)
129 {
130     LONG res = ERROR_SUCCESS;
131     HKEY interface_key;
132
133     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
134                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
135     if (res != ERROR_SUCCESS) goto error_return;
136
137     for (; res == ERROR_SUCCESS && list->iid; ++list) {
138         WCHAR buf[39];
139         HKEY iid_key;
140
141         StringFromGUID2(list->iid, buf, 39);
142         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
143                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
144         if (res != ERROR_SUCCESS) goto error_close_interface_key;
145
146         if (list->name) {
147             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
148                                  (CONST BYTE*)(list->name),
149                                  strlen(list->name) + 1);
150             if (res != ERROR_SUCCESS) goto error_close_iid_key;
151         }
152
153         if (list->base_iid) {
154             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
155             if (res != ERROR_SUCCESS) goto error_close_iid_key;
156         }
157
158         if (0 <= list->num_methods) {
159             static WCHAR const fmt[3] = { '%', 'd', 0 };
160             HKEY key;
161
162             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
163                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
164             if (res != ERROR_SUCCESS) goto error_close_iid_key;
165
166             wsprintfW(buf, fmt, list->num_methods);
167             res = RegSetValueExW(key, NULL, 0, REG_SZ,
168                                  (CONST BYTE*)buf,
169                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
170             RegCloseKey(key);
171
172             if (res != ERROR_SUCCESS) goto error_close_iid_key;
173         }
174
175         if (list->ps_clsid) {
176             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
177             if (res != ERROR_SUCCESS) goto error_close_iid_key;
178         }
179
180         if (list->ps_clsid32) {
181             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
182             if (res != ERROR_SUCCESS) goto error_close_iid_key;
183         }
184
185     error_close_iid_key:
186         RegCloseKey(iid_key);
187     }
188
189 error_close_interface_key:
190     RegCloseKey(interface_key);
191 error_return:
192     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
193 }
194
195 /***********************************************************************
196  *              unregister_interfaces
197  */
198 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
199 {
200     LONG res = ERROR_SUCCESS;
201     HKEY interface_key;
202
203     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
204                         KEY_READ | KEY_WRITE, &interface_key);
205     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
206     if (res != ERROR_SUCCESS) goto error_return;
207
208     for (; res == ERROR_SUCCESS && list->iid; ++list) {
209         WCHAR buf[39];
210
211         StringFromGUID2(list->iid, buf, 39);
212         res = RegDeleteTreeW(interface_key, buf);
213         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
214     }
215
216     RegCloseKey(interface_key);
217 error_return:
218     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
219 }
220
221 /***********************************************************************
222  *              register_coclasses
223  */
224 static HRESULT register_coclasses(struct regsvr_coclass const *list)
225 {
226     LONG res = ERROR_SUCCESS;
227     HKEY coclass_key;
228
229     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
230                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
231     if (res != ERROR_SUCCESS) goto error_return;
232
233     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
234         WCHAR buf[39];
235         HKEY clsid_key;
236
237         StringFromGUID2(list->clsid, buf, 39);
238         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
239                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
240         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
241
242         if (list->name) {
243             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
244                                  (CONST BYTE*)(list->name),
245                                  strlen(list->name) + 1);
246             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
247         }
248
249         if (list->ips) {
250             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
251             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
252         }
253
254         if (list->ips32) {
255             HKEY ips32_key;
256
257             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
258                                   KEY_READ | KEY_WRITE, NULL,
259                                   &ips32_key, NULL);
260             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
261
262             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
263                                  (CONST BYTE*)list->ips32,
264                                  lstrlenA(list->ips32) + 1);
265             if (res == ERROR_SUCCESS && list->ips32_tmodel)
266                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
267                                      (CONST BYTE*)list->ips32_tmodel,
268                                      strlen(list->ips32_tmodel) + 1);
269             RegCloseKey(ips32_key);
270             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
271         }
272
273         if (list->progid) {
274             res = register_key_defvalueA(clsid_key, progid_keyname,
275                                          list->progid);
276             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277
278             res = register_progid(buf, list->progid, NULL,
279                                   list->name, list->progid_extra);
280             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
281         }
282
283         if (list->viprogid) {
284             res = register_key_defvalueA(clsid_key, viprogid_keyname,
285                                          list->viprogid);
286             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287
288             res = register_progid(buf, list->viprogid, list->progid,
289                                   list->name, list->progid_extra);
290             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
291         }
292
293     error_close_clsid_key:
294         RegCloseKey(clsid_key);
295     }
296
297 error_close_coclass_key:
298     RegCloseKey(coclass_key);
299 error_return:
300     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
301 }
302
303 /***********************************************************************
304  *              unregister_coclasses
305  */
306 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
307 {
308     LONG res = ERROR_SUCCESS;
309     HKEY coclass_key;
310
311     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
312                         KEY_READ | KEY_WRITE, &coclass_key);
313     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
314     if (res != ERROR_SUCCESS) goto error_return;
315
316     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
317         WCHAR buf[39];
318
319         StringFromGUID2(list->clsid, buf, 39);
320         res = RegDeleteTreeW(coclass_key, buf);
321         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
322         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
323
324         if (list->progid) {
325             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
326             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
327             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
328         }
329
330         if (list->viprogid) {
331             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
332             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
333             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
334         }
335     }
336
337 error_close_coclass_key:
338     RegCloseKey(coclass_key);
339 error_return:
340     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
341 }
342
343 /***********************************************************************
344  *              regsvr_key_guid
345  */
346 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
347 {
348     WCHAR buf[39];
349
350     StringFromGUID2(guid, buf, 39);
351     return register_key_defvalueW(base, name, buf);
352 }
353
354 /***********************************************************************
355  *              regsvr_key_defvalueW
356  */
357 static LONG register_key_defvalueW(
358     HKEY base,
359     WCHAR const *name,
360     WCHAR const *value)
361 {
362     LONG res;
363     HKEY key;
364
365     res = RegCreateKeyExW(base, name, 0, NULL, 0,
366                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
367     if (res != ERROR_SUCCESS) return res;
368     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
369                          (lstrlenW(value) + 1) * sizeof(WCHAR));
370     RegCloseKey(key);
371     return res;
372 }
373
374 /***********************************************************************
375  *              regsvr_key_defvalueA
376  */
377 static LONG register_key_defvalueA(
378     HKEY base,
379     WCHAR const *name,
380     char const *value)
381 {
382     LONG res;
383     HKEY key;
384
385     res = RegCreateKeyExW(base, name, 0, NULL, 0,
386                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
387     if (res != ERROR_SUCCESS) return res;
388     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
389                          lstrlenA(value) + 1);
390     RegCloseKey(key);
391     return res;
392 }
393
394 /***********************************************************************
395  *              regsvr_progid
396  */
397 static LONG register_progid(
398     WCHAR const *clsid,
399     char const *progid,
400     char const *curver_progid,
401     char const *name,
402     char const *extra)
403 {
404     LONG res;
405     HKEY progid_key;
406
407     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
408                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
409                           &progid_key, NULL);
410     if (res != ERROR_SUCCESS) return res;
411
412     if (name) {
413         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
414                              (CONST BYTE*)name, strlen(name) + 1);
415         if (res != ERROR_SUCCESS) goto error_close_progid_key;
416     }
417
418     if (clsid) {
419         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
420         if (res != ERROR_SUCCESS) goto error_close_progid_key;
421     }
422
423     if (curver_progid) {
424         res = register_key_defvalueA(progid_key, curver_keyname,
425                                      curver_progid);
426         if (res != ERROR_SUCCESS) goto error_close_progid_key;
427     }
428
429     if (extra) {
430         HKEY extra_key;
431
432         res = RegCreateKeyExA(progid_key, extra, 0,
433                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
434                               &extra_key, NULL);
435         if (res == ERROR_SUCCESS)
436             RegCloseKey(extra_key);
437     }
438
439 error_close_progid_key:
440     RegCloseKey(progid_key);
441     return res;
442 }
443
444 /***********************************************************************
445  *              coclass list
446  */
447 static struct regsvr_coclass const coclass_list[] = {
448     {   &CLSID_StdURLMoniker,
449         "URL Moniker",
450         NULL,
451         "urlmon.dll",
452         "Apartment"
453     },
454     {   &CLSID_CdlProtocol,
455         "CDL: Asynchronous Pluggable Protocol Handler",
456         NULL,
457         "urlmon.dll",
458         "Apartment"
459     },
460     {   &CLSID_FileProtocol,
461         "file:, local: Asynchronous Pluggable Protocol Handler",
462         NULL,
463         "urlmon.dll",
464         "Apartment"
465     },
466     {   &CLSID_FtpProtocol,
467         "ftp: Asynchronous Pluggable Protocol Handler",
468         NULL,
469         "urlmon.dll",
470         "Apartment"
471     },
472     {   &CLSID_GopherProtocol,
473         "gopher: Asynchronous Pluggable Protocol Handler",
474         NULL,
475         "urlmon.dll",
476         "Apartment"
477     },
478     {   &CLSID_HttpProtocol,
479         "http: Asynchronous Pluggable Protocol Handler",
480         NULL,
481         "urlmon.dll",
482         "Apartment"
483     },
484     {   &CLSID_HttpSProtocol,
485         "https: Asynchronous Pluggable Protocol Handler",
486         NULL,
487         "urlmon.dll",
488         "Apartment"
489     },
490     {   &CLSID_MkProtocol,
491         "mk: Asynchronous Pluggable Protocol Handler",
492         NULL,
493         "urlmon.dll",
494         "Apartment"
495     },
496     {   &CLSID_InternetSecurityManager,
497         "Security Manager",
498         NULL,
499         "urlmon.dll",
500         "Both"
501     },
502     {   &CLSID_InternetZoneManager,
503         "URL Zone Manager",
504         NULL,
505         "urlmon.dll",
506         "Both"
507     },
508     { NULL }                    /* list terminator */
509 };
510
511 /***********************************************************************
512  *              interface list
513  */
514
515 static struct regsvr_interface const interface_list[] = {
516     { NULL }                    /* list terminator */
517 };
518
519 /***********************************************************************
520  *              register_inf
521  */
522
523 #define INF_SET_CLSID(clsid)                  \
524     do                                        \
525     {                                         \
526         static CHAR name[] = "CLSID_" #clsid; \
527                                               \
528         pse[i].pszName = name;                \
529         clsids[i++] = &CLSID_ ## clsid;       \
530     } while (0)
531
532 static HRESULT register_inf(BOOL doregister)
533 {
534     HRESULT hres;
535     HMODULE hAdvpack;
536     typeof(RegInstallA) *pRegInstall;
537     STRTABLEA strtable;
538     STRENTRYA pse[7];
539     static CLSID const *clsids[34];
540     int i = 0;
541
542     static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0};
543
544     INF_SET_CLSID(CdlProtocol);
545     INF_SET_CLSID(FileProtocol);
546     INF_SET_CLSID(FtpProtocol);
547     INF_SET_CLSID(GopherProtocol);
548     INF_SET_CLSID(HttpProtocol);
549     INF_SET_CLSID(HttpSProtocol);
550     INF_SET_CLSID(MkProtocol);
551
552     for(i = 0; i < sizeof(pse)/sizeof(pse[0]); i++) {
553         pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39);
554         sprintf(pse[i].pszValue, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
555                 clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0],
556                 clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4],
557                 clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]);
558     }
559
560     strtable.cEntries = sizeof(pse)/sizeof(pse[0]);
561     strtable.pse = pse;
562
563     hAdvpack = LoadLibraryW(wszAdvpack);
564     pRegInstall = (typeof(RegInstallA)*)GetProcAddress(hAdvpack, "RegInstall");
565
566     hres = pRegInstall(URLMON_hInstance, doregister ? "RegisterDll" : "UnregisterDll", &strtable);
567
568     for(i=0; i < sizeof(pse)/sizeof(pse[0]); i++)
569         HeapFree(GetProcessHeap(), 0, pse[i].pszValue);
570
571     return hres;
572 }
573
574 #undef INF_SET_CLSID
575
576 /***********************************************************************
577  *              DllRegisterServer (URLMON.@)
578  */
579 HRESULT WINAPI DllRegisterServer(void)
580 {
581     HRESULT hr;
582
583     TRACE("\n");
584
585     hr = register_coclasses(coclass_list);
586     if (SUCCEEDED(hr))
587         hr = register_interfaces(interface_list);
588     if(FAILED(hr))
589         return hr;
590     return register_inf(TRUE);
591 }
592
593 /***********************************************************************
594  *              DllUnregisterServer (URLMON.@)
595  */
596 HRESULT WINAPI DllUnregisterServer(void)
597 {
598     HRESULT hr;
599
600     TRACE("\n");
601
602     hr = unregister_coclasses(coclass_list);
603     if (SUCCEEDED(hr))
604         hr = unregister_interfaces(interface_list);
605     if(FAILED(hr))
606         return hr;
607     return register_inf(FALSE);
608 }