Implemented syslink control.
[wine] / dlls / shdocvw / regsvr.c
1 /*
2  *      self-registerable dll functions for shdocvw.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <string.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "winerror.h"
29
30 #include "shdocvw.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
35
36 /*
37  * Near the bottom of this file are the exported DllRegisterServer and
38  * DllUnregisterServer, which make all this worthwhile.
39  */
40
41 /***********************************************************************
42  *              interface for self-registering
43  */
44 struct regsvr_interface
45 {
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 */
52 };
53
54 static HRESULT register_interfaces(struct regsvr_interface const *list);
55 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
56
57 struct regsvr_coclass
58 {
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 */
67 };
68
69 static HRESULT register_coclasses(struct regsvr_coclass const *list);
70 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
71
72 /***********************************************************************
73  *              static string constants
74  */
75 static WCHAR const interface_keyname[10] = {
76     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
77 static WCHAR const base_ifa_keyname[14] = {
78     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
79     'e', 0 };
80 static WCHAR const num_methods_keyname[11] = {
81     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
82 static WCHAR const ps_clsid_keyname[15] = {
83     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
84     'i', 'd', 0 };
85 static WCHAR const ps_clsid32_keyname[17] = {
86     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
87     'i', 'd', '3', '2', 0 };
88 static WCHAR const clsid_keyname[6] = {
89     'C', 'L', 'S', 'I', 'D', 0 };
90 static WCHAR const curver_keyname[7] = {
91     'C', 'u', 'r', 'V', 'e', 'r', 0 };
92 static WCHAR const ips_keyname[13] = {
93     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
94     0 };
95 static WCHAR const ips32_keyname[15] = {
96     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
97     '3', '2', 0 };
98 static WCHAR const progid_keyname[7] = {
99     'P', 'r', 'o', 'g', 'I', 'D', 0 };
100 static WCHAR const viprogid_keyname[25] = {
101     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
102     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
103     0 };
104 static char const tmodel_valuename[] = "ThreadingModel";
105
106 /***********************************************************************
107  *              static helper functions
108  */
109 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
110 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
111                                    WCHAR const *value);
112 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
113                                    char const *value);
114 static LONG register_progid(WCHAR const *clsid,
115                             char const *progid, char const *curver_progid,
116                             char const *name, char const *extra);
117 static LONG recursive_delete_key(HKEY key);
118 static LONG recursive_delete_keyA(HKEY base, char const *name);
119 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
120
121 /***********************************************************************
122  *              register_interfaces
123  */
124 static HRESULT register_interfaces(struct regsvr_interface const *list)
125 {
126     LONG res = ERROR_SUCCESS;
127     HKEY interface_key;
128
129     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
130                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
131     if (res != ERROR_SUCCESS) goto error_return;
132
133     for (; res == ERROR_SUCCESS && list->iid; ++list) {
134         WCHAR buf[39];
135         HKEY iid_key;
136
137         StringFromGUID2(list->iid, buf, 39);
138         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
139                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
140         if (res != ERROR_SUCCESS) goto error_close_interface_key;
141
142         if (list->name) {
143             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
144                                  (CONST BYTE*)(list->name),
145                                  strlen(list->name) + 1);
146             if (res != ERROR_SUCCESS) goto error_close_iid_key;
147         }
148
149         if (list->base_iid) {
150             register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
151             if (res != ERROR_SUCCESS) goto error_close_iid_key;
152         }
153
154         if (0 <= list->num_methods) {
155             static WCHAR const fmt[3] = { '%', 'd', 0 };
156             HKEY key;
157
158             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
159                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
160             if (res != ERROR_SUCCESS) goto error_close_iid_key;
161
162             wsprintfW(buf, fmt, list->num_methods);
163             res = RegSetValueExW(key, NULL, 0, REG_SZ,
164                                  (CONST BYTE*)buf,
165                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
166             RegCloseKey(key);
167
168             if (res != ERROR_SUCCESS) goto error_close_iid_key;
169         }
170
171         if (list->ps_clsid) {
172             register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
173             if (res != ERROR_SUCCESS) goto error_close_iid_key;
174         }
175
176         if (list->ps_clsid32) {
177             register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
178             if (res != ERROR_SUCCESS) goto error_close_iid_key;
179         }
180
181     error_close_iid_key:
182         RegCloseKey(iid_key);
183     }
184
185 error_close_interface_key:
186     RegCloseKey(interface_key);
187 error_return:
188     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
189 }
190
191 /***********************************************************************
192  *              unregister_interfaces
193  */
194 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
195 {
196     LONG res = ERROR_SUCCESS;
197     HKEY interface_key;
198
199     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
200                         KEY_READ | KEY_WRITE, &interface_key);
201     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
202     if (res != ERROR_SUCCESS) goto error_return;
203
204     for (; res == ERROR_SUCCESS && list->iid; ++list) {
205         WCHAR buf[39];
206
207         StringFromGUID2(list->iid, buf, 39);
208         res = recursive_delete_keyW(interface_key, buf);
209     }
210
211     RegCloseKey(interface_key);
212 error_return:
213     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
214 }
215
216 /***********************************************************************
217  *              register_coclasses
218  */
219 static HRESULT register_coclasses(struct regsvr_coclass const *list)
220 {
221     LONG res = ERROR_SUCCESS;
222     HKEY coclass_key;
223
224     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
225                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
226     if (res != ERROR_SUCCESS) goto error_return;
227
228     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
229         WCHAR buf[39];
230         HKEY clsid_key;
231
232         StringFromGUID2(list->clsid, buf, 39);
233         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
234                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
235         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
236
237         if (list->name) {
238             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
239                                  (CONST BYTE*)(list->name),
240                                  strlen(list->name) + 1);
241             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
242         }
243
244         if (list->ips) {
245             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
246             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
247         }
248
249         if (list->ips32) {
250             HKEY ips32_key;
251
252             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
253                                   KEY_READ | KEY_WRITE, NULL,
254                                   &ips32_key, NULL);
255             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
256
257             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
258                                  (CONST BYTE*)list->ips32,
259                                  lstrlenA(list->ips32) + 1);
260             if (res == ERROR_SUCCESS && list->ips32_tmodel)
261                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
262                                      (CONST BYTE*)list->ips32_tmodel,
263                                      strlen(list->ips32_tmodel) + 1);
264             RegCloseKey(ips32_key);
265             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
266         }
267
268         if (list->progid) {
269             res = register_key_defvalueA(clsid_key, progid_keyname,
270                                          list->progid);
271             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
272
273             res = register_progid(buf, list->progid, NULL,
274                                   list->name, list->progid_extra);
275             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
276         }
277
278         if (list->viprogid) {
279             res = register_key_defvalueA(clsid_key, viprogid_keyname,
280                                          list->viprogid);
281             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
282
283             res = register_progid(buf, list->viprogid, list->progid,
284                                   list->name, list->progid_extra);
285             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
286         }
287
288     error_close_clsid_key:
289         RegCloseKey(clsid_key);
290     }
291
292 error_close_coclass_key:
293     RegCloseKey(coclass_key);
294 error_return:
295     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
296 }
297
298 /***********************************************************************
299  *              unregister_coclasses
300  */
301 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
302 {
303     LONG res = ERROR_SUCCESS;
304     HKEY coclass_key;
305
306     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
307                         KEY_READ | KEY_WRITE, &coclass_key);
308     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
309     if (res != ERROR_SUCCESS) goto error_return;
310
311     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
312         WCHAR buf[39];
313
314         StringFromGUID2(list->clsid, buf, 39);
315         res = recursive_delete_keyW(coclass_key, buf);
316         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
317
318         if (list->progid) {
319             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
320             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
321         }
322
323         if (list->viprogid) {
324             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
325             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
326         }
327     }
328
329 error_close_coclass_key:
330     RegCloseKey(coclass_key);
331 error_return:
332     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
333 }
334
335 /***********************************************************************
336  *              regsvr_key_guid
337  */
338 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
339 {
340     WCHAR buf[39];
341
342     StringFromGUID2(guid, buf, 39);
343     return register_key_defvalueW(base, name, buf);
344 }
345
346 /***********************************************************************
347  *              regsvr_key_defvalueW
348  */
349 static LONG register_key_defvalueW(
350     HKEY base,
351     WCHAR const *name,
352     WCHAR const *value)
353 {
354     LONG res;
355     HKEY key;
356
357     res = RegCreateKeyExW(base, name, 0, NULL, 0,
358                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
359     if (res != ERROR_SUCCESS) return res;
360     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
361                          (lstrlenW(value) + 1) * sizeof(WCHAR));
362     RegCloseKey(key);
363     return res;
364 }
365
366 /***********************************************************************
367  *              regsvr_key_defvalueA
368  */
369 static LONG register_key_defvalueA(
370     HKEY base,
371     WCHAR const *name,
372     char const *value)
373 {
374     LONG res;
375     HKEY key;
376
377     res = RegCreateKeyExW(base, name, 0, NULL, 0,
378                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
379     if (res != ERROR_SUCCESS) return res;
380     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
381                          lstrlenA(value) + 1);
382     RegCloseKey(key);
383     return res;
384 }
385
386 /***********************************************************************
387  *              regsvr_progid
388  */
389 static LONG register_progid(
390     WCHAR const *clsid,
391     char const *progid,
392     char const *curver_progid,
393     char const *name,
394     char const *extra)
395 {
396     LONG res;
397     HKEY progid_key;
398
399     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
400                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
401                           &progid_key, NULL);
402     if (res != ERROR_SUCCESS) return res;
403
404     if (name) {
405         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
406                              (CONST BYTE*)name, strlen(name) + 1);
407         if (res != ERROR_SUCCESS) goto error_close_progid_key;
408     }
409
410     if (clsid) {
411         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
412         if (res != ERROR_SUCCESS) goto error_close_progid_key;
413     }
414
415     if (curver_progid) {
416         res = register_key_defvalueA(progid_key, curver_keyname,
417                                      curver_progid);
418         if (res != ERROR_SUCCESS) goto error_close_progid_key;
419     }
420
421     if (extra) {
422         HKEY extra_key;
423
424         res = RegCreateKeyExA(progid_key, extra, 0,
425                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
426                               &extra_key, NULL);
427         if (res == ERROR_SUCCESS)
428             RegCloseKey(extra_key);
429     }
430
431 error_close_progid_key:
432     RegCloseKey(progid_key);
433     return res;
434 }
435
436 /***********************************************************************
437  *              recursive_delete_key
438  */
439 static LONG recursive_delete_key(HKEY key)
440 {
441     LONG res;
442     WCHAR subkey_name[MAX_PATH];
443     DWORD cName;
444     HKEY subkey;
445
446     for (;;) {
447         cName = sizeof(subkey_name) / sizeof(WCHAR);
448         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
449                             NULL, NULL, NULL, NULL);
450         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
451             res = ERROR_SUCCESS; /* presumably we're done enumerating */
452             break;
453         }
454         res = RegOpenKeyExW(key, subkey_name, 0,
455                             KEY_READ | KEY_WRITE, &subkey);
456         if (res == ERROR_FILE_NOT_FOUND) continue;
457         if (res != ERROR_SUCCESS) break;
458
459         res = recursive_delete_key(subkey);
460         RegCloseKey(subkey);
461         if (res != ERROR_SUCCESS) break;
462     }
463
464     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
465     return res;
466 }
467
468 /***********************************************************************
469  *              recursive_delete_keyA
470  */
471 static LONG recursive_delete_keyA(HKEY base, char const *name)
472 {
473     LONG res;
474     HKEY key;
475
476     res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
477     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
478     if (res != ERROR_SUCCESS) return res;
479     res = recursive_delete_key(key);
480     RegCloseKey(key);
481     return res;
482 }
483
484 /***********************************************************************
485  *              recursive_delete_keyW
486  */
487 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
488 {
489     LONG res;
490     HKEY key;
491
492     res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
493     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
494     if (res != ERROR_SUCCESS) return res;
495     res = recursive_delete_key(key);
496     RegCloseKey(key);
497     return res;
498 }
499
500 /***********************************************************************
501  *              coclass list
502  */
503 static struct regsvr_coclass const coclass_list[] = {
504     {   &CLSID_WebBrowser,
505         "Microsoft Web Browser",
506         NULL,
507         "shdocvw.dll",
508         "Apartment",
509         "Shell.Explorer.2",
510         "Shell.Explorer"
511     },
512     { NULL }                    /* list terminator */
513 };
514
515 /***********************************************************************
516  *              interface list
517  */
518
519 static struct regsvr_interface const interface_list[] = {
520     { NULL }                    /* list terminator */
521 };
522
523 /***********************************************************************
524  *              DllRegisterServer (SHDOCVW.@)
525  */
526 HRESULT WINAPI SHDOCVW_DllRegisterServer(void)
527 {
528     HRESULT hr;
529
530     TRACE("\n");
531
532     hr = register_coclasses(coclass_list);
533     if (SUCCEEDED(hr))
534         hr = register_interfaces(interface_list);
535     return hr;
536 }
537
538 /***********************************************************************
539  *              DllUnregisterServer (SHDOCVW.@)
540  */
541 HRESULT WINAPI SHDOCVW_DllUnregisterServer(void)
542 {
543     HRESULT hr;
544
545     TRACE("\n");
546
547     hr = unregister_coclasses(coclass_list);
548     if (SUCCEEDED(hr))
549         hr = unregister_interfaces(interface_list);
550     return hr;
551 }