1 /* 2 * Copyright 2009 Maarten Lankhorst 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "wine/test.h" 20 21 #define COBJMACROS 22 23 #include "initguid.h" 24 #ifndef __REACTOS__ 25 #include "endpointvolume.h" 26 #endif 27 #include "mmdeviceapi.h" 28 #include "audioclient.h" 29 #include "audiopolicy.h" 30 #include "dshow.h" 31 #include "dsound.h" 32 #include "devpkey.h" 33 34 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); 35 36 /* Some of the QueryInterface tests are really just to check if I got the IIDs right :) */ 37 38 /* IMMDeviceCollection appears to have no QueryInterface method and instead forwards to mme */ 39 static void test_collection(IMMDeviceEnumerator *mme, IMMDeviceCollection *col) 40 { 41 IMMDeviceCollection *col2; 42 IMMDeviceEnumerator *mme2; 43 IUnknown *unk; 44 HRESULT hr; 45 ULONG ref; 46 UINT numdev; 47 IMMDevice *dev; 48 49 /* collection doesn't keep a ref on parent */ 50 IMMDeviceEnumerator_AddRef(mme); 51 ref = IMMDeviceEnumerator_Release(mme); 52 ok(ref == 2, "Reference count on parent is %u\n", ref); 53 54 ref = IMMDeviceCollection_AddRef(col); 55 IMMDeviceCollection_Release(col); 56 ok(ref == 2, "Invalid reference count %u on collection\n", ref); 57 58 hr = IMMDeviceCollection_QueryInterface(col, &IID_IUnknown, NULL); 59 ok(hr == E_POINTER, "Null ppv returns %08x\n", hr); 60 61 hr = IMMDeviceCollection_QueryInterface(col, &IID_IUnknown, (void**)&unk); 62 ok(hr == S_OK, "Cannot query for IID_IUnknown: 0x%08x\n", hr); 63 if (hr == S_OK) 64 { 65 ok((IUnknown*)col == unk, "Pointers are not identical %p/%p/%p\n", col, unk, mme); 66 IUnknown_Release(unk); 67 } 68 69 hr = IMMDeviceCollection_QueryInterface(col, &IID_IMMDeviceCollection, (void**)&col2); 70 ok(hr == S_OK, "Cannot query for IID_IMMDeviceCollection: 0x%08x\n", hr); 71 if (hr == S_OK) 72 IMMDeviceCollection_Release(col2); 73 74 hr = IMMDeviceCollection_QueryInterface(col, &IID_IMMDeviceEnumerator, (void**)&mme2); 75 ok(hr == E_NOINTERFACE, "Query for IID_IMMDeviceEnumerator returned: 0x%08x\n", hr); 76 if (hr == S_OK) 77 IMMDeviceEnumerator_Release(mme2); 78 79 hr = IMMDeviceCollection_GetCount(col, NULL); 80 ok(hr == E_POINTER, "GetCount returned 0x%08x\n", hr); 81 82 hr = IMMDeviceCollection_GetCount(col, &numdev); 83 ok(hr == S_OK, "GetCount returned 0x%08x\n", hr); 84 85 dev = (void*)(LONG_PTR)0x12345678; 86 hr = IMMDeviceCollection_Item(col, numdev, &dev); 87 ok(hr == E_INVALIDARG, "Asking for too high device returned 0x%08x\n", hr); 88 ok(dev == NULL, "Returned non-null device\n"); 89 90 if (numdev) 91 { 92 hr = IMMDeviceCollection_Item(col, 0, NULL); 93 ok(hr == E_POINTER, "Query with null pointer returned 0x%08x\n", hr); 94 95 hr = IMMDeviceCollection_Item(col, 0, &dev); 96 ok(hr == S_OK, "Valid Item returned 0x%08x\n", hr); 97 ok(dev != NULL, "Device is null!\n"); 98 if (dev != NULL) 99 { 100 char temp[128]; 101 WCHAR *id = NULL; 102 if (IMMDevice_GetId(dev, &id) == S_OK) 103 { 104 IMMDevice *dev2; 105 106 temp[sizeof(temp)-1] = 0; 107 WideCharToMultiByte(CP_ACP, 0, id, -1, temp, sizeof(temp)-1, NULL, NULL); 108 trace("Device found: %s\n", temp); 109 110 hr = IMMDeviceEnumerator_GetDevice(mme, id, &dev2); 111 ok(hr == S_OK, "GetDevice failed: %08x\n", hr); 112 113 IMMDevice_Release(dev2); 114 115 CoTaskMemFree(id); 116 } 117 } 118 if (dev) 119 IMMDevice_Release(dev); 120 } 121 IMMDeviceCollection_Release(col); 122 } 123 124 static HRESULT WINAPI notif_QueryInterface(IMMNotificationClient *iface, 125 const GUID *riid, void **obj) 126 { 127 ok(0, "Unexpected QueryInterface call\n"); 128 return E_NOTIMPL; 129 } 130 131 static ULONG WINAPI notif_AddRef(IMMNotificationClient *iface) 132 { 133 ok(0, "Unexpected AddRef call\n"); 134 return 2; 135 } 136 137 static ULONG WINAPI notif_Release(IMMNotificationClient *iface) 138 { 139 ok(0, "Unexpected Release call\n"); 140 return 1; 141 } 142 143 static HRESULT WINAPI notif_OnDeviceStateChanged(IMMNotificationClient *iface, 144 const WCHAR *device_id, DWORD new_state) 145 { 146 ok(0, "Unexpected OnDeviceStateChanged call\n"); 147 return E_NOTIMPL; 148 } 149 150 static HRESULT WINAPI notif_OnDeviceAdded(IMMNotificationClient *iface, 151 const WCHAR *device_id) 152 { 153 ok(0, "Unexpected OnDeviceAdded call\n"); 154 return E_NOTIMPL; 155 } 156 157 static HRESULT WINAPI notif_OnDeviceRemoved(IMMNotificationClient *iface, 158 const WCHAR *device_id) 159 { 160 ok(0, "Unexpected OnDeviceRemoved call\n"); 161 return E_NOTIMPL; 162 } 163 164 static HRESULT WINAPI notif_OnDefaultDeviceChanged(IMMNotificationClient *iface, 165 EDataFlow flow, ERole role, const WCHAR *device_id) 166 { 167 ok(0, "Unexpected OnDefaultDeviceChanged call\n"); 168 return E_NOTIMPL; 169 } 170 171 static HRESULT WINAPI notif_OnPropertyValueChanged(IMMNotificationClient *iface, 172 const WCHAR *device_id, const PROPERTYKEY key) 173 { 174 ok(0, "Unexpected OnPropertyValueChanged call\n"); 175 return E_NOTIMPL; 176 } 177 178 static IMMNotificationClientVtbl notif_vtbl = { 179 notif_QueryInterface, 180 notif_AddRef, 181 notif_Release, 182 notif_OnDeviceStateChanged, 183 notif_OnDeviceAdded, 184 notif_OnDeviceRemoved, 185 notif_OnDefaultDeviceChanged, 186 notif_OnPropertyValueChanged 187 }; 188 189 static IMMNotificationClient notif = { ¬if_vtbl }; 190 191 /* Only do parameter tests here, the actual MMDevice testing should be a separate test */ 192 START_TEST(mmdevenum) 193 { 194 static const WCHAR not_a_deviceW[] = {'n','o','t','a','d','e','v','i','c','e',0}; 195 196 HRESULT hr; 197 IUnknown *unk = NULL; 198 IMMDeviceEnumerator *mme, *mme2; 199 ULONG ref; 200 IMMDeviceCollection *col; 201 IMMDevice *dev; 202 203 CoInitializeEx(NULL, COINIT_MULTITHREADED); 204 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); 205 if (FAILED(hr)) 206 { 207 skip("mmdevapi not available: 0x%08x\n", hr); 208 return; 209 } 210 211 /* Odd behavior.. bug? */ 212 ref = IMMDeviceEnumerator_AddRef(mme); 213 ok(ref == 3, "Invalid reference count after incrementing: %u\n", ref); 214 IMMDeviceEnumerator_Release(mme); 215 216 hr = IMMDeviceEnumerator_QueryInterface(mme, &IID_IUnknown, (void**)&unk); 217 ok(hr == S_OK, "returned 0x%08x\n", hr); 218 if (hr != S_OK) return; 219 220 ok( (LONG_PTR)mme == (LONG_PTR)unk, "Pointers are unequal %p/%p\n", unk, mme); 221 IUnknown_Release(unk); 222 223 /* Proving that it is static.. */ 224 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme2); 225 ok(hr == S_OK, "CoCreateInstance failed: 0x%08x\n", hr); 226 IMMDeviceEnumerator_Release(mme2); 227 ok(mme == mme2, "Pointers are not equal!\n"); 228 229 hr = IMMDeviceEnumerator_QueryInterface(mme, &IID_IUnknown, NULL); 230 ok(hr == E_POINTER, "Null pointer on QueryInterface returned %08x\n", hr); 231 232 hr = IMMDeviceEnumerator_QueryInterface(mme, &GUID_NULL, (void**)&unk); 233 ok(!unk, "Unk not reset to null after invalid QI\n"); 234 ok(hr == E_NOINTERFACE, "Invalid hr %08x returned on IID_NULL\n", hr); 235 236 hr = IMMDeviceEnumerator_GetDevice(mme, not_a_deviceW, NULL); 237 ok(hr == E_POINTER, "GetDevice gave wrong error: %08x\n", hr); 238 239 hr = IMMDeviceEnumerator_GetDevice(mme, NULL, &dev); 240 ok(hr == E_POINTER, "GetDevice gave wrong error: %08x\n", hr); 241 242 hr = IMMDeviceEnumerator_GetDevice(mme, not_a_deviceW, &dev); 243 ok(hr == E_INVALIDARG, "GetDevice gave wrong error: %08x\n", hr); 244 245 col = (void*)(LONG_PTR)0x12345678; 246 hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, 0xffff, DEVICE_STATEMASK_ALL, &col); 247 ok(hr == E_INVALIDARG, "Setting invalid data flow returned 0x%08x\n", hr); 248 ok(col == NULL, "Collection pointer non-null on failure\n"); 249 250 hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATEMASK_ALL+1, &col); 251 ok(hr == E_INVALIDARG, "Setting invalid mask returned 0x%08x\n", hr); 252 253 hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATEMASK_ALL, NULL); 254 ok(hr == E_POINTER, "Invalid pointer returned: 0x%08x\n", hr); 255 256 hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATEMASK_ALL, &col); 257 ok(hr == S_OK, "Valid EnumAudioEndpoints returned 0x%08x\n", hr); 258 if (hr == S_OK) 259 { 260 ok(!!col, "Returned null pointer\n"); 261 if (col) 262 test_collection(mme, col); 263 } 264 265 hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, NULL); 266 ok(hr == E_POINTER, "RegisterEndpointNotificationCallback failed: %08x\n", hr); 267 268 hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, ¬if); 269 ok(hr == S_OK, "RegisterEndpointNotificationCallback failed: %08x\n", hr); 270 271 hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, ¬if); 272 ok(hr == S_OK, "RegisterEndpointNotificationCallback failed: %08x\n", hr); 273 274 hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, NULL); 275 ok(hr == E_POINTER, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); 276 277 hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, (IMMNotificationClient*)0xdeadbeef); 278 ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); 279 280 hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); 281 ok(hr == S_OK, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); 282 283 hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); 284 ok(hr == S_OK, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); 285 286 hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); 287 ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08x\n", hr); 288 289 IMMDeviceEnumerator_Release(mme); 290 } 291