[PATCH 1/4] devenum: Register waveOut devices as codec devices.

Zebediah Figura z.figura12 at gmail.com
Sat Mar 31 12:07:41 CDT 2018


Signed-off-by: Zebediah Figura <z.figura12 at 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(&register_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();
 }
-- 
2.7.4




More information about the wine-devel mailing list