diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index d7c5a447f1d..f9b91721790 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -27,6 +27,7 @@ #include "winnls.h" #include "winreg.h" #include "wine/debug.h" +#include "wine/list.h" #include "wine/unicode.h" #include "initguid.h" @@ -1035,20 +1036,72 @@ static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHA return E_INVALIDARG; } +struct NotificationClientWrapper { + IMMNotificationClient *client; + struct list entry; +}; + +static struct list g_notif_clients = LIST_INIT(g_notif_clients); + +static CRITICAL_SECTION g_notif_lock; +static CRITICAL_SECTION_DEBUG g_notif_lock_debug = +{ + 0, 0, &g_notif_lock, + { &g_notif_lock_debug.ProcessLocksList, &g_notif_lock_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": g_notif_lock") } +}; +static CRITICAL_SECTION g_notif_lock = { &g_notif_lock_debug, -1, 0, 0, 0, 0 }; + static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client) { MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + struct NotificationClientWrapper *wrapper; + TRACE("(%p)->(%p)\n", This, client); - FIXME("stub\n"); + + if(!client) + return E_POINTER; + + wrapper = HeapAlloc(GetProcessHeap(), 0, sizeof(*wrapper)); + if(!wrapper) + return E_OUTOFMEMORY; + + wrapper->client = client; + + EnterCriticalSection(&g_notif_lock); + + list_add_tail(&g_notif_clients, &wrapper->entry); + + LeaveCriticalSection(&g_notif_lock); + return S_OK; } static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client) { MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); + struct NotificationClientWrapper *wrapper, *wrapper2; + TRACE("(%p)->(%p)\n", This, client); - FIXME("stub\n"); - return S_OK; + + if(!client) + return E_POINTER; + + EnterCriticalSection(&g_notif_lock); + + LIST_FOR_EACH_ENTRY_SAFE(wrapper, wrapper2, &g_notif_clients, + struct NotificationClientWrapper, entry){ + if(wrapper->client == client){ + list_remove(&wrapper->entry); + HeapFree(GetProcessHeap(), 0, wrapper); + LeaveCriticalSection(&g_notif_lock); + return S_OK; + } + } + + LeaveCriticalSection(&g_notif_lock); + + return E_NOTFOUND; } static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl = diff --git a/dlls/mmdevapi/tests/mmdevenum.c b/dlls/mmdevapi/tests/mmdevenum.c index 82dda407ef1..12e21561254 100644 --- a/dlls/mmdevapi/tests/mmdevenum.c +++ b/dlls/mmdevapi/tests/mmdevenum.c @@ -118,6 +118,73 @@ static void test_collection(IMMDeviceEnumerator *mme, IMMDeviceCollection *col) IMMDeviceCollection_Release(col); } +static HRESULT WINAPI notif_QueryInterface(IMMNotificationClient *iface, + const GUID *riid, void **obj) +{ + ok(0, "Unexpected QueryInterface call\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI notif_AddRef(IMMNotificationClient *iface) +{ + ok(0, "Unexpected AddRef call\n"); + return 2; +} + +static ULONG WINAPI notif_Release(IMMNotificationClient *iface) +{ + ok(0, "Unexpected Release call\n"); + return 1; +} + +static HRESULT WINAPI notif_OnDeviceStateChanged(IMMNotificationClient *iface, + const WCHAR *device_id, DWORD new_state) +{ + ok(0, "Unexpected OnDeviceStateChanged call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI notif_OnDeviceAdded(IMMNotificationClient *iface, + const WCHAR *device_id) +{ + ok(0, "Unexpected OnDeviceAdded call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI notif_OnDeviceRemoved(IMMNotificationClient *iface, + const WCHAR *device_id) +{ + ok(0, "Unexpected OnDeviceRemoved call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI notif_OnDefaultDeviceChanged(IMMNotificationClient *iface, + EDataFlow flow, ERole role, const WCHAR *device_id) +{ + ok(0, "Unexpected OnDefaultDeviceChanged call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI notif_OnPropertyValueChanged(IMMNotificationClient *iface, + const WCHAR *device_id, const PROPERTYKEY key) +{ + ok(0, "Unexpected OnPropertyValueChanged call\n"); + return E_NOTIMPL; +} + +static IMMNotificationClientVtbl notif_vtbl = { + notif_QueryInterface, + notif_AddRef, + notif_Release, + notif_OnDeviceStateChanged, + notif_OnDeviceAdded, + notif_OnDeviceRemoved, + notif_OnDefaultDeviceChanged, + notif_OnPropertyValueChanged +}; + +static IMMNotificationClient notif = { ¬if_vtbl }; + /* Only do parameter tests here, the actual MMDevice testing should be a separate test */ START_TEST(mmdevenum) { @@ -192,5 +259,29 @@ START_TEST(mmdevenum) test_collection(mme, col); } + hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, NULL); + ok(hr == E_POINTER, "RegisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, ¬if); + ok(hr == S_OK, "RegisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, ¬if); + ok(hr == S_OK, "RegisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, NULL); + ok(hr == E_POINTER, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, (IMMNotificationClient*)0xdeadbeef); + ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); + ok(hr == S_OK, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); + ok(hr == S_OK, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); + + hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); + ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); + IMMDeviceEnumerator_Release(mme); }