msxml3/tests: Avoid a crash that happens on some native systems.
[wine] / dlls / msxml3 / regsvr.c
1 /*
2  *      MSXML3 self-registerable dll functions
3  *
4  * Copyright (C) 2003 John K. Hohm
5  * Copyright (C) 2006 Robert Shearman
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "winerror.h"
32 #include "ole2.h"
33 #include "msxml.h"
34 #include "xmldom.h"
35 #include "xmldso.h"
36 #include "msxml2.h"
37
38 /* undef the #define in msxml2 so that we can access the v.2 version
39    independent CLSID as well as the v.3 one. */
40 #undef CLSID_DOMDocument
41
42 #include "msxml_private.h"
43
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(ole);
47
48 /*
49  * Near the bottom of this file are the exported DllRegisterServer and
50  * DllUnregisterServer, which make all this worthwhile.
51  */
52
53 /***********************************************************************
54  *              interface for self-registering
55  */
56 struct regsvr_interface
57 {
58     IID const *iid;             /* NULL for end of list */
59     LPCSTR name;                /* can be NULL to omit */
60     IID const *base_iid;        /* can be NULL to omit */
61     int num_methods;            /* can be <0 to omit */
62     CLSID const *ps_clsid;      /* can be NULL to omit */
63     CLSID const *ps_clsid32;    /* can be NULL to omit */
64 };
65
66 static HRESULT register_interfaces(struct regsvr_interface const *list);
67 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
68
69 struct regsvr_coclass
70 {
71     CLSID const *clsid;         /* NULL for end of list */
72     LPCSTR name;                /* can be NULL to omit */
73     LPCSTR ips;                 /* can be NULL to omit */
74     LPCSTR ips32;               /* can be NULL to omit */
75     LPCSTR ips32_tmodel;        /* can be NULL to omit */
76     LPCSTR progid;              /* can be NULL to omit */
77     LPCSTR version;             /* can be NULL to omit */
78 };
79
80 static HRESULT register_coclasses(struct regsvr_coclass const *list);
81 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
82
83 struct progid
84 {
85     LPCSTR name;                /* NULL for end of list */
86     LPCSTR description;         /* can be NULL to omit */
87     CLSID const *clsid;
88     LPCSTR curver;              /* can be NULL to omit */
89 };
90
91 static HRESULT register_progids(struct progid const *list);
92 static HRESULT unregister_progids(struct progid const *list);
93
94 /***********************************************************************
95  *              static string constants
96  */
97 static WCHAR const interface_keyname[10] = {
98     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
99 static WCHAR const base_ifa_keyname[14] = {
100     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
101     'e', 0 };
102 static WCHAR const num_methods_keyname[11] = {
103     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
104 static WCHAR const ps_clsid_keyname[15] = {
105     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
106     'i', 'd', 0 };
107 static WCHAR const ps_clsid32_keyname[17] = {
108     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
109     'i', 'd', '3', '2', 0 };
110 static WCHAR const clsid_keyname[6] = {
111     'C', 'L', 'S', 'I', 'D', 0 };
112 static WCHAR const ips_keyname[13] = {
113     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
114     0 };
115 static WCHAR const ips32_keyname[15] = {
116     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
117     '3', '2', 0 };
118 static WCHAR const progid_keyname[7] = {
119     'P', 'r', 'o', 'g', 'I', 'D', 0 };
120 static WCHAR const versionindependentprogid_keyname[] = {
121     'V', 'e', 'r', 's', 'i', 'o', 'n',
122     'I', 'n', 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 't',
123     'P', 'r', 'o', 'g', 'I', 'D', 0 };
124 static WCHAR const version_keyname[] = {
125     'V', 'e', 'r', 's', 'i', 'o', 'n', 0 };
126 static WCHAR const curver_keyname[] = {
127     'C', 'u', 'r', 'V', 'e', 'r', 0 };
128 static char const tmodel_valuename[] = "ThreadingModel";
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 recursive_delete_key(HKEY key);
139 static LONG recursive_delete_keyA(HKEY base, char const *name);
140 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
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 = recursive_delete_keyW(interface_key, buf);
230     }
231
232     RegCloseKey(interface_key);
233 error_return:
234     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
235 }
236
237 /***********************************************************************
238  *              register_coclasses
239  */
240 static HRESULT register_coclasses(struct regsvr_coclass const *list)
241 {
242     LONG res = ERROR_SUCCESS;
243     HKEY coclass_key;
244
245     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
246                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
247     if (res != ERROR_SUCCESS) goto error_return;
248
249     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
250         WCHAR buf[39];
251         HKEY clsid_key;
252
253         StringFromGUID2(list->clsid, buf, 39);
254         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
255                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
256         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
257
258         if (list->name) {
259             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
260                                  (CONST BYTE*)(list->name),
261                                  strlen(list->name) + 1);
262             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
263         }
264
265         if (list->ips) {
266             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
267             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
268         }
269
270         if (list->ips32) {
271             HKEY ips32_key;
272
273             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
274                                   KEY_READ | KEY_WRITE, NULL,
275                                   &ips32_key, NULL);
276             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277
278             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
279                                  (CONST BYTE*)list->ips32,
280                                  lstrlenA(list->ips32) + 1);
281             if (res == ERROR_SUCCESS && list->ips32_tmodel)
282                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
283                                      (CONST BYTE*)list->ips32_tmodel,
284                                      strlen(list->ips32_tmodel) + 1);
285             RegCloseKey(ips32_key);
286             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
287         }
288
289         if (list->progid) {
290             char *buffer = NULL;
291             LPCSTR progid;
292
293             if (list->version) {
294                 buffer = HeapAlloc(GetProcessHeap(), 0, strlen(list->progid) + strlen(list->version) + 2);
295                 if (!buffer) {
296                     res = ERROR_OUTOFMEMORY;
297                     goto error_close_clsid_key;
298                 }
299                 strcpy(buffer, list->progid);
300                 strcat(buffer, ".");
301                 strcat(buffer, list->version);
302                 progid = buffer;
303             } else
304                 progid = list->progid;
305             res = register_key_defvalueA(clsid_key, progid_keyname,
306                                          progid);
307             HeapFree(GetProcessHeap(), 0, buffer);
308             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
309
310             if (list->version) {
311                 res = register_key_defvalueA(clsid_key, versionindependentprogid_keyname,
312                                              list->progid);
313                 if (res != ERROR_SUCCESS) goto error_close_clsid_key;
314             }
315         }
316
317         if (list->version) {
318             res = register_key_defvalueA(clsid_key, version_keyname,
319                                          list->version);
320             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
321         }
322
323     error_close_clsid_key:
324         RegCloseKey(clsid_key);
325     }
326
327 error_close_coclass_key:
328     RegCloseKey(coclass_key);
329 error_return:
330     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
331 }
332
333 /***********************************************************************
334  *              unregister_coclasses
335  */
336 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
337 {
338     LONG res = ERROR_SUCCESS;
339     HKEY coclass_key;
340
341     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
342                         KEY_READ | KEY_WRITE, &coclass_key);
343     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
344     if (res != ERROR_SUCCESS) goto error_return;
345
346     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
347         WCHAR buf[39];
348
349         StringFromGUID2(list->clsid, buf, 39);
350         res = recursive_delete_keyW(coclass_key, buf);
351         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
352     }
353
354 error_close_coclass_key:
355     RegCloseKey(coclass_key);
356 error_return:
357     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
358 }
359
360 /***********************************************************************
361  *              register_progids
362  */
363 static HRESULT register_progids(struct progid const *list)
364 {
365     LONG res = ERROR_SUCCESS;
366
367     for (; res == ERROR_SUCCESS && list->name; ++list) {
368         WCHAR buf[39];
369         HKEY progid_key;
370
371         res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->name, 0,
372                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
373                           &progid_key, NULL);
374         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
375
376         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
377                          (CONST BYTE*)list->description,
378                          strlen(list->description) + 1);
379         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
380
381         StringFromGUID2(list->clsid, buf, 39);
382
383         res = register_key_defvalueW(progid_key, clsid_keyname, buf);
384         if (res != ERROR_SUCCESS) goto error_close_clsid_key;
385
386         if (list->curver) {
387             res = register_key_defvalueA(progid_key, curver_keyname, list->curver);
388             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
389         }
390
391     error_close_clsid_key:
392         RegCloseKey(progid_key);
393     }
394
395     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
396 }
397
398 /***********************************************************************
399  *              unregister_progids
400  */
401 static HRESULT unregister_progids(struct progid const *list)
402 {
403     LONG res = ERROR_SUCCESS;
404
405     for (; res == ERROR_SUCCESS && list->name; ++list) {
406         res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->name);
407     }
408
409     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
410 }
411
412 /***********************************************************************
413  *              regsvr_key_guid
414  */
415 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
416 {
417     WCHAR buf[39];
418
419     StringFromGUID2(guid, buf, 39);
420     return register_key_defvalueW(base, name, buf);
421 }
422
423 /***********************************************************************
424  *              regsvr_key_defvalueW
425  */
426 static LONG register_key_defvalueW(
427     HKEY base,
428     WCHAR const *name,
429     WCHAR const *value)
430 {
431     LONG res;
432     HKEY key;
433
434     res = RegCreateKeyExW(base, name, 0, NULL, 0,
435                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
436     if (res != ERROR_SUCCESS) return res;
437     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
438                          (lstrlenW(value) + 1) * sizeof(WCHAR));
439     RegCloseKey(key);
440     return res;
441 }
442
443 /***********************************************************************
444  *              regsvr_key_defvalueA
445  */
446 static LONG register_key_defvalueA(
447     HKEY base,
448     WCHAR const *name,
449     char const *value)
450 {
451     LONG res;
452     HKEY key;
453
454     res = RegCreateKeyExW(base, name, 0, NULL, 0,
455                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
456     if (res != ERROR_SUCCESS) return res;
457     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
458                          lstrlenA(value) + 1);
459     RegCloseKey(key);
460     return res;
461 }
462
463 /***********************************************************************
464  *              recursive_delete_key
465  */
466 static LONG recursive_delete_key(HKEY key)
467 {
468     LONG res;
469     WCHAR subkey_name[MAX_PATH];
470     DWORD cName;
471     HKEY subkey;
472
473     for (;;) {
474         cName = sizeof(subkey_name) / sizeof(WCHAR);
475         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
476                             NULL, NULL, NULL, NULL);
477         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
478             res = ERROR_SUCCESS; /* presumably we're done enumerating */
479             break;
480         }
481         res = RegOpenKeyExW(key, subkey_name, 0,
482                             KEY_READ | KEY_WRITE, &subkey);
483         if (res == ERROR_FILE_NOT_FOUND) continue;
484         if (res != ERROR_SUCCESS) break;
485
486         res = recursive_delete_key(subkey);
487         RegCloseKey(subkey);
488         if (res != ERROR_SUCCESS) break;
489     }
490
491     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
492     return res;
493 }
494
495 /***********************************************************************
496  *              recursive_delete_keyA
497  */
498 static LONG recursive_delete_keyA(HKEY base, char const *name)
499 {
500     LONG res;
501     HKEY key;
502
503     res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
504     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
505     if (res != ERROR_SUCCESS) return res;
506     res = recursive_delete_key(key);
507     RegCloseKey(key);
508     return res;
509 }
510
511 /***********************************************************************
512  *              recursive_delete_keyW
513  */
514 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
515 {
516     LONG res;
517     HKEY key;
518
519     res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
520     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
521     if (res != ERROR_SUCCESS) return res;
522     res = recursive_delete_key(key);
523     RegCloseKey(key);
524     return res;
525 }
526
527 /***********************************************************************
528  *              coclass list
529  */
530 static struct regsvr_coclass const coclass_list[] = {
531     {   &CLSID_DOMDocument,
532         "XML DOM Document",
533         NULL,
534         "msxml3.dll",
535         "Both",
536         "Microsoft.XMLDOM",
537         "1.0"
538     },
539     {   &CLSID_DOMDocument2,
540         "XML DOM Document",
541         NULL,
542         "msxml3.dll",
543         "Both",
544         "Msxml2.DOMDocument",
545         "3.0"
546     },
547     {   &CLSID_DOMDocument30,
548         "XML DOM Document 3.0",
549         NULL,
550         "msxml3.dll",
551         "Both",
552         "Msxml2.DOMDocument",
553         "3.0"
554     },
555     {   &CLSID_DOMFreeThreadedDocument,
556         "Free threaded XML DOM Document",
557         NULL,
558         "msxml3.dll",
559         "Both",
560         "Microsoft.FreeThreadedXMLDOM",
561         "1.0"
562     },
563     {   &CLSID_XMLHTTPRequest,
564         "XML HTTP Request",
565         NULL,
566         "msxml3.dll",
567         "Apartment",
568         "Microsoft.XMLHTTP",
569         "1.0"
570     },
571     {   &CLSID_XMLDSOControl,
572         "XML Data Source Object",
573         NULL,
574         "msxml3.dll",
575         "Apartment",
576         "Microsoft.XMLDSO",
577         "1.0"
578     },
579     {   &CLSID_XMLDocument,
580         "Msxml",
581         NULL,
582         "msxml3.dll",
583         "Both",
584         "Msxml"
585     },
586     {   &CLSID_XMLSchemaCache,
587         "XML Schema Cache",
588         NULL,
589         "msxml3.dll",
590         "Both",
591         "Msxml2.XMLSchemaCache",
592         "3.0"
593     },
594     {   &CLSID_XMLSchemaCache30,
595         "XML Schema Cache 3.0",
596         NULL,
597         "msxml3.dll",
598         "Both",
599         "Msxml2.XMLSchemaCache",
600         "3.0"
601     },
602     { NULL }                    /* list terminator */
603 };
604
605 /***********************************************************************
606  *              interface list
607  */
608 static struct regsvr_interface const interface_list[] = {
609     { NULL }                    /* list terminator */
610 };
611
612 /***********************************************************************
613  *              progid list
614  */
615 static struct progid const progid_list[] = {
616     {   "Microsoft.XMLDOM",
617         "XML DOM Document",
618         &CLSID_DOMDocument,
619         "Microsoft.XMLDOM.1.0"
620     },
621     {   "Microsoft.XMLDOM.1.0",
622         "XML DOM Document",
623         &CLSID_DOMDocument,
624         NULL
625     },
626     {   "MSXML.DOMDocument",
627         "XML DOM Document",
628         &CLSID_DOMDocument,
629         "Microsoft.XMLDOM.1.0"
630     },
631     {   "Msxml2.DOMDocument",
632         "XML DOM Document",
633         &CLSID_DOMDocument2,
634         "Msxml2.DOMDocument.3.0"
635     },
636     {   "Msxml2.DOMDocument.3.0",
637         "XML DOM Document 3.0",
638         &CLSID_DOMDocument30,
639         NULL
640     },
641     {   "Microsoft.FreeThreadedXMLDOM",
642         "Free threaded XML DOM Document",
643         &CLSID_DOMFreeThreadedDocument,
644         "Microsoft.FreeThreadedXMLDOM.1.0"
645     },
646     {   "Microsoft.FreeThreadedXMLDOM.1.0",
647         "Free threaded XML DOM Document",
648         &CLSID_DOMFreeThreadedDocument,
649         NULL
650     },
651     {   "MSXML.FreeThreadedDOMDocument",
652         "Free threaded XML DOM Document",
653         &CLSID_DOMFreeThreadedDocument,
654         "Microsoft.FreeThreadedXMLDOM.1.0"
655     },
656     {   "Microsoft.XMLHTTP",
657         "XML HTTP Request",
658         &CLSID_XMLHTTPRequest,
659         "Microsoft.XMLHTTP.1.0"
660     },
661     {   "Microsoft.XMLHTTP.1.0",
662         "XML HTTP Request",
663         &CLSID_XMLHTTPRequest,
664         NULL
665     },
666     {   "Microsoft.XMLDSO",
667         "XML Data Source Object",
668         &CLSID_XMLDSOControl,
669         "Microsoft.XMLDSO.1.0"
670     },
671     {   "Microsoft.XMLDSO.1.0",
672         "XML Data Source Object",
673         &CLSID_XMLDSOControl,
674         NULL
675     },
676     {   "Msxml",
677         "Msxml",
678         &CLSID_XMLDocument,
679         NULL
680     },
681     {   "Msxml2.XMLSchemaCache",
682         "XML Schema Cache",
683         &CLSID_XMLSchemaCache,
684         "Msxml2.XMLSchemaCache.3.0"
685     },
686     {   "Msxml2.XMLSchemaCache.3.0",
687         "XML Schema Cache 3.0",
688         &CLSID_XMLSchemaCache30,
689         NULL
690     },
691
692     { NULL }                    /* list terminator */
693 };
694
695 /***********************************************************************
696  *              DllRegisterServer (OLEAUT32.@)
697  */
698 HRESULT WINAPI DllRegisterServer(void)
699 {
700     HRESULT hr;
701
702     TRACE("\n");
703
704     hr = register_coclasses(coclass_list);
705     if (SUCCEEDED(hr))
706         hr = register_interfaces(interface_list);
707     if (SUCCEEDED(hr))
708         hr = register_progids(progid_list);
709     return hr;
710 }
711
712 /***********************************************************************
713  *              DllUnregisterServer (OLEAUT32.@)
714  */
715 HRESULT WINAPI DllUnregisterServer(void)
716 {
717     HRESULT hr;
718
719     TRACE("\n");
720
721     hr = unregister_coclasses(coclass_list);
722     if (SUCCEEDED(hr))
723         hr = unregister_interfaces(interface_list);
724     if (SUCCEEDED(hr))
725         hr = unregister_progids(progid_list);
726     return hr;
727 }