- Media Types (and Extensions) should use "Source Filter" instead of
[wine] / dlls / quartz / regsvr.c
1 /*
2  *      self-registerable dll functions for quartz.dll
3  *
4  * Copyright (C) 2003 John K. Hohm
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define COM_NO_WINDOWS_H
22 #include <stdarg.h>
23 #include <string.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winerror.h"
30
31 #include "ole2.h"
32 #include "uuids.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
37
38 /*
39  * Near the bottom of this file are the exported DllRegisterServer and
40  * DllUnregisterServer, which make all this worthwhile.
41  */
42
43 /***********************************************************************
44  *              interface for self-registering
45  */
46 struct regsvr_interface
47 {
48     IID const *iid;             /* NULL for end of list */
49     LPCSTR name;                /* can be NULL to omit */
50     IID const *base_iid;        /* can be NULL to omit */
51     int num_methods;            /* can be <0 to omit */
52     CLSID const *ps_clsid;      /* can be NULL to omit */
53     CLSID const *ps_clsid32;    /* can be NULL to omit */
54 };
55
56 static HRESULT register_interfaces(struct regsvr_interface const *list);
57 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
58
59 struct regsvr_coclass
60 {
61     CLSID const *clsid;         /* NULL for end of list */
62     LPCSTR name;                /* can be NULL to omit */
63     LPCSTR ips;                 /* can be NULL to omit */
64     LPCSTR ips32;               /* can be NULL to omit */
65     LPCSTR ips32_tmodel;        /* can be NULL to omit */
66     LPCSTR progid;              /* can be NULL to omit */
67     LPCSTR viprogid;            /* can be NULL to omit */
68     LPCSTR progid_extra;        /* can be NULL to omit */
69 };
70
71 static HRESULT register_coclasses(struct regsvr_coclass const *list);
72 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
73
74 struct regsvr_mediatype_parsing
75 {
76     CLSID const *majortype;     /* NULL for end of list */
77     CLSID const *subtype;
78     LPCSTR line[11];            /* NULL for end of list */
79 };
80
81 static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
82 static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
83
84 struct regsvr_mediatype_extension
85 {
86     CLSID const *majortype;     /* NULL for end of list */
87     CLSID const *subtype;
88     LPCSTR extension;
89 };
90
91 static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list);
92 static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension 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 curver_keyname[7] = {
113     'C', 'u', 'r', 'V', 'e', 'r', 0 };
114 static WCHAR const ips_keyname[13] = {
115     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
116     0 };
117 static WCHAR const ips32_keyname[15] = {
118     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
119     '3', '2', 0 };
120 static WCHAR const progid_keyname[7] = {
121     'P', 'r', 'o', 'g', 'I', 'D', 0 };
122 static WCHAR const viprogid_keyname[25] = {
123     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
124     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
125     0 };
126 static char const tmodel_valuename[] = "ThreadingModel";
127 static WCHAR const mediatype_name[11] = {
128     'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
129 static WCHAR const subtype_valuename[8] = {
130     'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
131 static WCHAR const sourcefilter_valuename[14] = {
132     'S', 'o', 'u', 'r', 'c', 'e', ' ', 'F', 'i', 'l', 't', 'e', 'r', 0 };
133 static WCHAR const extensions_keyname[11] = {
134     'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 0 };
135
136 /***********************************************************************
137  *              static helper functions
138  */
139 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
140 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
141                                    WCHAR const *value);
142 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
143                                    char const *value);
144 static LONG register_progid(WCHAR const *clsid,
145                             char const *progid, char const *curver_progid,
146                             char const *name, char const *extra);
147 static LONG recursive_delete_key(HKEY key);
148 static LONG recursive_delete_keyA(HKEY base, char const *name);
149 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
150
151 /***********************************************************************
152  *              register_interfaces
153  */
154 static HRESULT register_interfaces(struct regsvr_interface const *list)
155 {
156     LONG res = ERROR_SUCCESS;
157     HKEY interface_key;
158
159     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
160                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
161     if (res != ERROR_SUCCESS) goto error_return;
162
163     for (; res == ERROR_SUCCESS && list->iid; ++list) {
164         WCHAR buf[39];
165         HKEY iid_key;
166
167         StringFromGUID2(list->iid, buf, 39);
168         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
169                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
170         if (res != ERROR_SUCCESS) goto error_close_interface_key;
171
172         if (list->name) {
173             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
174                                  (CONST BYTE*)(list->name),
175                                  strlen(list->name) + 1);
176             if (res != ERROR_SUCCESS) goto error_close_iid_key;
177         }
178
179         if (list->base_iid) {
180             register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
181             if (res != ERROR_SUCCESS) goto error_close_iid_key;
182         }
183
184         if (0 <= list->num_methods) {
185             static WCHAR const fmt[3] = { '%', 'd', 0 };
186             HKEY key;
187
188             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
189                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
190             if (res != ERROR_SUCCESS) goto error_close_iid_key;
191
192             wsprintfW(buf, fmt, list->num_methods);
193             res = RegSetValueExW(key, NULL, 0, REG_SZ,
194                                  (CONST BYTE*)buf,
195                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
196             RegCloseKey(key);
197
198             if (res != ERROR_SUCCESS) goto error_close_iid_key;
199         }
200
201         if (list->ps_clsid) {
202             register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
203             if (res != ERROR_SUCCESS) goto error_close_iid_key;
204         }
205
206         if (list->ps_clsid32) {
207             register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
208             if (res != ERROR_SUCCESS) goto error_close_iid_key;
209         }
210
211     error_close_iid_key:
212         RegCloseKey(iid_key);
213     }
214
215 error_close_interface_key:
216     RegCloseKey(interface_key);
217 error_return:
218     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
219 }
220
221 /***********************************************************************
222  *              unregister_interfaces
223  */
224 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
225 {
226     LONG res = ERROR_SUCCESS;
227     HKEY interface_key;
228
229     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
230                         KEY_READ | KEY_WRITE, &interface_key);
231     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
232     if (res != ERROR_SUCCESS) goto error_return;
233
234     for (; res == ERROR_SUCCESS && list->iid; ++list) {
235         WCHAR buf[39];
236
237         StringFromGUID2(list->iid, buf, 39);
238         res = recursive_delete_keyW(interface_key, buf);
239     }
240
241     RegCloseKey(interface_key);
242 error_return:
243     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
244 }
245
246 /***********************************************************************
247  *              register_coclasses
248  */
249 static HRESULT register_coclasses(struct regsvr_coclass const *list)
250 {
251     LONG res = ERROR_SUCCESS;
252     HKEY coclass_key;
253
254     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
255                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
256     if (res != ERROR_SUCCESS) goto error_return;
257
258     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
259         WCHAR buf[39];
260         HKEY clsid_key;
261
262         StringFromGUID2(list->clsid, buf, 39);
263         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
264                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
265         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
266
267         if (list->name) {
268             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
269                                  (CONST BYTE*)(list->name),
270                                  strlen(list->name) + 1);
271             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
272         }
273
274         if (list->ips) {
275             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
276             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
277         }
278
279         if (list->ips32) {
280             HKEY ips32_key;
281
282             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
283                                   KEY_READ | KEY_WRITE, NULL,
284                                   &ips32_key, NULL);
285             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
286
287             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
288                                  (CONST BYTE*)list->ips32,
289                                  lstrlenA(list->ips32) + 1);
290             if (res == ERROR_SUCCESS && list->ips32_tmodel)
291                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
292                                      (CONST BYTE*)list->ips32_tmodel,
293                                      strlen(list->ips32_tmodel) + 1);
294             RegCloseKey(ips32_key);
295             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
296         }
297
298         if (list->progid) {
299             res = register_key_defvalueA(clsid_key, progid_keyname,
300                                          list->progid);
301             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
302
303             res = register_progid(buf, list->progid, NULL,
304                                   list->name, list->progid_extra);
305             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
306         }
307
308         if (list->viprogid) {
309             res = register_key_defvalueA(clsid_key, viprogid_keyname,
310                                          list->viprogid);
311             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
312
313             res = register_progid(buf, list->viprogid, list->progid,
314                                   list->name, list->progid_extra);
315             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
316         }
317
318     error_close_clsid_key:
319         RegCloseKey(clsid_key);
320     }
321
322 error_close_coclass_key:
323     RegCloseKey(coclass_key);
324 error_return:
325     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
326 }
327
328 /***********************************************************************
329  *              unregister_coclasses
330  */
331 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
332 {
333     LONG res = ERROR_SUCCESS;
334     HKEY coclass_key;
335
336     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
337                         KEY_READ | KEY_WRITE, &coclass_key);
338     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
339     if (res != ERROR_SUCCESS) goto error_return;
340
341     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
342         WCHAR buf[39];
343
344         StringFromGUID2(list->clsid, buf, 39);
345         res = recursive_delete_keyW(coclass_key, buf);
346         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
347
348         if (list->progid) {
349             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
350             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
351         }
352
353         if (list->viprogid) {
354             res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
355             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
356         }
357     }
358
359 error_close_coclass_key:
360     RegCloseKey(coclass_key);
361 error_return:
362     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
363 }
364
365 /***********************************************************************
366  *              register_mediatypes_parsing
367  */
368 static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
369 {
370     LONG res = ERROR_SUCCESS;
371     HKEY mediatype_key;
372     WCHAR buf[39];
373     int i;
374
375     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
376                           KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
377     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
378
379     for (; res == ERROR_SUCCESS && list->majortype; ++list) {
380         HKEY majortype_key = NULL;
381         HKEY subtype_key = NULL;
382
383         StringFromGUID2(list->majortype, buf, 39);
384         res = RegCreateKeyExW(mediatype_key, buf, 0, NULL, 0,
385                               KEY_READ | KEY_WRITE, NULL, &majortype_key, NULL);
386         if (res != ERROR_SUCCESS) goto error_close_keys;
387
388         StringFromGUID2(list->subtype, buf, 39);
389         res = RegCreateKeyExW(majortype_key, buf, 0, NULL, 0,
390                               KEY_READ | KEY_WRITE, NULL, &subtype_key, NULL);
391         if (res != ERROR_SUCCESS) goto error_close_keys;
392
393         StringFromGUID2(&CLSID_AsyncReader, buf, 39);
394         res = RegSetValueExW(subtype_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
395                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
396         if (res != ERROR_SUCCESS) goto error_close_keys;
397
398         for(i = 0; list->line[i]; i++) {
399             char buffer[3];
400             wsprintfA(buffer, "%d", i);
401             res = RegSetValueExA(subtype_key, buffer, 0, REG_SZ, (CONST BYTE*)list->line[i],
402                                  lstrlenA(list->line[i]));
403             if (res != ERROR_SUCCESS) goto error_close_keys;
404         }
405
406 error_close_keys:
407         if (majortype_key)
408             RegCloseKey(majortype_key);
409         if (subtype_key)
410             RegCloseKey(subtype_key);
411     }
412
413     RegCloseKey(mediatype_key);
414
415     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
416 }
417
418 /***********************************************************************
419  *              register_mediatypes_extension
420  */
421 static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list)
422 {
423     LONG res = ERROR_SUCCESS;
424     HKEY mediatype_key;
425     HKEY extensions_root_key = NULL;
426     WCHAR buf[39];
427
428     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
429                           KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
430     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
431
432     res = RegCreateKeyExW(mediatype_key, extensions_keyname, 0, NULL, 0,
433                           KEY_READ | KEY_WRITE, NULL, &extensions_root_key, NULL);
434     if (res != ERROR_SUCCESS) goto error_return;
435
436     for (; res == ERROR_SUCCESS && list->majortype; ++list) {
437         HKEY extension_key;
438
439         res = RegCreateKeyExA(extensions_root_key, list->extension, 0, NULL, 0,
440                               KEY_READ | KEY_WRITE, NULL, &extension_key, NULL);
441         if (res != ERROR_SUCCESS) break;
442
443         StringFromGUID2(list->majortype, buf, 39);
444         res = RegSetValueExW(extension_key, mediatype_name, 0, REG_SZ, (CONST BYTE*)buf,
445                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
446         if (res != ERROR_SUCCESS) goto error_close_key;
447
448         StringFromGUID2(list->subtype, buf, 39);
449         res = RegSetValueExW(extension_key, subtype_valuename, 0, REG_SZ, (CONST BYTE*)buf,
450                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
451         if (res != ERROR_SUCCESS) goto error_close_key;
452
453         StringFromGUID2(&CLSID_AsyncReader, buf, 39);
454         res = RegSetValueExW(extension_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
455                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
456         if (res != ERROR_SUCCESS) goto error_close_key;
457
458 error_close_key:
459         RegCloseKey(extension_key);
460     }
461
462 error_return:
463     RegCloseKey(mediatype_key);
464     if (extensions_root_key)
465         RegCloseKey(extensions_root_key);
466
467     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
468 }
469
470 /***********************************************************************
471  *              unregister_mediatypes_parsing
472  */
473 static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
474 {
475     LONG res;
476     HKEY mediatype_key;
477     HKEY majortype_key;
478     WCHAR buf[39];
479
480     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
481                         KEY_READ | KEY_WRITE, &mediatype_key);
482     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
483     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
484
485     for (; res == ERROR_SUCCESS && list->majortype; ++list) {
486         StringFromGUID2(list->majortype, buf, 39);
487         res = RegOpenKeyExW(mediatype_key, buf, 0,
488                         KEY_READ | KEY_WRITE, &majortype_key);
489         if (res == ERROR_FILE_NOT_FOUND) {
490             res = ERROR_SUCCESS;
491             continue;
492         }
493         if (res != ERROR_SUCCESS) break;
494
495         StringFromGUID2(list->subtype, buf, 39);
496         res = recursive_delete_keyW(majortype_key, buf);
497         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
498
499         /* Removed majortype key if there is no more subtype key */
500         res = RegDeleteKeyW(majortype_key, 0);
501         if (res == ERROR_ACCESS_DENIED) res = ERROR_SUCCESS;
502
503         RegCloseKey(majortype_key);
504     }
505
506     RegCloseKey(mediatype_key);
507
508     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
509 }
510
511 /***********************************************************************
512  *              unregister_mediatypes_extension
513  */
514 static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list)
515 {
516     LONG res;
517     HKEY mediatype_key;
518     HKEY extensions_root_key = NULL;
519
520     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
521                         KEY_READ | KEY_WRITE, &mediatype_key);
522     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
523     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
524
525     res = RegOpenKeyExW(mediatype_key, extensions_keyname, 0,
526                         KEY_READ | KEY_WRITE, &extensions_root_key);
527     if (res == ERROR_FILE_NOT_FOUND)
528         res = ERROR_SUCCESS;
529     else if (res == ERROR_SUCCESS)
530         for (; res == ERROR_SUCCESS && list->majortype; ++list) {
531             res = recursive_delete_keyA(extensions_root_key, list->extension);
532             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
533         }
534
535     RegCloseKey(mediatype_key);
536     if (extensions_root_key)
537         RegCloseKey(extensions_root_key);
538
539     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
540 }
541
542 /***********************************************************************
543  *              regsvr_key_guid
544  */
545 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
546 {
547     WCHAR buf[39];
548
549     StringFromGUID2(guid, buf, 39);
550     return register_key_defvalueW(base, name, buf);
551 }
552
553 /***********************************************************************
554  *              regsvr_key_defvalueW
555  */
556 static LONG register_key_defvalueW(
557     HKEY base,
558     WCHAR const *name,
559     WCHAR const *value)
560 {
561     LONG res;
562     HKEY key;
563
564     res = RegCreateKeyExW(base, name, 0, NULL, 0,
565                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
566     if (res != ERROR_SUCCESS) return res;
567     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
568                          (lstrlenW(value) + 1) * sizeof(WCHAR));
569     RegCloseKey(key);
570     return res;
571 }
572
573 /***********************************************************************
574  *              regsvr_key_defvalueA
575  */
576 static LONG register_key_defvalueA(
577     HKEY base,
578     WCHAR const *name,
579     char const *value)
580 {
581     LONG res;
582     HKEY key;
583
584     res = RegCreateKeyExW(base, name, 0, NULL, 0,
585                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
586     if (res != ERROR_SUCCESS) return res;
587     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
588                          lstrlenA(value) + 1);
589     RegCloseKey(key);
590     return res;
591 }
592
593 /***********************************************************************
594  *              regsvr_progid
595  */
596 static LONG register_progid(
597     WCHAR const *clsid,
598     char const *progid,
599     char const *curver_progid,
600     char const *name,
601     char const *extra)
602 {
603     LONG res;
604     HKEY progid_key;
605
606     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
607                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
608                           &progid_key, NULL);
609     if (res != ERROR_SUCCESS) return res;
610
611     if (name) {
612         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
613                              (CONST BYTE*)name, strlen(name) + 1);
614         if (res != ERROR_SUCCESS) goto error_close_progid_key;
615     }
616
617     if (clsid) {
618         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
619         if (res != ERROR_SUCCESS) goto error_close_progid_key;
620     }
621
622     if (curver_progid) {
623         res = register_key_defvalueA(progid_key, curver_keyname,
624                                      curver_progid);
625         if (res != ERROR_SUCCESS) goto error_close_progid_key;
626     }
627
628     if (extra) {
629         HKEY extra_key;
630
631         res = RegCreateKeyExA(progid_key, extra, 0,
632                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
633                               &extra_key, NULL);
634         if (res == ERROR_SUCCESS)
635             RegCloseKey(extra_key);
636     }
637
638 error_close_progid_key:
639     RegCloseKey(progid_key);
640     return res;
641 }
642
643 /***********************************************************************
644  *              recursive_delete_key
645  */
646 static LONG recursive_delete_key(HKEY key)
647 {
648     LONG res;
649     WCHAR subkey_name[MAX_PATH];
650     DWORD cName;
651     HKEY subkey;
652
653     for (;;) {
654         cName = sizeof(subkey_name) / sizeof(WCHAR);
655         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
656                             NULL, NULL, NULL, NULL);
657         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
658             res = ERROR_SUCCESS; /* presumably we're done enumerating */
659             break;
660         }
661         res = RegOpenKeyExW(key, subkey_name, 0,
662                             KEY_READ | KEY_WRITE, &subkey);
663         if (res == ERROR_FILE_NOT_FOUND) continue;
664         if (res != ERROR_SUCCESS) break;
665
666         res = recursive_delete_key(subkey);
667         RegCloseKey(subkey);
668         if (res != ERROR_SUCCESS) break;
669     }
670
671     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
672     return res;
673 }
674
675 /***********************************************************************
676  *              recursive_delete_keyA
677  */
678 static LONG recursive_delete_keyA(HKEY base, char const *name)
679 {
680     LONG res;
681     HKEY key;
682
683     res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
684     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
685     if (res != ERROR_SUCCESS) return res;
686     res = recursive_delete_key(key);
687     RegCloseKey(key);
688     return res;
689 }
690
691 /***********************************************************************
692  *              recursive_delete_keyW
693  */
694 static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
695 {
696     LONG res;
697     HKEY key;
698
699     res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
700     if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
701     if (res != ERROR_SUCCESS) return res;
702     res = recursive_delete_key(key);
703     RegCloseKey(key);
704     return res;
705 }
706
707 /***********************************************************************
708  *              coclass list
709  */
710 static struct regsvr_coclass const coclass_list[] = {
711     {   &CLSID_FilterGraph,
712         "Filter Graph",
713         NULL,
714         "quartz.dll",
715         "Both"
716     },
717     {   &CLSID_FilterMapper,
718         "Filter Mapper",
719         NULL,
720         "quartz.dll",
721         "Both"
722     },
723     {   &CLSID_FilterMapper2,
724         "Filter Mapper2",
725         NULL,
726         "quartz.dll",
727         "Both"
728     },
729     {   &CLSID_SystemClock,
730         "System Clock",
731         NULL,
732         "quartz.dll",
733         "Both"
734     },
735     {   &CLSID_MemoryAllocator,
736         "Memory Allocator",
737         NULL,
738         "quartz.dll",
739         "Both"
740     },
741     {   &CLSID_AsyncReader,
742         "File Source Filter",
743         NULL,
744         "quartz.dll",
745         "Both"
746     },
747     {   &CLSID_AviSplitter,
748         "AVI Splitter",
749         NULL,
750         "quartz.dll",
751         "Both"
752     },
753     {   &CLSID_AVIDec,
754         "AVI Decompressor",
755         NULL,
756         "quartz.dll",
757         "Both"
758     },
759     {   &CLSID_DSoundRender,
760         "DirectSound Audio Renderer",
761         NULL,
762         "quartz.dll",
763         "Both"
764     },
765     {   &CLSID_VideoRenderer,
766         "Video Renderer",
767         NULL,
768         "quartz.dll",
769         "Both"
770     },
771     { NULL }                    /* list terminator */
772 };
773
774 /***********************************************************************
775  *              interface list
776  */
777
778 static struct regsvr_interface const interface_list[] = {
779     { NULL }                    /* list terminator */
780 };
781
782 /***********************************************************************
783  *              mediatype list
784  */
785
786 static struct regsvr_mediatype_parsing const mediatype_parsing_list[] = {
787     {   &MEDIATYPE_Stream,
788         &MEDIASUBTYPE_Avi,
789         {   "0,4,,52494646,8,4,,41564920",
790             NULL }
791     },
792     {   &MEDIATYPE_Stream,
793         &MEDIASUBTYPE_MPEG1System,
794         {   "0, 16, FFFFFFFFF100010001800001FFFFFFFF, 000001BA2100010001800001000001BB",
795             NULL }
796     },
797     {   &MEDIATYPE_Stream,
798         &MEDIASUBTYPE_MPEG1VideoCD,
799         {   "0, 4, , 52494646, 8, 8, , 43445841666D7420, 36, 20, FFFFFFFF00000000FFFFFFFFFFFFFFFFFFFFFFFF, 646174610000000000FFFFFFFFFFFFFFFFFFFF00",
800             NULL }
801     },
802     {   &MEDIATYPE_Stream,
803         &MEDIASUBTYPE_MPEG1Video,
804         {   "0, 4, , 000001B3",
805             NULL }
806     },
807     {   &MEDIATYPE_Stream,
808         &MEDIASUBTYPE_MPEG1Audio,
809         {   "0, 2, FFE0, FFE0",
810             "0, 10, FFFFFFFF000000000000, 494433030080808080",
811             NULL }
812     },
813     {   &MEDIATYPE_Stream,
814         &MEDIASUBTYPE_QTMovie,
815         {   "4, 4, , 6d646174",
816             "4, 4, , 6d6f6f76",
817             NULL }
818     },
819     {   &MEDIATYPE_Stream,
820         &MEDIASUBTYPE_WAVE,
821         {   "0,4,,52494646,8,4,,57415645",
822             NULL }
823     },
824     {   &MEDIATYPE_Stream,
825         &MEDIASUBTYPE_AU,
826         {   "0,4,,2e736e64",
827             NULL }
828     },
829     {   &MEDIATYPE_Stream,
830         &MEDIASUBTYPE_AIFF,
831         {   "0,4,,464f524d,8,4,,41494646",
832             "0,4,,464f524d,8,4,,41494643",
833             NULL }
834     },
835     {   &MEDIATYPE_Stream,
836         &MEDIATYPE_Text,
837         {   "0,4,,4C595249",
838             "0,4,,6C797269",
839             NULL }
840     },
841     {   &MEDIATYPE_Stream,
842         &MEDIATYPE_Midi,
843         {   "0,4,,52494646,8,4,,524D4944",
844             "0,4,,4D546864",
845             NULL }
846     },
847     { NULL }                    /* list terminator */
848 };
849
850 /***********************************************************************
851  *              mediatype list
852  */
853
854 static struct regsvr_mediatype_extension const mediatype_extension_list[] = {
855     {   &MEDIATYPE_Stream,
856         &MEDIASUBTYPE_MPEG1Audio,
857         ".mp3"
858     },
859     { NULL }                    /* list terminator */
860 };
861
862 /***********************************************************************
863  *              DllRegisterServer (QUARTZ.@)
864  */
865 HRESULT WINAPI QUARTZ_DllRegisterServer(void)
866 {
867     HRESULT hr;
868
869     TRACE("\n");
870
871     hr = register_coclasses(coclass_list);
872     if (SUCCEEDED(hr))
873         hr = register_interfaces(interface_list);
874     if (SUCCEEDED(hr))
875         hr = register_mediatypes_parsing(mediatype_parsing_list);
876     if (SUCCEEDED(hr))
877         hr = register_mediatypes_extension(mediatype_extension_list);
878     return hr;
879 }
880
881 /***********************************************************************
882  *              DllUnregisterServer (QUARTZ.@)
883  */
884 HRESULT WINAPI QUARTZ_DllUnregisterServer(void)
885 {
886     HRESULT hr;
887
888     TRACE("\n");
889
890     hr = unregister_coclasses(coclass_list);
891     if (SUCCEEDED(hr))
892         hr = unregister_interfaces(interface_list);
893     if (SUCCEEDED(hr))
894         hr = unregister_mediatypes_parsing(mediatype_parsing_list);
895     if (SUCCEEDED(hr))
896         hr = unregister_mediatypes_extension(mediatype_extension_list);
897     return hr;
898 }