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(); }