Signed-off-by: Zebediah Figura z.figura12@gmail.com --- This fixes one facet of the error originally reported here: https://www.winehq.org/pipermail/wine-devel/2018-March/123533.html
dlls/devenum/Makefile.in | 4 +- dlls/devenum/createdevenum.c | 255 +++++++++++++++++++++++++-------------- dlls/devenum/fil_data.idl | 47 ++++++++ dlls/devenum/tests/devenum.c | 76 +++++++++++- dlls/quartz/tests/filtermapper.c | 18 +++ 5 files changed, 307 insertions(+), 93 deletions(-) create mode 100644 dlls/devenum/fil_data.idl
diff --git a/dlls/devenum/Makefile.in b/dlls/devenum/Makefile.in index 38ca83d..0a7e903 100644 --- a/dlls/devenum/Makefile.in +++ b/dlls/devenum/Makefile.in @@ -9,6 +9,8 @@ C_SRCS = \ mediacatenum.c \ parsedisplayname.c
-IDL_SRCS = devenum_classes.idl +IDL_SRCS = \ + devenum_classes.idl \ + fil_data.idl
RC_SRCS = devenum.rc diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c index c1e29fc..a6f6626 100644 --- a/dlls/devenum/createdevenum.c +++ b/dlls/devenum/createdevenum.c @@ -32,8 +32,12 @@
#include "wine/debug.h" #include "wine/unicode.h" +#include "wine/heap.h" #include "mmddk.h"
+#include "initguid.h" +#include "fil_data.h" + WINE_DEFAULT_DEBUG_CHANNEL(devenum);
extern HINSTANCE DEVENUM_hInstance; @@ -50,9 +54,11 @@ static const WCHAR wszTypes[] = {'T','y','p','e','s',0}; static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; static const WCHAR wszWaveInID[] = {'W','a','v','e','I','n','I','D',0}; static const WCHAR wszWaveOutID[] = {'W','a','v','e','O','u','t','I','D',0}; +static const WCHAR wszFilterData[] = {'F','i','l','t','e','r','D','a','t','a',0};
static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface); static HRESULT register_codecs(void); +static HRESULT DEVENUM_CreateAMCategoryKey(const CLSID * clsidCategory);
/********************************************************************** * DEVENUM_ICreateDevEnum_QueryInterface (also IUnknown) @@ -124,6 +130,36 @@ static HKEY open_special_category_key(const CLSID *clsid, BOOL create) return ret; }
+static HRESULT register_codec(const CLSID *class, const WCHAR *name, IMoniker **ret) +{ + static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','c','m',':',0}; + IParseDisplayName *parser; + WCHAR *buffer; + ULONG eaten; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser); + if (FAILED(hr)) + return hr; + + buffer = heap_alloc((strlenW(deviceW) + CHARS_IN_GUID + strlenW(name) + 1) * sizeof(WCHAR)); + if (!buffer) + { + IParseDisplayName_Release(parser); + return E_OUTOFMEMORY; + } + + strcpyW(buffer, deviceW); + StringFromGUID2(class, buffer + strlenW(buffer), CHARS_IN_GUID); + strcatW(buffer, backslashW); + strcatW(buffer, name); + + hr = IParseDisplayName_ParseDisplayName(parser, NULL, buffer, &eaten, ret); + IParseDisplayName_Release(parser); + heap_free(buffer); + return hr; +} + static void DEVENUM_ReadPinTypes(HKEY hkeyPinKey, REGFILTERPINS2 *rgPin) { HKEY hkeyTypes = NULL; @@ -312,21 +348,77 @@ static void DEVENUM_ReadPins(HKEY hkeyFilterClass, REGFILTER2 *rgf2) rgf2->u.s2.rgPins2 = rgPins; }
-static HRESULT DEVENUM_RegisterLegacyAmFilters(void) +static void free_regfilter2(REGFILTER2 *rgf) +{ + if (rgf->u.s2.rgPins2) + { + UINT iPin; + + for (iPin = 0; iPin < rgf->u.s2.cPins2; iPin++) + { + if (rgf->u.s2.rgPins2[iPin].lpMediaType) + { + UINT iType; + + for (iType = 0; iType < rgf->u.s2.rgPins2[iPin].nMediaTypes; iType++) + { + CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType[iType].clsMajorType); + CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType[iType].clsMinorType); + } + + CoTaskMemFree((void *)rgf->u.s2.rgPins2[iPin].lpMediaType); + } + } + + CoTaskMemFree((void *)rgf->u.s2.rgPins2); + } +} + +static void write_filter_data(IPropertyBag *prop_bag, REGFILTER2 *rgf) +{ + IAMFilterData *fildata; + SAFEARRAYBOUND sabound; + BYTE *data, *array; + VARIANT var = {0}; + ULONG size; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IAMFilterData, (void **)&fildata); + if (FAILED(hr)) goto cleanup; + + hr = IAMFilterData_CreateFilterData(fildata, rgf, &data, &size); + if (FAILED(hr)) goto cleanup; + + V_VT(&var) = VT_ARRAY | VT_UI1; + sabound.lLbound = 0; + sabound.cElements = size; + if (!(V_ARRAY(&var) = SafeArrayCreate(VT_UI1, 1, &sabound))) + goto cleanup; + hr = SafeArrayAccessData(V_ARRAY(&var), (void *)&array); + if (FAILED(hr)) goto cleanup; + + memcpy(array, data, size); + hr = SafeArrayUnaccessData(V_ARRAY(&var)); + if (FAILED(hr)) goto cleanup; + + hr = IPropertyBag_Write(prop_bag, wszFilterData, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + CoTaskMemFree(data); + IAMFilterData_Release(fildata); +} + +static void register_legacy_filters(void) { HKEY hkeyFilter = NULL; DWORD dwFilterSubkeys, i; LONG lRet; - IFilterMapper2 *pMapper = NULL; HRESULT hr;
- hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, - &IID_IFilterMapper2, (void **) &pMapper); - if (SUCCEEDED(hr)) - { - lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszFilterKeyName, 0, KEY_READ, &hkeyFilter); - hr = HRESULT_FROM_WIN32(lRet); - } + lRet = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszFilterKeyName, 0, KEY_READ, &hkeyFilter); + hr = HRESULT_FROM_WIN32(lRet);
if (SUCCEEDED(hr)) { @@ -335,106 +427,87 @@ static HRESULT DEVENUM_RegisterLegacyAmFilters(void) }
if (SUCCEEDED(hr)) + hr = DEVENUM_CreateAMCategoryKey(&CLSID_LegacyAmFilterCategory); + + if (SUCCEEDED(hr)) { for (i = 0; i < dwFilterSubkeys; i++) { WCHAR wszFilterSubkeyName[64]; DWORD cName = sizeof(wszFilterSubkeyName) / sizeof(WCHAR); + IPropertyBag *prop_bag = NULL; WCHAR wszRegKey[MAX_PATH]; - HKEY hkeyInstance = NULL; + HKEY classkey = NULL; + IMoniker *mon = NULL; + VARIANT var = {0}; + REGFILTER2 rgf2; + DWORD Type, len;
if (RegEnumKeyExW(hkeyFilter, i, wszFilterSubkeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) continue;
- strcpyW(wszRegKey, wszActiveMovieKey); - StringFromGUID2(&CLSID_LegacyAmFilterCategory, wszRegKey + strlenW(wszRegKey), CHARS_IN_GUID); + TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName));
- strcatW(wszRegKey, wszRegSeparator); + strcpyW(wszRegKey, clsidW); strcatW(wszRegKey, wszFilterSubkeyName);
- if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &hkeyInstance) == ERROR_SUCCESS) - { - RegCloseKey(hkeyInstance); - } - else - { - /* Filter is registered the IFilterMapper(1)-way in HKCR\Filter. Needs to be added to - * legacy am filter category. */ - HKEY hkeyFilterClass = NULL; - REGFILTER2 rgf2; - CLSID clsidFilter; - WCHAR wszFilterName[MAX_PATH]; - DWORD Type; - DWORD cbData; - HRESULT res; - IMoniker *pMoniker = NULL; - - TRACE("Registering %s\n", debugstr_w(wszFilterSubkeyName)); - - strcpyW(wszRegKey, clsid_keyname); - strcatW(wszRegKey, wszRegSeparator); - strcatW(wszRegKey, wszFilterSubkeyName); - - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &hkeyFilterClass) != ERROR_SUCCESS) - continue; - - rgf2.dwMerit = 0; - - cbData = sizeof(wszFilterName); - if (RegQueryValueExW(hkeyFilterClass, NULL, NULL, &Type, (LPBYTE)wszFilterName, &cbData) != ERROR_SUCCESS || - Type != REG_SZ) - goto cleanup; - - cbData = sizeof(rgf2.dwMerit); - if (RegQueryValueExW(hkeyFilterClass, wszMeritName, NULL, &Type, (LPBYTE)&rgf2.dwMerit, &cbData) != ERROR_SUCCESS || - Type != REG_DWORD) - goto cleanup; - - DEVENUM_ReadPins(hkeyFilterClass, &rgf2); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszRegKey, 0, KEY_READ, &classkey) != ERROR_SUCCESS) + continue;
- res = CLSIDFromString(wszFilterSubkeyName, &clsidFilter); - if (FAILED(res)) goto cleanup; + hr = register_codec(&CLSID_LegacyAmFilterCategory, wszFilterSubkeyName, &mon); + if (FAILED(hr)) goto cleanup;
- IFilterMapper2_RegisterFilter(pMapper, &clsidFilter, wszFilterName, &pMoniker, NULL, NULL, &rgf2); + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup;
- if (pMoniker) - IMoniker_Release(pMoniker); - - cleanup: - - if (hkeyFilterClass) RegCloseKey(hkeyFilterClass); - - if (rgf2.u.s2.rgPins2) - { - UINT iPin; - - for (iPin = 0; iPin < rgf2.u.s2.cPins2; iPin++) - { - if (rgf2.u.s2.rgPins2[iPin].lpMediaType) - { - UINT iType; - - for (iType = 0; iType < rgf2.u.s2.rgPins2[iPin].nMediaTypes; iType++) - { - CoTaskMemFree((void*)rgf2.u.s2.rgPins2[iPin].lpMediaType[iType].clsMajorType); - CoTaskMemFree((void*)rgf2.u.s2.rgPins2[iPin].lpMediaType[iType].clsMinorType); - } - - CoTaskMemFree((void*)rgf2.u.s2.rgPins2[iPin].lpMediaType); - } - } - - CoTaskMemFree((void*)rgf2.u.s2.rgPins2); - } + /* write friendly name */ + len = 0; + V_VT(&var) = VT_BSTR; + if (!RegQueryValueExW(classkey, NULL, NULL, &Type, NULL, &len)) + { + WCHAR *friendlyname = heap_alloc(len); + if (!friendlyname) + goto cleanup; + RegQueryValueExW(classkey, NULL, NULL, &Type, (BYTE *)friendlyname, &len); + V_BSTR(&var) = SysAllocStringLen(friendlyname, len/sizeof(WCHAR)); + heap_free(friendlyname); } + else + V_BSTR(&var) = SysAllocString(wszFilterSubkeyName); + + if (!V_BSTR(&var)) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + if (!(V_BSTR(&var) = SysAllocString(wszFilterSubkeyName))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf2.dwMerit = MERIT_NORMAL; + + len = sizeof(rgf2.dwMerit); + RegQueryValueExW(classkey, wszMeritName, NULL, &Type, (BYTE *)&rgf2.dwMerit, &len); + + DEVENUM_ReadPins(classkey, &rgf2); + + write_filter_data(prop_bag, &rgf2); + +cleanup: + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + RegCloseKey(classkey); + VariantClear(&var); + free_regfilter2(&rgf2); } }
if (hkeyFilter) RegCloseKey(hkeyFilter); - - if (pMapper) - IFilterMapper2_Release(pMapper); - - return S_OK; }
/********************************************************************** @@ -454,7 +527,7 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator( *ppEnumMoniker = NULL;
register_codecs(); - DEVENUM_RegisterLegacyAmFilters(); + register_legacy_filters();
return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker); } @@ -562,6 +635,8 @@ static HRESULT register_codecs(void) * or switched from pulseaudio to alsa, delete all old devices first */ RegOpenKeyW(HKEY_CURRENT_USER, wszActiveMovieKey, &basekey); + StringFromGUID2(&CLSID_LegacyAmFilterCategory, class, CHARS_IN_GUID); + RegDeleteTreeW(basekey, class); StringFromGUID2(&CLSID_AudioRendererCategory, class, CHARS_IN_GUID); RegDeleteTreeW(basekey, class); StringFromGUID2(&CLSID_AudioInputDeviceCategory, class, CHARS_IN_GUID); diff --git a/dlls/devenum/fil_data.idl b/dlls/devenum/fil_data.idl new file mode 100644 index 0000000..7e37a75 --- /dev/null +++ b/dlls/devenum/fil_data.idl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Vitaliy Margolen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma makedep header + +import "objidl.idl"; +import "strmif.idl"; +import "unknwn.idl"; + + +/***************************************************************************** + * IAMFilterData interface + */ +[ + object, + uuid(97f7c4d4-547b-4a5f-8332-536430ad2e4d), + pointer_default(unique) +] +interface IAMFilterData : IUnknown +{ + typedef [unique] IAMFilterData *LPIAMFILTERDATA; + + HRESULT ParseFilterData( + [in] BYTE * rgbFilterData, + [in] ULONG cb, + [out] BYTE ** prgbRegFilter2); + + HRESULT CreateFilterData( + [in] REGFILTER2 * prf2, + [out] BYTE ** prgbFilterData, + [out] ULONG * pcb); +} diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index a08dece..43d6eeb 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -27,11 +27,16 @@ #include "ole2.h" #include "strmif.h" #include "uuids.h" +#include "vfwmsgs.h"
static const WCHAR friendly_name[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; static const WCHAR fcc_handlerW[] = {'F','c','c','H','a','n','d','l','e','r',0}; +static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':',0}; static const WCHAR clsidW[] = {'C','L','S','I','D',0}; static const WCHAR mrleW[] = {'m','r','l','e',0}; +static const WCHAR swW[] = {'s','w',':',0}; +static const WCHAR cmW[] = {'c','m',':',0}; +static const WCHAR backslashW[] = {'\',0};
static void test_devenum(IBindCtx *bind_ctx) { @@ -304,7 +309,6 @@ static IMoniker *check_display_name_(int line, IParseDisplayName *parser, WCHAR
static void test_directshow_filter(void) { - static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','s','w',':',0}; static const WCHAR instanceW[] = {'\','I','n','s','t','a','n','c','e',0}; static const WCHAR clsidW[] = {'C','L','S','I','D','\',0}; static WCHAR testW[] = {'\','t','e','s','t',0}; @@ -321,6 +325,7 @@ static void test_directshow_filter(void) ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
lstrcpyW(buffer, deviceW); + lstrcatW(buffer, swW); StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); lstrcatW(buffer, testW); mon = check_display_name(parser, buffer); @@ -367,6 +372,7 @@ static void test_directshow_filter(void) /* name can be anything */
lstrcpyW(buffer, deviceW); + lstrcatW(buffer, swW); lstrcatW(buffer, testW+1); mon = check_display_name(parser, buffer);
@@ -405,7 +411,6 @@ static void test_directshow_filter(void)
static void test_codec(void) { - static const WCHAR deviceW[] = {'@','d','e','v','i','c','e',':','c','m',':',0}; static WCHAR testW[] = {'\','t','e','s','t',0}; IParseDisplayName *parser; IPropertyBag *prop_bag; @@ -419,6 +424,7 @@ static void test_codec(void) ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
lstrcpyW(buffer, deviceW); + lstrcatW(buffer, cmW); StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); lstrcatW(buffer, testW); mon = check_display_name(parser, buffer); @@ -456,6 +462,70 @@ static void test_codec(void) IParseDisplayName_Release(parser); }
+static void test_legacy_filter(void) +{ + static const WCHAR nameW[] = {'t','e','s','t',0}; + IParseDisplayName *parser; + IPropertyBag *prop_bag; + IFilterMapper *mapper; + IMoniker *mon; + WCHAR buffer[200]; + VARIANT var; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser); + ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr); + + hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper, (void **)&mapper); + ok(hr == S_OK, "Failed to create FilterMapper: %#x\n", hr); + + hr = IFilterMapper_RegisterFilter(mapper, CLSID_TestFilter, nameW, 0xdeadbeef); + if (hr == VFW_E_BAD_KEY) + { + win_skip("not enough permissions to register filters\n"); + goto end; + } + ok(hr == S_OK, "RegisterFilter failed: %#x\n", hr); + + lstrcpyW(buffer, deviceW); + lstrcatW(buffer, cmW); + StringFromGUID2(&CLSID_LegacyAmFilterCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, backslashW); + StringFromGUID2(&CLSID_TestFilter, buffer + lstrlenW(buffer), CHARS_IN_GUID); + + mon = check_display_name(parser, buffer); + ok(find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should be registered\n"); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "BindToStorage failed: %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + + StringFromGUID2(&CLSID_TestFilter, buffer, CHARS_IN_GUID); + ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n", + wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var))); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n", + wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var))); + + IPropertyBag_Release(prop_bag); + + hr = IFilterMapper_UnregisterFilter(mapper, CLSID_TestFilter); + ok(hr == S_OK, "UnregisterFilter failed: %#x\n", hr); + + ok(!find_moniker(&CLSID_LegacyAmFilterCategory, mon), "filter should not be registered\n"); + IMoniker_Release(mon); + +end: + IFilterMapper_Release(mapper); + IParseDisplayName_Release(parser); +} + START_TEST(devenum) { IBindCtx *bind_ctx = NULL; @@ -478,5 +548,7 @@ START_TEST(devenum) test_directshow_filter(); test_codec();
+ test_legacy_filter(); + CoUninitialize(); } diff --git a/dlls/quartz/tests/filtermapper.c b/dlls/quartz/tests/filtermapper.c index c9578c6..5a43785 100644 --- a/dlls/quartz/tests/filtermapper.c +++ b/dlls/quartz/tests/filtermapper.c @@ -294,6 +294,24 @@ static void test_legacy_filter_registration(void) hr = IFilterMapper_UnregisterFilter(mapper, clsid); ok(hr == S_OK, "FilterMapper_UnregisterFilter failed with %x\n", hr);
+ hr = IFilterMapper2_EnumMatchingFilters(mapper2, &enum_mon, 0, TRUE, MERIT_UNLIKELY, TRUE, + 0, NULL, NULL, &GUID_NULL, FALSE, FALSE, 0, NULL, NULL, &GUID_NULL); + ok(hr == S_OK, "IFilterMapper2_EnumMatchingFilters failed: %x\n", hr); + ok(!enum_find_filter(testfilterW, enum_mon), "IFilterMapper2 shouldn't find filter\n"); + IEnumMoniker_Release(enum_mon); + + found = FALSE; + hr = IFilterMapper_EnumMatchingFilters(mapper, &enum_reg, MERIT_UNLIKELY, TRUE, GUID_NULL, GUID_NULL, + FALSE, FALSE, GUID_NULL, GUID_NULL); + ok(hr == S_OK, "IFilterMapper_EnumMatchingFilters failed with %x\n", hr); + while(!found && IEnumRegFilters_Next(enum_reg, 1, ®filter, &count) == S_OK) + { + if (!lstrcmpW(regfilter->Name, testfilterW) && IsEqualGUID(&clsid, ®filter->Clsid)) + found = TRUE; + } + IEnumRegFilters_Release(enum_reg); + ok(!found, "IFilterMapper shouldn't find filter\n"); + ret = RegDeleteKeyW(HKEY_CLASSES_ROOT, key_name); ok(!ret, "RegDeleteKeyA failed: %lu\n", ret);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/Makefile.in | 2 +- dlls/devenum/createdevenum.c | 129 ++++++++++++++++++++++++++++------------- dlls/devenum/devenum.rc | 2 - dlls/devenum/devenum_private.h | 2 - dlls/devenum/tests/Makefile.in | 2 +- dlls/devenum/tests/devenum.c | 94 ++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+), 45 deletions(-)
diff --git a/dlls/devenum/Makefile.in b/dlls/devenum/Makefile.in index 0a7e903..8f81f93 100644 --- a/dlls/devenum/Makefile.in +++ b/dlls/devenum/Makefile.in @@ -1,5 +1,5 @@ MODULE = devenum.dll -IMPORTS = strmiids uuid ole32 oleaut32 avicap32 winmm user32 advapi32 +IMPORTS = strmiids uuid ole32 oleaut32 avicap32 winmm user32 advapi32 dsound DELAYIMPORTS = msvfw32
C_SRCS = \ diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c index a6f6626..5fc4725 100644 --- a/dlls/devenum/createdevenum.c +++ b/dlls/devenum/createdevenum.c @@ -29,6 +29,7 @@ #include "devenum_private.h" #include "vfw.h" #include "aviriff.h" +#include "dsound.h"
#include "wine/debug.h" #include "wine/unicode.h" @@ -510,6 +511,91 @@ cleanup: if (hkeyFilter) RegCloseKey(hkeyFilter); }
+static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, const WCHAR *module, void *context) +{ + 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}; + static const WCHAR directsoundW[] = {'D','i','r','e','c','t','S','o','u','n','d',':',' ',0}; + static const WCHAR dsguidW[] = {'D','S','G','u','i','d',0}; + IPropertyBag *prop_bag = NULL; + REGFILTERPINS2 rgpins = {0}; + REGPINTYPES rgtypes = {0}; + REGFILTER2 rgf = {0}; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + VARIANT var; + HRESULT hr; + + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) goto cleanup; + + V_VT(&var) = VT_BSTR; + if (guid) + { + WCHAR *name = heap_alloc(sizeof(defaultW) + strlenW(desc) * sizeof(WCHAR)); + if (!name) + goto cleanup; + strcpyW(name, directsoundW); + strcatW(name, desc); + + V_BSTR(&var) = SysAllocString(name); + heap_free(name); + } + else + V_BSTR(&var) = SysAllocString(defaultW); + + if (!V_BSTR(&var)) + goto cleanup; + + hr = register_codec(&CLSID_AudioRendererCategory, V_BSTR(&var), &mon); + if (FAILED(hr)) goto cleanup; + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + if (FAILED(hr)) goto cleanup; + + /* write friendly name */ + hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write clsid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(&CLSID_DSoundRender, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var); + if (FAILED(hr)) goto cleanup; + VariantClear(&var); + + /* write filter data */ + rgf.dwVersion = 2; + rgf.dwMerit = guid ? MERIT_DO_NOT_USE : MERIT_PREFERRED; + rgf.u.s2.cPins2 = 1; + rgf.u.s2.rgPins2 = &rgpins; + rgpins.dwFlags = REG_PINFLAG_B_RENDERER; + /* FIXME: native registers many more formats */ + rgpins.nMediaTypes = 1; + rgpins.lpMediaType = &rgtypes; + rgtypes.clsMajorType = &MEDIATYPE_Audio; + rgtypes.clsMinorType = &MEDIASUBTYPE_PCM; + + write_filter_data(prop_bag, &rgf); + + /* write DSound guid */ + V_VT(&var) = VT_BSTR; + StringFromGUID2(guid ? guid : &GUID_NULL, clsid, CHARS_IN_GUID); + if (!(V_BSTR(&var) = SysAllocString(clsid))) + goto cleanup; + hr = IPropertyBag_Write(prop_bag, dsguidW, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + + return TRUE; +} + /********************************************************************** * DEVENUM_ICreateDevEnum_CreateClassEnumerator */ @@ -519,6 +605,8 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator( IEnumMoniker **ppEnumMoniker, DWORD dwFlags) { + HRESULT hr; + TRACE("(%p)->(%s, %p, %x)\n", iface, debugstr_guid(clsidDeviceClass), ppEnumMoniker, dwFlags);
if (!ppEnumMoniker) @@ -528,6 +616,8 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
register_codecs(); register_legacy_filters(); + hr = DirectSoundEnumerateW(®ister_dsound_devices, NULL); + if (FAILED(hr)) return hr;
return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker); } @@ -621,8 +711,6 @@ static void register_vfw_codecs(void) static HRESULT register_codecs(void) { HRESULT res; - WCHAR szDSoundNameFormat[MAX_PATH + 1]; - WCHAR szDSoundName[MAX_PATH + 1]; WCHAR class[CHARS_IN_GUID]; DWORD iDefaultDevice = -1; UINT numDevs; @@ -658,12 +746,6 @@ static HRESULT register_codecs(void) rfp2.lpMedium = NULL; rfp2.clsPinCategory = &IID_NULL;
- if (!LoadStringW(DEVENUM_hInstance, IDS_DEVENUM_DS, szDSoundNameFormat, sizeof(szDSoundNameFormat)/sizeof(szDSoundNameFormat[0])-1)) - { - ERR("Couldn't get string resource (GetLastError() is %d)\n", GetLastError()); - return HRESULT_FROM_WIN32(GetLastError()); - } - res = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2, (void **) &pMapper); /* @@ -714,37 +796,6 @@ static HRESULT register_codecs(void) wocaps.szPname, &rf2);
- if (pMoniker) - { - VARIANT var; - - V_VT(&var) = VT_I4; - V_I4(&var) = i; - res = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID)&pPropBag); - if (SUCCEEDED(res)) - res = IPropertyBag_Write(pPropBag, wszWaveOutID, &var); - else - pPropBag = NULL; - - V_VT(&var) = VT_LPWSTR; - V_BSTR(&var) = wocaps.szPname; - if (SUCCEEDED(res)) - res = IPropertyBag_Write(pPropBag, wszFriendlyName, &var); - if (pPropBag) - IPropertyBag_Release(pPropBag); - IMoniker_Release(pMoniker); - pMoniker = NULL; - } - - wsprintfW(szDSoundName, szDSoundNameFormat, wocaps.szPname); - res = IFilterMapper2_RegisterFilter(pMapper, - &CLSID_DSoundRender, - szDSoundName, - &pMoniker, - &CLSID_AudioRendererCategory, - szDSoundName, - &rf2); - /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */
if (pMoniker) diff --git a/dlls/devenum/devenum.rc b/dlls/devenum/devenum.rc index d43c159..d9262e1 100644 --- a/dlls/devenum/devenum.rc +++ b/dlls/devenum/devenum.rc @@ -29,8 +29,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
STRINGTABLE { - IDS_DEVENUM_DSDEFAULT "Default DirectSound" - IDS_DEVENUM_DS "DirectSound: %s" IDS_DEVENUM_WODEFAULT "Default WaveOut Device" IDS_DEVENUM_MIDEFAULT "Default MidiOut Device" } diff --git a/dlls/devenum/devenum_private.h b/dlls/devenum/devenum_private.h index a483062..93147ad 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -101,8 +101,6 @@ extern const WCHAR clsid_keyname[6] DECLSPEC_HIDDEN; /********************************************************************** * Resource IDs */ -#define IDS_DEVENUM_DSDEFAULT 7 -#define IDS_DEVENUM_DS 8 #define IDS_DEVENUM_WODEFAULT 9 #define IDS_DEVENUM_MIDEFAULT 10 #define IDS_DEVENUM_KSDEFAULT 11 diff --git a/dlls/devenum/tests/Makefile.in b/dlls/devenum/tests/Makefile.in index f6ef993..028ba27 100644 --- a/dlls/devenum/tests/Makefile.in +++ b/dlls/devenum/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = devenum.dll -IMPORTS = oleaut32 ole32 advapi32 +IMPORTS = advapi32 dsound oleaut32 ole32
C_SRCS = \ devenum.c diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index 43d6eeb..c4bf8af 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -28,6 +28,10 @@ #include "strmif.h" #include "uuids.h" #include "vfwmsgs.h" +#include "mmsystem.h" +#include "dsound.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
static const WCHAR friendly_name[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; static const WCHAR fcc_handlerW[] = {'F','c','c','H','a','n','d','l','e','r',0}; @@ -526,6 +530,94 @@ end: IParseDisplayName_Release(parser); }
+static BOOL CALLBACK test_dsound(GUID *guid, const WCHAR *desc, const WCHAR *module, void *context) +{ + 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}; + static const WCHAR directsoundW[] = {'D','i','r','e','c','t','S','o','u','n','d',':',' ',0}; + static const WCHAR dsguidW[] = {'D','S','G','u','i','d',0}; + IParseDisplayName *parser; + IPropertyBag *prop_bag; + IMoniker *mon; + WCHAR buffer[200]; + WCHAR name[200]; + VARIANT var; + HRESULT hr; + + if (guid) + { + lstrcpyW(name, directsoundW); + lstrcatW(name, desc); + } + else + { + lstrcpyW(name, defaultW); + guid = (GUID *)&GUID_NULL; + } + + hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser); + ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr); + + lstrcpyW(buffer, deviceW); + lstrcatW(buffer, cmW); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, backslashW); + lstrcatW(buffer, name); + + mon = check_display_name(parser, buffer); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "BindToStorage failed: %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + /* Win8+ uses the GUID instead of the device name */ + IPropertyBag_Release(prop_bag); + IMoniker_Release(mon); + + lstrcpyW(buffer, deviceW); + lstrcatW(buffer, cmW); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, backslashW); + lstrcatW(buffer, directsoundW); + StringFromGUID2(guid, buffer + lstrlenW(buffer) - 1, CHARS_IN_GUID); + + mon = check_display_name(parser, buffer); + + hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag); + ok(hr == S_OK, "BindToStorage failed: %#x\n", hr); + + VariantInit(&var); + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + } + ok(hr == S_OK, "Read failed: %#x\n", hr); + + ok(!lstrcmpW(name, V_BSTR(&var)), "expected %s, got %s\n", + wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&var))); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + + StringFromGUID2(&CLSID_DSoundRender, buffer, CHARS_IN_GUID); + ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n", + wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var))); + + VariantClear(&var); + hr = IPropertyBag_Read(prop_bag, dsguidW, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + + StringFromGUID2(guid, buffer, CHARS_IN_GUID); + ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n", + wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var))); + + IPropertyBag_Release(prop_bag); + IMoniker_Release(mon); + IParseDisplayName_Release(parser); + return TRUE; +} + START_TEST(devenum) { IBindCtx *bind_ctx = NULL; @@ -549,6 +641,8 @@ START_TEST(devenum) test_codec();
test_legacy_filter(); + hr = DirectSoundEnumerateW(test_dsound, NULL); + ok(hr == S_OK, "got %#x\n", hr);
CoUninitialize(); }