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