windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / devenum / createdevenum.c
blobbc91b23580473cdbb4abcdd08812678b82f6a8ed
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 #include "devenum_private.h"
27 #include "vfw.h"
28 #include "aviriff.h"
29 #include "dsound.h"
31 #include "wine/debug.h"
32 #include "mmddk.h"
34 #include "initguid.h"
35 #include "wine/fil_data.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(devenum);
39 static HRESULT WINAPI devenum_factory_QueryInterface(ICreateDevEnum *iface, REFIID riid, void **ppv)
41 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
43 if (!ppv)
44 return E_POINTER;
46 if (IsEqualGUID(riid, &IID_IUnknown) ||
47 IsEqualGUID(riid, &IID_ICreateDevEnum))
49 *ppv = iface;
50 ICreateDevEnum_AddRef(iface);
51 return S_OK;
54 FIXME("- no interface IID: %s\n", debugstr_guid(riid));
55 *ppv = NULL;
56 return E_NOINTERFACE;
59 static ULONG WINAPI devenum_factory_AddRef(ICreateDevEnum *iface)
61 TRACE("\n");
63 return 2; /* non-heap based object */
66 static ULONG WINAPI devenum_factory_Release(ICreateDevEnum *iface)
68 TRACE("\n");
70 return 1; /* non-heap based object */
73 static HRESULT register_codec(const GUID *class, const WCHAR *name,
74 const GUID *clsid, const WCHAR *friendly_name, IPropertyBag **ret)
76 WCHAR guidstr[CHARS_IN_GUID];
77 IParseDisplayName *parser;
78 IPropertyBag *propbag;
79 IMoniker *mon;
80 WCHAR *buffer;
81 VARIANT var;
82 ULONG eaten;
83 HRESULT hr;
85 hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
86 if (FAILED(hr))
87 return hr;
89 if (!(buffer = malloc((wcslen(L"@device:cm:") + CHARS_IN_GUID + wcslen(name) + 1) * sizeof(WCHAR))))
91 IParseDisplayName_Release(parser);
92 return E_OUTOFMEMORY;
95 wcscpy(buffer, L"@device:cm:");
96 StringFromGUID2(class, buffer + wcslen(buffer), CHARS_IN_GUID);
97 wcscat(buffer, L"\\");
98 wcscat(buffer, name);
100 IParseDisplayName_ParseDisplayName(parser, NULL, buffer, &eaten, &mon);
101 IParseDisplayName_Release(parser);
102 free(buffer);
104 IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&propbag);
105 IMoniker_Release(mon);
107 V_VT(&var) = VT_BSTR;
108 V_BSTR(&var) = SysAllocString(friendly_name);
109 hr = IPropertyBag_Write(propbag, L"FriendlyName", &var);
110 VariantClear(&var);
111 if (FAILED(hr))
113 IPropertyBag_Release(propbag);
114 return hr;
117 V_VT(&var) = VT_BSTR;
118 StringFromGUID2(clsid, guidstr, ARRAY_SIZE(guidstr));
119 V_BSTR(&var) = SysAllocString(guidstr);
120 hr = IPropertyBag_Write(propbag, L"CLSID", &var);
121 VariantClear(&var);
122 if (FAILED(hr))
124 IPropertyBag_Release(propbag);
125 return hr;
128 *ret = propbag;
129 return S_OK;
132 static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey, REGFILTERPINS2 *rgPin)
134 HKEY hkeyTypes = NULL;
135 DWORD dwMajorTypes, i;
136 REGPINTYPES *lpMediaType = NULL;
137 DWORD dwMediaTypeSize = 0;
139 if (RegOpenKeyExW(hkeyPinKey, L"Types", 0, KEY_READ, &hkeyTypes) != ERROR_SUCCESS)
140 return ;
142 if (RegQueryInfoKeyW(hkeyTypes, NULL, NULL, NULL, &dwMajorTypes, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
143 != ERROR_SUCCESS)
145 RegCloseKey(hkeyTypes);
146 return ;
149 for (i = 0; i < dwMajorTypes; i++)
151 HKEY hkeyMajorType = NULL;
152 WCHAR wszMajorTypeName[64];
153 DWORD cName = ARRAY_SIZE(wszMajorTypeName);
154 DWORD dwMinorTypes, i1;
156 if (RegEnumKeyExW(hkeyTypes, i, wszMajorTypeName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
158 if (RegOpenKeyExW(hkeyTypes, wszMajorTypeName, 0, KEY_READ, &hkeyMajorType) != ERROR_SUCCESS) continue;
160 if (RegQueryInfoKeyW(hkeyMajorType, NULL, NULL, NULL, &dwMinorTypes, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
161 != ERROR_SUCCESS)
163 RegCloseKey(hkeyMajorType);
164 continue;
167 for (i1 = 0; i1 < dwMinorTypes; i1++)
169 WCHAR wszMinorTypeName[64];
170 CLSID *clsMajorType = NULL, *clsMinorType = NULL;
171 HRESULT hr;
173 cName = ARRAY_SIZE(wszMinorTypeName);
174 if (RegEnumKeyExW(hkeyMajorType, i1, wszMinorTypeName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
176 clsMinorType = CoTaskMemAlloc(sizeof(CLSID));
177 if (!clsMinorType) continue;
179 clsMajorType = CoTaskMemAlloc(sizeof(CLSID));
180 if (!clsMajorType) goto error_cleanup_types;
182 hr = CLSIDFromString(wszMinorTypeName, clsMinorType);
183 if (FAILED(hr)) goto error_cleanup_types;
185 hr = CLSIDFromString(wszMajorTypeName, clsMajorType);
186 if (FAILED(hr)) goto error_cleanup_types;
188 if (rgPin->nMediaTypes == dwMediaTypeSize)
190 DWORD dwNewSize = dwMediaTypeSize + (dwMediaTypeSize < 2 ? 1 : dwMediaTypeSize / 2);
191 REGPINTYPES *lpNewMediaType;
193 lpNewMediaType = CoTaskMemRealloc(lpMediaType, sizeof(REGPINTYPES) * dwNewSize);
194 if (!lpNewMediaType) goto error_cleanup_types;
196 lpMediaType = lpNewMediaType;
197 dwMediaTypeSize = dwNewSize;
200 lpMediaType[rgPin->nMediaTypes].clsMajorType = clsMajorType;
201 lpMediaType[rgPin->nMediaTypes].clsMinorType = clsMinorType;
202 rgPin->nMediaTypes++;
203 continue;
205 error_cleanup_types:
207 CoTaskMemFree(clsMajorType);
208 CoTaskMemFree(clsMinorType);
211 RegCloseKey(hkeyMajorType);
214 RegCloseKey(hkeyTypes);
216 if (lpMediaType && !rgPin->nMediaTypes)
218 CoTaskMemFree(lpMediaType);
219 lpMediaType = NULL;
222 rgPin->lpMediaType = lpMediaType;
225 static void DEVENUM_ReadPins(HKEY hkeyFilterClass, REGFILTER2 *rgf2)
227 HKEY hkeyPins = NULL;
228 DWORD dwPinsSubkeys, i;
229 REGFILTERPINS2 *rgPins = NULL;
231 rgf2->dwVersion = 2;
232 rgf2->cPins2 = 0;
233 rgf2->rgPins2 = NULL;
235 if (RegOpenKeyExW(hkeyFilterClass, L"Pins", 0, KEY_READ, &hkeyPins) != ERROR_SUCCESS)
236 return ;
238 if (RegQueryInfoKeyW(hkeyPins, NULL, NULL, NULL, &dwPinsSubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
239 != ERROR_SUCCESS)
241 RegCloseKey(hkeyPins);
242 return ;
245 if (dwPinsSubkeys)
247 rgPins = CoTaskMemAlloc(sizeof(REGFILTERPINS2) * dwPinsSubkeys);
248 if (!rgPins)
250 RegCloseKey(hkeyPins);
251 return ;
255 for (i = 0; i < dwPinsSubkeys; i++)
257 HKEY hkeyPinKey = NULL;
258 WCHAR wszPinName[MAX_PATH];
259 DWORD cName = ARRAY_SIZE(wszPinName);
260 REGFILTERPINS2 *rgPin = &rgPins[rgf2->cPins2];
261 DWORD value, size, Type;
262 LONG lRet;
264 memset(rgPin, 0, sizeof(*rgPin));
266 if (RegEnumKeyExW(hkeyPins, i, wszPinName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
268 if (RegOpenKeyExW(hkeyPins, wszPinName, 0, KEY_READ, &hkeyPinKey) != ERROR_SUCCESS) continue;
270 size = sizeof(DWORD);
271 lRet = RegQueryValueExW(hkeyPinKey, L"AllowedMany", NULL, &Type, (BYTE *)&value, &size);
272 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
273 goto error_cleanup;
274 if (value)
275 rgPin->dwFlags |= REG_PINFLAG_B_MANY;
277 size = sizeof(DWORD);
278 lRet = RegQueryValueExW(hkeyPinKey, L"AllowedZero", NULL, &Type, (BYTE *)&value, &size);
279 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
280 goto error_cleanup;
281 if (value)
282 rgPin->dwFlags |= REG_PINFLAG_B_ZERO;
284 size = sizeof(DWORD);
285 lRet = RegQueryValueExW(hkeyPinKey, L"Direction", NULL, &Type, (BYTE *)&value, &size);
286 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
287 goto error_cleanup;
288 if (value)
289 rgPin->dwFlags |= REG_PINFLAG_B_OUTPUT;
292 size = sizeof(DWORD);
293 lRet = RegQueryValueExW(hkeyPinKey, L"IsRendered", NULL, &Type, (BYTE *)&value, &size);
294 if (lRet != ERROR_SUCCESS || Type != REG_DWORD)
295 goto error_cleanup;
296 if (value)
297 rgPin->dwFlags |= REG_PINFLAG_B_RENDERER;
299 DEVENUM_ReadPinTypes(hkeyPinKey, rgPin);
301 ++rgf2->cPins2;
302 continue;
304 error_cleanup:
306 RegCloseKey(hkeyPinKey);
309 RegCloseKey(hkeyPins);
311 if (rgPins && !rgf2->cPins2)
313 CoTaskMemFree(rgPins);
314 rgPins = NULL;
317 rgf2->rgPins2 = rgPins;
320 static void free_regfilter2(REGFILTER2 *rgf)
322 if (rgf->rgPins2)
324 UINT iPin;
326 for (iPin = 0; iPin < rgf->cPins2; iPin++)
328 if (rgf->rgPins2[iPin].lpMediaType)
330 UINT iType;
332 for (iType = 0; iType < rgf->rgPins2[iPin].nMediaTypes; iType++)
334 CoTaskMemFree((void *)rgf->rgPins2[iPin].lpMediaType[iType].clsMajorType);
335 CoTaskMemFree((void *)rgf->rgPins2[iPin].lpMediaType[iType].clsMinorType);
338 CoTaskMemFree((void *)rgf->rgPins2[iPin].lpMediaType);
342 CoTaskMemFree((void *)rgf->rgPins2);
346 HRESULT create_filter_data(VARIANT *var, REGFILTER2 *rgf)
348 IAMFilterData *fildata;
349 BYTE *data = NULL;
350 ULONG size;
351 HRESULT hr;
353 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IAMFilterData, (void **)&fildata);
354 if (FAILED(hr))
355 return hr;
357 hr = IAMFilterData_CreateFilterData(fildata, rgf, &data, &size);
358 IAMFilterData_Release(fildata);
359 if (FAILED(hr))
360 return hr;
362 V_VT(var) = VT_ARRAY | VT_UI1;
363 if (!(V_ARRAY(var) = SafeArrayCreateVector(VT_UI1, 1, size)))
365 VariantClear(var);
366 CoTaskMemFree(data);
367 return E_OUTOFMEMORY;
370 memcpy(V_ARRAY(var)->pvData, data, size);
371 CoTaskMemFree(data);
372 return S_OK;
375 static void write_filter_data(IPropertyBag *prop_bag, REGFILTER2 *rgf)
377 VARIANT var;
379 if (SUCCEEDED(create_filter_data(&var, rgf)))
381 IPropertyBag_Write(prop_bag, L"FilterData", &var);
382 VariantClear(&var);
386 static void register_legacy_filters(void)
388 HKEY hkeyFilter = NULL;
389 DWORD dwFilterSubkeys, i;
390 LONG lRet;
391 HRESULT hr;
393 lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Filter", 0, KEY_READ, &hkeyFilter);
394 hr = HRESULT_FROM_WIN32(lRet);
396 if (SUCCEEDED(hr))
398 lRet = RegQueryInfoKeyW(hkeyFilter, NULL, NULL, NULL, &dwFilterSubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
399 hr = HRESULT_FROM_WIN32(lRet);
402 if (SUCCEEDED(hr))
404 for (i = 0; i < dwFilterSubkeys; i++)
406 WCHAR wszFilterSubkeyName[64];
407 DWORD cName = ARRAY_SIZE(wszFilterSubkeyName);
408 IPropertyBag *prop_bag = NULL;
409 WCHAR wszRegKey[MAX_PATH];
410 HKEY classkey = NULL;
411 REGFILTER2 rgf2;
412 DWORD Type, len;
413 GUID clsid;
415 if (RegEnumKeyExW(hkeyFilter, i, wszFilterSubkeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
417 TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName));
419 hr = CLSIDFromString(wszFilterSubkeyName, &clsid);
420 if (FAILED(hr))
421 continue;
423 swprintf(wszRegKey, ARRAY_SIZE(wszRegKey), L"CLSID\\%s", wszFilterSubkeyName);
424 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &classkey) != ERROR_SUCCESS)
425 continue;
427 len = 0;
428 if (!RegQueryValueExW(classkey, NULL, NULL, &Type, NULL, &len))
430 WCHAR *friendlyname = malloc(len);
431 if (!friendlyname)
433 RegCloseKey(classkey);
434 continue;
436 RegQueryValueExW(classkey, NULL, NULL, &Type, (BYTE *)friendlyname, &len);
438 hr = register_codec(&CLSID_LegacyAmFilterCategory, wszFilterSubkeyName,
439 &clsid, friendlyname, &prop_bag);
441 free(friendlyname);
443 else
444 hr = register_codec(&CLSID_LegacyAmFilterCategory, wszFilterSubkeyName,
445 &clsid, wszFilterSubkeyName, &prop_bag);
446 if (FAILED(hr))
448 RegCloseKey(classkey);
449 continue;
452 /* write filter data */
453 rgf2.dwMerit = MERIT_NORMAL;
455 len = sizeof(rgf2.dwMerit);
456 RegQueryValueExW(classkey, L"Merit", NULL, &Type, (BYTE *)&rgf2.dwMerit, &len);
458 DEVENUM_ReadPins(classkey, &rgf2);
460 write_filter_data(prop_bag, &rgf2);
462 IPropertyBag_Release(prop_bag);
463 RegCloseKey(classkey);
464 free_regfilter2(&rgf2);
468 if (hkeyFilter) RegCloseKey(hkeyFilter);
471 static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, const WCHAR *module, void *context)
473 static const WCHAR defaultW[] = L"Default DirectSound Device";
474 IPropertyBag *prop_bag = NULL;
475 REGFILTERPINS2 rgpins = {0};
476 REGPINTYPES rgtypes = {0};
477 REGFILTER2 rgf = {0};
478 WCHAR clsid[CHARS_IN_GUID];
479 VARIANT var;
480 HRESULT hr;
482 if (guid)
484 WCHAR *name = malloc(sizeof(defaultW) + wcslen(desc) * sizeof(WCHAR));
485 if (!name)
486 return FALSE;
487 wcscpy(name, L"DirectSound: ");
488 wcscat(name, desc);
490 hr = register_codec(&CLSID_AudioRendererCategory, name,
491 &CLSID_DSoundRender, name, &prop_bag);
492 free(name);
494 else
495 hr = register_codec(&CLSID_AudioRendererCategory, defaultW,
496 &CLSID_DSoundRender, defaultW, &prop_bag);
497 if (FAILED(hr))
498 return FALSE;
500 /* write filter data */
501 rgf.dwVersion = 2;
502 rgf.dwMerit = guid ? MERIT_DO_NOT_USE : MERIT_PREFERRED;
503 rgf.cPins2 = 1;
504 rgf.rgPins2 = &rgpins;
505 rgpins.dwFlags = REG_PINFLAG_B_RENDERER;
506 /* FIXME: native registers many more formats */
507 rgpins.nMediaTypes = 1;
508 rgpins.lpMediaType = &rgtypes;
509 rgtypes.clsMajorType = &MEDIATYPE_Audio;
510 rgtypes.clsMinorType = &MEDIASUBTYPE_PCM;
512 write_filter_data(prop_bag, &rgf);
514 /* write DSound guid */
515 V_VT(&var) = VT_BSTR;
516 StringFromGUID2(guid ? guid : &GUID_NULL, clsid, CHARS_IN_GUID);
517 if ((V_BSTR(&var) = SysAllocString(clsid)))
518 hr = IPropertyBag_Write(prop_bag, L"DSGuid", &var);
520 VariantClear(&var);
521 IPropertyBag_Release(prop_bag);
522 return TRUE;
525 static void register_waveout_devices(void)
527 IPropertyBag *prop_bag = NULL;
528 REGFILTERPINS2 rgpins = {0};
529 REGPINTYPES rgtypes = {0};
530 REGFILTER2 rgf = {0};
531 WAVEOUTCAPSW caps;
532 const WCHAR *name;
533 int i, count;
534 VARIANT var;
535 HRESULT hr;
537 count = waveOutGetNumDevs();
539 for (i = -1; i < count; i++)
541 waveOutGetDevCapsW(i, &caps, sizeof(caps));
543 name = (i == -1) ? L"Default WaveOut Device" : caps.szPname;
545 hr = register_codec(&CLSID_AudioRendererCategory, name,
546 &CLSID_AudioRender, name, &prop_bag);
547 if (FAILED(hr))
548 continue;
550 /* write filter data */
551 rgf.dwVersion = 2;
552 rgf.dwMerit = MERIT_DO_NOT_USE;
553 rgf.cPins2 = 1;
554 rgf.rgPins2 = &rgpins;
555 rgpins.dwFlags = REG_PINFLAG_B_RENDERER;
556 rgpins.nMediaTypes = 1;
557 rgpins.lpMediaType = &rgtypes;
558 rgtypes.clsMajorType = &MEDIATYPE_Audio;
559 rgtypes.clsMinorType = &MEDIASUBTYPE_NULL;
561 write_filter_data(prop_bag, &rgf);
563 /* write WaveOutId */
564 V_VT(&var) = VT_I4;
565 V_I4(&var) = i;
566 IPropertyBag_Write(prop_bag, L"WaveOutId", &var);
568 VariantClear(&var);
569 if (prop_bag) IPropertyBag_Release(prop_bag);
573 static void register_wavein_devices(void)
575 IPropertyBag *prop_bag = NULL;
576 REGFILTER2 rgf = {0};
577 WAVEINCAPSW caps;
578 int i, count;
579 VARIANT var;
580 HRESULT hr;
582 count = waveInGetNumDevs();
584 for (i = 0; i < count; i++)
586 waveInGetDevCapsW(i, &caps, sizeof(caps));
588 hr = register_codec(&CLSID_AudioInputDeviceCategory, caps.szPname,
589 &CLSID_AudioRecord, caps.szPname, &prop_bag);
590 if (FAILED(hr))
591 continue;
593 /* write filter data */
594 rgf.dwVersion = 2;
595 rgf.dwMerit = MERIT_DO_NOT_USE;
597 write_filter_data(prop_bag, &rgf);
599 /* write WaveInId */
600 V_VT(&var) = VT_I4;
601 V_I4(&var) = i;
602 IPropertyBag_Write(prop_bag, L"WaveInId", &var);
604 VariantClear(&var);
605 IPropertyBag_Release(prop_bag);
609 static void register_midiout_devices(void)
611 IPropertyBag *prop_bag = NULL;
612 REGFILTERPINS2 rgpins = {0};
613 REGPINTYPES rgtypes = {0};
614 REGFILTER2 rgf = {0};
615 MIDIOUTCAPSW caps;
616 const WCHAR *name;
617 int i, count;
618 VARIANT var;
619 HRESULT hr;
621 count = midiOutGetNumDevs();
623 for (i = -1; i < count; i++)
625 midiOutGetDevCapsW(i, &caps, sizeof(caps));
627 name = (i == -1) ? L"Default MidiOut Device" : caps.szPname;
629 hr = register_codec(&CLSID_MidiRendererCategory, name,
630 &CLSID_AVIMIDIRender, name, &prop_bag);
631 if (FAILED(hr))
632 continue;
634 /* write filter data */
635 rgf.dwVersion = 2;
636 rgf.dwMerit = (i == -1) ? MERIT_PREFERRED : MERIT_DO_NOT_USE;
637 rgf.cPins2 = 1;
638 rgf.rgPins2 = &rgpins;
639 rgpins.dwFlags = REG_PINFLAG_B_RENDERER;
640 rgpins.nMediaTypes = 1;
641 rgpins.lpMediaType = &rgtypes;
642 rgtypes.clsMajorType = &MEDIATYPE_Midi;
643 rgtypes.clsMinorType = &MEDIASUBTYPE_NULL;
645 write_filter_data(prop_bag, &rgf);
647 /* write MidiOutId */
648 V_VT(&var) = VT_I4;
649 V_I4(&var) = i;
650 IPropertyBag_Write(prop_bag, L"MidiOutId", &var);
652 VariantClear(&var);
653 IPropertyBag_Release(prop_bag);
657 static void register_vfw_codecs(void)
659 REGFILTERPINS2 rgpins[2] = {};
660 IPropertyBag *prop_bag = NULL;
661 REGPINTYPES rgtypes[2];
662 REGFILTER2 rgf;
663 GUID typeguid;
664 ICINFO info;
665 VARIANT var;
666 HRESULT hr;
667 int i = 0;
668 HIC hic;
670 while (ICInfo(ICTYPE_VIDEO, i++, &info))
672 WCHAR name[5] = {LOBYTE(LOWORD(info.fccHandler)), HIBYTE(LOWORD(info.fccHandler)),
673 LOBYTE(HIWORD(info.fccHandler)), HIBYTE(HIWORD(info.fccHandler))};
675 hic = ICOpen(ICTYPE_VIDEO, info.fccHandler, ICMODE_QUERY);
676 ICGetInfo(hic, &info, sizeof(info));
677 ICClose(hic);
679 hr = register_codec(&CLSID_VideoCompressorCategory, name,
680 &CLSID_AVICo, info.szDescription, &prop_bag);
681 if (FAILED(hr))
682 continue;
684 /* write filter data */
685 rgf.dwVersion = 2;
686 rgf.dwMerit = MERIT_DO_NOT_USE;
687 rgf.cPins2 = 2;
688 rgf.rgPins2 = rgpins;
689 rgpins[0].dwFlags = 0;
690 rgpins[0].nMediaTypes = 1;
691 rgpins[0].lpMediaType = &rgtypes[0];
692 rgtypes[0].clsMajorType = &MEDIATYPE_Video;
693 typeguid = MEDIASUBTYPE_PCM;
694 typeguid.Data1 = info.fccHandler;
695 rgtypes[0].clsMinorType = &typeguid;
696 rgpins[1].dwFlags = REG_PINFLAG_B_OUTPUT;
697 rgpins[1].nMediaTypes = 1;
698 rgpins[1].lpMediaType = &rgtypes[1];
699 rgtypes[1].clsMajorType = &MEDIATYPE_Video;
700 rgtypes[1].clsMinorType = &GUID_NULL;
702 write_filter_data(prop_bag, &rgf);
704 /* write WaveInId */
705 V_VT(&var) = VT_BSTR;
706 V_BSTR(&var) = SysAllocString(name);
707 IPropertyBag_Write(prop_bag, L"FccHandler", &var);
709 VariantClear(&var);
710 IPropertyBag_Release(prop_bag);
714 static void register_avicap_devices(void)
716 WCHAR friendlyname[32], version[32];
717 IPropertyBag *prop_bag = NULL;
718 REGFILTERPINS2 rgpins = {0};
719 REGPINTYPES rgtypes;
720 REGFILTER2 rgf;
721 WCHAR name[7];
722 VARIANT var;
723 HRESULT hr;
724 int i = 0;
726 for (i = 0; i < 10; ++i)
728 if (!capGetDriverDescriptionW(i, friendlyname, ARRAY_SIZE(friendlyname),
729 version, ARRAY_SIZE(version)))
730 continue;
732 swprintf(name, ARRAY_SIZE(name), L"video%d", i);
734 hr = register_codec(&CLSID_VideoInputDeviceCategory, name,
735 &CLSID_VfwCapture, friendlyname, &prop_bag);
736 if (FAILED(hr))
737 continue;
739 rgf.dwVersion = 2;
740 rgf.dwMerit = MERIT_DO_NOT_USE;
741 rgf.cPins2 = 1;
742 rgf.rgPins2 = &rgpins;
743 rgpins.dwFlags = 0;
744 rgpins.nMediaTypes = 1;
745 rgpins.lpMediaType = &rgtypes;
746 rgtypes.clsMajorType = &MEDIATYPE_Video;
747 rgtypes.clsMinorType = &MEDIASUBTYPE_None;
749 write_filter_data(prop_bag, &rgf);
751 /* write VFWIndex */
752 V_VT(&var) = VT_I4;
753 V_I4(&var) = i;
754 IPropertyBag_Write(prop_bag, L"VFWIndex", &var);
756 VariantClear(&var);
757 IPropertyBag_Release(prop_bag);
761 static HRESULT WINAPI devenum_factory_CreateClassEnumerator(ICreateDevEnum *iface,
762 REFCLSID class, IEnumMoniker **out, DWORD flags)
764 WCHAR guidstr[CHARS_IN_GUID];
765 HRESULT hr;
766 HKEY key;
768 TRACE("iface %p, class %s, out %p, flags %#lx.\n", iface, debugstr_guid(class), out, flags);
770 if (!out)
771 return E_POINTER;
773 *out = NULL;
775 if (!RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Microsoft\\ActiveMovie\\devenum", &key))
777 StringFromGUID2(class, guidstr, ARRAY_SIZE(guidstr));
778 RegDeleteTreeW(key, guidstr);
781 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory))
782 register_legacy_filters();
783 else if (IsEqualGUID(class, &CLSID_AudioRendererCategory))
785 hr = DirectSoundEnumerateW(&register_dsound_devices, NULL);
786 if (FAILED(hr)) return hr;
787 register_waveout_devices();
788 register_midiout_devices();
790 else if (IsEqualGUID(class, &CLSID_AudioInputDeviceCategory))
791 register_wavein_devices();
792 else if (IsEqualGUID(class, &CLSID_VideoCompressorCategory))
793 register_vfw_codecs();
794 else if (IsEqualGUID(class, &CLSID_VideoInputDeviceCategory))
795 register_avicap_devices();
797 if (SUCCEEDED(hr = enum_moniker_create(class, out)))
799 IMoniker *mon;
800 hr = IEnumMoniker_Next(*out, 1, &mon, NULL);
801 if (hr == S_OK)
803 IMoniker_Release(mon);
804 IEnumMoniker_Reset(*out);
806 else
808 IEnumMoniker_Release(*out);
809 *out = NULL;
813 return hr;
816 /**********************************************************************
817 * ICreateDevEnum_Vtbl
819 static const ICreateDevEnumVtbl ICreateDevEnum_Vtbl =
821 devenum_factory_QueryInterface,
822 devenum_factory_AddRef,
823 devenum_factory_Release,
824 devenum_factory_CreateClassEnumerator,
827 /**********************************************************************
828 * static CreateDevEnum instance
830 ICreateDevEnum devenum_factory = { &ICreateDevEnum_Vtbl };