winejoystick.drv: Remove unneeded address-of operator from array name.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23 #define COBJMACROS
24 #include <stdarg.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winreg.h"
32 #include "winerror.h"
33
34 #include "ole2.h"
35 #include "uuids.h"
36 #include "strmif.h"
37
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
41
42 /*
43  * Near the bottom of this file are the exported DllRegisterServer and
44  * DllUnregisterServer, which make all this worthwhile.
45  */
46
47 /***********************************************************************
48  *              interface for self-registering
49  */
50 struct regsvr_interface
51 {
52     IID const *iid;             /* NULL for end of list */
53     LPCSTR name;                /* can be NULL to omit */
54     IID const *base_iid;        /* can be NULL to omit */
55     int num_methods;            /* can be <0 to omit */
56     CLSID const *ps_clsid;      /* can be NULL to omit */
57     CLSID const *ps_clsid32;    /* can be NULL to omit */
58 };
59
60 static HRESULT register_interfaces(struct regsvr_interface const *list);
61 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
62
63 struct regsvr_coclass
64 {
65     CLSID const *clsid;         /* NULL for end of list */
66     LPCSTR name;                /* can be NULL to omit */
67     LPCSTR ips;                 /* can be NULL to omit */
68     LPCSTR ips32;               /* can be NULL to omit */
69     LPCSTR ips32_tmodel;        /* can be NULL to omit */
70     LPCSTR progid;              /* can be NULL to omit */
71     LPCSTR viprogid;            /* can be NULL to omit */
72     LPCSTR progid_extra;        /* 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 struct regsvr_mediatype_parsing
79 {
80     CLSID const *majortype;     /* NULL for end of list */
81     CLSID const *subtype;
82     LPCSTR line[11];            /* NULL for end of list */
83 };
84
85 static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
86 static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
87
88 struct regsvr_mediatype_extension
89 {
90     CLSID const *majortype;     /* NULL for end of list */
91     CLSID const *subtype;
92     LPCSTR extension;
93 };
94
95 struct mediatype
96 {
97     CLSID const *majortype;     /* NULL for end of list */
98     CLSID const *subtype;
99     DWORD fourcc;
100 };
101
102 struct pin
103 {
104     DWORD flags;                /* 0xFFFFFFFF for end of list */
105     struct mediatype mediatypes[11];
106 };
107
108 struct regsvr_filter
109 {
110     CLSID const *clsid;         /* NULL for end of list */
111     CLSID const *category;
112     WCHAR name[50];
113     DWORD merit;
114     struct pin pins[11];
115 };
116
117 static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list);
118 static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list);
119
120 static HRESULT register_filters(struct regsvr_filter const *list);
121 static HRESULT unregister_filters(struct regsvr_filter const *list);
122
123 /***********************************************************************
124  *              static string constants
125  */
126 static WCHAR const interface_keyname[10] = {
127     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
128 static WCHAR const base_ifa_keyname[14] = {
129     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
130     'e', 0 };
131 static WCHAR const num_methods_keyname[11] = {
132     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
133 static WCHAR const ps_clsid_keyname[15] = {
134     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
135     'i', 'd', 0 };
136 static WCHAR const ps_clsid32_keyname[17] = {
137     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
138     'i', 'd', '3', '2', 0 };
139 static WCHAR const clsid_keyname[6] = {
140     'C', 'L', 'S', 'I', 'D', 0 };
141 static WCHAR const curver_keyname[7] = {
142     'C', 'u', 'r', 'V', 'e', 'r', 0 };
143 static WCHAR const ips_keyname[13] = {
144     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
145     0 };
146 static WCHAR const ips32_keyname[15] = {
147     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
148     '3', '2', 0 };
149 static WCHAR const progid_keyname[7] = {
150     'P', 'r', 'o', 'g', 'I', 'D', 0 };
151 static WCHAR const viprogid_keyname[25] = {
152     'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
153     'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
154     0 };
155 static char const tmodel_valuename[] = "ThreadingModel";
156 static WCHAR const mediatype_name[11] = {
157     'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
158 static WCHAR const subtype_valuename[8] = {
159     'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
160 static WCHAR const sourcefilter_valuename[14] = {
161     'S', 'o', 'u', 'r', 'c', 'e', ' ', 'F', 'i', 'l', 't', 'e', 'r', 0 };
162 static WCHAR const extensions_keyname[11] = {
163     'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 0 };
164
165 /***********************************************************************
166  *              static helper functions
167  */
168 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
169 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
170                                    WCHAR const *value);
171 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
172                                    char const *value);
173 static LONG register_progid(WCHAR const *clsid,
174                             char const *progid, char const *curver_progid,
175                             char const *name, char const *extra);
176
177 /***********************************************************************
178  *              register_interfaces
179  */
180 static HRESULT register_interfaces(struct regsvr_interface const *list)
181 {
182     LONG res = ERROR_SUCCESS;
183     HKEY interface_key;
184
185     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
186                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
187     if (res != ERROR_SUCCESS) goto error_return;
188
189     for (; res == ERROR_SUCCESS && list->iid; ++list) {
190         WCHAR buf[39];
191         HKEY iid_key;
192
193         StringFromGUID2(list->iid, buf, 39);
194         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
195                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
196         if (res != ERROR_SUCCESS) goto error_close_interface_key;
197
198         if (list->name) {
199             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
200                                  (CONST BYTE*)(list->name),
201                                  strlen(list->name) + 1);
202             if (res != ERROR_SUCCESS) goto error_close_iid_key;
203         }
204
205         if (list->base_iid) {
206             res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
207             if (res != ERROR_SUCCESS) goto error_close_iid_key;
208         }
209
210         if (0 <= list->num_methods) {
211             static WCHAR const fmt[3] = { '%', 'd', 0 };
212             HKEY key;
213
214             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
215                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
216             if (res != ERROR_SUCCESS) goto error_close_iid_key;
217
218             wsprintfW(buf, fmt, list->num_methods);
219             res = RegSetValueExW(key, NULL, 0, REG_SZ,
220                                  (CONST BYTE*)buf,
221                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
222             RegCloseKey(key);
223
224             if (res != ERROR_SUCCESS) goto error_close_iid_key;
225         }
226
227         if (list->ps_clsid) {
228             res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
229             if (res != ERROR_SUCCESS) goto error_close_iid_key;
230         }
231
232         if (list->ps_clsid32) {
233             res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
234             if (res != ERROR_SUCCESS) goto error_close_iid_key;
235         }
236
237     error_close_iid_key:
238         RegCloseKey(iid_key);
239     }
240
241 error_close_interface_key:
242     RegCloseKey(interface_key);
243 error_return:
244     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
245 }
246
247 /***********************************************************************
248  *              unregister_interfaces
249  */
250 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
251 {
252     LONG res = ERROR_SUCCESS;
253     HKEY interface_key;
254
255     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
256                         KEY_READ | KEY_WRITE, &interface_key);
257     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
258     if (res != ERROR_SUCCESS) goto error_return;
259
260     for (; res == ERROR_SUCCESS && list->iid; ++list) {
261         WCHAR buf[39];
262
263         StringFromGUID2(list->iid, buf, 39);
264         res = RegDeleteTreeW(interface_key, buf);
265         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
266     }
267
268     RegCloseKey(interface_key);
269 error_return:
270     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
271 }
272
273 /***********************************************************************
274  *              register_coclasses
275  */
276 static HRESULT register_coclasses(struct regsvr_coclass const *list)
277 {
278     LONG res = ERROR_SUCCESS;
279     HKEY coclass_key;
280
281     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
282                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
283     if (res != ERROR_SUCCESS) goto error_return;
284
285     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
286         WCHAR buf[39];
287         HKEY clsid_key;
288
289         StringFromGUID2(list->clsid, buf, 39);
290         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
291                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
292         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
293
294         if (list->name) {
295             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
296                                  (CONST BYTE*)(list->name),
297                                  strlen(list->name) + 1);
298             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
299         }
300
301         if (list->ips) {
302             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
303             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
304         }
305
306         if (list->ips32) {
307             HKEY ips32_key;
308
309             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
310                                   KEY_READ | KEY_WRITE, NULL,
311                                   &ips32_key, NULL);
312             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
313
314             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
315                                  (CONST BYTE*)list->ips32,
316                                  lstrlenA(list->ips32) + 1);
317             if (res == ERROR_SUCCESS && list->ips32_tmodel)
318                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
319                                      (CONST BYTE*)list->ips32_tmodel,
320                                      strlen(list->ips32_tmodel) + 1);
321             RegCloseKey(ips32_key);
322             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
323         }
324
325         if (list->progid) {
326             res = register_key_defvalueA(clsid_key, progid_keyname,
327                                          list->progid);
328             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
329
330             res = register_progid(buf, list->progid, NULL,
331                                   list->name, list->progid_extra);
332             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
333         }
334
335         if (list->viprogid) {
336             res = register_key_defvalueA(clsid_key, viprogid_keyname,
337                                          list->viprogid);
338             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
339
340             res = register_progid(buf, list->viprogid, list->progid,
341                                   list->name, list->progid_extra);
342             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
343         }
344
345     error_close_clsid_key:
346         RegCloseKey(clsid_key);
347     }
348
349 error_close_coclass_key:
350     RegCloseKey(coclass_key);
351 error_return:
352     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
353 }
354
355 /***********************************************************************
356  *              unregister_coclasses
357  */
358 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
359 {
360     LONG res = ERROR_SUCCESS;
361     HKEY coclass_key;
362
363     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
364                         KEY_READ | KEY_WRITE, &coclass_key);
365     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
366     if (res != ERROR_SUCCESS) goto error_return;
367
368     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
369         WCHAR buf[39];
370
371         StringFromGUID2(list->clsid, buf, 39);
372         res = RegDeleteTreeW(coclass_key, buf);
373         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
374         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
375
376         if (list->progid) {
377             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
378             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
379             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
380         }
381
382         if (list->viprogid) {
383             res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
384             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
385             if (res != ERROR_SUCCESS) goto error_close_coclass_key;
386         }
387     }
388
389 error_close_coclass_key:
390     RegCloseKey(coclass_key);
391 error_return:
392     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
393 }
394
395 /***********************************************************************
396  *              register_mediatypes_parsing
397  */
398 static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
399 {
400     LONG res = ERROR_SUCCESS;
401     HKEY mediatype_key;
402     WCHAR buf[39];
403     int i;
404
405     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
406                           KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
407     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
408
409     for (; res == ERROR_SUCCESS && list->majortype; ++list) {
410         HKEY majortype_key = NULL;
411         HKEY subtype_key = NULL;
412
413         StringFromGUID2(list->majortype, buf, 39);
414         res = RegCreateKeyExW(mediatype_key, buf, 0, NULL, 0,
415                               KEY_READ | KEY_WRITE, NULL, &majortype_key, NULL);
416         if (res != ERROR_SUCCESS) goto error_close_keys;
417
418         StringFromGUID2(list->subtype, buf, 39);
419         res = RegCreateKeyExW(majortype_key, buf, 0, NULL, 0,
420                               KEY_READ | KEY_WRITE, NULL, &subtype_key, NULL);
421         if (res != ERROR_SUCCESS) goto error_close_keys;
422
423         StringFromGUID2(&CLSID_AsyncReader, buf, 39);
424         res = RegSetValueExW(subtype_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
425                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
426         if (res != ERROR_SUCCESS) goto error_close_keys;
427
428         for(i = 0; list->line[i]; i++) {
429             char buffer[3];
430             wsprintfA(buffer, "%d", i);
431             res = RegSetValueExA(subtype_key, buffer, 0, REG_SZ, (CONST BYTE*)list->line[i],
432                                  lstrlenA(list->line[i]));
433             if (res != ERROR_SUCCESS) goto error_close_keys;
434         }
435
436 error_close_keys:
437         if (majortype_key)
438             RegCloseKey(majortype_key);
439         if (subtype_key)
440             RegCloseKey(subtype_key);
441     }
442
443     RegCloseKey(mediatype_key);
444
445     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
446 }
447
448 /***********************************************************************
449  *              register_mediatypes_extension
450  */
451 static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list)
452 {
453     LONG res = ERROR_SUCCESS;
454     HKEY mediatype_key;
455     HKEY extensions_root_key = NULL;
456     WCHAR buf[39];
457
458     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
459                           KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
460     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
461
462     res = RegCreateKeyExW(mediatype_key, extensions_keyname, 0, NULL, 0,
463                           KEY_READ | KEY_WRITE, NULL, &extensions_root_key, NULL);
464     if (res != ERROR_SUCCESS) goto error_return;
465
466     for (; res == ERROR_SUCCESS && list->majortype; ++list) {
467         HKEY extension_key;
468
469         res = RegCreateKeyExA(extensions_root_key, list->extension, 0, NULL, 0,
470                               KEY_READ | KEY_WRITE, NULL, &extension_key, NULL);
471         if (res != ERROR_SUCCESS) break;
472
473         StringFromGUID2(list->majortype, buf, 39);
474         res = RegSetValueExW(extension_key, mediatype_name, 0, REG_SZ, (CONST BYTE*)buf,
475                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
476         if (res != ERROR_SUCCESS) goto error_close_key;
477
478         StringFromGUID2(list->subtype, buf, 39);
479         res = RegSetValueExW(extension_key, subtype_valuename, 0, REG_SZ, (CONST BYTE*)buf,
480                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
481         if (res != ERROR_SUCCESS) goto error_close_key;
482
483         StringFromGUID2(&CLSID_AsyncReader, buf, 39);
484         res = RegSetValueExW(extension_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
485                              (lstrlenW(buf) + 1) * sizeof(WCHAR));
486         if (res != ERROR_SUCCESS) goto error_close_key;
487
488 error_close_key:
489         RegCloseKey(extension_key);
490     }
491
492 error_return:
493     RegCloseKey(mediatype_key);
494     if (extensions_root_key)
495         RegCloseKey(extensions_root_key);
496
497     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
498 }
499
500 /***********************************************************************
501  *              unregister_mediatypes_parsing
502  */
503 static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
504 {
505     LONG res;
506     HKEY mediatype_key;
507     HKEY majortype_key;
508     WCHAR buf[39];
509
510     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
511                         KEY_READ | KEY_WRITE, &mediatype_key);
512     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
513     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
514
515     for (; res == ERROR_SUCCESS && list->majortype; ++list) {
516         StringFromGUID2(list->majortype, buf, 39);
517         res = RegOpenKeyExW(mediatype_key, buf, 0,
518                         KEY_READ | KEY_WRITE, &majortype_key);
519         if (res == ERROR_FILE_NOT_FOUND) {
520             res = ERROR_SUCCESS;
521             continue;
522         }
523         if (res != ERROR_SUCCESS) break;
524
525         StringFromGUID2(list->subtype, buf, 39);
526         res = RegDeleteTreeW(majortype_key, buf);
527         if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
528
529         /* Removed majortype key if there is no more subtype key */
530         res = RegDeleteKeyW(majortype_key, 0);
531         if (res == ERROR_ACCESS_DENIED) res = ERROR_SUCCESS;
532
533         RegCloseKey(majortype_key);
534     }
535
536     RegCloseKey(mediatype_key);
537
538     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
539 }
540
541 /***********************************************************************
542  *              unregister_mediatypes_extension
543  */
544 static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list)
545 {
546     LONG res;
547     HKEY mediatype_key;
548     HKEY extensions_root_key = NULL;
549
550     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
551                         KEY_READ | KEY_WRITE, &mediatype_key);
552     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
553     if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
554
555     res = RegOpenKeyExW(mediatype_key, extensions_keyname, 0,
556                         KEY_READ | KEY_WRITE, &extensions_root_key);
557     if (res == ERROR_FILE_NOT_FOUND)
558         res = ERROR_SUCCESS;
559     else if (res == ERROR_SUCCESS)
560         for (; res == ERROR_SUCCESS && list->majortype; ++list) {
561             res = RegDeleteTreeA(extensions_root_key, list->extension);
562             if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
563         }
564
565     RegCloseKey(mediatype_key);
566     if (extensions_root_key)
567         RegCloseKey(extensions_root_key);
568
569     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
570 }
571
572 /***********************************************************************
573  *              register_filters
574  */
575 static HRESULT register_filters(struct regsvr_filter const *list)
576 {
577     HRESULT hr;
578     IFilterMapper2* pFM2 = NULL;
579
580     CoInitialize(NULL);
581     hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
582
583     if (SUCCEEDED(hr)) {
584         for (; SUCCEEDED(hr) && list->clsid; ++list) {
585             REGFILTER2 rf2;
586             REGFILTERPINS2* prfp2;
587             int i;
588
589             for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) ;
590             rf2.dwVersion = 2;
591             rf2.dwMerit = list->merit;
592             rf2.u.s1.cPins2 = i;
593             rf2.u.s1.rgPins2 = prfp2 = CoTaskMemAlloc(i*sizeof(REGFILTERPINS2));
594             if (!prfp2) {
595                 hr = E_OUTOFMEMORY;
596                 break;
597             }
598             for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) {
599                 REGPINTYPES* lpMediatype;
600                 CLSID* lpClsid;
601                 int j, nbmt;
602                 
603                 for (nbmt = 0; list->pins[i].mediatypes[nbmt].majortype; nbmt++) ;
604                 /* Allocate a single buffer for regpintypes struct and clsids */
605                 lpMediatype = CoTaskMemAlloc(nbmt*(sizeof(REGPINTYPES) + 2*sizeof(CLSID)));
606                 if (!lpMediatype) {
607                     hr = E_OUTOFMEMORY;
608                     break;
609                 }
610                 lpClsid = (CLSID*) (lpMediatype + nbmt);
611                 for (j = 0; j < nbmt; j++) {
612                     (lpMediatype + j)->clsMajorType = lpClsid + j*2;
613                     memcpy(lpClsid + j*2, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
614                     (lpMediatype + j)->clsMinorType = lpClsid + j*2 + 1;
615                     if (list->pins[i].mediatypes[j].subtype)
616                         memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].subtype, sizeof(CLSID));
617                     else {
618                         /* Subtype are often a combination of major type + fourcc/tag */
619                         memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
620                         *(DWORD*)(lpClsid + j*2 + 1) = list->pins[i].mediatypes[j].fourcc;
621                     }
622                 }
623                 prfp2[i].dwFlags = list->pins[i].flags;
624                 prfp2[i].cInstances = 0;
625                 prfp2[i].nMediaTypes = j;
626                 prfp2[i].lpMediaType = lpMediatype;
627                 prfp2[i].nMediums = 0;
628                 prfp2[i].lpMedium = NULL;
629                 prfp2[i].clsPinCategory = NULL;
630             }
631
632             if (FAILED(hr)) {
633                 ERR("failed to register with hresult 0x%x\n", hr);
634                 CoTaskMemFree(prfp2);
635                 break;
636             }
637
638             hr = IFilterMapper2_RegisterFilter(pFM2, list->clsid, list->name, NULL, list->category, NULL, &rf2);
639
640             while (i) {
641                 CoTaskMemFree((REGPINTYPES*)prfp2[i-1].lpMediaType);
642                 i--;
643             }
644             CoTaskMemFree(prfp2);
645         }
646     }
647
648     if (pFM2)
649         IFilterMapper2_Release(pFM2);
650
651     CoUninitialize();
652
653     return hr;
654 }
655
656 /***********************************************************************
657  *              unregister_filters
658  */
659 static HRESULT unregister_filters(struct regsvr_filter const *list)
660 {
661     HRESULT hr;
662     IFilterMapper2* pFM2;
663
664     CoInitialize(NULL);
665     
666     hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
667
668     if (SUCCEEDED(hr)) {
669         for (; SUCCEEDED(hr) && list->clsid; ++list)
670             hr = IFilterMapper2_UnregisterFilter(pFM2, list->category, NULL, list->clsid);
671         IFilterMapper2_Release(pFM2);
672     }
673
674     CoUninitialize();
675     
676     return hr;
677 }
678
679 /***********************************************************************
680  *              regsvr_key_guid
681  */
682 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
683 {
684     WCHAR buf[39];
685
686     StringFromGUID2(guid, buf, 39);
687     return register_key_defvalueW(base, name, buf);
688 }
689
690 /***********************************************************************
691  *              regsvr_key_defvalueW
692  */
693 static LONG register_key_defvalueW(
694     HKEY base,
695     WCHAR const *name,
696     WCHAR const *value)
697 {
698     LONG res;
699     HKEY key;
700
701     res = RegCreateKeyExW(base, name, 0, NULL, 0,
702                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
703     if (res != ERROR_SUCCESS) return res;
704     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
705                          (lstrlenW(value) + 1) * sizeof(WCHAR));
706     RegCloseKey(key);
707     return res;
708 }
709
710 /***********************************************************************
711  *              regsvr_key_defvalueA
712  */
713 static LONG register_key_defvalueA(
714     HKEY base,
715     WCHAR const *name,
716     char const *value)
717 {
718     LONG res;
719     HKEY key;
720
721     res = RegCreateKeyExW(base, name, 0, NULL, 0,
722                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
723     if (res != ERROR_SUCCESS) return res;
724     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
725                          lstrlenA(value) + 1);
726     RegCloseKey(key);
727     return res;
728 }
729
730 /***********************************************************************
731  *              regsvr_progid
732  */
733 static LONG register_progid(
734     WCHAR const *clsid,
735     char const *progid,
736     char const *curver_progid,
737     char const *name,
738     char const *extra)
739 {
740     LONG res;
741     HKEY progid_key;
742
743     res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
744                           NULL, 0, KEY_READ | KEY_WRITE, NULL,
745                           &progid_key, NULL);
746     if (res != ERROR_SUCCESS) return res;
747
748     if (name) {
749         res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
750                              (CONST BYTE*)name, strlen(name) + 1);
751         if (res != ERROR_SUCCESS) goto error_close_progid_key;
752     }
753
754     if (clsid) {
755         res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
756         if (res != ERROR_SUCCESS) goto error_close_progid_key;
757     }
758
759     if (curver_progid) {
760         res = register_key_defvalueA(progid_key, curver_keyname,
761                                      curver_progid);
762         if (res != ERROR_SUCCESS) goto error_close_progid_key;
763     }
764
765     if (extra) {
766         HKEY extra_key;
767
768         res = RegCreateKeyExA(progid_key, extra, 0,
769                               NULL, 0, KEY_READ | KEY_WRITE, NULL,
770                               &extra_key, NULL);
771         if (res == ERROR_SUCCESS)
772             RegCloseKey(extra_key);
773     }
774
775 error_close_progid_key:
776     RegCloseKey(progid_key);
777     return res;
778 }
779
780 static GUID const CLSID_PSFactoryBuffer = {
781     0x92a3a302, 0xda7c, 0x4a1f, {0xba,0x7e,0x18,0x02,0xbb,0x5d,0x2d,0x02} };
782
783 /***********************************************************************
784  *              coclass list
785  */
786 static struct regsvr_coclass const coclass_list[] = {
787     {   &CLSID_FilterGraph,
788         "Filter Graph",
789         NULL,
790         "quartz.dll",
791         "Both"
792     },
793     {   &CLSID_FilterGraphNoThread,
794         "Filter Graph",
795         NULL,
796         "quartz.dll",
797         "Both"
798     },
799     {   &CLSID_FilterMapper,
800         "Filter Mapper",
801         NULL,
802         "quartz.dll",
803         "Both"
804     },
805     {   &CLSID_FilterMapper2,
806         "Filter Mapper2",
807         NULL,
808         "quartz.dll",
809         "Both"
810     },
811     {   &CLSID_SystemClock,
812         "System Clock",
813         NULL,
814         "quartz.dll",
815         "Both"
816     },
817     {   &CLSID_MemoryAllocator,
818         "Memory Allocator",
819         NULL,
820         "quartz.dll",
821         "Both"
822     },
823     {   &CLSID_SeekingPassThru,
824        "Seeking",
825        NULL,
826        "quartz.dll",
827        "Both"
828     },
829     {   &CLSID_AsyncReader,
830         "File Source Filter",
831         NULL,
832         "quartz.dll",
833         "Both"
834     },
835     {   &CLSID_AviSplitter,
836         "AVI Splitter",
837         NULL,
838         "quartz.dll",
839         "Both"
840     },
841     {   &CLSID_MPEG1Splitter,
842         "MPEG-I Stream Splitter",
843         NULL,
844         "quartz.dll",
845         "Both"
846     },
847     {   &CLSID_AVIDec,
848         "AVI Decompressor",
849         NULL,
850         "quartz.dll",
851         "Both"
852     },
853     {   &CLSID_DSoundRender,
854         "DirectSound Audio Renderer",
855         NULL,
856         "quartz.dll",
857         "Both"
858     },
859     {   &CLSID_AudioRender,
860         "Wave Audio Renderer",
861         NULL,
862         "quartz.dll",
863         "Both"
864     },
865     {   &CLSID_NullRenderer,
866         "Null Renderer",
867         NULL,
868         "quartz.dll",
869         "Both"
870     },
871     {   &CLSID_VideoRenderer,
872         "Video Renderer",
873         NULL,
874         "quartz.dll",
875         "Both"
876     },
877     {   &CLSID_VideoRendererDefault,
878         "Default Video Renderer",
879         NULL,
880         "quartz.dll",
881         "Both"
882     },
883     {   &CLSID_ACMWrapper,
884         "ACM wrapper",
885         NULL,
886         "quartz.dll",
887         "Both"
888     },
889     {   &CLSID_WAVEParser,
890         "Wave Parser",
891         NULL,
892         "quartz.dll",
893         "Both"
894     },
895     { NULL }                    /* list terminator */
896 };
897
898 /***********************************************************************
899  *              interface list
900  */
901
902 static struct regsvr_interface const interface_list[] = {
903     {   &IID_IFilterGraph,
904         "IFilterGraph",
905         NULL,
906         11,
907         NULL,
908         &CLSID_PSFactoryBuffer
909     },
910     {   &IID_IFilterGraph2,
911         "IFilterGraph2",
912         NULL,
913         21,
914         NULL,
915         &CLSID_PSFactoryBuffer
916     },
917     {   &IID_IFilterMapper,
918         "IFilterMapper",
919         NULL,
920         11,
921         NULL,
922         &CLSID_PSFactoryBuffer
923     },
924     {   &IID_IFilterMapper2,
925         "IFilterMapper2",
926         NULL,
927         7,
928         NULL,
929         &CLSID_PSFactoryBuffer
930     },
931     /* FIXME:
932     {   &IID_SeekingPassThru,
933         "ISeekingPassThru",
934         NULL,
935         4,
936         NULL,
937         &CLSID_PSFactoryBuffer
938     },
939     {   &IID_AsyncReader,
940         "IAsyncReader",
941         NULL,
942         11,
943         NULL,
944         &CLSID_PSFactoryBuffer
945     },
946     {   &IID_WAVEParser,
947         "IWAVEParser",
948         NULL,
949         11,
950         NULL,
951         &CLSID_PSFactoryBuffer
952     },*/
953     { NULL }                    /* list terminator */
954 };
955
956 /***********************************************************************
957  *              mediatype list
958  */
959
960 static struct regsvr_mediatype_parsing const mediatype_parsing_list[] = {
961     {   &MEDIATYPE_Stream,
962         &MEDIASUBTYPE_Avi,
963         {   "0,4,,52494646,8,4,,41564920",
964             NULL }
965     },
966     {   &MEDIATYPE_Stream,
967         &MEDIASUBTYPE_MPEG1System,
968         {   "0, 16, FFFFFFFFF100010001800001FFFFFFFF, 000001BA2100010001800001000001BB",
969             NULL }
970     },
971     {   &MEDIATYPE_Stream,
972         &MEDIASUBTYPE_MPEG1VideoCD,
973         {   "0, 4, , 52494646, 8, 8, , 43445841666D7420, 36, 20, FFFFFFFF00000000FFFFFFFFFFFFFFFFFFFFFFFF, 646174610000000000FFFFFFFFFFFFFFFFFFFF00",
974             NULL }
975     },
976     {   &MEDIATYPE_Stream,
977         &MEDIASUBTYPE_MPEG1Video,
978         {   "0, 4, , 000001B3",
979             NULL }
980     },
981     {   &MEDIATYPE_Stream,
982         &MEDIASUBTYPE_MPEG1Audio,
983         {   "0, 2, FFE0, FFE0",
984             "0, 10, FFFFFF00000080808080, 494433000000000000",
985             NULL }
986     },
987     {   &MEDIATYPE_Stream,
988         &MEDIASUBTYPE_QTMovie,
989         {   "4, 4, , 6d646174",
990             "4, 4, , 6d6f6f76",
991             NULL }
992     },
993     {   &MEDIATYPE_Stream,
994         &MEDIASUBTYPE_WAVE,
995         {   "0,4,,52494646,8,4,,57415645",
996             NULL }
997     },
998     {   &MEDIATYPE_Stream,
999         &MEDIASUBTYPE_AU,
1000         {   "0,4,,2e736e64",
1001             NULL }
1002     },
1003     {   &MEDIATYPE_Stream,
1004         &MEDIASUBTYPE_AIFF,
1005         {   "0,4,,464f524d,8,4,,41494646",
1006             "0,4,,464f524d,8,4,,41494643",
1007             NULL }
1008     },
1009     {   &MEDIATYPE_Stream,
1010         &MEDIATYPE_Text,
1011         {   "0,4,,4C595249",
1012             "0,4,,6C797269",
1013             NULL }
1014     },
1015     {   &MEDIATYPE_Stream,
1016         &MEDIATYPE_Midi,
1017         {   "0,4,,52494646,8,4,,524D4944",
1018             "0,4,,4D546864",
1019             NULL }
1020     },
1021     { NULL }                    /* list terminator */
1022 };
1023
1024 /***********************************************************************
1025  *              mediatype list
1026  */
1027
1028 static struct regsvr_mediatype_extension const mediatype_extension_list[] = {
1029     {   &MEDIATYPE_Stream,
1030         &MEDIASUBTYPE_MPEG1Audio,
1031         ".mp3"
1032     },
1033     { NULL }                    /* list terminator */
1034 };
1035
1036 /***********************************************************************
1037  *              filter list
1038  */
1039
1040 static struct regsvr_filter const filter_list[] = {
1041     {   &CLSID_AviSplitter,
1042         &CLSID_LegacyAmFilterCategory,
1043         {'A','V','I',' ','S','p','l','i','t','t','e','r',0},
1044         0x600000,
1045         {   {   0,
1046                 {   { &MEDIATYPE_Stream, &MEDIASUBTYPE_Avi },
1047                     { NULL }
1048                 },
1049             },
1050             {   REG_PINFLAG_B_OUTPUT,
1051                 {   { &MEDIATYPE_Video, &GUID_NULL },
1052                     { NULL }
1053                 },
1054             },
1055             { 0xFFFFFFFF },
1056         }
1057     },
1058     {   &CLSID_MPEG1Splitter,
1059         &CLSID_LegacyAmFilterCategory,
1060         {'M','P','E','G','-','I',' ','S','t','r','e','a','m',' ','S','p','l','i','t','t','e','r',0},
1061         0x600000,
1062         {   {   0,
1063                 {   { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Audio },
1064                     { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Video },
1065                     { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1System },
1066                     { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1VideoCD },
1067                     { NULL }
1068                 },
1069             },
1070             {   REG_PINFLAG_B_OUTPUT,
1071                 {   { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Packet },
1072                     { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload },
1073                     { NULL }
1074                 },
1075             },
1076             {   REG_PINFLAG_B_OUTPUT,
1077                 {   { &MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Packet },
1078                     { &MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Payload },
1079                     { NULL }
1080                 },
1081             },
1082             { 0xFFFFFFFF },
1083         }
1084     },
1085     {   &CLSID_NullRenderer,
1086         &CLSID_LegacyAmFilterCategory,
1087         {'N','u','l','l',' ','R','e','n','d','e','r','e','r',0},
1088         0x200000,
1089         {   {   REG_PINFLAG_B_RENDERER,
1090                 {   { &MEDIATYPE_NULL, &GUID_NULL },
1091                     { NULL }
1092                 },
1093             },
1094             { 0xFFFFFFFF },
1095         }
1096     },
1097     {   &CLSID_VideoRenderer,
1098         &CLSID_LegacyAmFilterCategory,
1099         {'V','i','d','e','o',' ','R','e','n','d','e','r','e','r',0},
1100         0x800000,
1101         {   {   REG_PINFLAG_B_RENDERER,
1102                 {   { &MEDIATYPE_Video, &GUID_NULL },
1103                     { NULL }
1104                 },
1105             },
1106             { 0xFFFFFFFF },
1107         }
1108     },
1109     {   &CLSID_VideoRendererDefault,
1110         &CLSID_LegacyAmFilterCategory,
1111         {'V','i','d','e','o',' ','R','e','n','d','e','r','e','r',0},
1112         0x800000,
1113         {   {   REG_PINFLAG_B_RENDERER,
1114                 {   { &MEDIATYPE_Video, &GUID_NULL },
1115                     { NULL }
1116                 },
1117             },
1118             { 0xFFFFFFFF },
1119         }
1120     },
1121     {   &CLSID_DSoundRender,
1122         &CLSID_LegacyAmFilterCategory,
1123         {'A','u','d','i','o',' ','R','e','n','d','e','r','e','r',0},
1124         0x800000,
1125         {   {   REG_PINFLAG_B_RENDERER,
1126                 {   { &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM },
1127 /*                  { &MEDIATYPE_Audio, &MEDIASUBTYPE_IEEE_FLOAT }, */
1128                     { NULL }
1129                 },
1130             },
1131             { 0xFFFFFFFF },
1132         }
1133     },
1134     {   &CLSID_AudioRender,
1135         &CLSID_LegacyAmFilterCategory,
1136         {'A','u','d','i','o',' ','R','e','n','d','e','r','e','r',0},
1137         0x800000,
1138         {   {   REG_PINFLAG_B_RENDERER,
1139                 {   { &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM },
1140 /*                  { &MEDIATYPE_Audio, &MEDIASUBTYPE_IEEE_FLOAT }, */
1141                     { NULL }
1142                 },
1143             },
1144             { 0xFFFFFFFF },
1145         }
1146     },
1147     {   &CLSID_AVIDec,
1148         &CLSID_LegacyAmFilterCategory,
1149         {'A','V','I',' ','D','e','c','o','m','p','r','e','s','s','o','r',0},
1150         0x600000,
1151         {   {   0,
1152                 {   { &MEDIATYPE_Video, &GUID_NULL },
1153                     { NULL }
1154                 },
1155             },
1156             {   REG_PINFLAG_B_OUTPUT,
1157                 {   { &MEDIATYPE_Video, &GUID_NULL },
1158                     { NULL }
1159                 },
1160             },
1161             { 0xFFFFFFFF },
1162         }
1163     },
1164     {   &CLSID_AsyncReader,
1165         &CLSID_LegacyAmFilterCategory,
1166         {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','A','s','y','n','c','.',')',0},
1167         0x400000,
1168         {   {   REG_PINFLAG_B_OUTPUT,
1169                 {   { &MEDIATYPE_Stream, &GUID_NULL },
1170                     { NULL }
1171                 },
1172             },
1173             { 0xFFFFFFFF },
1174         }
1175     },
1176     {   &CLSID_ACMWrapper,
1177         &CLSID_LegacyAmFilterCategory,
1178         {'A','C','M',' ','W','r','a','p','p','e','r',0},
1179         0x600000,
1180         {   {   0,
1181                 {   { &MEDIATYPE_Audio, &GUID_NULL },
1182                     { NULL }
1183                 },
1184             },
1185             {   REG_PINFLAG_B_OUTPUT,
1186                 {   { &MEDIATYPE_Audio, &GUID_NULL },
1187                     { NULL }
1188                 },
1189             },
1190             { 0xFFFFFFFF },
1191         }
1192     },
1193     {   &CLSID_WAVEParser,
1194         &CLSID_LegacyAmFilterCategory,
1195         {'W','a','v','e',' ','P','a','r','s','e','r',0},
1196         0x400000,
1197         {   {   0,
1198                 {   { &MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE },
1199                     { &MEDIATYPE_Stream, &MEDIASUBTYPE_AU },
1200                     { &MEDIATYPE_Stream, &MEDIASUBTYPE_AIFF },
1201                     { NULL }
1202                 },
1203             },
1204             {   REG_PINFLAG_B_OUTPUT,
1205                 {   { &MEDIATYPE_Audio, &GUID_NULL },
1206                     { NULL }
1207                 },
1208             },
1209             { 0xFFFFFFFF },
1210         }
1211     },
1212     { NULL }            /* list terminator */
1213 };
1214
1215 /***********************************************************************
1216  *              DllRegisterServer (QUARTZ.@)
1217  */
1218 HRESULT WINAPI DllRegisterServer(void)
1219 {
1220     HRESULT hr;
1221
1222     TRACE("\n");
1223
1224     hr = register_coclasses(coclass_list);
1225     if (SUCCEEDED(hr))
1226         hr = register_interfaces(interface_list);
1227     if (SUCCEEDED(hr))
1228         hr = register_mediatypes_parsing(mediatype_parsing_list);
1229     if (SUCCEEDED(hr))
1230         hr = register_mediatypes_extension(mediatype_extension_list);
1231     if (SUCCEEDED(hr))
1232         hr = register_filters(filter_list);
1233     return hr;
1234 }
1235
1236 /***********************************************************************
1237  *              DllUnregisterServer (QUARTZ.@)
1238  */
1239 HRESULT WINAPI DllUnregisterServer(void)
1240 {
1241     HRESULT hr;
1242
1243     TRACE("\n");
1244
1245     hr = unregister_filters(filter_list);
1246     if (SUCCEEDED(hr))
1247         hr = unregister_coclasses(coclass_list);
1248     if (SUCCEEDED(hr))
1249         hr = unregister_interfaces(interface_list);
1250     if (SUCCEEDED(hr))
1251         hr = unregister_mediatypes_parsing(mediatype_parsing_list);
1252     if (SUCCEEDED(hr))
1253         hr = unregister_mediatypes_extension(mediatype_extension_list);
1254     return hr;
1255 }