Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/devenum/createdevenum.c | 131 +++++++++++++++++++++++++---------------- dlls/devenum/devenum.rc | 1 - dlls/devenum/devenum_private.h | 1 - dlls/devenum/tests/Makefile.in | 2 +- dlls/devenum/tests/devenum.c | 109 ++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+), 54 deletions(-)
diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c index 6884ffc..e3fe049 100644 --- a/dlls/devenum/createdevenum.c +++ b/dlls/devenum/createdevenum.c @@ -594,6 +594,85 @@ cleanup: return TRUE; }
+static void register_waveout_devices(void) +{ + 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}; + static const WCHAR waveoutidW[] = {'W','a','v','e','O','u','t','I','d',0}; + IPropertyBag *prop_bag = NULL; + REGFILTERPINS2 rgpins = {0}; + REGPINTYPES rgtypes = {0}; + REGFILTER2 rgf = {0}; + WCHAR clsid[CHARS_IN_GUID]; + IMoniker *mon = NULL; + WAVEOUTCAPSW caps; + int i, count; + VARIANT var; + HRESULT hr; + + hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); + if (FAILED(hr)) return; + + count = waveOutGetNumDevs(); + + for (i = -1; i < count; i++) + { + waveOutGetDevCapsW(i, &caps, sizeof(caps)); + + V_VT(&var) = VT_BSTR; + + if (i == -1) /* WAVE_MAPPER */ + V_BSTR(&var) = SysAllocString(defaultW); + else + V_BSTR(&var) = SysAllocString(caps.szPname); + 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_AudioRender, 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 = MERIT_DO_NOT_USE; + rgf.u.s2.cPins2 = 1; + rgf.u.s2.rgPins2 = &rgpins; + rgpins.dwFlags = REG_PINFLAG_B_RENDERER; + rgpins.nMediaTypes = 1; + rgpins.lpMediaType = &rgtypes; + rgtypes.clsMajorType = &MEDIATYPE_Audio; + rgtypes.clsMinorType = &MEDIASUBTYPE_NULL; + + write_filter_data(prop_bag, &rgf); + + /* write WaveOutId */ + V_VT(&var) = VT_I4; + V_I4(&var) = i; + hr = IPropertyBag_Write(prop_bag, waveoutidW, &var); + if (FAILED(hr)) goto cleanup; + +cleanup: + VariantClear(&var); + if (prop_bag) IPropertyBag_Release(prop_bag); + if (mon) IMoniker_Release(mon); + } +} + /********************************************************************** * DEVENUM_ICreateDevEnum_CreateClassEnumerator */ @@ -616,6 +695,7 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator( register_legacy_filters(); hr = DirectSoundEnumerateW(®ister_dsound_devices, NULL); if (FAILED(hr)) return hr; + register_waveout_devices();
return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker); } @@ -752,62 +832,11 @@ static HRESULT register_codecs(void) if (SUCCEEDED(res)) { UINT i; - WAVEOUTCAPSW wocaps; WAVEINCAPSW wicaps; MIDIOUTCAPSW mocaps; REGPINTYPES * pTypes; IPropertyBag * pPropBag = NULL;
- numDevs = waveOutGetNumDevs(); - - res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); - if (FAILED(res)) /* can't register any devices in this category */ - numDevs = 0; - - rfp2.dwFlags = REG_PINFLAG_B_RENDERER; - for (i = 0; i < numDevs; i++) - { - if (waveOutGetDevCapsW(i, &wocaps, sizeof(WAVEOUTCAPSW)) - == MMSYSERR_NOERROR) - { - IMoniker * pMoniker = NULL; - - rfp2.nMediaTypes = 1; - pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); - if (!pTypes) - { - IFilterMapper2_Release(pMapper); - return E_OUTOFMEMORY; - } - /* FIXME: Native devenum seems to register a lot more types for - * DSound than we do. Not sure what purpose they serve */ - pTypes[0].clsMajorType = &MEDIATYPE_Audio; - pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM; - - rfp2.lpMediaType = pTypes; - - res = IFilterMapper2_RegisterFilter(pMapper, - &CLSID_AudioRender, - wocaps.szPname, - &pMoniker, - &CLSID_AudioRendererCategory, - wocaps.szPname, - &rf2); - - /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ - - if (pMoniker) - IMoniker_Release(pMoniker); - - if (i == iDefaultDevice) - { - FIXME("Default device\n"); - } - - CoTaskMemFree(pTypes); - } - } - numDevs = waveInGetNumDevs();
res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioInputDeviceCategory); diff --git a/dlls/devenum/devenum.rc b/dlls/devenum/devenum.rc index d9262e1..95e39d6 100644 --- a/dlls/devenum/devenum.rc +++ b/dlls/devenum/devenum.rc @@ -29,7 +29,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
STRINGTABLE { - 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 93147ad..c891083 100644 --- a/dlls/devenum/devenum_private.h +++ b/dlls/devenum/devenum_private.h @@ -101,7 +101,6 @@ extern const WCHAR clsid_keyname[6] DECLSPEC_HIDDEN; /********************************************************************** * Resource IDs */ -#define IDS_DEVENUM_WODEFAULT 9 #define IDS_DEVENUM_MIDEFAULT 10 #define IDS_DEVENUM_KSDEFAULT 11 #define IDS_DEVENUM_KS 12 diff --git a/dlls/devenum/tests/Makefile.in b/dlls/devenum/tests/Makefile.in index 028ba27..a673f20 100644 --- a/dlls/devenum/tests/Makefile.in +++ b/dlls/devenum/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = devenum.dll -IMPORTS = advapi32 dsound oleaut32 ole32 +IMPORTS = advapi32 dsound oleaut32 ole32 winmm
C_SRCS = \ devenum.c diff --git a/dlls/devenum/tests/devenum.c b/dlls/devenum/tests/devenum.c index c4bf8af..79f5ed8 100644 --- a/dlls/devenum/tests/devenum.c +++ b/dlls/devenum/tests/devenum.c @@ -30,6 +30,7 @@ #include "vfwmsgs.h" #include "mmsystem.h" #include "dsound.h" +#include "mmddk.h"
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
@@ -37,11 +38,25 @@ static const WCHAR friendly_name[] = {'F','r','i','e','n','d','l','y','N','a','m 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 waveW[] = {'w','a','v','e',':',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 inline WCHAR *strchrW( const WCHAR *str, WCHAR ch ) +{ + do { if (*str == ch) return (WCHAR *)str; } while (*str++); + return NULL; +} + +static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n ) +{ + if (n <= 0) return 0; + while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + static void test_devenum(IBindCtx *bind_ctx) { IEnumMoniker *enum_cat, *enum_moniker; @@ -618,6 +633,99 @@ static BOOL CALLBACK test_dsound(GUID *guid, const WCHAR *desc, const WCHAR *mod return TRUE; }
+static void test_waveout(void) +{ + 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}; + static const WCHAR waveoutidW[] = {'W','a','v','e','O','u','t','I','d',0}; + IParseDisplayName *parser; + IPropertyBag *prop_bag; + IMoniker *mon; + WCHAR endpoint[200]; + WAVEOUTCAPSW caps; + WCHAR buffer[200]; + const WCHAR *name; + MMRESULT mmr; + int count, i; + 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); + + count = waveOutGetNumDevs(); + + for (i = -1; i < count; i++) + { + waveOutGetDevCapsW(i, &caps, sizeof(caps)); + + if (i == -1) /* WAVE_MAPPER */ + name = defaultW; + else + name = caps.szPname; + + 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)) + { + IPropertyBag_Release(prop_bag); + IMoniker_Release(mon); + + /* Win8+ uses the endpoint GUID instead of the device name */ + mmr = waveOutMessage((HWAVEOUT)(DWORD_PTR) i, DRV_QUERYFUNCTIONINSTANCEID, + (DWORD_PTR) endpoint, sizeof(endpoint)); + ok(!mmr, "waveOutMessage failed: %u\n", mmr); + + lstrcpyW(buffer, deviceW); + lstrcatW(buffer, cmW); + StringFromGUID2(&CLSID_AudioRendererCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID); + lstrcatW(buffer, backslashW); + lstrcatW(buffer, waveW); + lstrcatW(buffer, strchrW(endpoint, '}') + 2); + + 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); + + hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL); + } + ok(hr == S_OK, "Read failed: %#x\n", hr); + + ok(!strncmpW(name, V_BSTR(&var), lstrlenW(name)), "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_AudioRender, 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, waveoutidW, &var, NULL); + ok(hr == S_OK, "Read failed: %#x\n", hr); + + ok(V_I4(&var) == i, "expected %d, got %d\n", i, V_I4(&var)); + + IPropertyBag_Release(prop_bag); + IMoniker_Release(mon); + } + + IParseDisplayName_Release(parser); +} + START_TEST(devenum) { IBindCtx *bind_ctx = NULL; @@ -643,6 +751,7 @@ START_TEST(devenum) test_legacy_filter(); hr = DirectSoundEnumerateW(test_dsound, NULL); ok(hr == S_OK, "got %#x\n", hr); + test_waveout();
CoUninitialize(); }