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"
42 WINE_DEFAULT_DEBUG_CHANNEL(devenum
);
44 extern HINSTANCE DEVENUM_hInstance
;
46 static const WCHAR wszFilterKeyName
[] = {'F','i','l','t','e','r',0};
47 static const WCHAR wszMeritName
[] = {'M','e','r','i','t',0};
48 static const WCHAR wszPins
[] = {'P','i','n','s',0};
49 static const WCHAR wszAllowedMany
[] = {'A','l','l','o','w','e','d','M','a','n','y',0};
50 static const WCHAR wszAllowedZero
[] = {'A','l','l','o','w','e','d','Z','e','r','o',0};
51 static const WCHAR wszDirection
[] = {'D','i','r','e','c','t','i','o','n',0};
52 static const WCHAR wszIsRendered
[] = {'I','s','R','e','n','d','e','r','e','d',0};
53 static const WCHAR wszTypes
[] = {'T','y','p','e','s',0};
54 static const WCHAR wszFriendlyName
[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
55 static const WCHAR wszFilterData
[] = {'F','i','l','t','e','r','D','a','t','a',0};
57 static ULONG WINAPI
DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum
* iface
);
58 static HRESULT
register_codecs(void);
59 static HRESULT
DEVENUM_CreateAMCategoryKey(const CLSID
* clsidCategory
);
61 /**********************************************************************
62 * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown)
64 static HRESULT WINAPI
DEVENUM_ICreateDevEnum_QueryInterface(ICreateDevEnum
*iface
, REFIID riid
,
67 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), ppv
);
72 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
73 IsEqualGUID(riid
, &IID_ICreateDevEnum
))
76 DEVENUM_ICreateDevEnum_AddRef(iface
);
80 FIXME("- no interface IID: %s\n", debugstr_guid(riid
));
85 /**********************************************************************
86 * DEVENUM_ICreateDevEnum_AddRef (also IUnknown)
88 static ULONG WINAPI
DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum
* iface
)
94 return 2; /* non-heap based object */
97 /**********************************************************************
98 * DEVENUM_ICreateDevEnum_Release (also IUnknown)
100 static ULONG WINAPI
DEVENUM_ICreateDevEnum_Release(ICreateDevEnum
* iface
)
104 DEVENUM_UnlockModule();
106 return 1; /* non-heap based object */
109 static HRESULT
register_codec(const CLSID
*class, const WCHAR
*name
, IMoniker
**ret
)
111 static const WCHAR deviceW
[] = {'@','d','e','v','i','c','e',':','c','m',':',0};
112 IParseDisplayName
*parser
;
117 hr
= CoCreateInstance(&CLSID_CDeviceMoniker
, NULL
, CLSCTX_INPROC
, &IID_IParseDisplayName
, (void **)&parser
);
121 buffer
= heap_alloc((strlenW(deviceW
) + CHARS_IN_GUID
+ strlenW(name
) + 1) * sizeof(WCHAR
));
124 IParseDisplayName_Release(parser
);
125 return E_OUTOFMEMORY
;
128 strcpyW(buffer
, deviceW
);
129 StringFromGUID2(class, buffer
+ strlenW(buffer
), CHARS_IN_GUID
);
130 strcatW(buffer
, backslashW
);
131 strcatW(buffer
, name
);
133 hr
= IParseDisplayName_ParseDisplayName(parser
, NULL
, buffer
, &eaten
, ret
);
134 IParseDisplayName_Release(parser
);
139 static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey
, REGFILTERPINS2
*rgPin
)
141 HKEY hkeyTypes
= NULL
;
142 DWORD dwMajorTypes
, i
;
143 REGPINTYPES
*lpMediaType
= NULL
;
144 DWORD dwMediaTypeSize
= 0;
146 if (RegOpenKeyExW(hkeyPinKey
, wszTypes
, 0, KEY_READ
, &hkeyTypes
) != ERROR_SUCCESS
)
149 if (RegQueryInfoKeyW(hkeyTypes
, NULL
, NULL
, NULL
, &dwMajorTypes
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
152 RegCloseKey(hkeyTypes
);
156 for (i
= 0; i
< dwMajorTypes
; i
++)
158 HKEY hkeyMajorType
= NULL
;
159 WCHAR wszMajorTypeName
[64];
160 DWORD cName
= sizeof(wszMajorTypeName
) / sizeof(WCHAR
);
161 DWORD dwMinorTypes
, i1
;
163 if (RegEnumKeyExW(hkeyTypes
, i
, wszMajorTypeName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
165 if (RegOpenKeyExW(hkeyTypes
, wszMajorTypeName
, 0, KEY_READ
, &hkeyMajorType
) != ERROR_SUCCESS
) continue;
167 if (RegQueryInfoKeyW(hkeyMajorType
, NULL
, NULL
, NULL
, &dwMinorTypes
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
170 RegCloseKey(hkeyMajorType
);
174 for (i1
= 0; i1
< dwMinorTypes
; i1
++)
176 WCHAR wszMinorTypeName
[64];
177 CLSID
*clsMajorType
= NULL
, *clsMinorType
= NULL
;
180 cName
= sizeof(wszMinorTypeName
) / sizeof(WCHAR
);
181 if (RegEnumKeyExW(hkeyMajorType
, i1
, wszMinorTypeName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
183 clsMinorType
= CoTaskMemAlloc(sizeof(CLSID
));
184 if (!clsMinorType
) continue;
186 clsMajorType
= CoTaskMemAlloc(sizeof(CLSID
));
187 if (!clsMajorType
) goto error_cleanup_types
;
189 hr
= CLSIDFromString(wszMinorTypeName
, clsMinorType
);
190 if (FAILED(hr
)) goto error_cleanup_types
;
192 hr
= CLSIDFromString(wszMajorTypeName
, clsMajorType
);
193 if (FAILED(hr
)) goto error_cleanup_types
;
195 if (rgPin
->nMediaTypes
== dwMediaTypeSize
)
197 DWORD dwNewSize
= dwMediaTypeSize
+ (dwMediaTypeSize
< 2 ? 1 : dwMediaTypeSize
/ 2);
198 REGPINTYPES
*lpNewMediaType
;
200 lpNewMediaType
= CoTaskMemRealloc(lpMediaType
, sizeof(REGPINTYPES
) * dwNewSize
);
201 if (!lpNewMediaType
) goto error_cleanup_types
;
203 lpMediaType
= lpNewMediaType
;
204 dwMediaTypeSize
= dwNewSize
;
207 lpMediaType
[rgPin
->nMediaTypes
].clsMajorType
= clsMajorType
;
208 lpMediaType
[rgPin
->nMediaTypes
].clsMinorType
= clsMinorType
;
209 rgPin
->nMediaTypes
++;
214 CoTaskMemFree(clsMajorType
);
215 CoTaskMemFree(clsMinorType
);
218 RegCloseKey(hkeyMajorType
);
221 RegCloseKey(hkeyTypes
);
223 if (lpMediaType
&& !rgPin
->nMediaTypes
)
225 CoTaskMemFree(lpMediaType
);
229 rgPin
->lpMediaType
= lpMediaType
;
232 static void DEVENUM_ReadPins(HKEY hkeyFilterClass
, REGFILTER2
*rgf2
)
234 HKEY hkeyPins
= NULL
;
235 DWORD dwPinsSubkeys
, i
;
236 REGFILTERPINS2
*rgPins
= NULL
;
239 rgf2
->u
.s2
.cPins2
= 0;
240 rgf2
->u
.s2
.rgPins2
= NULL
;
242 if (RegOpenKeyExW(hkeyFilterClass
, wszPins
, 0, KEY_READ
, &hkeyPins
) != ERROR_SUCCESS
)
245 if (RegQueryInfoKeyW(hkeyPins
, NULL
, NULL
, NULL
, &dwPinsSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
)
248 RegCloseKey(hkeyPins
);
254 rgPins
= CoTaskMemAlloc(sizeof(REGFILTERPINS2
) * dwPinsSubkeys
);
257 RegCloseKey(hkeyPins
);
262 for (i
= 0; i
< dwPinsSubkeys
; i
++)
264 HKEY hkeyPinKey
= NULL
;
265 WCHAR wszPinName
[MAX_PATH
];
266 DWORD cName
= sizeof(wszPinName
) / sizeof(WCHAR
);
267 REGFILTERPINS2
*rgPin
= &rgPins
[rgf2
->u
.s2
.cPins2
];
268 DWORD value
, size
, Type
;
271 memset(rgPin
, 0, sizeof(*rgPin
));
273 if (RegEnumKeyExW(hkeyPins
, i
, wszPinName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
275 if (RegOpenKeyExW(hkeyPins
, wszPinName
, 0, KEY_READ
, &hkeyPinKey
) != ERROR_SUCCESS
) continue;
277 size
= sizeof(DWORD
);
278 lRet
= RegQueryValueExW(hkeyPinKey
, wszAllowedMany
, NULL
, &Type
, (BYTE
*)&value
, &size
);
279 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
282 rgPin
->dwFlags
|= REG_PINFLAG_B_MANY
;
284 size
= sizeof(DWORD
);
285 lRet
= RegQueryValueExW(hkeyPinKey
, wszAllowedZero
, NULL
, &Type
, (BYTE
*)&value
, &size
);
286 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
289 rgPin
->dwFlags
|= REG_PINFLAG_B_ZERO
;
291 size
= sizeof(DWORD
);
292 lRet
= RegQueryValueExW(hkeyPinKey
, wszDirection
, NULL
, &Type
, (BYTE
*)&value
, &size
);
293 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
296 rgPin
->dwFlags
|= REG_PINFLAG_B_OUTPUT
;
299 size
= sizeof(DWORD
);
300 lRet
= RegQueryValueExW(hkeyPinKey
, wszIsRendered
, NULL
, &Type
, (BYTE
*)&value
, &size
);
301 if (lRet
!= ERROR_SUCCESS
|| Type
!= REG_DWORD
)
304 rgPin
->dwFlags
|= REG_PINFLAG_B_RENDERER
;
306 DEVENUM_ReadPinTypes(hkeyPinKey
, rgPin
);
313 RegCloseKey(hkeyPinKey
);
316 RegCloseKey(hkeyPins
);
318 if (rgPins
&& !rgf2
->u
.s2
.cPins2
)
320 CoTaskMemFree(rgPins
);
324 rgf2
->u
.s2
.rgPins2
= rgPins
;
327 static void free_regfilter2(REGFILTER2
*rgf
)
329 if (rgf
->u
.s2
.rgPins2
)
333 for (iPin
= 0; iPin
< rgf
->u
.s2
.cPins2
; iPin
++)
335 if (rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
)
339 for (iType
= 0; iType
< rgf
->u
.s2
.rgPins2
[iPin
].nMediaTypes
; iType
++)
341 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
[iType
].clsMajorType
);
342 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
[iType
].clsMinorType
);
345 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
[iPin
].lpMediaType
);
349 CoTaskMemFree((void *)rgf
->u
.s2
.rgPins2
);
353 static void write_filter_data(IPropertyBag
*prop_bag
, REGFILTER2
*rgf
)
355 IAMFilterData
*fildata
;
356 SAFEARRAYBOUND sabound
;
362 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC
, &IID_IAMFilterData
, (void **)&fildata
);
363 if (FAILED(hr
)) goto cleanup
;
365 hr
= IAMFilterData_CreateFilterData(fildata
, rgf
, &data
, &size
);
366 if (FAILED(hr
)) goto cleanup
;
368 V_VT(&var
) = VT_ARRAY
| VT_UI1
;
370 sabound
.cElements
= size
;
371 if (!(V_ARRAY(&var
) = SafeArrayCreate(VT_UI1
, 1, &sabound
)))
373 hr
= SafeArrayAccessData(V_ARRAY(&var
), (void *)&array
);
374 if (FAILED(hr
)) goto cleanup
;
376 memcpy(array
, data
, size
);
377 hr
= SafeArrayUnaccessData(V_ARRAY(&var
));
378 if (FAILED(hr
)) goto cleanup
;
380 hr
= IPropertyBag_Write(prop_bag
, wszFilterData
, &var
);
381 if (FAILED(hr
)) goto cleanup
;
386 IAMFilterData_Release(fildata
);
389 static void register_legacy_filters(void)
391 HKEY hkeyFilter
= NULL
;
392 DWORD dwFilterSubkeys
, i
;
396 lRet
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszFilterKeyName
, 0, KEY_READ
, &hkeyFilter
);
397 hr
= HRESULT_FROM_WIN32(lRet
);
401 lRet
= RegQueryInfoKeyW(hkeyFilter
, NULL
, NULL
, NULL
, &dwFilterSubkeys
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
402 hr
= HRESULT_FROM_WIN32(lRet
);
406 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_LegacyAmFilterCategory
);
410 for (i
= 0; i
< dwFilterSubkeys
; i
++)
412 WCHAR wszFilterSubkeyName
[64];
413 DWORD cName
= sizeof(wszFilterSubkeyName
) / sizeof(WCHAR
);
414 IPropertyBag
*prop_bag
= NULL
;
415 WCHAR wszRegKey
[MAX_PATH
];
416 HKEY classkey
= NULL
;
417 IMoniker
*mon
= NULL
;
422 if (RegEnumKeyExW(hkeyFilter
, i
, wszFilterSubkeyName
, &cName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) continue;
424 TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName
));
426 strcpyW(wszRegKey
, clsidW
);
427 strcatW(wszRegKey
, wszFilterSubkeyName
);
429 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszRegKey
, 0, KEY_READ
, &classkey
) != ERROR_SUCCESS
)
432 hr
= register_codec(&CLSID_LegacyAmFilterCategory
, wszFilterSubkeyName
, &mon
);
433 if (FAILED(hr
)) goto cleanup
;
435 hr
= IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
);
436 if (FAILED(hr
)) goto cleanup
;
438 /* write friendly name */
440 V_VT(&var
) = VT_BSTR
;
441 if (!RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, NULL
, &len
))
443 WCHAR
*friendlyname
= heap_alloc(len
);
446 RegQueryValueExW(classkey
, NULL
, NULL
, &Type
, (BYTE
*)friendlyname
, &len
);
447 V_BSTR(&var
) = SysAllocStringLen(friendlyname
, len
/sizeof(WCHAR
));
448 heap_free(friendlyname
);
451 V_BSTR(&var
) = SysAllocString(wszFilterSubkeyName
);
455 hr
= IPropertyBag_Write(prop_bag
, wszFriendlyName
, &var
);
456 if (FAILED(hr
)) goto cleanup
;
460 V_VT(&var
) = VT_BSTR
;
461 if (!(V_BSTR(&var
) = SysAllocString(wszFilterSubkeyName
)))
463 hr
= IPropertyBag_Write(prop_bag
, clsid_keyname
, &var
);
464 if (FAILED(hr
)) goto cleanup
;
467 /* write filter data */
468 rgf2
.dwMerit
= MERIT_NORMAL
;
470 len
= sizeof(rgf2
.dwMerit
);
471 RegQueryValueExW(classkey
, wszMeritName
, NULL
, &Type
, (BYTE
*)&rgf2
.dwMerit
, &len
);
473 DEVENUM_ReadPins(classkey
, &rgf2
);
475 write_filter_data(prop_bag
, &rgf2
);
478 if (prop_bag
) IPropertyBag_Release(prop_bag
);
479 if (mon
) IMoniker_Release(mon
);
480 RegCloseKey(classkey
);
482 free_regfilter2(&rgf2
);
486 if (hkeyFilter
) RegCloseKey(hkeyFilter
);
489 static BOOL CALLBACK
register_dsound_devices(GUID
*guid
, const WCHAR
*desc
, const WCHAR
*module
, void *context
)
491 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};
492 static const WCHAR directsoundW
[] = {'D','i','r','e','c','t','S','o','u','n','d',':',' ',0};
493 static const WCHAR dsguidW
[] = {'D','S','G','u','i','d',0};
494 IPropertyBag
*prop_bag
= NULL
;
495 REGFILTERPINS2 rgpins
= {0};
496 REGPINTYPES rgtypes
= {0};
497 REGFILTER2 rgf
= {0};
498 WCHAR clsid
[CHARS_IN_GUID
];
499 IMoniker
*mon
= NULL
;
503 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory
);
504 if (FAILED(hr
)) goto cleanup
;
506 V_VT(&var
) = VT_BSTR
;
509 WCHAR
*name
= heap_alloc(sizeof(defaultW
) + strlenW(desc
) * sizeof(WCHAR
));
512 strcpyW(name
, directsoundW
);
515 V_BSTR(&var
) = SysAllocString(name
);
519 V_BSTR(&var
) = SysAllocString(defaultW
);
524 hr
= register_codec(&CLSID_AudioRendererCategory
, V_BSTR(&var
), &mon
);
525 if (FAILED(hr
)) goto cleanup
;
527 hr
= IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
);
528 if (FAILED(hr
)) goto cleanup
;
530 /* write friendly name */
531 hr
= IPropertyBag_Write(prop_bag
, wszFriendlyName
, &var
);
532 if (FAILED(hr
)) goto cleanup
;
536 V_VT(&var
) = VT_BSTR
;
537 StringFromGUID2(&CLSID_DSoundRender
, clsid
, CHARS_IN_GUID
);
538 if (!(V_BSTR(&var
) = SysAllocString(clsid
)))
540 hr
= IPropertyBag_Write(prop_bag
, clsid_keyname
, &var
);
541 if (FAILED(hr
)) goto cleanup
;
544 /* write filter data */
546 rgf
.dwMerit
= guid
? MERIT_DO_NOT_USE
: MERIT_PREFERRED
;
548 rgf
.u
.s2
.rgPins2
= &rgpins
;
549 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
550 /* FIXME: native registers many more formats */
551 rgpins
.nMediaTypes
= 1;
552 rgpins
.lpMediaType
= &rgtypes
;
553 rgtypes
.clsMajorType
= &MEDIATYPE_Audio
;
554 rgtypes
.clsMinorType
= &MEDIASUBTYPE_PCM
;
556 write_filter_data(prop_bag
, &rgf
);
558 /* write DSound guid */
559 V_VT(&var
) = VT_BSTR
;
560 StringFromGUID2(guid
? guid
: &GUID_NULL
, clsid
, CHARS_IN_GUID
);
561 if (!(V_BSTR(&var
) = SysAllocString(clsid
)))
563 hr
= IPropertyBag_Write(prop_bag
, dsguidW
, &var
);
564 if (FAILED(hr
)) goto cleanup
;
568 if (prop_bag
) IPropertyBag_Release(prop_bag
);
569 if (mon
) IMoniker_Release(mon
);
574 static void register_waveout_devices(void)
576 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};
577 static const WCHAR waveoutidW
[] = {'W','a','v','e','O','u','t','I','d',0};
578 IPropertyBag
*prop_bag
= NULL
;
579 REGFILTERPINS2 rgpins
= {0};
580 REGPINTYPES rgtypes
= {0};
581 REGFILTER2 rgf
= {0};
582 WCHAR clsid
[CHARS_IN_GUID
];
583 IMoniker
*mon
= NULL
;
589 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory
);
590 if (FAILED(hr
)) return;
592 count
= waveOutGetNumDevs();
594 for (i
= -1; i
< count
; i
++)
596 waveOutGetDevCapsW(i
, &caps
, sizeof(caps
));
598 V_VT(&var
) = VT_BSTR
;
600 if (i
== -1) /* WAVE_MAPPER */
601 V_BSTR(&var
) = SysAllocString(defaultW
);
603 V_BSTR(&var
) = SysAllocString(caps
.szPname
);
607 hr
= register_codec(&CLSID_AudioRendererCategory
, V_BSTR(&var
), &mon
);
608 if (FAILED(hr
)) goto cleanup
;
610 hr
= IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
);
611 if (FAILED(hr
)) goto cleanup
;
613 /* write friendly name */
614 hr
= IPropertyBag_Write(prop_bag
, wszFriendlyName
, &var
);
615 if (FAILED(hr
)) goto cleanup
;
619 V_VT(&var
) = VT_BSTR
;
620 StringFromGUID2(&CLSID_AudioRender
, clsid
, CHARS_IN_GUID
);
621 if (!(V_BSTR(&var
) = SysAllocString(clsid
)))
623 hr
= IPropertyBag_Write(prop_bag
, clsid_keyname
, &var
);
624 if (FAILED(hr
)) goto cleanup
;
627 /* write filter data */
629 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
631 rgf
.u
.s2
.rgPins2
= &rgpins
;
632 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
633 rgpins
.nMediaTypes
= 1;
634 rgpins
.lpMediaType
= &rgtypes
;
635 rgtypes
.clsMajorType
= &MEDIATYPE_Audio
;
636 rgtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
638 write_filter_data(prop_bag
, &rgf
);
640 /* write WaveOutId */
643 hr
= IPropertyBag_Write(prop_bag
, waveoutidW
, &var
);
644 if (FAILED(hr
)) goto cleanup
;
648 if (prop_bag
) IPropertyBag_Release(prop_bag
);
649 if (mon
) IMoniker_Release(mon
);
653 static void register_wavein_devices(void)
655 static const WCHAR waveinidW
[] = {'W','a','v','e','I','n','I','d',0};
656 IPropertyBag
*prop_bag
= NULL
;
657 REGFILTER2 rgf
= {0};
658 WCHAR clsid
[CHARS_IN_GUID
];
659 IMoniker
*mon
= NULL
;
665 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory
);
666 if (FAILED(hr
)) return;
668 count
= waveInGetNumDevs();
670 for (i
= 0; i
< count
; i
++)
672 waveInGetDevCapsW(i
, &caps
, sizeof(caps
));
674 V_VT(&var
) = VT_BSTR
;
676 V_BSTR(&var
) = SysAllocString(caps
.szPname
);
680 hr
= register_codec(&CLSID_AudioInputDeviceCategory
, V_BSTR(&var
), &mon
);
681 if (FAILED(hr
)) goto cleanup
;
683 hr
= IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
);
684 if (FAILED(hr
)) goto cleanup
;
686 /* write friendly name */
687 hr
= IPropertyBag_Write(prop_bag
, wszFriendlyName
, &var
);
688 if (FAILED(hr
)) goto cleanup
;
692 V_VT(&var
) = VT_BSTR
;
693 StringFromGUID2(&CLSID_AudioRecord
, clsid
, CHARS_IN_GUID
);
694 if (!(V_BSTR(&var
) = SysAllocString(clsid
)))
696 hr
= IPropertyBag_Write(prop_bag
, clsid_keyname
, &var
);
697 if (FAILED(hr
)) goto cleanup
;
700 /* write filter data */
702 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
704 write_filter_data(prop_bag
, &rgf
);
709 hr
= IPropertyBag_Write(prop_bag
, waveinidW
, &var
);
710 if (FAILED(hr
)) goto cleanup
;
714 if (prop_bag
) IPropertyBag_Release(prop_bag
);
715 if (mon
) IMoniker_Release(mon
);
719 static void register_midiout_devices(void)
721 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};
722 static const WCHAR midioutidW
[] = {'M','i','d','i','O','u','t','I','d',0};
723 IPropertyBag
*prop_bag
= NULL
;
724 REGFILTERPINS2 rgpins
= {0};
725 REGPINTYPES rgtypes
= {0};
726 REGFILTER2 rgf
= {0};
727 WCHAR clsid
[CHARS_IN_GUID
];
728 IMoniker
*mon
= NULL
;
734 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory
);
735 if (FAILED(hr
)) return;
737 count
= midiOutGetNumDevs();
739 for (i
= -1; i
< count
; i
++)
741 midiOutGetDevCapsW(i
, &caps
, sizeof(caps
));
743 V_VT(&var
) = VT_BSTR
;
745 if (i
== -1) /* MIDI_MAPPER */
746 V_BSTR(&var
) = SysAllocString(defaultW
);
748 V_BSTR(&var
) = SysAllocString(caps
.szPname
);
752 hr
= register_codec(&CLSID_MidiRendererCategory
, V_BSTR(&var
), &mon
);
753 if (FAILED(hr
)) goto cleanup
;
755 hr
= IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
);
756 if (FAILED(hr
)) goto cleanup
;
758 /* write friendly name */
759 hr
= IPropertyBag_Write(prop_bag
, wszFriendlyName
, &var
);
760 if (FAILED(hr
)) goto cleanup
;
764 V_VT(&var
) = VT_BSTR
;
765 StringFromGUID2(&CLSID_AVIMIDIRender
, clsid
, CHARS_IN_GUID
);
766 if (!(V_BSTR(&var
) = SysAllocString(clsid
)))
768 hr
= IPropertyBag_Write(prop_bag
, clsid_keyname
, &var
);
769 if (FAILED(hr
)) goto cleanup
;
772 /* write filter data */
774 rgf
.dwMerit
= (i
== -1) ? MERIT_PREFERRED
: MERIT_DO_NOT_USE
;
776 rgf
.u
.s2
.rgPins2
= &rgpins
;
777 rgpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
778 rgpins
.nMediaTypes
= 1;
779 rgpins
.lpMediaType
= &rgtypes
;
780 rgtypes
.clsMajorType
= &MEDIATYPE_Midi
;
781 rgtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
783 write_filter_data(prop_bag
, &rgf
);
785 /* write MidiOutId */
788 hr
= IPropertyBag_Write(prop_bag
, midioutidW
, &var
);
789 if (FAILED(hr
)) goto cleanup
;
793 if (prop_bag
) IPropertyBag_Release(prop_bag
);
794 if (mon
) IMoniker_Release(mon
);
798 static void register_vfw_codecs(void)
800 static const WCHAR fcchandlerW
[] = {'F','c','c','H','a','n','d','l','e','r',0};
801 REGFILTERPINS2 rgpins
[2] = {};
802 IPropertyBag
*prop_bag
= NULL
;
803 REGPINTYPES rgtypes
[2];
805 WCHAR clsid
[CHARS_IN_GUID
];
806 IMoniker
*mon
= NULL
;
814 hr
= DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory
);
815 if (FAILED(hr
)) return;
817 while (ICInfo(ICTYPE_VIDEO
, i
++, &info
))
819 WCHAR name
[5] = {LOBYTE(LOWORD(info
.fccHandler
)), HIBYTE(LOWORD(info
.fccHandler
)),
820 LOBYTE(HIWORD(info
.fccHandler
)), HIBYTE(HIWORD(info
.fccHandler
))};
822 hic
= ICOpen(ICTYPE_VIDEO
, info
.fccHandler
, ICMODE_QUERY
);
823 ICGetInfo(hic
, &info
, sizeof(info
));
826 V_VT(&var
) = VT_BSTR
;
828 V_BSTR(&var
) = SysAllocString(name
);
832 hr
= register_codec(&CLSID_VideoCompressorCategory
, V_BSTR(&var
), &mon
);
833 if (FAILED(hr
)) goto cleanup
;
835 hr
= IMoniker_BindToStorage(mon
, NULL
, NULL
, &IID_IPropertyBag
, (void **)&prop_bag
);
836 if (FAILED(hr
)) goto cleanup
;
839 hr
= IPropertyBag_Write(prop_bag
, fcchandlerW
, &var
);
840 if (FAILED(hr
)) goto cleanup
;
843 /* write friendly name */
844 V_VT(&var
) = VT_BSTR
;
845 if (!(V_BSTR(&var
) = SysAllocString(info
.szDescription
)))
848 hr
= IPropertyBag_Write(prop_bag
, wszFriendlyName
, &var
);
849 if (FAILED(hr
)) goto cleanup
;
853 V_VT(&var
) = VT_BSTR
;
854 StringFromGUID2(&CLSID_AVICo
, clsid
, CHARS_IN_GUID
);
855 if (!(V_BSTR(&var
) = SysAllocString(clsid
)))
857 hr
= IPropertyBag_Write(prop_bag
, clsid_keyname
, &var
);
858 if (FAILED(hr
)) goto cleanup
;
861 /* write filter data */
863 rgf
.dwMerit
= MERIT_DO_NOT_USE
;
865 rgf
.u
.s2
.rgPins2
= rgpins
;
866 rgpins
[0].dwFlags
= 0;
867 rgpins
[0].nMediaTypes
= 1;
868 rgpins
[0].lpMediaType
= &rgtypes
[0];
869 rgtypes
[0].clsMajorType
= &MEDIATYPE_Video
;
870 typeguid
= MEDIASUBTYPE_PCM
;
871 typeguid
.Data1
= info
.fccHandler
;
872 rgtypes
[0].clsMinorType
= &typeguid
;
873 rgpins
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
874 rgpins
[1].nMediaTypes
= 1;
875 rgpins
[1].lpMediaType
= &rgtypes
[1];
876 rgtypes
[1].clsMajorType
= &MEDIATYPE_Video
;
877 rgtypes
[1].clsMinorType
= &GUID_NULL
;
879 write_filter_data(prop_bag
, &rgf
);
883 if (prop_bag
) IPropertyBag_Release(prop_bag
);
884 if (mon
) IMoniker_Release(mon
);
888 /**********************************************************************
889 * DEVENUM_ICreateDevEnum_CreateClassEnumerator
891 static HRESULT WINAPI
DEVENUM_ICreateDevEnum_CreateClassEnumerator(
892 ICreateDevEnum
* iface
,
893 REFCLSID clsidDeviceClass
,
894 IEnumMoniker
**ppEnumMoniker
,
899 TRACE("(%p)->(%s, %p, %x)\n", iface
, debugstr_guid(clsidDeviceClass
), ppEnumMoniker
, dwFlags
);
904 *ppEnumMoniker
= NULL
;
907 register_legacy_filters();
908 hr
= DirectSoundEnumerateW(®ister_dsound_devices
, NULL
);
909 if (FAILED(hr
)) return hr
;
910 register_waveout_devices();
911 register_wavein_devices();
912 register_midiout_devices();
913 register_vfw_codecs();
915 return create_EnumMoniker(clsidDeviceClass
, ppEnumMoniker
);
918 /**********************************************************************
919 * ICreateDevEnum_Vtbl
921 static const ICreateDevEnumVtbl ICreateDevEnum_Vtbl
=
923 DEVENUM_ICreateDevEnum_QueryInterface
,
924 DEVENUM_ICreateDevEnum_AddRef
,
925 DEVENUM_ICreateDevEnum_Release
,
926 DEVENUM_ICreateDevEnum_CreateClassEnumerator
,
929 /**********************************************************************
930 * static CreateDevEnum instance
932 ICreateDevEnum DEVENUM_CreateDevEnum
= { &ICreateDevEnum_Vtbl
};
934 /**********************************************************************
935 * DEVENUM_CreateAMCategoryKey (INTERNAL)
937 * Creates a registry key for a category at HKEY_CURRENT_USER\Software\
938 * Microsoft\ActiveMovie\devenum\{clsid}
940 static HRESULT
DEVENUM_CreateAMCategoryKey(const CLSID
* clsidCategory
)
942 WCHAR wszRegKey
[MAX_PATH
];
944 HKEY hkeyDummy
= NULL
;
946 strcpyW(wszRegKey
, wszActiveMovieKey
);
948 if (!StringFromGUID2(clsidCategory
, wszRegKey
+ strlenW(wszRegKey
), sizeof(wszRegKey
)/sizeof(wszRegKey
[0]) - strlenW(wszRegKey
)))
953 LONG lRes
= RegCreateKeyW(HKEY_CURRENT_USER
, wszRegKey
, &hkeyDummy
);
954 res
= HRESULT_FROM_WIN32(lRes
);
958 RegCloseKey(hkeyDummy
);
961 ERR("Failed to create key HKEY_CURRENT_USER\\%s\n", debugstr_w(wszRegKey
));
966 static HRESULT
register_codecs(void)
969 WCHAR
class[CHARS_IN_GUID
];
970 DWORD iDefaultDevice
= -1;
971 IFilterMapper2
* pMapper
= NULL
;
976 /* Since devices can change between session, for example because you just plugged in a webcam
977 * or switched from pulseaudio to alsa, delete all old devices first
979 RegOpenKeyW(HKEY_CURRENT_USER
, wszActiveMovieKey
, &basekey
);
980 StringFromGUID2(&CLSID_LegacyAmFilterCategory
, class, CHARS_IN_GUID
);
981 RegDeleteTreeW(basekey
, class);
982 StringFromGUID2(&CLSID_AudioRendererCategory
, class, CHARS_IN_GUID
);
983 RegDeleteTreeW(basekey
, class);
984 StringFromGUID2(&CLSID_AudioInputDeviceCategory
, class, CHARS_IN_GUID
);
985 RegDeleteTreeW(basekey
, class);
986 StringFromGUID2(&CLSID_VideoInputDeviceCategory
, class, CHARS_IN_GUID
);
987 RegDeleteTreeW(basekey
, class);
988 StringFromGUID2(&CLSID_MidiRendererCategory
, class, CHARS_IN_GUID
);
989 RegDeleteTreeW(basekey
, class);
990 StringFromGUID2(&CLSID_VideoCompressorCategory
, class, CHARS_IN_GUID
);
991 RegDeleteTreeW(basekey
, class);
992 RegCloseKey(basekey
);
995 rf2
.dwMerit
= MERIT_PREFERRED
;
997 rf2
.u
.s2
.rgPins2
= &rfp2
;
1000 rfp2
.lpMedium
= NULL
;
1001 rfp2
.clsPinCategory
= &IID_NULL
;
1003 res
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC
,
1004 &IID_IFilterMapper2
, (void **) &pMapper
);
1006 * Fill in info for devices
1011 REGPINTYPES
* pTypes
;
1012 IPropertyBag
* pPropBag
= NULL
;
1014 res
= DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory
);
1016 for (i
= 0; i
< 10; i
++)
1018 WCHAR szDeviceName
[32], szDeviceVersion
[32], szDevicePath
[10];
1020 if (capGetDriverDescriptionW ((WORD
) i
,
1021 szDeviceName
, sizeof(szDeviceName
)/sizeof(WCHAR
),
1022 szDeviceVersion
, sizeof(szDeviceVersion
)/sizeof(WCHAR
)))
1024 IMoniker
* pMoniker
= NULL
;
1025 WCHAR dprintf
[] = { 'v','i','d','e','o','%','d',0 };
1026 snprintfW(szDevicePath
, sizeof(szDevicePath
)/sizeof(WCHAR
), dprintf
, i
);
1027 /* The above code prevents 1 device with a different ID overwriting another */
1029 rfp2
.nMediaTypes
= 1;
1030 pTypes
= CoTaskMemAlloc(rfp2
.nMediaTypes
* sizeof(REGPINTYPES
));
1032 IFilterMapper2_Release(pMapper
);
1033 return E_OUTOFMEMORY
;
1036 pTypes
[0].clsMajorType
= &MEDIATYPE_Video
;
1037 pTypes
[0].clsMinorType
= &MEDIASUBTYPE_None
;
1039 rfp2
.lpMediaType
= pTypes
;
1041 res
= IFilterMapper2_RegisterFilter(pMapper
,
1045 &CLSID_VideoInputDeviceCategory
,
1050 OLECHAR wszVfwIndex
[] = { 'V','F','W','I','n','d','e','x',0 };
1054 res
= IMoniker_BindToStorage(pMoniker
, NULL
, NULL
, &IID_IPropertyBag
, (LPVOID
)&pPropBag
);
1055 if (SUCCEEDED(res
)) {
1056 res
= IPropertyBag_Write(pPropBag
, wszVfwIndex
, &var
);
1057 IPropertyBag_Release(pPropBag
);
1059 IMoniker_Release(pMoniker
);
1062 if (i
== iDefaultDevice
) FIXME("Default device\n");
1063 CoTaskMemFree(pTypes
);
1069 IFilterMapper2_Release(pMapper
);