[PATCH v3 0/4] MR9915: mmedvapi: Device name changes.
The test in the last commit would still need an implementation, which turned out to be more complicated than the possible benefits. -- v3: mmdevapi/tests: Test for DEVPKEY_Device_FriendlyName in the registry. mmdevapi: Adjust device names. mmdevapi/tests: Check device friendly name pattern. mmdevapi/tests: Simplify a trace. https://gitlab.winehq.org/wine/wine/-/merge_requests/9915
From: Bernhard Kölbl <bkoelbl@codeweavers.com> --- dlls/mmdevapi/tests/propstore.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/mmdevapi/tests/propstore.c b/dlls/mmdevapi/tests/propstore.c index b333a556567..284e8b94368 100644 --- a/dlls/mmdevapi/tests/propstore.c +++ b/dlls/mmdevapi/tests/propstore.c @@ -43,15 +43,12 @@ static void test_propertystore(IPropertyStore *store) const WAVEFORMATEXTENSIBLE *format; HRESULT hr; PROPVARIANT pv; - char temp[128]; - temp[sizeof(temp)-1] = 0; pv.vt = VT_EMPTY; hr = IPropertyStore_GetValue(store, &PKEY_AudioEndpoint_GUID, &pv); ok(hr == S_OK, "Failed with %08lx\n", hr); ok(pv.vt == VT_LPWSTR, "Value should be %i, is %i\n", VT_LPWSTR, pv.vt); - WideCharToMultiByte(CP_ACP, 0, pv.pwszVal, -1, temp, sizeof(temp)-1, NULL, NULL); - trace("guid: %s\n", temp); + trace("guid: %s\n", debugstr_w(pv.pwszVal)); PropVariantClear(&pv); pv.vt = VT_EMPTY; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9915
From: Bernhard Kölbl <bkoelbl@codeweavers.com> --- dlls/mmdevapi/tests/propstore.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dlls/mmdevapi/tests/propstore.c b/dlls/mmdevapi/tests/propstore.c index 284e8b94368..51d87592c55 100644 --- a/dlls/mmdevapi/tests/propstore.c +++ b/dlls/mmdevapi/tests/propstore.c @@ -41,8 +41,9 @@ static const WCHAR software_renderW[] = static void test_propertystore(IPropertyStore *store) { const WAVEFORMATEXTENSIBLE *format; + WCHAR temp[256] = { 0 }; + PROPVARIANT pv, pv2; HRESULT hr; - PROPVARIANT pv; pv.vt = VT_EMPTY; hr = IPropertyStore_GetValue(store, &PKEY_AudioEndpoint_GUID, &pv); @@ -55,6 +56,22 @@ static void test_propertystore(IPropertyStore *store) hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); ok(hr == S_OK, "Failed with %08lx\n", hr); ok(pv.vt == VT_LPWSTR && pv.pwszVal, "FriendlyName value had wrong type: 0x%x or was NULL\n", pv.vt); + + pv2.vt = VT_EMPTY; + hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv2); + ok(hr == S_OK, "Failed with %#lx\n", hr); + ok(pv2.vt == VT_LPWSTR && pv2.pwszVal, "Device_DeviceDesc value had wrong type: %#x or was NULL\n", pv2.vt); + + swprintf(temp, ARRAY_SIZE(temp), L"%ls (%ls)", pv2.pwszVal, pv.pwszVal); + + PropVariantClear(&pv); + PropVariantClear(&pv2); + + pv.vt = VT_EMPTY; + hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + ok(hr == S_OK, "Failed with %#lx\n", hr); + ok(pv.vt == VT_LPWSTR && pv.pwszVal, "Device_FriendlyName value had wrong type: %#x or was NULL\n", pv.vt); + todo_wine ok(!wcscmp(temp, pv.pwszVal), "Expected Device_FriendlyName %s, but got %s\n", debugstr_w(temp), debugstr_w(pv.pwszVal)); PropVariantClear(&pv); pv.vt = VT_EMPTY; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9915
From: Bernhard Kölbl <bkoelbl@codeweavers.com> --- dlls/mmdevapi/devenum.c | 17 ++++++++++++++++- dlls/mmdevapi/tests/propstore.c | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index d147d246636..66d950854fd 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -496,7 +496,9 @@ static MMDevice *MMDevice_Create(const WCHAR *name, GUID *id, EDataFlow flow, DW RegSetValueExW(key, L"DeviceState", 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD)); if (!RegCreateKeyExW(key, L"Properties", 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) { + const WCHAR *type = L"Other Device"; PROPVARIANT pv; + DWORD len; pv.vt = VT_LPWSTR; pv.pwszVal = cur->drv_id; @@ -515,10 +517,23 @@ static MMDevice *MMDevice_Create(const WCHAR *name, GUID *id, EDataFlow flow, DW PropVariantClear(&pv2); } - MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); + + if (flow == eCapture) + type = L"Microphone"; + else if (flow == eRender) + type = L"Speakers"; + + pv.pwszVal = (LPWSTR)type; MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv); + len = (wcslen(type) + wcslen(cur->drv_id) + wcslen(L" ()") + 1) * sizeof(WCHAR); + pv.vt = VT_LPWSTR; + pv.pwszVal = CoTaskMemAlloc(len); + swprintf(pv.pwszVal, len, L"%ls (%ls)", type, cur->drv_id); + MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + CoTaskMemFree(pv.pwszVal); + pv.pwszVal = guidstr; MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv); diff --git a/dlls/mmdevapi/tests/propstore.c b/dlls/mmdevapi/tests/propstore.c index 51d87592c55..5c15ba24aee 100644 --- a/dlls/mmdevapi/tests/propstore.c +++ b/dlls/mmdevapi/tests/propstore.c @@ -71,7 +71,7 @@ static void test_propertystore(IPropertyStore *store) hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); ok(hr == S_OK, "Failed with %#lx\n", hr); ok(pv.vt == VT_LPWSTR && pv.pwszVal, "Device_FriendlyName value had wrong type: %#x or was NULL\n", pv.vt); - todo_wine ok(!wcscmp(temp, pv.pwszVal), "Expected Device_FriendlyName %s, but got %s\n", debugstr_w(temp), debugstr_w(pv.pwszVal)); + ok(!wcscmp(temp, pv.pwszVal), "Expected Device_FriendlyName %s, but got %s\n", debugstr_w(temp), debugstr_w(pv.pwszVal)); PropVariantClear(&pv); pv.vt = VT_EMPTY; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9915
From: Bernhard Kölbl <bkoelbl@codeweavers.com> --- dlls/mmdevapi/tests/propstore.c | 41 +++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/dlls/mmdevapi/tests/propstore.c b/dlls/mmdevapi/tests/propstore.c index 5c15ba24aee..18024428102 100644 --- a/dlls/mmdevapi/tests/propstore.c +++ b/dlls/mmdevapi/tests/propstore.c @@ -37,6 +37,8 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); static const WCHAR software_renderW[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Render"; +static const WCHAR software_captureW[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Capture"; static void test_propertystore(IPropertyStore *store) { @@ -147,19 +149,21 @@ static void test_getat(IPropertyStore *store) ok(found_desc, "DEVPKEY_Device_DeviceDesc not found\n"); } -static void test_setvalue_on_wow64(IPropertyStore *store) +static void test_setvalue_on_wow64(IPropertyStore *store, EDataFlow data_flow) { PROPVARIANT pv; HRESULT hr; LONG ret; - WCHAR *guidW; + WCHAR *guidW, value[128]; HKEY root, props, devkey; DWORD type, regval, size; static const PROPERTYKEY PKEY_Bogus = { {0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x00}}, 0x7f }; + static const WCHAR friendly_nameW[] = L"{A45C254E-DF1C-4EFD-8020-67D146A850E0},14"; static const WCHAR bogusW[] = L"{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F00},127"; + const WCHAR *rootW = data_flow ? software_captureW : software_renderW; PropVariantInit(&pv); @@ -187,7 +191,7 @@ static void test_setvalue_on_wow64(IPropertyStore *store) ok(pv.ulVal == 0xAB, "Got wrong value: 0x%lx\n", pv.ulVal); /* should find the key in 64-bit view */ - ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, software_renderW, 0, KEY_READ|KEY_WOW64_64KEY, &root); + ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, rootW, 0, KEY_READ|KEY_WOW64_64KEY, &root); ok(ret == ERROR_SUCCESS, "Couldn't open mmdevices Render key: %lu\n", ret); ret = RegOpenKeyExW(root, guidW, 0, KEY_READ|KEY_WOW64_64KEY, &devkey); @@ -203,6 +207,25 @@ static void test_setvalue_on_wow64(IPropertyStore *store) ok(type == REG_DWORD, "Got wrong value type: %lu\n", type); ok(regval == 0xAB, "Got wrong value: 0x%lx\n", regval); + /* DEVPKEY_Device_FriendlyName won't be stored in the registry. */ + pv.vt = VT_EMPTY; + hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + ok(hr == S_OK, "IPropertyStore_GetValue failed with %#lx\n", hr); + ok(pv.vt == VT_LPWSTR && pv.pwszVal, "DeviceInterface_FriendlyName returned incorrect type %#x\n", pv.vt); + + size = ARRAY_SIZE(value); + ret = RegQueryValueExW(props, friendly_nameW, NULL, NULL, (BYTE *)&value, &size); + todo_wine ok(ret == ERROR_FILE_NOT_FOUND, "RegQueryValueExW returned unexpected value %lu\n", ret); + + pv.vt = VT_LPWSTR; + pv.pwszVal = (WCHAR *)L"FooBar"; + hr = IPropertyStore_SetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + todo_wine ok(hr == E_ACCESSDENIED, "IPropertyStore_SetValue failed with %#lx\n", hr); + + size = ARRAY_SIZE(value); + ret = RegQueryValueExW(props, friendly_nameW, NULL, NULL, (BYTE *)&value, &size); + todo_wine ok(ret == ERROR_FILE_NOT_FOUND, "RegQueryValueExW returned unexpected value %lu\n", ret); + RegCloseKey(props); RegCloseKey(devkey); RegCloseKey(root); @@ -235,13 +258,15 @@ START_TEST(propstore) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); ok(hr == S_OK, "Got hr %#lx.\n", hr); - hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eRender, DEVICE_STATE_ACTIVE, &collection); + hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATE_ACTIVE, &collection); ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IMMDeviceCollection_GetCount(collection, &count); ok(hr == S_OK, "Got hr %#lx.\n", hr); for (i = 0; i < count; ++i) { + IMMEndpoint *endpoint; + EDataFlow data_flow; IMMDevice *dev; hr = IMMDeviceCollection_Item(collection, i, &dev); @@ -265,12 +290,18 @@ START_TEST(propstore) hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &store); ok(hr == S_OK, "Opening valid store returned %08lx\n", hr); + hr = IMMDevice_QueryInterface(dev, &IID_IMMEndpoint, (void **)&endpoint); + ok(hr == S_OK, "IMMDevice_QueryInterface returned %#lx\n", hr); + hr = IMMEndpoint_GetDataFlow(endpoint, &data_flow); + ok(hr == S_OK, "IMMEndpoint_GetDataFlow returned %#lx\n", hr); + test_propertystore(store); test_deviceinterface(store); test_getat(store); if (is_wow64) - test_setvalue_on_wow64(store); + test_setvalue_on_wow64(store, data_flow); + IMMEndpoint_Release(endpoint); IPropertyStore_Release(store); IMMDevice_Release(dev); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9915
Paul Gofman (@gofman) commented about dlls/mmdevapi/tests/propstore.c:
ok(type == REG_DWORD, "Got wrong value type: %lu\n", type); ok(regval == 0xAB, "Got wrong value: 0x%lx\n", regval);
+ /* DEVPKEY_Device_FriendlyName won't be stored in the registry. */ + pv.vt = VT_EMPTY; + hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); + ok(hr == S_OK, "IPropertyStore_GetValue failed with %#lx\n", hr); + ok(pv.vt == VT_LPWSTR && pv.pwszVal, "DeviceInterface_FriendlyName returned incorrect type %#x\n", pv.vt); + + size = ARRAY_SIZE(value); + ret = RegQueryValueExW(props, friendly_nameW, NULL, NULL, (BYTE *)&value, &size); + todo_wine ok(ret == ERROR_FILE_NOT_FOUND, "RegQueryValueExW returned unexpected value %lu\n", ret); + + pv.vt = VT_LPWSTR; + pv.pwszVal = (WCHAR *)L"FooBar"; + hr = IPropertyStore_SetValue(store, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv);
I'd suggest to drop this test. If that ever succeeds (like probably currently in Wine) or maybe with admin rights on Windows (not sure though if that can actually happen in default setups, probably would need changing ownership of reg keys) that may mess audio device setup. While what is tested here is not related to what functional changes are about anyway. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9915#note_127410
Paul Gofman (@gofman) commented about dlls/mmdevapi/devenum.c:
PropVariantClear(&pv2); }
- MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); + + if (flow == eCapture) + type = L"Microphone"; + else if (flow == eRender) + type = L"Speakers"; + + pv.pwszVal = (LPWSTR)type;
Extra type variable looks excessive, also flow can be only eRender or eCapture here. So probably just ```pv.pwszVal = (LPWSTR)(flow == eCapture ? L"Microphone" : L"Speakers")```? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9915#note_127413
On Tue Jan 20 15:50:18 2026 +0000, Paul Gofman wrote:
Extra type variable looks excessive, also flow can be only eRender or eCapture here. So probably just ```pv.pwszVal = (LPWSTR)(flow == eCapture ? L"Microphone" : L"Speakers")```? Oh, I see type is used below, so nvm then (while can still probably drop "Other type").
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9915#note_127414
On Tue Jan 20 15:45:12 2026 +0000, Paul Gofman wrote:
I'd suggest to drop this test. If that ever succeeds (like probably currently in Wine) or maybe with admin rights on Windows (not sure though if that can actually happen in default setups, probably would need changing ownership of reg keys) that may mess audio device setup. While what is tested here is not related to what functional changes are about anyway. sure
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9915#note_127416
participants (3)
-
Bernhard Kölbl -
Bernhard Kölbl (@besentv) -
Paul Gofman (@gofman)