Somehow the field is not present for sound capture devices, at least on my Win11.
Fixes Tom Clancy's Splinter Cell: Conviction not finding any sound devices and refusing to start.
-- v2: dxdiagn: Fill szHardwareId for sound render devices.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/dxdiagn/Makefile.in | 2 +- dlls/dxdiagn/dxdiag_main.c | 2 +- dlls/dxdiagn/dxdiag_private.h | 4 -- dlls/dxdiagn/provider.c | 73 ++++++++++++++++++++++++++++++++++ dlls/dxdiagn/tests/container.c | 1 + 5 files changed, 76 insertions(+), 6 deletions(-)
diff --git a/dlls/dxdiagn/Makefile.in b/dlls/dxdiagn/Makefile.in index da0b48b9894..e556a93f8e8 100644 --- a/dlls/dxdiagn/Makefile.in +++ b/dlls/dxdiagn/Makefile.in @@ -1,5 +1,5 @@ MODULE = dxdiagn.dll -IMPORTS = strmiids dxguid uuid d3d9 ddraw dsound version ole32 oleaut32 user32 advapi32 +IMPORTS = strmiids dxguid d3d9 ddraw dsound version ole32 oleaut32 user32 advapi32
SOURCES = \ container.c \ diff --git a/dlls/dxdiagn/dxdiag_main.c b/dlls/dxdiagn/dxdiag_main.c index 90e769cd81f..0198508fd48 100644 --- a/dlls/dxdiagn/dxdiag_main.c +++ b/dlls/dxdiagn/dxdiag_main.c @@ -23,13 +23,13 @@
#include <stdarg.h>
+#include "initguid.h" #include "windef.h" #include "winbase.h" #include "objbase.h" #include "oleauto.h" #include "oleidl.h" #include "rpcproxy.h" -#include "initguid.h" #include "dxdiag_private.h" #include "wine/debug.h"
diff --git a/dlls/dxdiagn/dxdiag_private.h b/dlls/dxdiagn/dxdiag_private.h index 5f4b7c28fd0..5c5f51e7bb5 100644 --- a/dlls/dxdiagn/dxdiag_private.h +++ b/dlls/dxdiagn/dxdiag_private.h @@ -23,10 +23,6 @@
#include <stdarg.h>
-#include "windef.h" -#include "winbase.h" -#include "wingdi.h" - #include "wine/list.h" #include "dxdiag.h" #include "resource.h" diff --git a/dlls/dxdiagn/provider.c b/dlls/dxdiagn/provider.c index 05fe76849a2..88011ac87d2 100644 --- a/dlls/dxdiagn/provider.c +++ b/dlls/dxdiagn/provider.c @@ -31,6 +31,7 @@ #include "d3d9.h" #include "strmif.h" #include "initguid.h" +#include "mmdeviceapi.h" #include "wine/fil_data.h" #include "psapi.h" #include "wbemcli.h" @@ -1242,6 +1243,7 @@ static HRESULT build_displaydevices_tree(IDxDiagContainerImpl_Container *node) struct enum_context { IDxDiagContainerImpl_Container *cont; + IMMDeviceCollection *devices; HRESULT hr; int index; }; @@ -1261,6 +1263,7 @@ BOOL CALLBACK dsound_enum(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID cont IDxDiagContainerImpl_Container *device; WCHAR buffer[256]; const WCHAR *p, *name; + UINT32 i, count;
/* the default device is enumerated twice, one time without GUID */ if (!guid) return TRUE; @@ -1296,6 +1299,62 @@ BOOL CALLBACK dsound_enum(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID cont if (FAILED(enum_ctx->hr)) return FALSE;
+ if (enum_ctx->devices && SUCCEEDED(IMMDeviceCollection_GetCount(enum_ctx->devices, &count))) + { + static const PROPERTYKEY devicepath_key = + { + {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2 + }; + IPropertyStore *ps; + WCHAR *start, *end; + IMMDevice *mmdev; + PROPVARIANT pv; + HRESULT hr; + + for (i = 0; i < count; ++i) + { + mmdev = NULL; + ps = NULL; + hr = IMMDeviceCollection_Item(enum_ctx->devices, i, &mmdev); + if (SUCCEEDED(hr)) + hr = IMMDevice_OpenPropertyStore(mmdev, STGM_READ, &ps); + PropVariantInit(&pv); + if (SUCCEEDED(hr)) + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&PKEY_AudioEndpoint_GUID, &pv); + if (SUCCEEDED(hr)) + { + StringFromGUID2(guid, buffer, ARRAY_SIZE(buffer)); + hr = pv.vt == VT_LPWSTR && !wcsicmp(buffer, pv.pwszVal) ? S_OK : E_FAIL; + PropVariantClear(&pv); + } + PropVariantInit(&pv); + if (SUCCEEDED(hr)) + hr = IPropertyStore_GetValue(ps, &devicepath_key, &pv); + if (SUCCEEDED(hr) && pv.vt == VT_LPWSTR) + { + if ((start = wcsstr(pv.pwszVal, L"}."))) + start += 2; + else + start = pv.pwszVal; + if (wcsnicmp(start, L"ROOT", 4) && (end = wcschr(start, '\')) && (end = wcschr(end + 1, '\')) + && end - start < ARRAY_SIZE(buffer)) + { + memcpy(buffer, start, (end - start) * sizeof(WCHAR)); + buffer[end - start] = 0; + start = buffer; + } + add_bstr_property(device, L"szHardwareID", start); + PropVariantClear(&pv); + } + if (ps) + IPropertyStore_Release(ps); + if (mmdev) + IMMDevice_Release(mmdev); + if (SUCCEEDED(hr)) + break; + } + } + enum_ctx->index++; return TRUE; } @@ -1304,6 +1363,7 @@ static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node) { struct enum_context enum_ctx; IDxDiagContainerImpl_Container *cont; + IMMDeviceEnumerator *mmdevenum;
cont = allocate_information_node(L"DxDiag_SoundDevices"); if (!cont) @@ -1315,7 +1375,20 @@ static HRESULT build_directsound_tree(IDxDiagContainerImpl_Container *node) enum_ctx.hr = S_OK; enum_ctx.index = 0;
+ enum_ctx.devices = NULL; + if (SUCCEEDED(CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, + (void **)&mmdevenum))) + { + IMMDeviceEnumerator_EnumAudioEndpoints(mmdevenum, eAll, DEVICE_STATE_ACTIVE, &enum_ctx.devices); + IMMDeviceEnumerator_Release(mmdevenum); + } + DirectSoundEnumerateW(dsound_enum, &enum_ctx); + if (enum_ctx.devices) + { + IMMDeviceCollection_Release(enum_ctx.devices); + enum_ctx.devices = NULL; + } if (FAILED(enum_ctx.hr)) return enum_ctx.hr;
diff --git a/dlls/dxdiagn/tests/container.c b/dlls/dxdiagn/tests/container.c index 146c83070d8..c511b9da672 100644 --- a/dlls/dxdiagn/tests/container.c +++ b/dlls/dxdiagn/tests/container.c @@ -945,6 +945,7 @@ static void test_DxDiag_SoundDevices(void) {L"szGuidDeviceID", VT_BSTR}, {L"szDriverName", VT_BSTR}, {L"szDriverPath", VT_BSTR}, + {L"szHardwareID", VT_BSTR}, };
IDxDiagContainer *sound_cont = NULL;
v2: - remove a double ';'.