From cec8dd343a831fb7016a219c8e7228b8872e1fb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 15 Aug 2015 02:59:17 +0200
Subject: [PATCH] dxdiagn: Enumerate DirectSound devices and add some basic
 properties.

---
 dlls/dxdiagn/Makefile.in       |   2 +-
 dlls/dxdiagn/provider.c        |  91 +++++++++++++++++++++
 dlls/dxdiagn/tests/container.c | 141 +++++++++++++++++++++++++++++++++
 3 files changed, 233 insertions(+), 1 deletion(-)

diff --git a/dlls/dxdiagn/Makefile.in b/dlls/dxdiagn/Makefile.in
index fa4b611f245..88c99803b06 100644
--- a/dlls/dxdiagn/Makefile.in
+++ b/dlls/dxdiagn/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = dxdiagn.dll
-IMPORTS   = strmiids dxguid uuid d3d9 ddraw version ole32 oleaut32 user32 advapi32
+IMPORTS   = strmiids dxguid uuid d3d9 ddraw version ole32 oleaut32 user32 advapi32 dsound
 
 EXTRADLLFLAGS = -mno-cygwin
 
diff --git a/dlls/dxdiagn/provider.c b/dlls/dxdiagn/provider.c
index 6b6f4e640cc..4ae5046b818 100644
--- a/dlls/dxdiagn/provider.c
+++ b/dlls/dxdiagn/provider.c
@@ -36,6 +36,7 @@
 #include "wine/fil_data.h"
 #include "psapi.h"
 #include "wbemcli.h"
+#include "dsound.h"
 
 #include "wine/debug.h"
 
@@ -1364,11 +1365,85 @@ static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node)
     return fill_display_information_fallback(node);
 }
 
+struct enum_context
+{
+    IDxDiagContainerImpl_Container *cont;
+    HRESULT hr;
+    int index;
+};
+
+static const WCHAR szGUIDFmt[] =
+{
+    '%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0',
+    '2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2',
+    'x','%','0','2','x','%','0','2','x','%','0','2','x',0
+};
+
+static LPWSTR guid_to_string(LPWSTR lpwstr, REFGUID lpcguid)
+{
+    wsprintfW(lpwstr, szGUIDFmt, lpcguid->Data1, lpcguid->Data2,
+        lpcguid->Data3, lpcguid->Data4[0], lpcguid->Data4[1],
+        lpcguid->Data4[2], lpcguid->Data4[3], lpcguid->Data4[4],
+        lpcguid->Data4[5], lpcguid->Data4[6], lpcguid->Data4[7]);
+
+    return lpwstr;
+}
+
+BOOL CALLBACK dsound_enum(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID context)
+{
+    static const WCHAR deviceid_fmtW[] = {'%','u',0};
+    static const WCHAR szGuidDeviceID[] = {'s','z','G','u','i','d','D','e','v','i','c','e','I','D',0};
+    static const WCHAR szDriverPath[] = {'s','z','D','r','i','v','e','r','P','a','t','h',0};
+
+    struct enum_context *enum_ctx = context;
+    IDxDiagContainerImpl_Container *device;
+    WCHAR buffer[256];
+    const WCHAR *p, *name;
+
+    /* the default device is enumerated twice, one time without GUID */
+    if (!guid) return TRUE;
+
+    _snwprintf(buffer, sizeof(buffer)/sizeof(WCHAR), deviceid_fmtW, enum_ctx->index);
+    device = allocate_information_node(buffer);
+    if (!device)
+    {
+        enum_ctx->hr = E_OUTOFMEMORY;
+        return FALSE;
+    }
+
+    add_subcontainer(enum_ctx->cont, device);
+
+    guid_to_string(buffer, guid);
+    enum_ctx->hr = add_bstr_property(device, szGuidDeviceID, buffer);
+    if (FAILED(enum_ctx->hr))
+        return FALSE;
+
+    enum_ctx->hr = add_bstr_property(device, szDescription, desc);
+    if (FAILED(enum_ctx->hr))
+        return FALSE;
+
+    enum_ctx->hr = add_bstr_property(device, szDriverPath, module);
+    if (FAILED(enum_ctx->hr))
+        return FALSE;
+
+    name = module;
+    if ((p = wcsrchr(name, '\\'))) name = p + 1;
+    if ((p = wcsrchr(name, '/'))) name = p + 1;
+
+    enum_ctx->hr = add_bstr_property(device, szDriverName, name);
+    if (FAILED(enum_ctx->hr))
+        return FALSE;
+
+    enum_ctx->index++;
+    return TRUE;
+}
+
 static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
 {
     static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
     static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e','D','e','v','i','c','e','s',0};
 
+    struct enum_context enum_ctx;
     IDxDiagContainerImpl_Container *cont;
 
     cont = allocate_information_node(DxDiag_SoundDevices);
@@ -1377,12 +1452,28 @@ static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node)
 
     add_subcontainer(node, cont);
 
+    enum_ctx.cont = cont;
+    enum_ctx.hr = S_OK;
+    enum_ctx.index = 0;
+
+    DirectSoundEnumerateW(dsound_enum, &enum_ctx);
+    if (FAILED(enum_ctx.hr))
+        return enum_ctx.hr;
+
     cont = allocate_information_node(DxDiag_SoundCaptureDevices);
     if (!cont)
         return E_OUTOFMEMORY;
 
     add_subcontainer(node, cont);
 
+    enum_ctx.cont = cont;
+    enum_ctx.hr = S_OK;
+    enum_ctx.index = 0;
+
+    DirectSoundCaptureEnumerateW(dsound_enum, &enum_ctx);
+    if (FAILED(enum_ctx.hr))
+        return enum_ctx.hr;
+
     return S_OK;
 }
 
diff --git a/dlls/dxdiagn/tests/container.c b/dlls/dxdiagn/tests/container.c
index 90287ad0e74..e8d5ac33a83 100644
--- a/dlls/dxdiagn/tests/container.c
+++ b/dlls/dxdiagn/tests/container.c
@@ -36,6 +36,11 @@ static IDxDiagContainer *pddc;
 
 static const WCHAR DxDiag_SystemInfo[] = {'D','x','D','i','a','g','_','S','y','s','t','e','m','I','n','f','o',0};
 static const WCHAR DxDiag_DisplayDevices[] = {'D','x','D','i','a','g','_','D','i','s','p','l','a','y','D','e','v','i','c','e','s',0};
+static const WCHAR DxDiag_SoundDevices[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d','.',
+                                            'D','x','D','i','a','g','_','S','o','u','n','d','D','e','v','i','c','e','s',0};
+static const WCHAR DxDiag_SoundCaptureDevices[] = {'D','x','D','i','a','g','_','D','i','r','e','c','t','S','o','u','n','d','.',
+                                                   'D','x','D','i','a','g','_','S','o','u','n','d','C','a','p','t','u','r','e',
+                                                   'D','e','v','i','c','e','s',0};
 
 static BOOL create_root_IDxDiagContainer(void)
 {
@@ -993,6 +998,140 @@ cleanup:
     IDxDiagProvider_Release(pddp);
 }
 
+static void test_DxDiag_SoundDevices(void)
+{
+    static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
+    static const WCHAR szGuidDeviceID[] = {'s','z','G','u','i','d','D','e','v','i','c','e','I','D',0};
+    static const WCHAR szDriverPath[] = {'s','z','D','r','i','v','e','r','P','a','t','h',0};
+    static const WCHAR szDriverName[] = {'s','z','D','r','i','v','e','r','N','a','m','e',0};
+
+    static const struct property_test property_tests[] =
+    {
+        {szDescription, VT_BSTR},
+        {szGuidDeviceID, VT_BSTR},
+        {szDriverName, VT_BSTR},
+        {szDriverPath, VT_BSTR},
+    };
+
+    IDxDiagContainer *sound_cont = NULL;
+    DWORD count, i;
+    HRESULT hr;
+
+    if (!create_root_IDxDiagContainer())
+    {
+        skip("Unable to create the root IDxDiagContainer\n");
+        return;
+    }
+
+    hr = IDxDiagContainer_GetChildContainer(pddc, DxDiag_SoundDevices, &sound_cont);
+    ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
+
+    if (hr != S_OK)
+        goto cleanup;
+
+    hr = IDxDiagContainer_GetNumberOfProps(sound_cont, &count);
+    ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
+    if (hr == S_OK)
+        ok(count == 0, "Expected count to be 0, got %u\n", count);
+
+    hr = IDxDiagContainer_GetNumberOfChildContainers(sound_cont, &count);
+    ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
+
+    if (hr != S_OK)
+        goto cleanup;
+
+    for (i = 0; i < count; i++)
+    {
+        WCHAR child_container[256];
+        IDxDiagContainer *child;
+
+        hr = IDxDiagContainer_EnumChildContainerNames(sound_cont, i, child_container, sizeof(child_container)/sizeof(WCHAR));
+        ok(hr == S_OK, "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
+
+        hr = IDxDiagContainer_GetChildContainer(sound_cont, child_container, &child);
+        ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
+
+        if (hr == S_OK)
+        {
+            trace("Testing container %s\n", wine_dbgstr_w(child_container));
+            test_container_properties(child, property_tests, sizeof(property_tests)/sizeof(property_tests[0]));
+        }
+        IDxDiagContainer_Release(child);
+    }
+
+cleanup:
+    if (sound_cont) IDxDiagContainer_Release(sound_cont);
+    IDxDiagContainer_Release(pddc);
+    IDxDiagProvider_Release(pddp);
+}
+
+static void test_DxDiag_SoundCaptureDevices(void)
+{
+    static const WCHAR szDescription[] = {'s','z','D','e','s','c','r','i','p','t','i','o','n',0};
+    static const WCHAR szGuidDeviceID[] = {'s','z','G','u','i','d','D','e','v','i','c','e','I','D',0};
+    static const WCHAR szDriverPath[] = {'s','z','D','r','i','v','e','r','P','a','t','h',0};
+    static const WCHAR szDriverName[] = {'s','z','D','r','i','v','e','r','N','a','m','e',0};
+
+    static const struct property_test property_tests[] =
+    {
+        {szDescription, VT_BSTR},
+        {szGuidDeviceID, VT_BSTR},
+        {szDriverName, VT_BSTR},
+        {szDriverPath, VT_BSTR},
+    };
+
+    IDxDiagContainer *sound_cont = NULL;
+    DWORD count, i;
+    HRESULT hr;
+
+    if (!create_root_IDxDiagContainer())
+    {
+        skip("Unable to create the root IDxDiagContainer\n");
+        return;
+    }
+
+    hr = IDxDiagContainer_GetChildContainer(pddc, DxDiag_SoundCaptureDevices, &sound_cont);
+    ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
+
+    if (hr != S_OK)
+        goto cleanup;
+
+    hr = IDxDiagContainer_GetNumberOfProps(sound_cont, &count);
+    ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfProps to return S_OK, got 0x%08x\n", hr);
+    if (hr == S_OK)
+        ok(count == 0, "Expected count to be 0, got %u\n", count);
+
+    hr = IDxDiagContainer_GetNumberOfChildContainers(sound_cont, &count);
+    ok(hr == S_OK, "Expected IDxDiagContainer::GetNumberOfChildContainers to return S_OK, got 0x%08x\n", hr);
+
+    if (hr != S_OK)
+        goto cleanup;
+
+    for (i = 0; i < count; i++)
+    {
+        WCHAR child_container[256];
+        IDxDiagContainer *child;
+
+        hr = IDxDiagContainer_EnumChildContainerNames(sound_cont, i, child_container, sizeof(child_container)/sizeof(WCHAR));
+        ok(hr == S_OK, "Expected IDxDiagContainer::EnumChildContainerNames to return S_OK, got 0x%08x\n", hr);
+
+        hr = IDxDiagContainer_GetChildContainer(sound_cont, child_container, &child);
+        ok(hr == S_OK, "Expected IDxDiagContainer::GetChildContainer to return S_OK, got 0x%08x\n", hr);
+
+        if (hr == S_OK)
+        {
+            trace("Testing container %s\n", wine_dbgstr_w(child_container));
+            test_container_properties(child, property_tests, sizeof(property_tests)/sizeof(property_tests[0]));
+        }
+        IDxDiagContainer_Release(child);
+    }
+
+cleanup:
+    if (sound_cont) IDxDiagContainer_Release(sound_cont);
+    IDxDiagContainer_Release(pddc);
+    IDxDiagProvider_Release(pddp);
+}
+
 START_TEST(container)
 {
     CoInitialize(NULL);
@@ -1007,5 +1146,7 @@ START_TEST(container)
     test_root_children();
     test_DxDiag_SystemInfo();
     test_DxDiag_DisplayDevices();
+    test_DxDiag_SoundDevices();
+    test_DxDiag_SoundCaptureDevices();
     CoUninitialize();
 }
-- 
2.24.0

