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 HRESULT
create_filter_data(VARIANT
*var
, REGFILTER2
*rgf
)
356 IAMFilterData
*fildata
;
361 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC
, &IID_IAMFilterData
, (void **)&fildata
);
365 hr
= IAMFilterData_CreateFilterData(fildata
, rgf
, &data
, &size
);
366 IAMFilterData_Release(fildata
);
370 V_VT(var
) = VT_ARRAY
| VT_UI1
;
371 if (!(V_ARRAY(var
) = SafeArrayCreateVector(VT_UI1
, 1, size
)))
375 return E_OUTOFMEMORY
;
378 memcpy(V_ARRAY(var
)->pvData
, data
, size
);
383 static void write_filter_data(IPropertyBag
*prop_bag
, REGFILTER2
*rgf
)
387 if (SUCCEEDED(create_filter_data(&var
, rgf
)))
389 IPropertyBag_Write(prop_bag
, L
"FilterData", &var
);
394 static void register_legacy_filters(void)
396 HKEY hkeyFilter
= NULL
;
397 DWORD dwFilterSubkeys
, i
;
401 lRet
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Filter", 0, KEY_READ
, &hkeyFilter
);
402 hr
= HRESULT_FROM_WIN32(lRet
);
406 lRet
= RegQueryInfoKeyW(hkeyFilter
, NULL
, NULL
, NULL
, &dwFilterSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
407 hr
= HRESULT_FROM_WIN32(lRet
);
412 for (i
= 0; i
< dwFilterSubkeys
; i
++)
414 WCHAR wszFilterSubkeyName
[64];
415 DWORD cName
= ARRAY_SIZE(wszFilterSubkeyName
);
416 IPropertyBag
*prop_bag
= NULL
;
417 WCHAR wszRegKey
[MAX_PATH
];
418 HKEY classkey
= NULL
;
423 if (RegEnumKeyExW(hkeyFilter
, i
, wszFilterSubkeyName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
425 TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName
));
427 hr
= CLSIDFromString(wszFilterSubkeyName
, &clsid
);
431 swprintf(wszRegKey
, ARRAY_SIZE(wszRegKey
), L
"CLSID\\%s", wszFilterSubkeyName
);
432 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszRegKey
, 0, KEY_READ
, &classkey
) != ERROR_SUCCESS
)
436 if (!RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, NULL
, &len
))
438 WCHAR
*friendlyname
= heap_alloc(len
);
441 RegCloseKey(classkey
);
444 RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, (BYTE
*)friendlyname
, &len
);
446 hr
= register_codec(&CLSID_LegacyAmFilterCategory
, wszFilterSubkeyName
,
447 &clsid
, friendlyname
, &prop_bag
);
449 heap_free(friendlyname
);
452 hr
= register_codec(&CLSID_LegacyAmFilterCategory
, wszFilterSubkeyName
,
453 &clsid
, wszFilterSubkeyName
, &prop_bag
);
456 RegCloseKey(classkey
);
460 /* write filter data */
461 rgf2
.dwMerit
= MERIT_NORMAL
;
463 len
= sizeof(rgf2
.dwMerit
);
464 RegQueryValueExW(classkey
, L
"Merit", NULL
, &Type
, (BYTE
*)&rgf2
.dwMerit
, &len
);
466 DEVENUM_ReadPins(classkey
, &rgf2
);
468 write_filter_data(prop_bag
, &rgf2
);
470 IPropertyBag_Release(prop_bag
);
471 RegCloseKey(classkey
);
472 free_regfilter2(&rgf2
);
476 if (hkeyFilter
) RegCloseKey(hkeyFilter
);
479 static BOOL CALLBACK
register_dsound_devices(GUID
*guid
, const WCHAR
*desc
, const WCHAR
*module
, void *context
)
481 static const WCHAR defaultW
[] = L
"Default DirectSound Device";
482 IPropertyBag
*prop_bag
= NULL
;
483 REGFILTERPINS2 rgpins
= {0};
484 REGPINTYPES rgtypes
= {0};
485 REGFILTER2 rgf
= {0};
486 WCHAR clsid
[CHARS_IN_GUID
];
492 WCHAR
*name
= heap_alloc(sizeof(defaultW
) + wcslen(desc
) * sizeof(WCHAR
));
495 wcscpy(name
, L
"DirectSound: ");
498 hr
= register_codec(&CLSID_AudioRendererCategory
, name
,
499 &CLSID_DSoundRender
, name
, &prop_bag
);
503 hr
= register_codec(&CLSID_AudioRendererCategory
, defaultW
,
504 &CLSID_DSoundRender
, defaultW
, &prop_bag
);
508 /* write filter data */
510 rgf
.dwMerit
= guid
? MERIT_DO_NOT_USE
: MERIT_PREFERRED
;
512 rgf
.u
.s2
.rgPins2
= &rgpins
;
513 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
514 /* FIXME: native registers many more formats */
515 rgpins
.nMediaTypes
= 1;
516 rgpins
.lpMediaType
= &rgtypes
;
517 rgtypes
.clsMajorType
= &MEDIATYPE_Audio
;
518 rgtypes
.clsMinorType
= &MEDIASUBTYPE_PCM
;
520 write_filter_data(prop_bag
, &rgf
);
522 /* write DSound guid */
523 V_VT(&var
) = VT_BSTR
;
524 StringFromGUID2(guid
? guid
: &GUID_NULL
, clsid
, CHARS_IN_GUID
);
525 if ((V_BSTR(&var
) = SysAllocString(clsid
)))
526 hr
= IPropertyBag_Write(prop_bag
, L
"DSGuid", &var
);
529 IPropertyBag_Release(prop_bag
);
533 static void register_waveout_devices(void)
535 IPropertyBag
*prop_bag
= NULL
;
536 REGFILTERPINS2 rgpins
= {0};
537 REGPINTYPES rgtypes
= {0};
538 REGFILTER2 rgf
= {0};
545 count
= waveOutGetNumDevs();
547 for (i
= -1; i
< count
; i
++)
549 waveOutGetDevCapsW(i
, &caps
, sizeof(caps
));
551 name
= (i
== -1) ? L
"Default WaveOut Device" : caps
.szPname
;
553 hr
= register_codec(&CLSID_AudioRendererCategory
, name
,
554 &CLSID_AudioRender
, name
, &prop_bag
);
558 /* write filter data */
560 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
562 rgf
.u
.s2
.rgPins2
= &rgpins
;
563 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
564 rgpins
.nMediaTypes
= 1;
565 rgpins
.lpMediaType
= &rgtypes
;
566 rgtypes
.clsMajorType
= &MEDIATYPE_Audio
;
567 rgtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
569 write_filter_data(prop_bag
, &rgf
);
571 /* write WaveOutId */
574 IPropertyBag_Write(prop_bag
, L
"WaveOutId", &var
);
577 if (prop_bag
) IPropertyBag_Release(prop_bag
);
581 static void register_wavein_devices(void)
583 IPropertyBag
*prop_bag
= NULL
;
584 REGFILTER2 rgf
= {0};
590 count
= waveInGetNumDevs();
592 for (i
= 0; i
< count
; i
++)
594 waveInGetDevCapsW(i
, &caps
, sizeof(caps
));
596 hr
= register_codec(&CLSID_AudioInputDeviceCategory
, caps
.szPname
,
597 &CLSID_AudioRecord
, caps
.szPname
, &prop_bag
);
601 /* write filter data */
603 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
605 write_filter_data(prop_bag
, &rgf
);
610 IPropertyBag_Write(prop_bag
, L
"WaveInId", &var
);
613 IPropertyBag_Release(prop_bag
);
617 static void register_midiout_devices(void)
619 IPropertyBag
*prop_bag
= NULL
;
620 REGFILTERPINS2 rgpins
= {0};
621 REGPINTYPES rgtypes
= {0};
622 REGFILTER2 rgf
= {0};
629 count
= midiOutGetNumDevs();
631 for (i
= -1; i
< count
; i
++)
633 midiOutGetDevCapsW(i
, &caps
, sizeof(caps
));
635 name
= (i
== -1) ? L
"Default MidiOut Device" : caps
.szPname
;
637 hr
= register_codec(&CLSID_MidiRendererCategory
, name
,
638 &CLSID_AVIMIDIRender
, name
, &prop_bag
);
642 /* write filter data */
644 rgf
.dwMerit
= (i
== -1) ? MERIT_PREFERRED
: MERIT_DO_NOT_USE
;
646 rgf
.u
.s2
.rgPins2
= &rgpins
;
647 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
648 rgpins
.nMediaTypes
= 1;
649 rgpins
.lpMediaType
= &rgtypes
;
650 rgtypes
.clsMajorType
= &MEDIATYPE_Midi
;
651 rgtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
653 write_filter_data(prop_bag
, &rgf
);
655 /* write MidiOutId */
658 IPropertyBag_Write(prop_bag
, L
"MidiOutId", &var
);
661 IPropertyBag_Release(prop_bag
);
665 static void register_vfw_codecs(void)
667 REGFILTERPINS2 rgpins
[2] = {};
668 IPropertyBag
*prop_bag
= NULL
;
669 REGPINTYPES rgtypes
[2];
678 while (ICInfo(ICTYPE_VIDEO
, i
++, &info
))
680 WCHAR name
[5] = {LOBYTE(LOWORD(info
.fccHandler
)), HIBYTE(LOWORD(info
.fccHandler
)),
681 LOBYTE(HIWORD(info
.fccHandler
)), HIBYTE(HIWORD(info
.fccHandler
))};
683 hic
= ICOpen(ICTYPE_VIDEO
, info
.fccHandler
, ICMODE_QUERY
);
684 ICGetInfo(hic
, &info
, sizeof(info
));
687 hr
= register_codec(&CLSID_VideoCompressorCategory
, name
,
688 &CLSID_AVICo
, info
.szDescription
, &prop_bag
);
692 /* write filter data */
694 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
696 rgf
.u
.s2
.rgPins2
= rgpins
;
697 rgpins
[0].dwFlags
= 0;
698 rgpins
[0].nMediaTypes
= 1;
699 rgpins
[0].lpMediaType
= &rgtypes
[0];
700 rgtypes
[0].clsMajorType
= &MEDIATYPE_Video
;
701 typeguid
= MEDIASUBTYPE_PCM
;
702 typeguid
.Data1
= info
.fccHandler
;
703 rgtypes
[0].clsMinorType
= &typeguid
;
704 rgpins
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
705 rgpins
[1].nMediaTypes
= 1;
706 rgpins
[1].lpMediaType
= &rgtypes
[1];
707 rgtypes
[1].clsMajorType
= &MEDIATYPE_Video
;
708 rgtypes
[1].clsMinorType
= &GUID_NULL
;
710 write_filter_data(prop_bag
, &rgf
);
713 V_VT(&var
) = VT_BSTR
;
714 V_BSTR(&var
) = SysAllocString(name
);
715 IPropertyBag_Write(prop_bag
, L
"FccHandler", &var
);
718 IPropertyBag_Release(prop_bag
);
722 static void register_avicap_devices(void)
724 WCHAR friendlyname
[32], version
[32];
725 IPropertyBag
*prop_bag
= NULL
;
726 REGFILTERPINS2 rgpins
= {0};
734 for (i
= 0; i
< 10; ++i
)
736 if (!capGetDriverDescriptionW(i
, friendlyname
, ARRAY_SIZE(friendlyname
),
737 version
, ARRAY_SIZE(version
)))
740 swprintf(name
, ARRAY_SIZE(name
), L
"video%d", i
);
742 hr
= register_codec(&CLSID_VideoInputDeviceCategory
, name
,
743 &CLSID_VfwCapture
, friendlyname
, &prop_bag
);
748 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
750 rgf
.u
.s2
.rgPins2
= &rgpins
;
752 rgpins
.nMediaTypes
= 1;
753 rgpins
.lpMediaType
= &rgtypes
;
754 rgtypes
.clsMajorType
= &MEDIATYPE_Video
;
755 rgtypes
.clsMinorType
= &MEDIASUBTYPE_None
;
757 write_filter_data(prop_bag
, &rgf
);
762 IPropertyBag_Write(prop_bag
, L
"VFWIndex", &var
);
765 IPropertyBag_Release(prop_bag
);
769 static HRESULT WINAPI
devenum_factory_CreateClassEnumerator(ICreateDevEnum
*iface
,
770 REFCLSID
class, IEnumMoniker
**out
, DWORD flags
)
772 WCHAR guidstr
[CHARS_IN_GUID
];
776 TRACE("iface %p, class %s, out %p, flags %#x.\n", iface
, debugstr_guid(class), out
, flags
);
783 if (!RegOpenKeyW(HKEY_CURRENT_USER
, L
"Software\\Microsoft\\ActiveMovie\\devenum", &key
))
785 StringFromGUID2(class, guidstr
, ARRAY_SIZE(guidstr
));
786 RegDeleteTreeW(key
, guidstr
);
789 if (IsEqualGUID(class, &CLSID_LegacyAmFilterCategory
))
790 register_legacy_filters();
791 else if (IsEqualGUID(class, &CLSID_AudioRendererCategory
))
793 hr
= DirectSoundEnumerateW(®ister_dsound_devices
, NULL
);
794 if (FAILED(hr
)) return hr
;
795 register_waveout_devices();
796 register_midiout_devices();
798 else if (IsEqualGUID(class, &CLSID_AudioInputDeviceCategory
))
799 register_wavein_devices();
800 else if (IsEqualGUID(class, &CLSID_VideoCompressorCategory
))
801 register_vfw_codecs();
802 else if (IsEqualGUID(class, &CLSID_VideoInputDeviceCategory
))
803 register_avicap_devices();
805 if (SUCCEEDED(hr
= enum_moniker_create(class, out
)))
808 hr
= IEnumMoniker_Next(*out
, 1, &mon
, NULL
);
811 IMoniker_Release(mon
);
812 IEnumMoniker_Reset(*out
);
816 IEnumMoniker_Release(*out
);
824 /**********************************************************************
825 * ICreateDevEnum_Vtbl
827 static const ICreateDevEnumVtbl ICreateDevEnum_Vtbl
=
829 devenum_factory_QueryInterface
,
830 devenum_factory_AddRef
,
831 devenum_factory_Release
,
832 devenum_factory_CreateClassEnumerator
,
835 /**********************************************************************
836 * static CreateDevEnum instance
838 ICreateDevEnum devenum_factory
= { &ICreateDevEnum_Vtbl
};