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/unicode.h"
36 #include "wine/heap.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
,
64 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
69 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
70 IsEqualGUID(riid
, &IID_ICreateDevEnum
))
73 DEVENUM_ICreateDevEnum_AddRef(iface
);
77 FIXME("- no interface IID: %s\n", debugstr_guid(riid
));
82 /**********************************************************************
83 * DEVENUM_ICreateDevEnum_AddRef (also IUnknown)
85 static ULONG WINAPI
DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum
* iface
)
91 return 2; /* non-heap based object */
94 /**********************************************************************
95 * DEVENUM_ICreateDevEnum_Release (also IUnknown)
97 static ULONG WINAPI
DEVENUM_ICreateDevEnum_Release(ICreateDevEnum
* iface
)
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
;
119 hr
= CoCreateInstance(&CLSID_CDeviceMoniker
, NULL
, CLSCTX_INPROC
, &IID_IParseDisplayName
, (void **)&parser
);
123 buffer
= heap_alloc((strlenW(deviceW
) + CHARS_IN_GUID
+ strlenW(name
) + 1) * sizeof(WCHAR
));
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
);
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
);
148 IPropertyBag_Release(propbag
);
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
);
159 IPropertyBag_Release(propbag
);
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
)
177 if (RegQueryInfoKeyW(hkeyTypes
, NULL
, NULL
, NULL
, &dwMajorTypes
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
180 RegCloseKey(hkeyTypes
);
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
)
198 RegCloseKey(hkeyMajorType
);
202 for (i1
= 0; i1
< dwMinorTypes
; i1
++)
204 WCHAR wszMinorTypeName
[64];
205 CLSID
*clsMajorType
= NULL
, *clsMinorType
= NULL
;
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
++;
242 CoTaskMemFree(clsMajorType
);
243 CoTaskMemFree(clsMinorType
);
246 RegCloseKey(hkeyMajorType
);
249 RegCloseKey(hkeyTypes
);
251 if (lpMediaType
&& !rgPin
->nMediaTypes
)
253 CoTaskMemFree(lpMediaType
);
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
;
267 rgf2
->u
.s2
.cPins2
= 0;
268 rgf2
->u
.s2
.rgPins2
= NULL
;
270 if (RegOpenKeyExW(hkeyFilterClass
, wszPins
, 0, KEY_READ
, &hkeyPins
) != ERROR_SUCCESS
)
273 if (RegQueryInfoKeyW(hkeyPins
, NULL
, NULL
, NULL
, &dwPinsSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
276 RegCloseKey(hkeyPins
);
282 rgPins
= CoTaskMemAlloc(sizeof(REGFILTERPINS2
) * dwPinsSubkeys
);
285 RegCloseKey(hkeyPins
);
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
;
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
)
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
)
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
)
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
)
332 rgPin
->dwFlags
|= REG_PINFLAG_B_RENDERER
;
334 DEVENUM_ReadPinTypes(hkeyPinKey
, rgPin
);
341 RegCloseKey(hkeyPinKey
);
344 RegCloseKey(hkeyPins
);
346 if (rgPins
&& !rgf2
->u
.s2
.cPins2
)
348 CoTaskMemFree(rgPins
);
352 rgf2
->u
.s2
.rgPins2
= rgPins
;
355 static void free_regfilter2(REGFILTER2
*rgf
)
357 if (rgf
->u
.s2
.rgPins2
)
361 for (iPin
= 0; iPin
< rgf
->u
.s2
.cPins2
; iPin
++)
363 if (rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
)
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
;
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
;
398 sabound
.cElements
= size
;
399 if (!(V_ARRAY(&var
) = SafeArrayCreate(VT_UI1
, 1, &sabound
)))
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
;
414 IAMFilterData_Release(fildata
);
417 static void register_legacy_filters(void)
419 HKEY hkeyFilter
= NULL
;
420 DWORD dwFilterSubkeys
, i
;
424 lRet
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszFilterKeyName
, 0, KEY_READ
, &hkeyFilter
);
425 hr
= HRESULT_FROM_WIN32(lRet
);
429 lRet
= RegQueryInfoKeyW(hkeyFilter
, NULL
, NULL
, NULL
, &dwFilterSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
430 hr
= HRESULT_FROM_WIN32(lRet
);
434 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_LegacyAmFilterCategory
);
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
;
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
);
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
)
465 if (!RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, NULL
, &len
))
467 WCHAR
*friendlyname
= heap_alloc(len
);
470 RegCloseKey(classkey
);
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
);
481 hr
= register_codec(&CLSID_LegacyAmFilterCategory
, wszFilterSubkeyName
,
482 &clsid
, wszFilterSubkeyName
, &prop_bag
);
485 RegCloseKey(classkey
);
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
];
521 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory
);
527 WCHAR
*name
= heap_alloc(sizeof(defaultW
) + strlenW(desc
) * sizeof(WCHAR
));
530 strcpyW(name
, directsoundW
);
533 hr
= register_codec(&CLSID_AudioRendererCategory
, name
,
534 &CLSID_DSoundRender
, name
, &prop_bag
);
538 hr
= register_codec(&CLSID_AudioRendererCategory
, defaultW
,
539 &CLSID_DSoundRender
, defaultW
, &prop_bag
);
543 /* write filter data */
545 rgf
.dwMerit
= guid
? MERIT_DO_NOT_USE
: MERIT_PREFERRED
;
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
);
564 IPropertyBag_Release(prop_bag
);
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};
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
);
598 /* write filter data */
600 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
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 */
614 IPropertyBag_Write(prop_bag
, waveoutidW
, &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};
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
);
645 /* write filter data */
647 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
649 write_filter_data(prop_bag
, &rgf
);
654 IPropertyBag_Write(prop_bag
, waveinidW
, &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};
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
);
691 /* write filter data */
693 rgf
.dwMerit
= (i
== -1) ? MERIT_PREFERRED
: MERIT_DO_NOT_USE
;
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 */
707 IPropertyBag_Write(prop_bag
, midioutidW
, &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];
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
));
740 hr
= register_codec(&CLSID_VideoCompressorCategory
, name
,
741 &CLSID_AVICo
, info
.szDescription
, &prop_bag
);
745 /* write filter data */
747 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
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
);
766 V_VT(&var
) = VT_BSTR
;
767 V_BSTR(&var
) = SysAllocString(name
);
768 IPropertyBag_Write(prop_bag
, fcchandlerW
, &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};
788 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory
);
792 for (i
= 0; i
< 10; ++i
)
794 if (!capGetDriverDescriptionW(i
, name
, ARRAY_SIZE(name
), version
, ARRAY_SIZE(version
)))
797 friendlyname
[5] = '0' + i
;
799 hr
= register_codec(&CLSID_VideoInputDeviceCategory
, name
,
800 &CLSID_VfwCapture
, friendlyname
, &prop_bag
);
805 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
807 rgf
.u
.s2
.rgPins2
= &rgpins
;
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
);
819 IPropertyBag_Write(prop_bag
, vfwindexW
, &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
];
836 TRACE("iface %p, class %s, out %p, flags %#x.\n", iface
, debugstr_guid(class), out
, flags
);
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(®ister_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
)))
868 hr
= IEnumMoniker_Next(*out
, 1, &mon
, NULL
);
871 IMoniker_Release(mon
);
872 IEnumMoniker_Reset(*out
);
876 IEnumMoniker_Release(*out
);
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
];
910 HKEY hkeyDummy
= NULL
;
912 strcpyW(wszRegKey
, wszActiveMovieKey
);
914 if (!StringFromGUID2(clsidCategory
, wszRegKey
+ strlenW(wszRegKey
), ARRAY_SIZE(wszRegKey
) - strlenW(wszRegKey
)))
919 LONG lRes
= RegCreateKeyW(HKEY_CURRENT_USER
, wszRegKey
, &hkeyDummy
);
920 res
= HRESULT_FROM_WIN32(lRes
);
924 RegCloseKey(hkeyDummy
);
927 ERR("Failed to create key HKEY_CURRENT_USER\\%s\n", debugstr_w(wszRegKey
));