jscript: Added SCRIPTSTATE_CONNECTED implementation.
[wine] / dlls / ole32 / regsvr.c
1 /*
2  *      self-registerable dll functions for ole32.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 "config.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31 #include "objbase.h"
32
33 #include "ole2.h"
34 #include "olectl.h"
35 #include "comcat.h"
36 #include "initguid.h"
37 #include "compobj_private.h"
38 #include "moniker.h"
39
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43
44 /*
45  * Near the bottom of this file are the exported DllRegisterServer and
46  * DllUnregisterServer, which make all this worthwhile.
47  */
48
49 /***********************************************************************
50  *              interface for self-registering
51  */
52 struct regsvr_interface
53 {
54     IID const *iid;             /* NULL for end of list */
55     LPCSTR name;                /* can be NULL to omit */
56     IID const *base_iid;        /* can be NULL to omit */
57     int num_methods;            /* can be <0 to omit */
58     CLSID const *ps_clsid;      /* can be NULL to omit */
59     CLSID const *ps_clsid32;    /* can be NULL to omit */
60 };
61
62 static HRESULT register_interfaces(struct regsvr_interface const *list);
63 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
64
65 struct regsvr_coclass
66 {
67     CLSID const *clsid;         /* NULL for end of list */
68     LPCSTR name;                /* can be NULL to omit */
69     LPCSTR ips;                 /* can be NULL to omit */
70     LPCSTR ips32;               /* can be NULL to omit */
71     LPCSTR ips32_tmodel;        /* can be NULL to omit */
72     LPCSTR progid;              /* can be NULL to omit */
73 };
74
75 static HRESULT register_coclasses(struct regsvr_coclass const *list);
76 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
77
78 /***********************************************************************
79  *              static string constants
80  */
81 static WCHAR const interface_keyname[10] = {
82     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
83 static WCHAR const base_ifa_keyname[14] = {
84     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
85     'e', 0 };
86 static WCHAR const num_methods_keyname[11] = {
87     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
88 static WCHAR const ps_clsid_keyname[15] = {
89     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
90     'i', 'd', 0 };
91 static WCHAR const ps_clsid32_keyname[17] = {
92     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
93     'i', 'd', '3', '2', 0 };
94 static WCHAR const clsid_keyname[6] = {
95     'C', 'L', 'S', 'I', 'D', 0 };
96 static WCHAR const ips_keyname[13] = {
97     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
98     0 };
99 static WCHAR const ips32_keyname[15] = {
100     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
101     '3', '2', 0 };
102 static WCHAR const progid_keyname[7] = {
103     'P', 'r', 'o', 'g', 'I', 'D', 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, char const *progid,
115                             char const *name);
116
117 /***********************************************************************
118  *              register_interfaces
119  */
120 static HRESULT register_interfaces(struct regsvr_interface const *list)
121 {
122     LONG res = ERROR_SUCCESS;
123     HKEY interface_key;
124
125     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
126                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
127     if (res != ERROR_SUCCESS) goto error_return;
128
129     for (; res == ERROR_SUCCESS && list->iid; ++list) {
130         WCHAR buf[39];
131         HKEY iid_key;
132
133         StringFromGUID2(list->iid, buf, 39);
134         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
135                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
136         if (res != ERROR_SUCCESS) goto error_close_interface_key;
137
138         if (list->name) {
139             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
140                                  (CONST BYTE*)(list->name),
141                                  strlen(list->name) + 1);
142             if (res != ERROR_SUCCESS) goto error_close_iid_key;
143         }
144
145         if (list->base_iid) {
146             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
147             if (res != ERROR_SUCCESS) goto error_close_iid_key;
148         }
149
150         if (0 <= list->num_methods) {
151             static WCHAR const fmt[3] = { '%', 'd', 0 };
152             HKEY key;
153
154             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
155                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
156             if (res != ERROR_SUCCESS) goto error_close_iid_key;
157
158             wsprintfW(buf, fmt, list->num_methods);
159             res = RegSetValueExW(key, NULL, 0, REG_SZ,
160                                  (CONST BYTE*)buf,
161                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
162             RegCloseKey(key);
163
164             if (res != ERROR_SUCCESS) goto error_close_iid_key;
165         }
166
167         if (list->ps_clsid) {
168             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
169             if (res != ERROR_SUCCESS) goto error_close_iid_key;
170         }
171
172         if (list->ps_clsid32) {
173             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
174             if (res != ERROR_SUCCESS) goto error_close_iid_key;
175         }
176
177     error_close_iid_key:
178         RegCloseKey(iid_key);
179     }
180
181 error_close_interface_key:
182     RegCloseKey(interface_key);
183 error_return:
184     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
185 }
186
187 /***********************************************************************
188  *              unregister_interfaces
189  */
190 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
191 {
192     LONG res = ERROR_SUCCESS;
193     HKEY interface_key;
194
195     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
196                         KEY_READ | KEY_WRITE, &interface_key);
197     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
198     if (res != ERROR_SUCCESS) goto error_return;
199
200     for (; res == ERROR_SUCCESS && list->iid; ++list) {
201         WCHAR buf[39];
202
203         StringFromGUID2(list->iid, buf, 39);
204         res = RegDeleteTreeW(interface_key, buf);
205         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
206     }
207
208     RegCloseKey(interface_key);
209 error_return:
210     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
211 }
212
213 /***********************************************************************
214  *              register_coclasses
215  */
216 static HRESULT register_coclasses(struct regsvr_coclass const *list)
217 {
218     LONG res = ERROR_SUCCESS;
219     HKEY coclass_key;
220
221     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
222                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
223     if (res != ERROR_SUCCESS) goto error_return;
224
225     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
226         WCHAR buf[39];
227         HKEY clsid_key;
228
229         StringFromGUID2(list->clsid, buf, 39);
230         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
231                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
232         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
233
234         if (list->name) {
235             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
236                                  (CONST BYTE*)(list->name),
237                                  strlen(list->name) + 1);
238             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
239         }
240
241         if (list->ips) {
242             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
243             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
244         }
245
246         if (list->ips32) {
247             HKEY ips32_key;
248
249             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
250                                   KEY_READ | KEY_WRITE, NULL,
251                                   &ips32_key, NULL);
252             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
253
254             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
255                                  (CONST BYTE*)list->ips32,
256                                  lstrlenA(list->ips32) + 1);
257             if (res == ERROR_SUCCESS && list->ips32_tmodel)
258                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
259                                      (CONST BYTE*)list->ips32_tmodel,
260                                      strlen(list->ips32_tmodel) + 1);
261             RegCloseKey(ips32_key);
262             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
263         }
264
265         if (list->progid) {
266             res = register_key_defvalueA(clsid_key, progid_keyname,
267                                          list->progid);
268             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
269
270             res = register_progid(buf, list->progid, list->name);
271             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
272         }
273
274     error_close_clsid_key:
275         RegCloseKey(clsid_key);
276     }
277
278 error_close_coclass_key:
279     RegCloseKey(coclass_key);
280 error_return:
281     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
282 }
283
284 /***********************************************************************
285  *              unregister_coclasses
286  */
287 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
288 {
289     LONG res = ERROR_SUCCESS;
290     HKEY coclass_key;
291
292     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
293                         KEY_READ | KEY_WRITE, &coclass_key);
294     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
295     if (res != ERROR_SUCCESS) goto error_return;
296
297     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
298         WCHAR buf[39];
299
300         StringFromGUID2(list->clsid, buf, 39);
301         res = RegDeleteTreeW(coclass_key, buf);
302         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
303         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
304
305         if (list->progid) {
306             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
307             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
308             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
309         }
310     }
311
312 error_close_coclass_key:
313     RegCloseKey(coclass_key);
314 error_return:
315     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
316 }
317
318 /***********************************************************************
319  *              regsvr_key_guid
320  */
321 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
322 {
323     WCHAR buf[39];
324
325     StringFromGUID2(guid, buf, 39);
326     return register_key_defvalueW(base, name, buf);
327 }
328
329 /***********************************************************************
330  *              regsvr_key_defvalueW
331  */
332 static LONG register_key_defvalueW(
333     HKEY base,
334     WCHAR const *name,
335     WCHAR const *value)
336 {
337     LONG res;
338     HKEY key;
339
340     res = RegCreateKeyExW(base, name, 0, NULL, 0,
341                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
342     if (res != ERROR_SUCCESS) return res;
343     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
344                          (lstrlenW(value) + 1) * sizeof(WCHAR));
345     RegCloseKey(key);
346     return res;
347 }
348
349 /***********************************************************************
350  *              regsvr_key_defvalueA
351  */
352 static LONG register_key_defvalueA(
353     HKEY base,
354     WCHAR const *name,
355     char const *value)
356 {
357     LONG res;
358     HKEY key;
359
360     res = RegCreateKeyExW(base, name, 0, NULL, 0,
361                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
362     if (res != ERROR_SUCCESS) return res;
363     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
364                          lstrlenA(value) + 1);
365     RegCloseKey(key);
366     return res;
367 }
368
369 /***********************************************************************
370  *              regsvr_progid
371  */
372 static LONG register_progid(
373     WCHAR const *clsid,
374     char const *progid,
375     char const *name)
376 {
377     LONG res;
378     HKEY progid_key;
379
380     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
381                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
382                           &progid_key, NULL);
383     if (res != ERROR_SUCCESS) return res;
384
385     if (name) {
386         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
387                              (CONST BYTE*)name, strlen(name) + 1);
388         if (res != ERROR_SUCCESS) goto error_close_progid_key;
389     }
390
391     if (clsid) {
392         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
393         if (res != ERROR_SUCCESS) goto error_close_progid_key;
394     }
395
396 error_close_progid_key:
397     RegCloseKey(progid_key);
398     return res;
399 }
400
401 /***********************************************************************
402  *              coclass list
403  */
404 static GUID const CLSID_StdOleLink = {
405     0x00000300, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
406
407 static GUID const CLSID_PackagerMoniker = {
408     0x00000308, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
409
410 static GUID const CLSID_PSFactoryBuffer_actxprxy = {
411     0xB8DA6310, 0xE19B, 0x11D0, {0x93,0x3C,0x00,0xA0,0xC9,0x0D,0xCA,0xA9} };
412
413 extern GUID const CLSID_Picture_Metafile;
414 extern GUID const CLSID_Picture_Dib;
415
416 static struct regsvr_coclass const coclass_list[] = {
417     {   &CLSID_StdOleLink,
418         "StdOleLink",
419         NULL,
420         "ole32.dll",
421         NULL
422     },
423     {   &CLSID_FileMoniker,
424         "FileMoniker",
425         NULL,
426         "ole32.dll",
427         "Both",
428         "file"
429     },
430     {   &CLSID_ItemMoniker,
431         "ItemMoniker",
432         NULL,
433         "ole32.dll",
434         "Both"
435     },
436     {   &CLSID_AntiMoniker,
437         "AntiMoniker",
438         NULL,
439         "ole32.dll",
440         "Both"
441     },
442     {   &CLSID_PointerMoniker,
443         "PointerMoniker",
444         NULL,
445         "ole32.dll",
446         "Both"
447     },
448     {   &CLSID_PackagerMoniker,
449         "PackagerMoniker",
450         NULL,
451         "ole32.dll",
452         "Both"
453     },
454     {   &CLSID_CompositeMoniker,
455         "CompositeMoniker",
456         NULL,
457         "ole32.dll",
458         "Both"
459     },
460     {   &CLSID_DfMarshal,
461         "DfMarshal",
462         NULL,
463         "ole32.dll",
464         "Both"
465     },
466     {   &CLSID_Picture_Metafile,
467         "Picture (Metafile)",
468         NULL,
469         "ole32.dll",
470         NULL,
471         "StaticMetafile"
472     },
473     {   &CLSID_Picture_Dib,
474         "Picture (Device Independent Bitmap)",
475         NULL,
476         "ole32.dll",
477         NULL,
478         "StaticDib"
479     },
480     {   &CLSID_ClassMoniker,
481         "ClassMoniker",
482         NULL,
483         "ole32.dll",
484         "Both",
485         "CLSID"
486     },
487     {   &CLSID_PSFactoryBuffer,
488         "PSFactoryBuffer",
489         NULL,
490         "ole32.dll",
491         "Both"
492     },
493     {   &CLSID_StdGlobalInterfaceTable,
494         "StdGlobalInterfaceTable",
495         NULL,
496         "ole32.dll",
497         "Apartment"
498     },
499     {   &CLSID_StdComponentCategoriesMgr,
500         "Component Categories Manager",
501         NULL,
502         "ole32.dll",
503         "Both"
504     },
505     { NULL }                    /* list terminator */
506 };
507
508 /***********************************************************************
509  *              interface list
510  */
511
512 #define INTERFACE_ENTRY(interface, base, clsid32, clsid16) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), clsid16, clsid32 }
513 #define BAS_INTERFACE_ENTRY(interface, base) INTERFACE_ENTRY(interface, &IID_##base, &CLSID_PSFactoryBuffer, NULL)
514 #define STD_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer, NULL)
515 #define ACTX_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer_actxprxy, NULL)
516 #define LCL_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, NULL, NULL)
517
518 static const struct regsvr_interface interface_list[] = {
519     LCL_INTERFACE_ENTRY(IUnknown),
520     STD_INTERFACE_ENTRY(IClassFactory),
521     LCL_INTERFACE_ENTRY(IMalloc),
522     LCL_INTERFACE_ENTRY(IMarshal),
523     STD_INTERFACE_ENTRY(ILockBytes),
524     STD_INTERFACE_ENTRY(IStorage),
525     STD_INTERFACE_ENTRY(IStream),
526     STD_INTERFACE_ENTRY(IEnumSTATSTG),
527     STD_INTERFACE_ENTRY(IBindCtx),
528     BAS_INTERFACE_ENTRY(IMoniker, IPersistStream),
529     STD_INTERFACE_ENTRY(IRunningObjectTable),
530     STD_INTERFACE_ENTRY(IRootStorage),
531     LCL_INTERFACE_ENTRY(IMessageFilter),
532     LCL_INTERFACE_ENTRY(IStdMarshalInfo),
533     LCL_INTERFACE_ENTRY(IExternalConnection),
534     LCL_INTERFACE_ENTRY(IMallocSpy),
535     LCL_INTERFACE_ENTRY(IMultiQI),
536     STD_INTERFACE_ENTRY(IEnumUnknown),
537     STD_INTERFACE_ENTRY(IEnumString),
538     STD_INTERFACE_ENTRY(IEnumMoniker),
539     STD_INTERFACE_ENTRY(IEnumFORMATETC),
540     STD_INTERFACE_ENTRY(IEnumOLEVERB),
541     STD_INTERFACE_ENTRY(IEnumSTATDATA),
542     BAS_INTERFACE_ENTRY(IPersistStream, IPersist),
543     BAS_INTERFACE_ENTRY(IPersistStorage, IPersist),
544     BAS_INTERFACE_ENTRY(IPersistFile, IPersist),
545     STD_INTERFACE_ENTRY(IPersist),
546     STD_INTERFACE_ENTRY(IViewObject),
547     STD_INTERFACE_ENTRY(IDataObject),
548     STD_INTERFACE_ENTRY(IAdviseSink),
549     LCL_INTERFACE_ENTRY(IDataAdviseHolder),
550     LCL_INTERFACE_ENTRY(IOleAdviseHolder),
551     STD_INTERFACE_ENTRY(IOleObject),
552     BAS_INTERFACE_ENTRY(IOleInPlaceObject, IOleWindow),
553     STD_INTERFACE_ENTRY(IOleWindow),
554     BAS_INTERFACE_ENTRY(IOleInPlaceUIWindow, IOleWindow),
555     STD_INTERFACE_ENTRY(IOleInPlaceFrame),
556     BAS_INTERFACE_ENTRY(IOleInPlaceActiveObject, IOleWindow),
557     STD_INTERFACE_ENTRY(IOleClientSite),
558     BAS_INTERFACE_ENTRY(IOleInPlaceSite, IOleWindow),
559     STD_INTERFACE_ENTRY(IParseDisplayName),
560     BAS_INTERFACE_ENTRY(IOleContainer, IParseDisplayName),
561     BAS_INTERFACE_ENTRY(IOleItemContainer, IOleContainer),
562     STD_INTERFACE_ENTRY(IOleLink),
563     STD_INTERFACE_ENTRY(IOleCache),
564     LCL_INTERFACE_ENTRY(IDropSource),
565     STD_INTERFACE_ENTRY(IDropTarget),
566     BAS_INTERFACE_ENTRY(IAdviseSink2, IAdviseSink),
567     STD_INTERFACE_ENTRY(IRunnableObject),
568     BAS_INTERFACE_ENTRY(IViewObject2, IViewObject),
569     BAS_INTERFACE_ENTRY(IOleCache2, IOleCache),
570     STD_INTERFACE_ENTRY(IOleCacheControl),
571     STD_INTERFACE_ENTRY(IRemUnknown),
572     LCL_INTERFACE_ENTRY(IClientSecurity),
573     LCL_INTERFACE_ENTRY(IServerSecurity),
574     STD_INTERFACE_ENTRY(ISequentialStream),
575     ACTX_INTERFACE_ENTRY(IEnumGUID),
576     ACTX_INTERFACE_ENTRY(IEnumCATEGORYINFO),
577     ACTX_INTERFACE_ENTRY(ICatRegister),
578     ACTX_INTERFACE_ENTRY(ICatInformation),
579     { NULL }                    /* list terminator */
580 };
581
582 /***********************************************************************
583  *              DllRegisterServer (OLE32.@)
584  */
585 HRESULT WINAPI DllRegisterServer(void)
586 {
587     HRESULT hr;
588
589     TRACE("\n");
590
591     hr = register_coclasses(coclass_list);
592     if (SUCCEEDED(hr))
593         hr = register_interfaces(interface_list);
594     return hr;
595 }
596
597 /***********************************************************************
598  *              DllUnregisterServer (OLE32.@)
599  */
600 HRESULT WINAPI DllUnregisterServer(void)
601 {
602     HRESULT hr;
603
604     TRACE("\n");
605
606     hr = unregister_coclasses(coclass_list);
607     if (SUCCEEDED(hr))
608         hr = unregister_interfaces(interface_list);
609     return hr;
610 }