d3dx8: Implement D3DXPlaneDotCoord.
[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
142 /***********************************************************************
143  *              register_interfaces
144  */
145 static HRESULT register_interfaces(struct regsvr_interface const *list)
146 {
147     LONG res = ERROR_SUCCESS;
148     HKEY interface_key;
149
150     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
151                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
152     if (res != ERROR_SUCCESS) goto error_return;
153
154     for (; res == ERROR_SUCCESS && list->iid; ++list) {
155         WCHAR buf[39];
156         HKEY iid_key;
157
158         StringFromGUID2(list->iid, buf, 39);
159         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
160                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
161         if (res != ERROR_SUCCESS) goto error_close_interface_key;
162
163         if (list->name) {
164             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
165                                  (CONST BYTE*)(list->name),
166                                  strlen(list->name) + 1);
167             if (res != ERROR_SUCCESS) goto error_close_iid_key;
168         }
169
170         if (list->base_iid) {
171             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
172             if (res != ERROR_SUCCESS) goto error_close_iid_key;
173         }
174
175         if (0 <= list->num_methods) {
176             static WCHAR const fmt[3] = { '%', 'd', 0 };
177             HKEY key;
178
179             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
180                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
181             if (res != ERROR_SUCCESS) goto error_close_iid_key;
182
183             wsprintfW(buf, fmt, list->num_methods);
184             res = RegSetValueExW(key, NULL, 0, REG_SZ,
185                                  (CONST BYTE*)buf,
186                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
187             RegCloseKey(key);
188
189             if (res != ERROR_SUCCESS) goto error_close_iid_key;
190         }
191
192         if (list->ps_clsid) {
193             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
194             if (res != ERROR_SUCCESS) goto error_close_iid_key;
195         }
196
197         if (list->ps_clsid32) {
198             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
199             if (res != ERROR_SUCCESS) goto error_close_iid_key;
200         }
201
202     error_close_iid_key:
203         RegCloseKey(iid_key);
204     }
205
206 error_close_interface_key:
207     RegCloseKey(interface_key);
208 error_return:
209     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
210 }
211
212 /***********************************************************************
213  *              unregister_interfaces
214  */
215 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
216 {
217     LONG res = ERROR_SUCCESS;
218     HKEY interface_key;
219
220     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
221                         KEY_READ | KEY_WRITE, &interface_key);
222     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
223     if (res != ERROR_SUCCESS) goto error_return;
224
225     for (; res == ERROR_SUCCESS && list->iid; ++list) {
226         WCHAR buf[39];
227
228         StringFromGUID2(list->iid, buf, 39);
229         res = RegDeleteTreeW(interface_key, buf);
230         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
231     }
232
233     RegCloseKey(interface_key);
234 error_return:
235     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
236 }
237
238 /***********************************************************************
239  *              register_coclasses
240  */
241 static HRESULT register_coclasses(struct regsvr_coclass const *list)
242 {
243     LONG res = ERROR_SUCCESS;
244     HKEY coclass_key;
245
246     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
247                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
248     if (res != ERROR_SUCCESS) goto error_return;
249
250     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
251         WCHAR buf[39];
252         HKEY clsid_key;
253
254         StringFromGUID2(list->clsid, buf, 39);
255         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
256                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
257         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
258
259         if (list->name) {
260             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
261                                  (CONST BYTE*)(list->name),
262                                  strlen(list->name) + 1);
263             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
264         }
265
266         if (list->ips) {
267             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
268             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
269         }
270
271         if (list->ips32) {
272             HKEY ips32_key;
273
274             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
275                                   KEY_READ | KEY_WRITE, NULL,
276                                   &ips32_key, NULL);
277             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
278
279             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
280                                  (CONST BYTE*)list->ips32,
281                                  lstrlenA(list->ips32) + 1);
282             if (res == ERROR_SUCCESS && list->ips32_tmodel)
283                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
284                                      (CONST BYTE*)list->ips32_tmodel,
285                                      strlen(list->ips32_tmodel) + 1);
286             RegCloseKey(ips32_key);
287             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
288         }
289
290         if (list->flags & SHELLEX_MAYCHANGEDEFAULTMENU) {
291             HKEY shellex_key, mcdm_key;
292
293             res = RegCreateKeyExW(clsid_key, shellex_keyname, 0, NULL, 0,
294                                   KEY_READ | KEY_WRITE, NULL,
295                                   &shellex_key, NULL);
296             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
297             res = RegCreateKeyExW(shellex_key, mcdm_keyname, 0, NULL, 0,
298                                   KEY_READ | KEY_WRITE, NULL,
299                                   &mcdm_key, NULL);
300             RegCloseKey(shellex_key);
301             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
302             RegCloseKey(mcdm_key);
303         }
304
305         if (list->flags & 
306                 (SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES))
307         {
308             HKEY shellfolder_key;
309
310             res = RegCreateKeyExW(clsid_key, shellfolder_keyname, 0, NULL, 0,
311                                   KEY_READ | KEY_WRITE, NULL,
312                                   &shellfolder_key, NULL);
313             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
314             if (list->flags & SHELLFOLDER_WANTSFORPARSING)
315                 res = RegSetValueExA(shellfolder_key, wfparsing_valuename, 0, REG_SZ, (const BYTE *)"", 1);
316             if (list->flags & SHELLFOLDER_ATTRIBUTES) 
317                 res = RegSetValueExA(shellfolder_key, attributes_valuename, 0, REG_DWORD, 
318                                      (const BYTE *)&list->dwAttributes, sizeof(DWORD));
319             if (list->flags & SHELLFOLDER_CALLFORATTRIBUTES) 
320                 res = RegSetValueExA(shellfolder_key, cfattributes_valuename, 0, REG_DWORD,
321                                      (const BYTE *)&list->dwCallForAttributes, sizeof(DWORD));
322             RegCloseKey(shellfolder_key);
323             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
324         }
325
326         if (list->progid) {
327             res = register_key_defvalueA(clsid_key, progid_keyname,
328                                          list->progid);
329             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
330
331             res = register_progid(buf, list->progid, NULL,
332                                   list->name, list->progid_extra);
333             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
334         }
335
336         if (list->viprogid) {
337             res = register_key_defvalueA(clsid_key, viprogid_keyname,
338                                          list->viprogid);
339             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
340
341             res = register_progid(buf, list->viprogid, list->progid,
342                                   list->name, list->progid_extra);
343             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
344         }
345
346     error_close_clsid_key:
347         RegCloseKey(clsid_key);
348     }
349
350 error_close_coclass_key:
351     RegCloseKey(coclass_key);
352 error_return:
353     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
354 }
355
356 /***********************************************************************
357  *              unregister_coclasses
358  */
359 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
360 {
361     LONG res = ERROR_SUCCESS;
362     HKEY coclass_key;
363
364     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
365                         KEY_READ | KEY_WRITE, &coclass_key);
366     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
367     if (res != ERROR_SUCCESS) goto error_return;
368
369     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
370         WCHAR buf[39];
371
372         StringFromGUID2(list->clsid, buf, 39);
373         res = RegDeleteTreeW(coclass_key, buf);
374         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
375         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
376
377         if (list->progid) {
378             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
379             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
380             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
381         }
382
383         if (list->viprogid) {
384             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
385             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
386             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
387         }
388     }
389
390 error_close_coclass_key:
391     RegCloseKey(coclass_key);
392 error_return:
393     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
394 }
395
396 /***********************************************************************
397  *              regsvr_key_guid
398  */
399 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
400 {
401     WCHAR buf[39];
402
403     StringFromGUID2(guid, buf, 39);
404     return register_key_defvalueW(base, name, buf);
405 }
406
407 /***********************************************************************
408  *              regsvr_key_defvalueW
409  */
410 static LONG register_key_defvalueW(
411     HKEY base,
412     WCHAR const *name,
413     WCHAR const *value)
414 {
415     LONG res;
416     HKEY key;
417
418     res = RegCreateKeyExW(base, name, 0, NULL, 0,
419                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
420     if (res != ERROR_SUCCESS) return res;
421     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
422                          (lstrlenW(value) + 1) * sizeof(WCHAR));
423     RegCloseKey(key);
424     return res;
425 }
426
427 /***********************************************************************
428  *              regsvr_key_defvalueA
429  */
430 static LONG register_key_defvalueA(
431     HKEY base,
432     WCHAR const *name,
433     char const *value)
434 {
435     LONG res;
436     HKEY key;
437
438     res = RegCreateKeyExW(base, name, 0, NULL, 0,
439                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
440     if (res != ERROR_SUCCESS) return res;
441     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
442                          lstrlenA(value) + 1);
443     RegCloseKey(key);
444     return res;
445 }
446
447 /***********************************************************************
448  *              regsvr_progid
449  */
450 static LONG register_progid(
451     WCHAR const *clsid,
452     char const *progid,
453     char const *curver_progid,
454     char const *name,
455     char const *extra)
456 {
457     LONG res;
458     HKEY progid_key;
459
460     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
461                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
462                           &progid_key, NULL);
463     if (res != ERROR_SUCCESS) return res;
464
465     if (name) {
466         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
467                              (CONST BYTE*)name, strlen(name) + 1);
468         if (res != ERROR_SUCCESS) goto error_close_progid_key;
469     }
470
471     if (clsid) {
472         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
473         if (res != ERROR_SUCCESS) goto error_close_progid_key;
474     }
475
476     if (curver_progid) {
477         res = register_key_defvalueA(progid_key, curver_keyname,
478                                      curver_progid);
479         if (res != ERROR_SUCCESS) goto error_close_progid_key;
480     }
481
482     if (extra) {
483         HKEY extra_key;
484
485         res = RegCreateKeyExA(progid_key, extra, 0,
486                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
487                               &extra_key, NULL);
488         if (res == ERROR_SUCCESS)
489             RegCloseKey(extra_key);
490     }
491
492 error_close_progid_key:
493     RegCloseKey(progid_key);
494     return res;
495 }
496
497 static const GUID CLSID_MicrosoftBrowserArchitecture =
498 {0xa5e46e3a, 0x8849, 0x11d1, {0x9d, 0x8c, 0x00, 0xc0, 0x4f, 0xc9, 0x9d, 0x61}};
499 static const GUID CLSID_MruLongList =
500 {0x53bd6b4e, 0x3780, 0x4693, {0xaf, 0xc3, 0x71, 0x61, 0xc2, 0xf3, 0xee, 0x9c}};
501
502 /***********************************************************************
503  *              coclass list
504  */
505 static struct regsvr_coclass const coclass_list[] = {
506     {   &CLSID_WebBrowser_V1,
507         "Microsoft Web Browser Version 1",
508         NULL,
509         "shdocvw.dll",
510         "Apartment",
511         "Shell.Explorer.1",
512         "Shell.Explorer"
513     },
514     {   &CLSID_WebBrowser,
515         "Microsoft Web Browser",
516         NULL,
517         "shdocvw.dll",
518         "Apartment",
519         "Shell.Explorer.2",
520         "Shell.Explorer"
521     },
522     {   &CLSID_InternetExplorer,
523         "Internet Explorer(Ver 1.0)",
524         NULL,
525         NULL,
526         NULL,
527         "InternetExplorer.Application.1",
528         "InternetExplorer.Application"
529     },
530     {   &CLSID_ShellSearchAssistantOC,
531         "SearchAssistantOC",
532         NULL,
533         "shdocvw.dll",
534         "Apartment",
535         "SearchAssistantOC.SearchAssistantOC.1",
536         "SearchAssistantOC.SearchAssistantOC"
537     },
538     {   &CLSID_ShellShellNameSpace,
539         "Shell Name Space",
540         NULL,
541         "shdocvw.dll",
542         "Apartment",
543         "ShellNameSpace.ShellNameSpace.1",
544         "ShellNameSpace.ShellNameSpace"
545     },
546     {   &CLSID_ShellNameSpace,
547         "Shell Name Space",
548         NULL,
549         "shdocvw.dll",
550         "Apartment",
551         "ShellNameSpace.ShellNameSpace.1",
552         "ShellNameSpace.ShellNameSpace"
553     },
554     {   &CLSID_ShellUIHelper,
555         "Microsoft Shell UI Helper",
556         NULL,
557         "shdocvw.dll",
558         "Apartment",
559         "Shell.UIHelper.1",
560         NULL
561     },
562     {   &CLSID_ShellWindows,
563         "ShellWindows",
564         NULL,
565         "shdocvw.dll",
566         "Apartment",
567         NULL,
568         NULL
569     },
570     {   &CLSID_SearchAssistantOC,
571         "SearchAssistantOC",
572         NULL,
573         "shdocvw.dll",
574         "Apartment",
575         "SearchAssistantOC.SearchAssistantOC.1",
576         "SearchAssistantOC.SearchAssistantOC"
577     },
578     {
579         &CLSID_MicrosoftBrowserArchitecture,
580         "Microsoft Browser Architecture",
581         NULL,
582         "shdocvw.dll",
583         "Apartment",
584         NULL,
585         NULL
586     },
587     {
588         &CLSID_MruLongList,
589         "MruLongList",
590         NULL,
591         "shdocvw.dll",
592         "Apartment",
593         NULL,
594         NULL
595     },
596     {
597         &CLSID_CUrlHistory,
598         "Microsoft Url History Service",
599         NULL,
600         "shdocvw.dll",
601         "Apartment",
602         NULL,
603         NULL
604     },
605     {
606         &CLSID_Internet,
607         "Internet Explorer",
608         NULL,
609         "shdocvw.dll",
610         "Apartment",
611         NULL,
612         NULL,
613         NULL,
614         SHELLFOLDER_ATTRIBUTES,
615         SFGAO_CANDELETE|SFGAO_CANLINK
616     },
617     { NULL }                    /* list terminator */
618 };
619
620 /***********************************************************************
621  *              interface list
622  */
623
624 static struct regsvr_interface const interface_list[] = {
625     { NULL }                    /* list terminator */
626 };
627
628 static HRESULT register_localserver(void)
629 {
630     HKEY coclass_key = 0, clsid_key = 0;
631     WCHAR buf[39], path[MAX_PATH];
632     LONG res;
633     UINT len;
634
635     res = SHGetFolderPathW(NULL, CSIDL_FLAG_CREATE|CSIDL_PROGRAM_FILES,
636                            NULL, SHGFP_TYPE_CURRENT, path);
637     if (FAILED(res))
638         return res;
639
640     len = lstrlenW(path);
641     if ((len + (sizeof szIERelPath/sizeof(WCHAR)) + 1) > MAX_PATH)
642         return E_FAIL;
643
644     path[len] = '\\';
645     lstrcpyW(&path[len+1], szIERelPath);
646
647     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
648                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
649     if (res != ERROR_SUCCESS) goto err;
650
651     StringFromGUID2(&CLSID_InternetExplorer, buf, 39);
652     res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
653                           KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
654     if (res != ERROR_SUCCESS) goto err;
655
656     res = register_key_defvalueW(clsid_key, lcs32_keyname, path);
657     if (res != ERROR_SUCCESS) goto err;
658
659 err:
660     if (clsid_key) RegCloseKey(clsid_key);
661     if (coclass_key) RegCloseKey(coclass_key);
662     return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
663 }
664
665 static HRESULT register_typelib(void)
666 {
667     ITypeLib *typelib;
668     HRESULT hres;
669
670     static const WCHAR wszSHDocVw[] = {'s','h','d','o','c','v','w','.','d','l','l',0};
671
672     hres = LoadTypeLibEx(wszSHDocVw, REGKIND_REGISTER, &typelib);
673     if(FAILED(hres)) {
674         ERR("Could not load typelib: %08x\n", hres);
675         return hres;
676     }
677
678     ITypeLib_Release(typelib);
679
680     return hres;
681 }
682
683 static HRESULT unregister_typelib(void)
684 {
685     return UnRegisterTypeLib(&LIBID_SHDocVw, 1, 1, LOCALE_SYSTEM_DEFAULT, SYS_WIN32);
686 }
687
688 /***********************************************************************
689  *              DllRegisterServer (SHDOCVW.@)
690  */
691 HRESULT WINAPI DllRegisterServer(void)
692 {
693     HRESULT hr;
694
695     TRACE("\n");
696
697     hr = register_coclasses(coclass_list);
698     if (SUCCEEDED(hr))
699         hr = register_interfaces(interface_list);
700     if (SUCCEEDED(hr))
701         hr = register_localserver();
702     if(SUCCEEDED(hr))
703         hr = register_typelib();
704
705     return hr;
706 }
707
708 /***********************************************************************
709  *              DllUnregisterServer (SHDOCVW.@)
710  */
711 HRESULT WINAPI DllUnregisterServer(void)
712 {
713     HRESULT hr;
714
715     TRACE("\n");
716
717     hr = unregister_coclasses(coclass_list);
718     if (SUCCEEDED(hr))
719         hr = unregister_interfaces(interface_list);
720     if(SUCCEEDED(hr))
721         hr = unregister_typelib();
722
723     return hr;
724 }