ntdll/tests: Fix exception test for CPUs that do segment limit checks differently.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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     DWORD flags;
68     DWORD dwAttributes;
69     DWORD dwCallForAttributes;
70 };
71
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
77
78 static HRESULT register_coclasses(struct regsvr_coclass const *list);
79 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
80
81 /***********************************************************************
82  *              static string constants
83  */
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',
88     'e', 0 };
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',
93     'i', 'd', 0 };
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',
103     0 };
104 static WCHAR const ips32_keyname[15] = {
105     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
106     '3', '2', 0 };
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',
112     0 };
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 };
129
130 /***********************************************************************
131  *              static helper functions
132  */
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,
135                                    WCHAR const *value);
136 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
137                                    char const *value);
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);
144
145 /***********************************************************************
146  *              register_interfaces
147  */
148 static HRESULT register_interfaces(struct regsvr_interface const *list)
149 {
150     LONG res = ERROR_SUCCESS;
151     HKEY interface_key;
152
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;
156
157     for (; res == ERROR_SUCCESS && list->iid; ++list) {
158         WCHAR buf[39];
159         HKEY iid_key;
160
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;
165
166         if (list->name) {
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;
171         }
172
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;
176         }
177
178         if (0 <= list->num_methods) {
179             static WCHAR const fmt[3] = { '%', 'd', 0 };
180             HKEY key;
181
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;
185
186             wsprintfW(buf, fmt, list->num_methods);
187             res = RegSetValueExW(key, NULL, 0, REG_SZ,
188                                  (CONST BYTE*)buf,
189                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
190             RegCloseKey(key);
191
192             if (res != ERROR_SUCCESS) goto error_close_iid_key;
193         }
194
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;
198         }
199
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;
203         }
204
205     error_close_iid_key:
206         RegCloseKey(iid_key);
207     }
208
209 error_close_interface_key:
210     RegCloseKey(interface_key);
211 error_return:
212     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
213 }
214
215 /***********************************************************************
216  *              unregister_interfaces
217  */
218 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
219 {
220     LONG res = ERROR_SUCCESS;
221     HKEY interface_key;
222
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;
227
228     for (; res == ERROR_SUCCESS && list->iid; ++list) {
229         WCHAR buf[39];
230
231         StringFromGUID2(list->iid, buf, 39);
232         res = recursive_delete_keyW(interface_key, buf);
233     }
234
235     RegCloseKey(interface_key);
236 error_return:
237     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
238 }
239
240 /***********************************************************************
241  *              register_coclasses
242  */
243 static HRESULT register_coclasses(struct regsvr_coclass const *list)
244 {
245     LONG res = ERROR_SUCCESS;
246     HKEY coclass_key;
247
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;
251
252     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
253         WCHAR buf[39];
254         HKEY clsid_key;
255
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;
260
261         if (list->name) {
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;
266         }
267
268         if (list->ips) {
269             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
270             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
271         }
272
273         if (list->ips32) {
274             HKEY ips32_key;
275
276             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
277                                   KEY_READ | KEY_WRITE, NULL,
278                                   &ips32_key, NULL);
279             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
280
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;
290         }
291
292         if (list->flags & SHELLEX_MAYCHANGEDEFAULTMENU) {
293             HKEY shellex_key, mcdm_key;
294
295             res = RegCreateKeyExW(clsid_key, shellex_keyname, 0, NULL, 0,
296                                   KEY_READ | KEY_WRITE, NULL,
297                                   &shellex_key, 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,
301                                   &mcdm_key, NULL);
302             RegCloseKey(shellex_key);
303             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
304             RegCloseKey(mcdm_key);
305         }
306
307         if (list->flags & 
308                 (SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES))
309         {
310             HKEY shellfolder_key;
311
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;
326         }
327
328         if (list->progid) {
329             res = register_key_defvalueA(clsid_key, progid_keyname,
330                                          list->progid);
331             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
332
333             res = register_progid(buf, list->progid, NULL,
334                                   list->name, list->progid_extra);
335             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
336         }
337
338         if (list->viprogid) {
339             res = register_key_defvalueA(clsid_key, viprogid_keyname,
340                                          list->viprogid);
341             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
342
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;
346         }
347
348     error_close_clsid_key:
349         RegCloseKey(clsid_key);
350     }
351
352 error_close_coclass_key:
353     RegCloseKey(coclass_key);
354 error_return:
355     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
356 }
357
358 /***********************************************************************
359  *              unregister_coclasses
360  */
361 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
362 {
363     LONG res = ERROR_SUCCESS;
364     HKEY coclass_key;
365
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;
370
371     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
372         WCHAR buf[39];
373
374         StringFromGUID2(list->clsid, buf, 39);
375         res = recursive_delete_keyW(coclass_key, buf);
376         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
377
378         if (list->progid) {
379             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
380             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
381         }
382
383         if (list->viprogid) {
384             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
385             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
386         }
387     }
388
389 error_close_coclass_key:
390     RegCloseKey(coclass_key);
391 error_return:
392     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
393 }
394
395 /***********************************************************************
396  *              regsvr_key_guid
397  */
398 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
399 {
400     WCHAR buf[39];
401
402     StringFromGUID2(guid, buf, 39);
403     return register_key_defvalueW(base, name, buf);
404 }
405
406 /***********************************************************************
407  *              regsvr_key_defvalueW
408  */
409 static LONG register_key_defvalueW(
410     HKEY base,
411     WCHAR const *name,
412     WCHAR const *value)
413 {
414     LONG res;
415     HKEY key;
416
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));
422     RegCloseKey(key);
423     return res;
424 }
425
426 /***********************************************************************
427  *              regsvr_key_defvalueA
428  */
429 static LONG register_key_defvalueA(
430     HKEY base,
431     WCHAR const *name,
432     char const *value)
433 {
434     LONG res;
435     HKEY key;
436
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);
442     RegCloseKey(key);
443     return res;
444 }
445
446 /***********************************************************************
447  *              regsvr_progid
448  */
449 static LONG register_progid(
450     WCHAR const *clsid,
451     char const *progid,
452     char const *curver_progid,
453     char const *name,
454     char const *extra)
455 {
456     LONG res;
457     HKEY progid_key;
458
459     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
460                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
461                           &progid_key, NULL);
462     if (res != ERROR_SUCCESS) return res;
463
464     if (name) {
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;
468     }
469
470     if (clsid) {
471         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
472         if (res != ERROR_SUCCESS) goto error_close_progid_key;
473     }
474
475     if (curver_progid) {
476         res = register_key_defvalueA(progid_key, curver_keyname,
477                                      curver_progid);
478         if (res != ERROR_SUCCESS) goto error_close_progid_key;
479     }
480
481     if (extra) {
482         HKEY extra_key;
483
484         res = RegCreateKeyExA(progid_key, extra, 0,
485                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
486                               &extra_key, NULL);
487         if (res == ERROR_SUCCESS)
488             RegCloseKey(extra_key);
489     }
490
491 error_close_progid_key:
492     RegCloseKey(progid_key);
493     return res;
494 }
495
496 /***********************************************************************
497  *              recursive_delete_key
498  */
499 static LONG recursive_delete_key(HKEY key)
500 {
501     LONG res;
502     WCHAR subkey_name[MAX_PATH];
503     DWORD cName;
504     HKEY subkey;
505
506     for (;;) {
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 */
512             break;
513         }
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;
518
519         res = recursive_delete_key(subkey);
520         RegCloseKey(subkey);
521         if (res != ERROR_SUCCESS) break;
522     }
523
524     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
525     return res;
526 }
527
528 /***********************************************************************
529  *              recursive_delete_keyA
530  */
531 static LONG recursive_delete_keyA(HKEY base, char const *name)
532 {
533     LONG res;
534     HKEY key;
535
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);
540     RegCloseKey(key);
541     return res;
542 }
543
544 /***********************************************************************
545  *              recursive_delete_keyW
546  */
547 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
548 {
549     LONG res;
550     HKEY key;
551
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);
556     RegCloseKey(key);
557     return res;
558 }
559
560
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}};
565
566 /***********************************************************************
567  *              coclass list
568  */
569 static struct regsvr_coclass const coclass_list[] = {
570     {   &CLSID_WebBrowser_V1,
571         "Microsoft Web Browser Version 1",
572         NULL,
573         "shdocvw.dll",
574         "Apartment",
575         "Shell.Explorer.1",
576         "Shell.Explorer"
577     },
578     {   &CLSID_WebBrowser,
579         "Microsoft Web Browser",
580         NULL,
581         "shdocvw.dll",
582         "Apartment",
583         "Shell.Explorer.2",
584         "Shell.Explorer"
585     },
586     {   &CLSID_InternetExplorer,
587         "Internet Explorer(Ver 1.0)",
588         NULL,
589         NULL,
590         NULL,
591         "InternetExplorer.Application.1",
592         "InternetExplorer.Application"
593     },
594     {   &CLSID_ShellSearchAssistantOC,
595         "SearchAssistantOC",
596         NULL,
597         "shdocvw.dll",
598         "Apartment",
599         "SearchAssistantOC.SearchAssistantOC.1",
600         "SearchAssistantOC.SearchAssistantOC"
601     },
602     {   &CLSID_ShellShellNameSpace,
603         "Shell Name Space",
604         NULL,
605         "shdocvw.dll",
606         "Apartment",
607         "ShellNameSpace.ShellNameSpace.1",
608         "ShellNameSpace.ShellNameSpace"
609     },
610     {   &CLSID_ShellNameSpace,
611         "Shell Name Space",
612         NULL,
613         "shdocvw.dll",
614         "Apartment",
615         "ShellNameSpace.ShellNameSpace.1",
616         "ShellNameSpace.ShellNameSpace"
617     },
618     {   &CLSID_ShellUIHelper,
619         "Microsoft Shell UI Helper",
620         NULL,
621         "shdocvw.dll",
622         "Apartment",
623         "Shell.UIHelper.1",
624         NULL
625     },
626     {   &CLSID_ShellWindows,
627         "ShellWindows",
628         NULL,
629         "shdocvw.dll",
630         "Apartment",
631         NULL,
632         NULL
633     },
634     {   &CLSID_SearchAssistantOC,
635         "SearchAssistantOC",
636         NULL,
637         "shdocvw.dll",
638         "Apartment",
639         "SearchAssistantOC.SearchAssistantOC.1",
640         "SearchAssistantOC.SearchAssistantOC"
641     },
642     {
643         &CLSID_MicrosoftBrowserArchitecture,
644         "Microsoft Browser Architecture",
645         NULL,
646         "shdocvw.dll",
647         "Apartment",
648         NULL,
649         NULL
650     },
651     {
652         &CLSID_MruLongList,
653         "MruLongList",
654         NULL,
655         "shdocvw.dll",
656         "Apartment",
657         NULL,
658         NULL
659     },
660     {
661         &CLSID_CUrlHistory,
662         "Microsoft Url History Service",
663         NULL,
664         "shdocvw.dll",
665         "Apartment",
666         NULL,
667         NULL
668     },
669     {
670         &CLSID_Internet,
671         "Internet Explorer",
672         NULL,
673         "shdocvw.dll",
674         "Apartment",
675         NULL,
676         NULL,
677         NULL,
678         SHELLFOLDER_ATTRIBUTES,
679         SFGAO_CANDELETE|SFGAO_CANLINK
680     },
681     { NULL }                    /* list terminator */
682 };
683
684 /***********************************************************************
685  *              interface list
686  */
687
688 static struct regsvr_interface const interface_list[] = {
689     { NULL }                    /* list terminator */
690 };
691
692 static HRESULT register_localserver(void)
693 {
694     HKEY coclass_key = 0, clsid_key = 0;
695     WCHAR buf[39], path[MAX_PATH];
696     LONG res;
697     UINT len;
698
699     res = SHGetFolderPathW(NULL, CSIDL_FLAG_CREATE|CSIDL_PROGRAM_FILES,
700                            NULL, SHGFP_TYPE_CURRENT, path);
701     if (FAILED(res))
702         return res;
703
704     len = lstrlenW(path);
705     if ((len + (sizeof szIERelPath/sizeof(WCHAR)) + 1) > MAX_PATH)
706         return E_FAIL;
707
708     path[len] = '\\';
709     lstrcpyW(&path[len+1], szIERelPath);
710
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;
714
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;
719
720     res = register_key_defvalueW(clsid_key, lcs32_keyname, path);
721     if (res != ERROR_SUCCESS) goto err;
722
723 err:
724     if (clsid_key) RegCloseKey(clsid_key);
725     if (coclass_key) RegCloseKey(coclass_key);
726     return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
727 }
728
729 static HRESULT register_typelib(void)
730 {
731     ITypeLib *typelib;
732     HRESULT hres;
733
734     static const WCHAR wszSHDocVw[] = {'s','h','d','o','c','v','w','.','d','l','l',0};
735
736     hres = LoadTypeLibEx(wszSHDocVw, REGKIND_REGISTER, &typelib);
737     if(FAILED(hres)) {
738         ERR("Could not load typelib: %08x\n", hres);
739         return hres;
740     }
741
742     ITypeLib_Release(typelib);
743
744     return hres;
745 }
746
747 static HRESULT unregister_typelib(void)
748 {
749     return UnRegisterTypeLib(&LIBID_SHDocVw, 1, 1, LOCALE_SYSTEM_DEFAULT, SYS_WIN32);
750 }
751
752 /***********************************************************************
753  *              DllRegisterServer (SHDOCVW.@)
754  */
755 HRESULT WINAPI DllRegisterServer(void)
756 {
757     HRESULT hr;
758
759     TRACE("\n");
760
761     hr = register_coclasses(coclass_list);
762     if (SUCCEEDED(hr))
763         hr = register_interfaces(interface_list);
764     if (SUCCEEDED(hr))
765         hr = register_localserver();
766     if(SUCCEEDED(hr))
767         hr = register_typelib();
768
769     return hr;
770 }
771
772 /***********************************************************************
773  *              DllUnregisterServer (SHDOCVW.@)
774  */
775 HRESULT WINAPI DllUnregisterServer(void)
776 {
777     HRESULT hr;
778
779     TRACE("\n");
780
781     hr = unregister_coclasses(coclass_list);
782     if (SUCCEEDED(hr))
783         hr = unregister_interfaces(interface_list);
784     if(SUCCEEDED(hr))
785         hr = unregister_typelib();
786
787     return hr;
788 }