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
21 * - Implements ICreateDevEnum interface which creates an IEnumMoniker
23 * - Also creates the special registry keys created at run-time
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
29 #include "devenum_private.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
39 #include "wine/fil_data.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(devenum
);
43 static HRESULT WINAPI
devenum_factory_QueryInterface(ICreateDevEnum
*iface
, REFIID riid
, void **ppv
)
45 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
50 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
51 IsEqualGUID(riid
, &IID_ICreateDevEnum
))
54 ICreateDevEnum_AddRef(iface
);
58 FIXME("- no interface IID: %s\n", debugstr_guid(riid
));
63 static ULONG WINAPI
devenum_factory_AddRef(ICreateDevEnum
*iface
)
69 return 2; /* non-heap based object */
72 static ULONG WINAPI
devenum_factory_Release(ICreateDevEnum
*iface
)
76 DEVENUM_UnlockModule();
78 return 1; /* non-heap based object */
81 static HRESULT
register_codec(const GUID
*class, const WCHAR
*name
,
82 const GUID
*clsid
, const WCHAR
*friendly_name
, IPropertyBag
**ret
)
84 WCHAR guidstr
[CHARS_IN_GUID
];
85 IParseDisplayName
*parser
;
86 IPropertyBag
*propbag
;
93 hr
= CoCreateInstance(&CLSID_CDeviceMoniker
, NULL
, CLSCTX_INPROC
, &IID_IParseDisplayName
, (void **)&parser
);
97 if (!(buffer
= heap_alloc((wcslen(L
"@device:cm:") + CHARS_IN_GUID
+ wcslen(name
) + 1) * sizeof(WCHAR
))))
99 IParseDisplayName_Release(parser
);
100 return E_OUTOFMEMORY
;
103 wcscpy(buffer
, L
"@device:cm:");
104 StringFromGUID2(class, buffer
+ wcslen(buffer
), CHARS_IN_GUID
);
105 wcscat(buffer
, L
"\\");
106 wcscat(buffer
, name
);
108 IParseDisplayName_ParseDisplayName(parser
, NULL
, buffer
, &eaten
, &mon
);
109 IParseDisplayName_Release(parser
);
112 IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&propbag
);
113 IMoniker_Release(mon
);
115 V_VT(&var
) = VT_BSTR
;
116 V_BSTR(&var
) = SysAllocString(friendly_name
);
117 hr
= IPropertyBag_Write(propbag
, L
"FriendlyName", &var
);
121 IPropertyBag_Release(propbag
);
125 V_VT(&var
) = VT_BSTR
;
126 StringFromGUID2(clsid
, guidstr
, ARRAY_SIZE(guidstr
));
127 V_BSTR(&var
) = SysAllocString(guidstr
);
128 hr
= IPropertyBag_Write(propbag
, L
"CLSID", &var
);
132 IPropertyBag_Release(propbag
);
140 static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey
, REGFILTERPINS2
*rgPin
)
142 HKEY hkeyTypes
= NULL
;
143 DWORD dwMajorTypes
, i
;
144 REGPINTYPES
*lpMediaType
= NULL
;
145 DWORD dwMediaTypeSize
= 0;
147 if (RegOpenKeyExW(hkeyPinKey
, L
"Types", 0, KEY_READ
, &hkeyTypes
) != ERROR_SUCCESS
)
150 if (RegQueryInfoKeyW(hkeyTypes
, NULL
, NULL
, NULL
, &dwMajorTypes
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
153 RegCloseKey(hkeyTypes
);
157 for (i
= 0; i
< dwMajorTypes
; i
++)
159 HKEY hkeyMajorType
= NULL
;
160 WCHAR wszMajorTypeName
[64];
161 DWORD cName
= ARRAY_SIZE(wszMajorTypeName
);
162 DWORD dwMinorTypes
, i1
;
164 if (RegEnumKeyExW(hkeyTypes
, i
, wszMajorTypeName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
166 if (RegOpenKeyExW(hkeyTypes
, wszMajorTypeName
, 0, KEY_READ
, &hkeyMajorType
) != ERROR_SUCCESS
) continue;
168 if (RegQueryInfoKeyW(hkeyMajorType
, NULL
, NULL
, NULL
, &dwMinorTypes
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
171 RegCloseKey(hkeyMajorType
);
175 for (i1
= 0; i1
< dwMinorTypes
; i1
++)
177 WCHAR wszMinorTypeName
[64];
178 CLSID
*clsMajorType
= NULL
, *clsMinorType
= NULL
;
181 cName
= ARRAY_SIZE(wszMinorTypeName
);
182 if (RegEnumKeyExW(hkeyMajorType
, i1
, wszMinorTypeName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
184 clsMinorType
= CoTaskMemAlloc(sizeof(CLSID
));
185 if (!clsMinorType
) continue;
187 clsMajorType
= CoTaskMemAlloc(sizeof(CLSID
));
188 if (!clsMajorType
) goto error_cleanup_types
;
190 hr
= CLSIDFromString(wszMinorTypeName
, clsMinorType
);
191 if (FAILED(hr
)) goto error_cleanup_types
;
193 hr
= CLSIDFromString(wszMajorTypeName
, clsMajorType
);
194 if (FAILED(hr
)) goto error_cleanup_types
;
196 if (rgPin
->nMediaTypes
== dwMediaTypeSize
)
198 DWORD dwNewSize
= dwMediaTypeSize
+ (dwMediaTypeSize
< 2 ? 1 : dwMediaTypeSize
/ 2);
199 REGPINTYPES
*lpNewMediaType
;
201 lpNewMediaType
= CoTaskMemRealloc(lpMediaType
, sizeof(REGPINTYPES
) * dwNewSize
);
202 if (!lpNewMediaType
) goto error_cleanup_types
;
204 lpMediaType
= lpNewMediaType
;
205 dwMediaTypeSize
= dwNewSize
;
208 lpMediaType
[rgPin
->nMediaTypes
].clsMajorType
= clsMajorType
;
209 lpMediaType
[rgPin
->nMediaTypes
].clsMinorType
= clsMinorType
;
210 rgPin
->nMediaTypes
++;
215 CoTaskMemFree(clsMajorType
);
216 CoTaskMemFree(clsMinorType
);
219 RegCloseKey(hkeyMajorType
);
222 RegCloseKey(hkeyTypes
);
224 if (lpMediaType
&& !rgPin
->nMediaTypes
)
226 CoTaskMemFree(lpMediaType
);
230 rgPin
->lpMediaType
= lpMediaType
;
233 static void DEVENUM_ReadPins(HKEY hkeyFilterClass
, REGFILTER2
*rgf2
)
235 HKEY hkeyPins
= NULL
;
236 DWORD dwPinsSubkeys
, i
;
237 REGFILTERPINS2
*rgPins
= NULL
;
240 rgf2
->u
.s2
.cPins2
= 0;
241 rgf2
->u
.s2
.rgPins2
= NULL
;
243 if (RegOpenKeyExW(hkeyFilterClass
, L
"Pins", 0, KEY_READ
, &hkeyPins
) != ERROR_SUCCESS
)
246 if (RegQueryInfoKeyW(hkeyPins
, NULL
, NULL
, NULL
, &dwPinsSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
249 RegCloseKey(hkeyPins
);
255 rgPins
= CoTaskMemAlloc(sizeof(REGFILTERPINS2
) * dwPinsSubkeys
);
258 RegCloseKey(hkeyPins
);
263 for (i
= 0; i
< dwPinsSubkeys
; i
++)
265 HKEY hkeyPinKey
= NULL
;
266 WCHAR wszPinName
[MAX_PATH
];
267 DWORD cName
= ARRAY_SIZE(wszPinName
);
268 REGFILTERPINS2
*rgPin
= &rgPins
[rgf2
->u
.s2
.cPins2
];
269 DWORD value
, size
, Type
;
272 memset(rgPin
, 0, sizeof(*rgPin
));
274 if (RegEnumKeyExW(hkeyPins
, i
, wszPinName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
276 if (RegOpenKeyExW(hkeyPins
, wszPinName
, 0, KEY_READ
, &hkeyPinKey
) != ERROR_SUCCESS
) continue;
278 size
= sizeof(DWORD
);
279 lRet
= RegQueryValueExW(hkeyPinKey
, L
"AllowedMany", NULL
, &Type
, (BYTE
*)&value
, &size
);
280 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
283 rgPin
->dwFlags
|= REG_PINFLAG_B_MANY
;
285 size
= sizeof(DWORD
);
286 lRet
= RegQueryValueExW(hkeyPinKey
, L
"AllowedZero", NULL
, &Type
, (BYTE
*)&value
, &size
);
287 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
290 rgPin
->dwFlags
|= REG_PINFLAG_B_ZERO
;
292 size
= sizeof(DWORD
);
293 lRet
= RegQueryValueExW(hkeyPinKey
, L
"Direction", NULL
, &Type
, (BYTE
*)&value
, &size
);
294 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
297 rgPin
->dwFlags
|= REG_PINFLAG_B_OUTPUT
;
300 size
= sizeof(DWORD
);
301 lRet
= RegQueryValueExW(hkeyPinKey
, L
"IsRendered", NULL
, &Type
, (BYTE
*)&value
, &size
);
302 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
305 rgPin
->dwFlags
|= REG_PINFLAG_B_RENDERER
;
307 DEVENUM_ReadPinTypes(hkeyPinKey
, rgPin
);
314 RegCloseKey(hkeyPinKey
);
317 RegCloseKey(hkeyPins
);
319 if (rgPins
&& !rgf2
->u
.s2
.cPins2
)
321 CoTaskMemFree(rgPins
);
325 rgf2
->u
.s2
.rgPins2
= rgPins
;
328 static void free_regfilter2(REGFILTER2
*rgf
)
330 if (rgf
->u
.s2
.rgPins2
)
334 for (iPin
= 0; iPin
< rgf
->u
.s2
.cPins2
; iPin
++)
336 if (rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
)
340 for (iType
= 0; iType
< rgf
->u
.s2
.rgPins2
[iPin
].nMediaTypes
; iType
++)
342 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
[iType
].clsMajorType
);
343 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
[iType
].clsMinorType
);
346 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
);
350 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
);
354 static void write_filter_data(IPropertyBag
*prop_bag
, REGFILTER2
*rgf
)
356 BYTE
*data
= NULL
, *array
;
357 IAMFilterData
*fildata
;
358 SAFEARRAYBOUND sabound
;
363 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC
, &IID_IAMFilterData
, (void **)&fildata
);
364 if (FAILED(hr
)) goto cleanup
;
366 hr
= IAMFilterData_CreateFilterData(fildata
, rgf
, &data
, &size
);
367 if (FAILED(hr
)) goto cleanup
;
369 V_VT(&var
) = VT_ARRAY
| VT_UI1
;
371 sabound
.cElements
= size
;
372 if (!(V_ARRAY(&var
) = SafeArrayCreate(VT_UI1
, 1, &sabound
)))
374 hr
= SafeArrayAccessData(V_ARRAY(&var
), (void *)&array
);
375 if (FAILED(hr
)) goto cleanup
;
377 memcpy(array
, data
, size
);
378 hr
= SafeArrayUnaccessData(V_ARRAY(&var
));
379 if (FAILED(hr
)) goto cleanup
;
381 hr
= IPropertyBag_Write(prop_bag
, L
"FilterData", &var
);
382 if (FAILED(hr
)) goto cleanup
;
387 IAMFilterData_Release(fildata
);
390 static void register_legacy_filters(void)
392 HKEY hkeyFilter
= NULL
;
393 DWORD dwFilterSubkeys
, i
;
397 lRet
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Filter", 0, KEY_READ
, &hkeyFilter
);
398 hr
= HRESULT_FROM_WIN32(lRet
);
402 lRet
= RegQueryInfoKeyW(hkeyFilter
, NULL
, NULL
, NULL
, &dwFilterSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
403 hr
= HRESULT_FROM_WIN32(lRet
);
408 for (i
= 0; i
< dwFilterSubkeys
; i
++)
410 WCHAR wszFilterSubkeyName
[64];
411 DWORD cName
= ARRAY_SIZE(wszFilterSubkeyName
);
412 IPropertyBag
*prop_bag
= NULL
;
413 WCHAR wszRegKey
[MAX_PATH
];
414 HKEY classkey
= NULL
;
419 if (RegEnumKeyExW(hkeyFilter
, i
, wszFilterSubkeyName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
421 TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName
));
423 hr
= CLSIDFromString(wszFilterSubkeyName
, &clsid
);
427 swprintf(wszRegKey
, ARRAY_SIZE(wszRegKey
), L
"CLSID\\%s", wszFilterSubkeyName
);
428 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszRegKey
, 0, KEY_READ
, &classkey
) != ERROR_SUCCESS
)
432 if (!RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, NULL
, &len
))
434 WCHAR
*friendlyname
= heap_alloc(len
);
437 RegCloseKey(classkey
);
440 RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, (BYTE
*)friendlyname
, &len
);
442 hr
= register_codec(&CLSID_LegacyAmFilterCategory
, wszFilterSubkeyName
,
443 &clsid
, friendlyname
, &prop_bag
);
445 heap_free(friendlyname
);
448 hr
= register_codec(&CLSID_LegacyAmFilterCategory
, wszFilterSubkeyName
,
449 &clsid
, wszFilterSubkeyName
, &prop_bag
);
452 RegCloseKey(classkey
);
456 /* write filter data */
457 rgf2
.dwMerit
= MERIT_NORMAL
;
459 len
= sizeof(rgf2
.dwMerit
);
460 RegQueryValueExW(classkey
, L
"Merit", NULL
, &Type
, (BYTE
*)&rgf2
.dwMerit
, &len
);
462 DEVENUM_ReadPins(classkey
, &rgf2
);
464 write_filter_data(prop_bag
, &rgf2
);
466 IPropertyBag_Release(prop_bag
);
467 RegCloseKey(classkey
);
468 free_regfilter2(&rgf2
);
472 if (hkeyFilter
) RegCloseKey(hkeyFilter
);
475 static BOOL CALLBACK
register_dsound_devices(GUID
*guid
, const WCHAR
*desc
, const WCHAR
*module
, void *context
)
477 static const WCHAR defaultW
[] = L
"Default DirectSound Device";
478 IPropertyBag
*prop_bag
= NULL
;
479 REGFILTERPINS2 rgpins
= {0};
480 REGPINTYPES rgtypes
= {0};
481 REGFILTER2 rgf
= {0};
482 WCHAR clsid
[CHARS_IN_GUID
];
488 WCHAR
*name
= heap_alloc(sizeof(defaultW
) + wcslen(desc
) * sizeof(WCHAR
));
491 wcscpy(name
, L
"DirectSound: ");
494 hr
= register_codec(&CLSID_AudioRendererCategory
, name
,
495 &CLSID_DSoundRender
, name
, &prop_bag
);
499 hr
= register_codec(&CLSID_AudioRendererCategory
, defaultW
,
500 &CLSID_DSoundRender
, defaultW
, &prop_bag
);
504 /* write filter data */
506 rgf
.dwMerit
= guid
? MERIT_DO_NOT_USE
: MERIT_PREFERRED
;
508 rgf
.u
.s2
.rgPins2
= &rgpins
;
509 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
510 /* FIXME: native registers many more formats */
511 rgpins
.nMediaTypes
= 1;
512 rgpins
.lpMediaType
= &rgtypes
;
513 rgtypes
.clsMajorType
= &MEDIATYPE_Audio
;
514 rgtypes
.clsMinorType
= &MEDIASUBTYPE_PCM
;
516 write_filter_data(prop_bag
, &rgf
);
518 /* write DSound guid */
519 V_VT(&var
) = VT_BSTR
;
520 StringFromGUID2(guid
? guid
: &GUID_NULL
, clsid
, CHARS_IN_GUID
);
521 if ((V_BSTR(&var
) = SysAllocString(clsid
)))
522 hr
= IPropertyBag_Write(prop_bag
, L
"DSGuid", &var
);
525 IPropertyBag_Release(prop_bag
);
529 static void register_waveout_devices(void)
531 IPropertyBag
*prop_bag
= NULL
;
532 REGFILTERPINS2 rgpins
= {0};
533 REGPINTYPES rgtypes
= {0};
534 REGFILTER2 rgf
= {0};
541 count
= waveOutGetNumDevs();
543 for (i
= -1; i
< count
; i
++)
545 waveOutGetDevCapsW(i
, &caps
, sizeof(caps
));
547 name
= (i
== -1) ? L
"Default WaveOut Device" : caps
.szPname
;
549 hr
= register_codec(&CLSID_AudioRendererCategory
, name
,
550 &CLSID_AudioRender
, name
, &prop_bag
);
554 /* write filter data */
556 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
558 rgf
.u
.s2
.rgPins2
= &rgpins
;
559 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
560 rgpins
.nMediaTypes
= 1;
561 rgpins
.lpMediaType
= &rgtypes
;
562 rgtypes
.clsMajorType
= &MEDIATYPE_Audio
;
563 rgtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
565 write_filter_data(prop_bag
, &rgf
);
567 /* write WaveOutId */
570 IPropertyBag_Write(prop_bag
, L
"WaveOutId", &var
);
573 if (prop_bag
) IPropertyBag_Release(prop_bag
);
577 static void register_wavein_devices(void)
579 IPropertyBag
*prop_bag
= NULL
;
580 REGFILTER2 rgf
= {0};
586 count
= waveInGetNumDevs();
588 for (i
= 0; i
< count
; i
++)
590 waveInGetDevCapsW(i
, &caps
, sizeof(caps
));
592 hr
= register_codec(&CLSID_AudioInputDeviceCategory
, caps
.szPname
,
593 &CLSID_AudioRecord
, caps
.szPname
, &prop_bag
);
597 /* write filter data */
599 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
601 write_filter_data(prop_bag
, &rgf
);
606 IPropertyBag_Write(prop_bag
, L
"WaveInId", &var
);
609 IPropertyBag_Release(prop_bag
);
613 static void register_midiout_devices(void)
615 IPropertyBag
*prop_bag
= NULL
;
616 REGFILTERPINS2 rgpins
= {0};
617 REGPINTYPES rgtypes
= {0};
618 REGFILTER2 rgf
= {0};
625 count
= midiOutGetNumDevs();
627 for (i
= -1; i
< count
; i
++)
629 midiOutGetDevCapsW(i
, &caps
, sizeof(caps
));
631 name
= (i
== -1) ? L
"Default MidiOut Device" : caps
.szPname
;
633 hr
= register_codec(&CLSID_MidiRendererCategory
, name
,
634 &CLSID_AVIMIDIRender
, name
, &prop_bag
);
638 /* write filter data */
640 rgf
.dwMerit
= (i
== -1) ? MERIT_PREFERRED
: MERIT_DO_NOT_USE
;
642 rgf
.u
.s2
.rgPins2
= &rgpins
;
643 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
644 rgpins
.nMediaTypes
= 1;
645 rgpins
.lpMediaType
= &rgtypes
;
646 rgtypes
.clsMajorType
= &MEDIATYPE_Midi
;
647 rgtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
649 write_filter_data(prop_bag
, &rgf
);
651 /* write MidiOutId */
654 IPropertyBag_Write(prop_bag
, L
"MidiOutId", &var
);
657 IPropertyBag_Release(prop_bag
);
661 static void register_vfw_codecs(void)
663 REGFILTERPINS2 rgpins
[2] = {};
664 IPropertyBag
*prop_bag
= NULL
;
665 REGPINTYPES rgtypes
[2];
674 while (ICInfo(ICTYPE_VIDEO
, i
++, &info
))
676 WCHAR name
[5] = {LOBYTE(LOWORD(info
.fccHandler
)), HIBYTE(LOWORD(info
.fccHandler
)),
677 LOBYTE(HIWORD(info
.fccHandler
)), HIBYTE(HIWORD(info
.fccHandler
))};
679 hic
= ICOpen(ICTYPE_VIDEO
, info
.fccHandler
, ICMODE_QUERY
);
680 ICGetInfo(hic
, &info
, sizeof(info
));
683 hr
= register_codec(&CLSID_VideoCompressorCategory
, name
,
684 &CLSID_AVICo
, info
.szDescription
, &prop_bag
);
688 /* write filter data */
690 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
692 rgf
.u
.s2
.rgPins2
= rgpins
;
693 rgpins
[0].dwFlags
= 0;
694 rgpins
[0].nMediaTypes
= 1;
695 rgpins
[0].lpMediaType
= &rgtypes
[0];
696 rgtypes
[0].clsMajorType
= &MEDIATYPE_Video
;
697 typeguid
= MEDIASUBTYPE_PCM
;
698 typeguid
.Data1
= info
.fccHandler
;
699 rgtypes
[0].clsMinorType
= &typeguid
;
700 rgpins
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
701 rgpins
[1].nMediaTypes
= 1;
702 rgpins
[1].lpMediaType
= &rgtypes
[1];
703 rgtypes
[1].clsMajorType
= &MEDIATYPE_Video
;
704 rgtypes
[1].clsMinorType
= &GUID_NULL
;
706 write_filter_data(prop_bag
, &rgf
);
709 V_VT(&var
) = VT_BSTR
;
710 V_BSTR(&var
) = SysAllocString(name
);
711 IPropertyBag_Write(prop_bag
, L
"FccHandler", &var
);
714 IPropertyBag_Release(prop_bag
);
718 static void register_avicap_devices(void)
720 WCHAR friendlyname
[32], version
[32];
721 IPropertyBag
*prop_bag
= NULL
;
722 REGFILTERPINS2 rgpins
= {0};
730 for (i
= 0; i
< 10; ++i
)
732 if (!capGetDriverDescriptionW(i
, friendlyname
, ARRAY_SIZE(friendlyname
),
733 version
, ARRAY_SIZE(version
)))
736 swprintf(name
, ARRAY_SIZE(name
), L
"video%d", i
);
738 hr
= register_codec(&CLSID_VideoInputDeviceCategory
, name
,
739 &CLSID_VfwCapture
, friendlyname
, &prop_bag
);
744 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
746 rgf
.u
.s2
.rgPins2
= &rgpins
;
748 rgpins
.nMediaTypes
= 1;
749 rgpins
.lpMediaType
= &rgtypes
;
750 rgtypes
.clsMajorType
= &MEDIATYPE_Video
;
751 rgtypes
.clsMinorType
= &MEDIASUBTYPE_None
;
753 write_filter_data(prop_bag
, &rgf
);
758 IPropertyBag_Write(prop_bag
, L
"VFWIndex", &var
);
761 IPropertyBag_Release(prop_bag
);
765 static HRESULT WINAPI
devenum_factory_CreateClassEnumerator(ICreateDevEnum
*iface
,
766 REFCLSID
class, IEnumMoniker
**out
, DWORD flags
)
768 WCHAR guidstr
[CHARS_IN_GUID
];
772 TRACE("iface %p, class %s, out %p, flags %#x.\n", iface
, debugstr_guid(class), out
, flags
);
779 if (!RegOpenKeyW(HKEY_CURRENT_USER
, L
"Software\\Microsoft\\ActiveMovie\\devenum", &key
))
781 StringFromGUID2(class, guidstr
, ARRAY_SIZE(guidstr
));
782 RegDeleteTreeW(key
, guidstr
);
785 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory
))
786 register_legacy_filters();
787 else if (IsEqualGUID(class, &CLSID_AudioRendererCategory
))
789 hr
= DirectSoundEnumerateW(®ister_dsound_devices
, NULL
);
790 if (FAILED(hr
)) return hr
;
791 register_waveout_devices();
792 register_midiout_devices();
794 else if (IsEqualGUID(class, &CLSID_AudioInputDeviceCategory
))
795 register_wavein_devices();
796 else if (IsEqualGUID(class, &CLSID_VideoCompressorCategory
))
797 register_vfw_codecs();
798 else if (IsEqualGUID(class, &CLSID_VideoInputDeviceCategory
))
799 register_avicap_devices();
801 if (SUCCEEDED(hr
= enum_moniker_create(class, out
)))
804 hr
= IEnumMoniker_Next(*out
, 1, &mon
, NULL
);
807 IMoniker_Release(mon
);
808 IEnumMoniker_Reset(*out
);
812 IEnumMoniker_Release(*out
);
820 /**********************************************************************
821 * ICreateDevEnum_Vtbl
823 static const ICreateDevEnumVtbl ICreateDevEnum_Vtbl
=
825 devenum_factory_QueryInterface
,
826 devenum_factory_AddRef
,
827 devenum_factory_Release
,
828 devenum_factory_CreateClassEnumerator
,
831 /**********************************************************************
832 * static CreateDevEnum instance
834 ICreateDevEnum devenum_factory
= { &ICreateDevEnum_Vtbl
};