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