Release 4.0.4.
[wine.git] / dlls / devenum / createdevenum.c
blob65c1ccd225c12dda7d92c97a0af84842d156f43b
1 /*
2 * ICreateDevEnum implementation for DEVENUM.dll
4 * Copyright (C) 2002 Robert Shearman
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.
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.
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
20 * NOTES ON THIS FILE:
21 * - Implements ICreateDevEnum interface which creates an IEnumMoniker
22 * implementation
23 * - Also creates the special registry keys created at run-time
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
29 #include "devenum_private.h"
30 #include "vfw.h"
31 #include "aviriff.h"
32 #include "dsound.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "wine/heap.h"
37 #include "mmddk.h"
39 #include "initguid.h"
40 #include "wine/fil_data.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(devenum);
44 static const WCHAR wszFilterKeyName[] = {'F','i','l','t','e','r',0};
45 static const WCHAR wszMeritName[] = {'M','e','r','i','t',0};
46 static const WCHAR wszPins[] = {'P','i','n','s',0};
47 static const WCHAR wszAllowedMany[] = {'A','l','l','o','w','e','d','M','a','n','y',0};
48 static const WCHAR wszAllowedZero[] = {'A','l','l','o','w','e','d','Z','e','r','o',0};
49 static const WCHAR wszDirection[] = {'D','i','r','e','c','t','i','o','n',0};
50 static const WCHAR wszIsRendered[] = {'I','s','R','e','n','d','e','r','e','d',0};
51 static const WCHAR wszTypes[] = {'T','y','p','e','s',0};
52 static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
53 static const WCHAR wszFilterData[] = {'F','i','l','t','e','r','D','a','t','a',0};
55 static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface);
56 static HRESULT DEVENUM_CreateAMCategoryKey(const CLSID * clsidCategory);
58 /**********************************************************************
59 * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown)
61 static HRESULT WINAPI DEVENUM_ICreateDevEnum_QueryInterface(ICreateDevEnum *iface, REFIID riid,
62 void **ppv)
64 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
66 if (!ppv)
67 return E_POINTER;
69 if (IsEqualGUID(riid, &IID_IUnknown) ||
70 IsEqualGUID(riid, &IID_ICreateDevEnum))
72 *ppv = iface;
73 DEVENUM_ICreateDevEnum_AddRef(iface);
74 return S_OK;
77 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
78 *ppv = NULL;
79 return E_NOINTERFACE;
82 /**********************************************************************
83 * DEVENUM_ICreateDevEnum_AddRef (also IUnknown)
85 static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface)
87 TRACE("\n");
89 DEVENUM_LockModule();
91 return 2; /* non-heap based object */
94 /**********************************************************************
95 * DEVENUM_ICreateDevEnum_Release (also IUnknown)
97 static ULONG WINAPI DEVENUM_ICreateDevEnum_Release(ICreateDevEnum * iface)
99 TRACE("\n");
101 DEVENUM_UnlockModule();
103 return 1; /* non-heap based object */
106 static HRESULT register_codec(const GUID *class, const WCHAR *name,
107 const GUID *clsid, const WCHAR *friendly_name, IPropertyBag **ret)
109 static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','c','m',':',0};
110 WCHAR guidstr[CHARS_IN_GUID];
111 IParseDisplayName *parser;
112 IPropertyBag *propbag;
113 IMoniker *mon;
114 WCHAR *buffer;
115 VARIANT var;
116 ULONG eaten;
117 HRESULT hr;
119 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
120 if (FAILED(hr))
121 return hr;
123 buffer = heap_alloc((strlenW(deviceW) + CHARS_IN_GUID + strlenW(name) + 1) * sizeof(WCHAR));
124 if (!buffer)
126 IParseDisplayName_Release(parser);
127 return E_OUTOFMEMORY;
130 strcpyW(buffer, deviceW);
131 StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID);
132 strcatW(buffer, backslashW);
133 strcatW(buffer, name);
135 IParseDisplayName_ParseDisplayName(parser, NULL, buffer, &eaten, &mon);
136 IParseDisplayName_Release(parser);
137 heap_free(buffer);
139 IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&propbag);
140 IMoniker_Release(mon);
142 V_VT(&var) = VT_BSTR;
143 V_BSTR(&var) = SysAllocString(friendly_name);
144 hr = IPropertyBag_Write(propbag, wszFriendlyName, &var);
145 VariantClear(&var);
146 if (FAILED(hr))
148 IPropertyBag_Release(propbag);
149 return hr;
152 V_VT(&var) = VT_BSTR;
153 StringFromGUID2(clsid, guidstr, ARRAY_SIZE(guidstr));
154 V_BSTR(&var) = SysAllocString(guidstr);
155 hr = IPropertyBag_Write(propbag, clsidW, &var);
156 VariantClear(&var);
157 if (FAILED(hr))
159 IPropertyBag_Release(propbag);
160 return hr;
163 *ret = propbag;
164 return S_OK;
167 static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey, REGFILTERPINS2 *rgPin)
169 HKEY hkeyTypes = NULL;
170 DWORD dwMajorTypes, i;
171 REGPINTYPES *lpMediaType = NULL;
172 DWORD dwMediaTypeSize = 0;
174 if (RegOpenKeyExW(hkeyPinKey, wszTypes, 0, KEY_READ, &hkeyTypes) != ERROR_SUCCESS)
175 return ;
177 if (RegQueryInfoKeyW(hkeyTypes, NULL, NULL, NULL, &dwMajorTypes, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
178 != ERROR_SUCCESS)
180 RegCloseKey(hkeyTypes);
181 return ;
184 for (i = 0; i < dwMajorTypes; i++)
186 HKEY hkeyMajorType = NULL;
187 WCHAR wszMajorTypeName[64];
188 DWORD cName = ARRAY_SIZE(wszMajorTypeName);
189 DWORD dwMinorTypes, i1;
191 if (RegEnumKeyExW(hkeyTypes, i, wszMajorTypeName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
193 if (RegOpenKeyExW(hkeyTypes, wszMajorTypeName, 0, KEY_READ, &hkeyMajorType) != ERROR_SUCCESS) continue;
195 if (RegQueryInfoKeyW(hkeyMajorType, NULL, NULL, NULL, &dwMinorTypes, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
196 != ERROR_SUCCESS)
198 RegCloseKey(hkeyMajorType);
199 continue;
202 for (i1 = 0; i1 < dwMinorTypes; i1++)
204 WCHAR wszMinorTypeName[64];
205 CLSID *clsMajorType = NULL, *clsMinorType = NULL;
206 HRESULT hr;
208 cName = ARRAY_SIZE(wszMinorTypeName);
209 if (RegEnumKeyExW(hkeyMajorType, i1, wszMinorTypeName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
211 clsMinorType = CoTaskMemAlloc(sizeof(CLSID));
212 if (!clsMinorType) continue;
214 clsMajorType = CoTaskMemAlloc(sizeof(CLSID));
215 if (!clsMajorType) goto error_cleanup_types;
217 hr = CLSIDFromString(wszMinorTypeName, clsMinorType);
218 if (FAILED(hr)) goto error_cleanup_types;
220 hr = CLSIDFromString(wszMajorTypeName, clsMajorType);
221 if (FAILED(hr)) goto error_cleanup_types;
223 if (rgPin->nMediaTypes == dwMediaTypeSize)
225 DWORD dwNewSize = dwMediaTypeSize + (dwMediaTypeSize < 2 ? 1 : dwMediaTypeSize / 2);
226 REGPINTYPES *lpNewMediaType;
228 lpNewMediaType = CoTaskMemRealloc(lpMediaType, sizeof(REGPINTYPES) * dwNewSize);
229 if (!lpNewMediaType) goto error_cleanup_types;
231 lpMediaType = lpNewMediaType;
232 dwMediaTypeSize = dwNewSize;
235 lpMediaType[rgPin->nMediaTypes].clsMajorType = clsMajorType;
236 lpMediaType[rgPin->nMediaTypes].clsMinorType = clsMinorType;
237 rgPin->nMediaTypes++;
238 continue;
240 error_cleanup_types:
242 CoTaskMemFree(clsMajorType);
243 CoTaskMemFree(clsMinorType);
246 RegCloseKey(hkeyMajorType);
249 RegCloseKey(hkeyTypes);
251 if (lpMediaType && !rgPin->nMediaTypes)
253 CoTaskMemFree(lpMediaType);
254 lpMediaType = NULL;
257 rgPin->lpMediaType = lpMediaType;
260 static void DEVENUM_ReadPins(HKEY hkeyFilterClass, REGFILTER2 *rgf2)
262 HKEY hkeyPins = NULL;
263 DWORD dwPinsSubkeys, i;
264 REGFILTERPINS2 *rgPins = NULL;
266 rgf2->dwVersion = 2;
267 rgf2->u.s2.cPins2 = 0;
268 rgf2->u.s2.rgPins2 = NULL;
270 if (RegOpenKeyExW(hkeyFilterClass, wszPins, 0, KEY_READ, &hkeyPins) != ERROR_SUCCESS)
271 return ;
273 if (RegQueryInfoKeyW(hkeyPins, NULL, NULL, NULL, &dwPinsSubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
274 != ERROR_SUCCESS)
276 RegCloseKey(hkeyPins);
277 return ;
280 if (dwPinsSubkeys)
282 rgPins = CoTaskMemAlloc(sizeof(REGFILTERPINS2) * dwPinsSubkeys);
283 if (!rgPins)
285 RegCloseKey(hkeyPins);
286 return ;
290 for (i = 0; i < dwPinsSubkeys; i++)
292 HKEY hkeyPinKey = NULL;
293 WCHAR wszPinName[MAX_PATH];
294 DWORD cName = ARRAY_SIZE(wszPinName);
295 REGFILTERPINS2 *rgPin = &rgPins[rgf2->u.s2.cPins2];
296 DWORD value, size, Type;
297 LONG lRet;
299 memset(rgPin, 0, sizeof(*rgPin));
301 if (RegEnumKeyExW(hkeyPins, i, wszPinName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
303 if (RegOpenKeyExW(hkeyPins, wszPinName, 0, KEY_READ, &hkeyPinKey) != ERROR_SUCCESS) continue;
305 size = sizeof(DWORD);
306 lRet = RegQueryValueExW(hkeyPinKey, wszAllowedMany, NULL, &Type, (BYTE *)&value, &size);
307 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
308 goto error_cleanup;
309 if (value)
310 rgPin->dwFlags |= REG_PINFLAG_B_MANY;
312 size = sizeof(DWORD);
313 lRet = RegQueryValueExW(hkeyPinKey, wszAllowedZero, NULL, &Type, (BYTE *)&value, &size);
314 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
315 goto error_cleanup;
316 if (value)
317 rgPin->dwFlags |= REG_PINFLAG_B_ZERO;
319 size = sizeof(DWORD);
320 lRet = RegQueryValueExW(hkeyPinKey, wszDirection, NULL, &Type, (BYTE *)&value, &size);
321 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
322 goto error_cleanup;
323 if (value)
324 rgPin->dwFlags |= REG_PINFLAG_B_OUTPUT;
327 size = sizeof(DWORD);
328 lRet = RegQueryValueExW(hkeyPinKey, wszIsRendered, NULL, &Type, (BYTE *)&value, &size);
329 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
330 goto error_cleanup;
331 if (value)
332 rgPin->dwFlags |= REG_PINFLAG_B_RENDERER;
334 DEVENUM_ReadPinTypes(hkeyPinKey, rgPin);
336 ++rgf2->u.s2.cPins2;
337 continue;
339 error_cleanup:
341 RegCloseKey(hkeyPinKey);
344 RegCloseKey(hkeyPins);
346 if (rgPins && !rgf2->u.s2.cPins2)
348 CoTaskMemFree(rgPins);
349 rgPins = NULL;
352 rgf2->u.s2.rgPins2 = rgPins;
355 static void free_regfilter2(REGFILTER2 *rgf)
357 if (rgf->u.s2.rgPins2)
359 UINT iPin;
361 for (iPin = 0; iPin < rgf->u.s2.cPins2; iPin++)
363 if (rgf->u.s2.rgPins2[iPin].lpMediaType)
365 UINT iType;
367 for (iType = 0; iType < rgf->u.s2.rgPins2[iPin].nMediaTypes; iType++)
369 CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType[iType].clsMajorType);
370 CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType[iType].clsMinorType);
373 CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType);
377 CoTaskMemFree((void *)rgf->u.s2.rgPins2);
381 static void write_filter_data(IPropertyBag *prop_bag, REGFILTER2 *rgf)
383 IAMFilterData *fildata;
384 SAFEARRAYBOUND sabound;
385 BYTE *data, *array;
386 VARIANT var = {};
387 ULONG size;
388 HRESULT hr;
390 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IAMFilterData, (void **)&fildata);
391 if (FAILED(hr)) goto cleanup;
393 hr = IAMFilterData_CreateFilterData(fildata, rgf, &data, &size);
394 if (FAILED(hr)) goto cleanup;
396 V_VT(&var) = VT_ARRAY | VT_UI1;
397 sabound.lLbound = 0;
398 sabound.cElements = size;
399 if (!(V_ARRAY(&var) = SafeArrayCreate(VT_UI1, 1, &sabound)))
400 goto cleanup;
401 hr = SafeArrayAccessData(V_ARRAY(&var), (void *)&array);
402 if (FAILED(hr)) goto cleanup;
404 memcpy(array, data, size);
405 hr = SafeArrayUnaccessData(V_ARRAY(&var));
406 if (FAILED(hr)) goto cleanup;
408 hr = IPropertyBag_Write(prop_bag, wszFilterData, &var);
409 if (FAILED(hr)) goto cleanup;
411 cleanup:
412 VariantClear(&var);
413 CoTaskMemFree(data);
414 IAMFilterData_Release(fildata);
417 static void register_legacy_filters(void)
419 HKEY hkeyFilter = NULL;
420 DWORD dwFilterSubkeys, i;
421 LONG lRet;
422 HRESULT hr;
424 lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszFilterKeyName, 0, KEY_READ, &hkeyFilter);
425 hr = HRESULT_FROM_WIN32(lRet);
427 if (SUCCEEDED(hr))
429 lRet = RegQueryInfoKeyW(hkeyFilter, NULL, NULL, NULL, &dwFilterSubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
430 hr = HRESULT_FROM_WIN32(lRet);
433 if (SUCCEEDED(hr))
434 hr = DEVENUM_CreateAMCategoryKey(&CLSID_LegacyAmFilterCategory);
436 if (SUCCEEDED(hr))
438 for (i = 0; i < dwFilterSubkeys; i++)
440 WCHAR wszFilterSubkeyName[64];
441 DWORD cName = ARRAY_SIZE(wszFilterSubkeyName);
442 IPropertyBag *prop_bag = NULL;
443 WCHAR wszRegKey[MAX_PATH];
444 HKEY classkey = NULL;
445 REGFILTER2 rgf2;
446 DWORD Type, len;
447 GUID clsid;
449 if (RegEnumKeyExW(hkeyFilter, i, wszFilterSubkeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
451 TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName));
453 hr = CLSIDFromString(wszFilterSubkeyName, &clsid);
454 if (FAILED(hr))
455 continue;
457 strcpyW(wszRegKey, clsidW);
458 strcatW(wszRegKey, backslashW);
459 strcatW(wszRegKey, wszFilterSubkeyName);
461 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &classkey) != ERROR_SUCCESS)
462 continue;
464 len = 0;
465 if (!RegQueryValueExW(classkey, NULL, NULL, &Type, NULL, &len))
467 WCHAR *friendlyname = heap_alloc(len);
468 if (!friendlyname)
470 RegCloseKey(classkey);
471 continue;
473 RegQueryValueExW(classkey, NULL, NULL, &Type, (BYTE *)friendlyname, &len);
475 hr = register_codec(&CLSID_LegacyAmFilterCategory, wszFilterSubkeyName,
476 &clsid, friendlyname, &prop_bag);
478 heap_free(friendlyname);
480 else
481 hr = register_codec(&CLSID_LegacyAmFilterCategory, wszFilterSubkeyName,
482 &clsid, wszFilterSubkeyName, &prop_bag);
483 if (FAILED(hr))
485 RegCloseKey(classkey);
486 continue;
489 /* write filter data */
490 rgf2.dwMerit = MERIT_NORMAL;
492 len = sizeof(rgf2.dwMerit);
493 RegQueryValueExW(classkey, wszMeritName, NULL, &Type, (BYTE *)&rgf2.dwMerit, &len);
495 DEVENUM_ReadPins(classkey, &rgf2);
497 write_filter_data(prop_bag, &rgf2);
499 IPropertyBag_Release(prop_bag);
500 RegCloseKey(classkey);
501 free_regfilter2(&rgf2);
505 if (hkeyFilter) RegCloseKey(hkeyFilter);
508 static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, const WCHAR *module, void *context)
510 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','D','i','r','e','c','t','S','o','u','n','d',' ','D','e','v','i','c','e',0};
511 static const WCHAR directsoundW[] = {'D','i','r','e','c','t','S','o','u','n','d',':',' ',0};
512 static const WCHAR dsguidW[] = {'D','S','G','u','i','d',0};
513 IPropertyBag *prop_bag = NULL;
514 REGFILTERPINS2 rgpins = {0};
515 REGPINTYPES rgtypes = {0};
516 REGFILTER2 rgf = {0};
517 WCHAR clsid[CHARS_IN_GUID];
518 VARIANT var;
519 HRESULT hr;
521 hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
522 if (FAILED(hr))
523 return FALSE;
525 if (guid)
527 WCHAR *name = heap_alloc(sizeof(defaultW) + strlenW(desc) * sizeof(WCHAR));
528 if (!name)
529 return FALSE;
530 strcpyW(name, directsoundW);
531 strcatW(name, desc);
533 hr = register_codec(&CLSID_AudioRendererCategory, name,
534 &CLSID_DSoundRender, name, &prop_bag);
535 heap_free(name);
537 else
538 hr = register_codec(&CLSID_AudioRendererCategory, defaultW,
539 &CLSID_DSoundRender, defaultW, &prop_bag);
540 if (FAILED(hr))
541 return FALSE;
543 /* write filter data */
544 rgf.dwVersion = 2;
545 rgf.dwMerit = guid ? MERIT_DO_NOT_USE : MERIT_PREFERRED;
546 rgf.u.s2.cPins2 = 1;
547 rgf.u.s2.rgPins2 = &rgpins;
548 rgpins.dwFlags = REG_PINFLAG_B_RENDERER;
549 /* FIXME: native registers many more formats */
550 rgpins.nMediaTypes = 1;
551 rgpins.lpMediaType = &rgtypes;
552 rgtypes.clsMajorType = &MEDIATYPE_Audio;
553 rgtypes.clsMinorType = &MEDIASUBTYPE_PCM;
555 write_filter_data(prop_bag, &rgf);
557 /* write DSound guid */
558 V_VT(&var) = VT_BSTR;
559 StringFromGUID2(guid ? guid : &GUID_NULL, clsid, CHARS_IN_GUID);
560 if ((V_BSTR(&var) = SysAllocString(clsid)))
561 hr = IPropertyBag_Write(prop_bag, dsguidW, &var);
563 VariantClear(&var);
564 IPropertyBag_Release(prop_bag);
565 return TRUE;
568 static void register_waveout_devices(void)
570 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','W','a','v','e','O','u','t',' ','D','e','v','i','c','e',0};
571 static const WCHAR waveoutidW[] = {'W','a','v','e','O','u','t','I','d',0};
572 IPropertyBag *prop_bag = NULL;
573 REGFILTERPINS2 rgpins = {0};
574 REGPINTYPES rgtypes = {0};
575 REGFILTER2 rgf = {0};
576 WAVEOUTCAPSW caps;
577 const WCHAR *name;
578 int i, count;
579 VARIANT var;
580 HRESULT hr;
582 hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
583 if (FAILED(hr)) return;
585 count = waveOutGetNumDevs();
587 for (i = -1; i < count; i++)
589 waveOutGetDevCapsW(i, &caps, sizeof(caps));
591 name = (i == -1) ? defaultW : caps.szPname;
593 hr = register_codec(&CLSID_AudioRendererCategory, name,
594 &CLSID_AudioRender, name, &prop_bag);
595 if (FAILED(hr))
596 continue;
598 /* write filter data */
599 rgf.dwVersion = 2;
600 rgf.dwMerit = MERIT_DO_NOT_USE;
601 rgf.u.s2.cPins2 = 1;
602 rgf.u.s2.rgPins2 = &rgpins;
603 rgpins.dwFlags = REG_PINFLAG_B_RENDERER;
604 rgpins.nMediaTypes = 1;
605 rgpins.lpMediaType = &rgtypes;
606 rgtypes.clsMajorType = &MEDIATYPE_Audio;
607 rgtypes.clsMinorType = &MEDIASUBTYPE_NULL;
609 write_filter_data(prop_bag, &rgf);
611 /* write WaveOutId */
612 V_VT(&var) = VT_I4;
613 V_I4(&var) = i;
614 IPropertyBag_Write(prop_bag, waveoutidW, &var);
616 VariantClear(&var);
617 if (prop_bag) IPropertyBag_Release(prop_bag);
621 static void register_wavein_devices(void)
623 static const WCHAR waveinidW[] = {'W','a','v','e','I','n','I','d',0};
624 IPropertyBag *prop_bag = NULL;
625 REGFILTER2 rgf = {0};
626 WAVEINCAPSW caps;
627 int i, count;
628 VARIANT var;
629 HRESULT hr;
631 hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
632 if (FAILED(hr)) return;
634 count = waveInGetNumDevs();
636 for (i = 0; i < count; i++)
638 waveInGetDevCapsW(i, &caps, sizeof(caps));
640 hr = register_codec(&CLSID_AudioInputDeviceCategory, caps.szPname,
641 &CLSID_AudioRecord, caps.szPname, &prop_bag);
642 if (FAILED(hr))
643 continue;
645 /* write filter data */
646 rgf.dwVersion = 2;
647 rgf.dwMerit = MERIT_DO_NOT_USE;
649 write_filter_data(prop_bag, &rgf);
651 /* write WaveInId */
652 V_VT(&var) = VT_I4;
653 V_I4(&var) = i;
654 IPropertyBag_Write(prop_bag, waveinidW, &var);
656 VariantClear(&var);
657 IPropertyBag_Release(prop_bag);
661 static void register_midiout_devices(void)
663 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',' ','M','i','d','i','O','u','t',' ','D','e','v','i','c','e',0};
664 static const WCHAR midioutidW[] = {'M','i','d','i','O','u','t','I','d',0};
665 IPropertyBag *prop_bag = NULL;
666 REGFILTERPINS2 rgpins = {0};
667 REGPINTYPES rgtypes = {0};
668 REGFILTER2 rgf = {0};
669 MIDIOUTCAPSW caps;
670 const WCHAR *name;
671 int i, count;
672 VARIANT var;
673 HRESULT hr;
675 hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
676 if (FAILED(hr)) return;
678 count = midiOutGetNumDevs();
680 for (i = -1; i < count; i++)
682 midiOutGetDevCapsW(i, &caps, sizeof(caps));
684 name = (i == -1) ? defaultW : caps.szPname;
686 hr = register_codec(&CLSID_MidiRendererCategory, name,
687 &CLSID_AVIMIDIRender, name, &prop_bag);
688 if (FAILED(hr))
689 continue;
691 /* write filter data */
692 rgf.dwVersion = 2;
693 rgf.dwMerit = (i == -1) ? MERIT_PREFERRED : MERIT_DO_NOT_USE;
694 rgf.u.s2.cPins2 = 1;
695 rgf.u.s2.rgPins2 = &rgpins;
696 rgpins.dwFlags = REG_PINFLAG_B_RENDERER;
697 rgpins.nMediaTypes = 1;
698 rgpins.lpMediaType = &rgtypes;
699 rgtypes.clsMajorType = &MEDIATYPE_Midi;
700 rgtypes.clsMinorType = &MEDIASUBTYPE_NULL;
702 write_filter_data(prop_bag, &rgf);
704 /* write MidiOutId */
705 V_VT(&var) = VT_I4;
706 V_I4(&var) = i;
707 IPropertyBag_Write(prop_bag, midioutidW, &var);
709 VariantClear(&var);
710 IPropertyBag_Release(prop_bag);
714 static void register_vfw_codecs(void)
716 static const WCHAR fcchandlerW[] = {'F','c','c','H','a','n','d','l','e','r',0};
717 REGFILTERPINS2 rgpins[2] = {};
718 IPropertyBag *prop_bag = NULL;
719 REGPINTYPES rgtypes[2];
720 REGFILTER2 rgf;
721 GUID typeguid;
722 ICINFO info;
723 VARIANT var;
724 HRESULT hr;
725 int i = 0;
726 HIC hic;
728 hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
729 if (FAILED(hr)) return;
731 while (ICInfo(ICTYPE_VIDEO, i++, &info))
733 WCHAR name[5] = {LOBYTE(LOWORD(info.fccHandler)), HIBYTE(LOWORD(info.fccHandler)),
734 LOBYTE(HIWORD(info.fccHandler)), HIBYTE(HIWORD(info.fccHandler))};
736 hic = ICOpen(ICTYPE_VIDEO, info.fccHandler, ICMODE_QUERY);
737 ICGetInfo(hic, &info, sizeof(info));
738 ICClose(hic);
740 hr = register_codec(&CLSID_VideoCompressorCategory, name,
741 &CLSID_AVICo, info.szDescription, &prop_bag);
742 if (FAILED(hr))
743 continue;
745 /* write filter data */
746 rgf.dwVersion = 2;
747 rgf.dwMerit = MERIT_DO_NOT_USE;
748 rgf.u.s2.cPins2 = 2;
749 rgf.u.s2.rgPins2 = rgpins;
750 rgpins[0].dwFlags = 0;
751 rgpins[0].nMediaTypes = 1;
752 rgpins[0].lpMediaType = &rgtypes[0];
753 rgtypes[0].clsMajorType = &MEDIATYPE_Video;
754 typeguid = MEDIASUBTYPE_PCM;
755 typeguid.Data1 = info.fccHandler;
756 rgtypes[0].clsMinorType = &typeguid;
757 rgpins[1].dwFlags = REG_PINFLAG_B_OUTPUT;
758 rgpins[1].nMediaTypes = 1;
759 rgpins[1].lpMediaType = &rgtypes[1];
760 rgtypes[1].clsMajorType = &MEDIATYPE_Video;
761 rgtypes[1].clsMinorType = &GUID_NULL;
763 write_filter_data(prop_bag, &rgf);
765 /* write WaveInId */
766 V_VT(&var) = VT_BSTR;
767 V_BSTR(&var) = SysAllocString(name);
768 IPropertyBag_Write(prop_bag, fcchandlerW, &var);
770 VariantClear(&var);
771 IPropertyBag_Release(prop_bag);
775 static void register_avicap_devices(void)
777 static const WCHAR vfwindexW[] = {'V','F','W','I','n','d','e','x',0};
778 WCHAR friendlyname[] = {'v','i','d','e','o','0',0};
779 IPropertyBag *prop_bag = NULL;
780 WCHAR name[32], version[32];
781 REGFILTERPINS2 rgpins = {0};
782 REGPINTYPES rgtypes;
783 REGFILTER2 rgf;
784 VARIANT var;
785 HRESULT hr;
786 int i = 0;
788 hr = DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory);
789 if (FAILED(hr))
790 return;
792 for (i = 0; i < 10; ++i)
794 if (!capGetDriverDescriptionW(i, name, ARRAY_SIZE(name), version, ARRAY_SIZE(version)))
795 break;
797 friendlyname[5] = '0' + i;
799 hr = register_codec(&CLSID_VideoInputDeviceCategory, name,
800 &CLSID_VfwCapture, friendlyname, &prop_bag);
801 if (FAILED(hr))
802 continue;
804 rgf.dwVersion = 2;
805 rgf.dwMerit = MERIT_DO_NOT_USE;
806 rgf.u.s2.cPins2 = 1;
807 rgf.u.s2.rgPins2 = &rgpins;
808 rgpins.dwFlags = 0;
809 rgpins.nMediaTypes = 1;
810 rgpins.lpMediaType = &rgtypes;
811 rgtypes.clsMajorType = &MEDIATYPE_Video;
812 rgtypes.clsMinorType = &MEDIASUBTYPE_None;
814 write_filter_data(prop_bag, &rgf);
816 /* write VFWIndex */
817 V_VT(&var) = VT_I4;
818 V_I4(&var) = i;
819 IPropertyBag_Write(prop_bag, vfwindexW, &var);
821 VariantClear(&var);
822 IPropertyBag_Release(prop_bag);
826 /**********************************************************************
827 * DEVENUM_ICreateDevEnum_CreateClassEnumerator
829 static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
830 ICreateDevEnum *iface, REFCLSID class, IEnumMoniker **out, DWORD flags)
832 WCHAR guidstr[CHARS_IN_GUID];
833 HRESULT hr;
834 HKEY key;
836 TRACE("iface %p, class %s, out %p, flags %#x.\n", iface, debugstr_guid(class), out, flags);
838 if (!out)
839 return E_POINTER;
841 *out = NULL;
843 if (!RegOpenKeyW(HKEY_CURRENT_USER, wszActiveMovieKey, &key))
845 StringFromGUID2(class, guidstr, ARRAY_SIZE(guidstr));
846 RegDeleteTreeW(key, guidstr);
849 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory))
850 register_legacy_filters();
851 else if (IsEqualGUID(class, &CLSID_AudioRendererCategory))
853 hr = DirectSoundEnumerateW(&register_dsound_devices, NULL);
854 if (FAILED(hr)) return hr;
855 register_waveout_devices();
856 register_midiout_devices();
858 else if (IsEqualGUID(class, &CLSID_AudioInputDeviceCategory))
859 register_wavein_devices();
860 else if (IsEqualGUID(class, &CLSID_VideoCompressorCategory))
861 register_vfw_codecs();
862 else if (IsEqualGUID(class, &CLSID_VideoInputDeviceCategory))
863 register_avicap_devices();
865 if (SUCCEEDED(hr = create_EnumMoniker(class, out)))
867 IMoniker *mon;
868 hr = IEnumMoniker_Next(*out, 1, &mon, NULL);
869 if (hr == S_OK)
871 IMoniker_Release(mon);
872 IEnumMoniker_Reset(*out);
874 else
876 IEnumMoniker_Release(*out);
877 *out = NULL;
881 return hr;
884 /**********************************************************************
885 * ICreateDevEnum_Vtbl
887 static const ICreateDevEnumVtbl ICreateDevEnum_Vtbl =
889 DEVENUM_ICreateDevEnum_QueryInterface,
890 DEVENUM_ICreateDevEnum_AddRef,
891 DEVENUM_ICreateDevEnum_Release,
892 DEVENUM_ICreateDevEnum_CreateClassEnumerator,
895 /**********************************************************************
896 * static CreateDevEnum instance
898 ICreateDevEnum DEVENUM_CreateDevEnum = { &ICreateDevEnum_Vtbl };
900 /**********************************************************************
901 * DEVENUM_CreateAMCategoryKey (INTERNAL)
903 * Creates a registry key for a category at HKEY_CURRENT_USER\Software\
904 * Microsoft\ActiveMovie\devenum\{clsid}
906 static HRESULT DEVENUM_CreateAMCategoryKey(const CLSID * clsidCategory)
908 WCHAR wszRegKey[MAX_PATH];
909 HRESULT res = S_OK;
910 HKEY hkeyDummy = NULL;
912 strcpyW(wszRegKey, wszActiveMovieKey);
914 if (!StringFromGUID2(clsidCategory, wszRegKey + strlenW(wszRegKey), ARRAY_SIZE(wszRegKey) - strlenW(wszRegKey)))
915 res = E_INVALIDARG;
917 if (SUCCEEDED(res))
919 LONG lRes = RegCreateKeyW(HKEY_CURRENT_USER, wszRegKey, &hkeyDummy);
920 res = HRESULT_FROM_WIN32(lRes);
923 if (hkeyDummy)
924 RegCloseKey(hkeyDummy);
926 if (FAILED(res))
927 ERR("Failed to create key HKEY_CURRENT_USER\\%s\n", debugstr_w(wszRegKey));
929 return res;