static void hotplug_uninit(struct ao *ao) { MP_DBG(ao, "Hotplug uninit\n"); struct wasapi_state *state = ao->priv; wasapi_change_uninit(ao); SAFE_RELEASE(state->pEnumerator, IMMDeviceEnumerator_Release(state->pEnumerator)); CoUninitialize(); }
void wasapi_change_uninit(struct ao *ao) { struct wasapi_state *state = ao->priv; struct change_notify *change = &state->change; if (change->pEnumerator && change->client.lpVtbl) { IMMDeviceEnumerator_UnregisterEndpointNotificationCallback( change->pEnumerator, (IMMNotificationClient *)change); } SAFE_RELEASE(change->pEnumerator, IMMDeviceEnumerator_Release(change->pEnumerator)); }
static void apply_speaker_configs(void) { UINT i; IMMDeviceEnumerator *devenum; IMMDevice *dev; IPropertyStore *ps; PROPVARIANT pv; HRESULT hr; hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&devenum); if(FAILED(hr)){ ERR("Unable to create MMDeviceEnumerator: 0x%08x\n", hr); return; } PropVariantInit(&pv); pv.vt = VT_UI4; for (i = 0; i < num_render_devs; i++) { hr = IMMDeviceEnumerator_GetDevice(devenum, render_devs[i].id, &dev); if(FAILED(hr)){ WARN("Could not get MMDevice for %s: 0x%08x\n", wine_dbgstr_w(render_devs[i].id), hr); continue; } hr = IMMDevice_OpenPropertyStore(dev, STGM_WRITE, &ps); if(FAILED(hr)){ WARN("Could not open property store for %s: 0x%08x\n", wine_dbgstr_w(render_devs[i].id), hr); IMMDevice_Release(dev); continue; } pv.u.ulVal = speaker_configs[render_devs[i].speaker_config].speaker_mask; hr = IPropertyStore_SetValue(ps, &PKEY_AudioEndpoint_PhysicalSpeakers, &pv); if (FAILED(hr)) WARN("IPropertyStore_SetValue failed for %s: 0x%08x\n", wine_dbgstr_w(render_devs[i].id), hr); IPropertyStore_Release(ps); IMMDevice_Release(dev); } IMMDeviceEnumerator_Release(devenum); }
JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_wasapi_WASAPI_IMMDeviceEnumerator_1Release (JNIEnv *env, jclass clazz, jlong thiz) { IMMDeviceEnumerator *iMMDeviceEnumerator = (IMMDeviceEnumerator *) (intptr_t) thiz; /* * There is statically allocated IMMNotificationClient instance which is to * be registered with every IMMDeviceEnumerator instance. */ IMMDeviceEnumerator_UnregisterEndpointNotificationCallback( iMMDeviceEnumerator, (IMMNotificationClient *) &WASAPI_iMMNotificationClient); IMMDeviceEnumerator_Release(iMMDeviceEnumerator); }
static void test_first_device(void) { IMMDeviceEnumerator *devenum; IMMDevice *defdev; IPropertyStore *ps; PROPVARIANT pv; HRESULT hr; hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&devenum); if(FAILED(hr)){ win_skip("MMDevAPI is not available, skipping default device test\n"); return; } hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, eMultimedia, &defdev); if (hr == E_NOTFOUND) { win_skip("No default device found\n"); return; } ok(hr == S_OK, "GetDefaultAudioEndpoint failed: %08x\n", hr); hr = IMMDevice_OpenPropertyStore(defdev, STGM_READ, &ps); ok(hr == S_OK, "OpenPropertyStore failed: %08x\n", hr); PropVariantInit(&pv); hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv); ok(hr == S_OK, "GetValue failed: %08x\n", hr); CLSIDFromString(pv.u.pwszVal, &default_info.guid); PropVariantClear(&pv); IPropertyStore_Release(ps); IMMDevice_Release(defdev); IMMDeviceEnumerator_Release(devenum); hr = pDirectSoundEnumerateA(&default_device_cb, NULL); ok(hr == S_OK, "DirectSoundEnumerateA failed: %08x\n", hr); }
/* The MMDeviceEnumerator object has to be created & destroyed * from the same thread. */ static DWORD WINAPI devenum_thread_proc(void *arg) { HANDLE evt = arg; HRESULT hr; MSG msg; hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if(FAILED(hr)){ ERR("CoInitializeEx failed: %08x\n", hr); return 1; } hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&g_devenum); if(FAILED(hr)){ ERR("CoCreateInstance failed: %08x\n", hr); CoUninitialize(); return 1; } SetEvent(evt); PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); while(GetMessageW(&msg, NULL, 0, 0)){ if(msg.hwnd) DispatchMessageW(&msg); else ERR("Unknown message: %04x\n", msg.message); } IMMDeviceEnumerator_Release(g_devenum); g_devenum = NULL; CoUninitialize(); return 0; }
static void release_mmdevenum(IMMDeviceEnumerator *devenum, HRESULT init_hr) { IMMDeviceEnumerator_Release(devenum); if(SUCCEEDED(init_hr)) CoUninitialize(); }
static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr) { ThreadRequest *req = ptr; IMMDeviceEnumerator *Enumerator; ALuint deviceCount = 0; ALCmmdevProxy *proxy; HRESULT hr, cohr; MSG msg; TRACE("Starting message thread\n"); cohr = CoInitialize(NULL); if(FAILED(cohr)) { WARN("Failed to initialize COM: 0x%08lx\n", cohr); ReturnMsgResponse(req, cohr); return 0; } hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); if(FAILED(hr)) { WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); CoUninitialize(); ReturnMsgResponse(req, hr); return 0; } Enumerator = ptr; IMMDeviceEnumerator_Release(Enumerator); Enumerator = NULL; CoUninitialize(); /* HACK: Force Windows to create a message queue for this thread before * returning success, otherwise PostThreadMessage may fail if it gets * called before GetMessage. */ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); TRACE("Message thread initialization complete\n"); ReturnMsgResponse(req, S_OK); TRACE("Starting message loop\n"); while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last)) { TRACE("Got message %u\n", msg.message); switch(msg.message) { case WM_USER_OpenDevice: req = (ThreadRequest*)msg.wParam; proxy = (ALCmmdevProxy*)msg.lParam; hr = cohr = S_OK; if(++deviceCount == 1) hr = cohr = CoInitialize(NULL); if(SUCCEEDED(hr)) hr = V0(proxy,openProxy)(); if(FAILED(hr)) { if(--deviceCount == 0 && SUCCEEDED(cohr)) CoUninitialize(); } ReturnMsgResponse(req, hr); continue; case WM_USER_ResetDevice: req = (ThreadRequest*)msg.wParam; proxy = (ALCmmdevProxy*)msg.lParam; hr = V0(proxy,resetProxy)(); ReturnMsgResponse(req, hr); continue; case WM_USER_StartDevice: req = (ThreadRequest*)msg.wParam; proxy = (ALCmmdevProxy*)msg.lParam; hr = V0(proxy,startProxy)(); ReturnMsgResponse(req, hr); continue; case WM_USER_StopDevice: req = (ThreadRequest*)msg.wParam; proxy = (ALCmmdevProxy*)msg.lParam; V0(proxy,stopProxy)(); ReturnMsgResponse(req, S_OK); continue; case WM_USER_CloseDevice: req = (ThreadRequest*)msg.wParam; proxy = (ALCmmdevProxy*)msg.lParam; V0(proxy,closeProxy)(); if(--deviceCount == 0) CoUninitialize(); ReturnMsgResponse(req, S_OK); continue; case WM_USER_Enumerate: req = (ThreadRequest*)msg.wParam; hr = cohr = S_OK; if(++deviceCount == 1) hr = cohr = CoInitialize(NULL); if(SUCCEEDED(hr)) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { Enumerator = ptr; if(msg.lParam == ALL_DEVICE_PROBE) hr = probe_devices(Enumerator, eRender, &PlaybackDevices); else if(msg.lParam == CAPTURE_DEVICE_PROBE) hr = probe_devices(Enumerator, eCapture, &CaptureDevices); IMMDeviceEnumerator_Release(Enumerator); Enumerator = NULL; } if(--deviceCount == 0 && SUCCEEDED(cohr)) CoUninitialize(); ReturnMsgResponse(req, hr); continue; default: ERR("Unexpected message: %u\n", msg.message); continue; } } TRACE("Message loop finished\n"); return 0; }
static void initAudioDlg (HWND hDlg) { WCHAR display_str[256], format_str[256], sysdefault_str[256], disabled_str[64]; IMMDeviceEnumerator *devenum; BOOL have_driver = FALSE; HRESULT hr; UINT i; WINE_TRACE("\n"); LoadStringW(GetModuleHandleW(NULL), IDS_AUDIO_DRIVER, format_str, sizeof(format_str) / sizeof(*format_str)); LoadStringW(GetModuleHandleW(NULL), IDS_AUDIO_DRIVER_NONE, disabled_str, sizeof(disabled_str) / sizeof(*disabled_str)); LoadStringW(GetModuleHandleW(NULL), IDS_AUDIO_SYSDEFAULT, sysdefault_str, sizeof(sysdefault_str) / sizeof(*sysdefault_str)); hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&devenum); if(SUCCEEDED(hr)){ PROPVARIANT pv; load_devices(devenum, eRender, &num_render_devs, &render_devs); load_devices(devenum, eCapture, &num_capture_devs, &capture_devs); PropVariantInit(&pv); if(get_driver_name(devenum, &pv) && pv.u.pwszVal[0] != '\0'){ have_driver = TRUE; wnsprintfW(display_str, sizeof(display_str) / sizeof(*display_str), format_str, pv.u.pwszVal); lstrcatW(g_drv_keyW, pv.u.pwszVal); } PropVariantClear(&pv); IMMDeviceEnumerator_Release(devenum); } SendDlgItemMessageW(hDlg, IDC_AUDIOOUT_DEVICE, CB_ADDSTRING, 0, (LPARAM)sysdefault_str); SendDlgItemMessageW(hDlg, IDC_AUDIOOUT_DEVICE, CB_SETCURSEL, 0, 0); SendDlgItemMessageW(hDlg, IDC_VOICEOUT_DEVICE, CB_ADDSTRING, 0, (LPARAM)sysdefault_str); SendDlgItemMessageW(hDlg, IDC_VOICEOUT_DEVICE, CB_SETCURSEL, 0, 0); SendDlgItemMessageW(hDlg, IDC_AUDIOIN_DEVICE, CB_ADDSTRING, 0, (LPARAM)sysdefault_str); SendDlgItemMessageW(hDlg, IDC_AUDIOIN_DEVICE, CB_SETCURSEL, 0, 0); SendDlgItemMessageW(hDlg, IDC_VOICEIN_DEVICE, CB_ADDSTRING, 0, (LPARAM)sysdefault_str); SendDlgItemMessageW(hDlg, IDC_VOICEIN_DEVICE, CB_SETCURSEL, 0, 0); i = 0; while (speaker_configs[i].text_id != 0) { WCHAR speaker_str[256]; LoadStringW(GetModuleHandleW(NULL), speaker_configs[i].text_id, speaker_str, sizeof(speaker_str) / sizeof(*speaker_str)); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_SPEAKERS, CB_ADDSTRING, 0, (LPARAM)speaker_str); i++; } if(have_driver){ WCHAR *reg_out_dev, *reg_vout_dev, *reg_in_dev, *reg_vin_dev; BOOL default_dev_found = FALSE; reg_out_dev = get_reg_keyW(HKEY_CURRENT_USER, g_drv_keyW, reg_out_nameW, NULL); reg_vout_dev = get_reg_keyW(HKEY_CURRENT_USER, g_drv_keyW, reg_vout_nameW, NULL); reg_in_dev = get_reg_keyW(HKEY_CURRENT_USER, g_drv_keyW, reg_in_nameW, NULL); reg_vin_dev = get_reg_keyW(HKEY_CURRENT_USER, g_drv_keyW, reg_vin_nameW, NULL); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_DEVICE, CB_SETCURSEL, i, 0); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_SPEAKERS, CB_SETCURSEL, render_devs[i].speaker_config, 0); for(i = 0; i < num_render_devs; ++i){ if(!render_devs[i].id) continue; SendDlgItemMessageW(hDlg, IDC_AUDIOOUT_DEVICE, CB_ADDSTRING, 0, (LPARAM)render_devs[i].name.u.pwszVal); SendDlgItemMessageW(hDlg, IDC_AUDIOOUT_DEVICE, CB_SETITEMDATA, i + 1, (LPARAM)&render_devs[i]); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_DEVICE, CB_ADDSTRING, 0, (LPARAM)render_devs[i].name.u.pwszVal); if(reg_out_dev && !lstrcmpW(render_devs[i].id, reg_out_dev)){ SendDlgItemMessageW(hDlg, IDC_AUDIOOUT_DEVICE, CB_SETCURSEL, i + 1, 0); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_DEVICE, CB_SETCURSEL, i, 0); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_SPEAKERS, CB_SETCURSEL, render_devs[i].speaker_config, 0); default_dev_found = TRUE; } SendDlgItemMessageW(hDlg, IDC_VOICEOUT_DEVICE, CB_ADDSTRING, 0, (LPARAM)render_devs[i].name.u.pwszVal); SendDlgItemMessageW(hDlg, IDC_VOICEOUT_DEVICE, CB_SETITEMDATA, i + 1, (LPARAM)&render_devs[i]); if(reg_vout_dev && !lstrcmpW(render_devs[i].id, reg_vout_dev)) SendDlgItemMessageW(hDlg, IDC_VOICEOUT_DEVICE, CB_SETCURSEL, i + 1, 0); } if(!default_dev_found && num_render_devs > 0){ SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_DEVICE, CB_SETCURSEL, 0, 0); SendDlgItemMessageW(hDlg, IDC_SPEAKERCONFIG_SPEAKERS, CB_SETCURSEL, render_devs[0].speaker_config, 0); } for(i = 0; i < num_capture_devs; ++i){ if(!capture_devs[i].id) continue; SendDlgItemMessageW(hDlg, IDC_AUDIOIN_DEVICE, CB_ADDSTRING, 0, (LPARAM)capture_devs[i].name.u.pwszVal); SendDlgItemMessageW(hDlg, IDC_AUDIOIN_DEVICE, CB_SETITEMDATA, i + 1, (LPARAM)&capture_devs[i]); if(reg_in_dev && !lstrcmpW(capture_devs[i].id, reg_in_dev)) SendDlgItemMessageW(hDlg, IDC_AUDIOIN_DEVICE, CB_SETCURSEL, i + 1, 0); SendDlgItemMessageW(hDlg, IDC_VOICEIN_DEVICE, CB_ADDSTRING, 0, (LPARAM)capture_devs[i].name.u.pwszVal); SendDlgItemMessageW(hDlg, IDC_VOICEIN_DEVICE, CB_SETITEMDATA, i + 1, (LPARAM)&capture_devs[i]); if(reg_vin_dev && !lstrcmpW(capture_devs[i].id, reg_vin_dev)) SendDlgItemMessageW(hDlg, IDC_VOICEIN_DEVICE, CB_SETCURSEL, i + 1, 0); } HeapFree(GetProcessHeap(), 0, reg_out_dev); HeapFree(GetProcessHeap(), 0, reg_vout_dev); HeapFree(GetProcessHeap(), 0, reg_in_dev); HeapFree(GetProcessHeap(), 0, reg_vin_dev); }else wnsprintfW(display_str, sizeof(display_str) / sizeof(*display_str), format_str, disabled_str); SetDlgItemTextW(hDlg, IDC_AUDIO_DRIVER, display_str); }
static DWORD CALLBACK MMDevApiMsgProc(void *ptr) { ThreadRequest *req = ptr; IMMDeviceEnumerator *Enumerator; ALuint deviceCount = 0; MMDevApiData *data; ALCdevice *device; HRESULT hr, cohr; MSG msg; TRACE("Starting message thread\n"); cohr = CoInitialize(NULL); if(FAILED(cohr)) { WARN("Failed to initialize COM: 0x%08lx\n", cohr); req->result = cohr; SetEvent(req->FinishedEvt); return 0; } hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); if(FAILED(hr)) { WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); CoUninitialize(); req->result = hr; SetEvent(req->FinishedEvt); return 0; } Enumerator = ptr; IMMDeviceEnumerator_Release(Enumerator); Enumerator = NULL; CoUninitialize(); req->result = S_OK; SetEvent(req->FinishedEvt); TRACE("Starting message loop\n"); while(GetMessage(&msg, NULL, 0, 0)) { TRACE("Got message %u\n", msg.message); switch(msg.message) { case WM_USER_OpenDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; data = device->ExtraData; hr = cohr = S_OK; if(++deviceCount == 1) hr = cohr = CoInitialize(NULL); if(SUCCEEDED(hr)) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { Enumerator = ptr; if(!data->devid) hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev); else hr = IMMDeviceEnumerator_GetDevice(Enumerator, data->devid, &data->mmdev); IMMDeviceEnumerator_Release(Enumerator); Enumerator = NULL; } if(SUCCEEDED(hr)) hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); if(SUCCEEDED(hr)) { data->client = ptr; device->DeviceName = get_device_name(data->mmdev); } if(FAILED(hr)) { if(data->mmdev) IMMDevice_Release(data->mmdev); data->mmdev = NULL; if(--deviceCount == 0 && SUCCEEDED(cohr)) CoUninitialize(); } req->result = hr; SetEvent(req->FinishedEvt); continue; case WM_USER_ResetDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; req->result = DoReset(device); SetEvent(req->FinishedEvt); continue; case WM_USER_StartDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; data = device->ExtraData; ResetEvent(data->NotifyEvent); hr = IAudioClient_SetEventHandle(data->client, data->NotifyEvent); if(FAILED(hr)) ERR("Failed to set event handle: 0x%08lx\n", hr); else { hr = IAudioClient_Start(data->client); if(FAILED(hr)) ERR("Failed to start audio client: 0x%08lx\n", hr); } if(SUCCEEDED(hr)) hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr); if(SUCCEEDED(hr)) { data->render = ptr; data->thread = StartThread(MMDevApiProc, device); if(!data->thread) { if(data->render) IAudioRenderClient_Release(data->render); data->render = NULL; IAudioClient_Stop(data->client); ERR("Failed to start thread\n"); hr = E_FAIL; } } req->result = hr; SetEvent(req->FinishedEvt); continue; case WM_USER_StopDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; data = device->ExtraData; if(data->thread) { data->killNow = 1; StopThread(data->thread); data->thread = NULL; data->killNow = 0; IAudioRenderClient_Release(data->render); data->render = NULL; IAudioClient_Stop(data->client); } req->result = S_OK; SetEvent(req->FinishedEvt); continue; case WM_USER_CloseDevice: req = (ThreadRequest*)msg.wParam; device = (ALCdevice*)msg.lParam; data = device->ExtraData; IAudioClient_Release(data->client); data->client = NULL; IMMDevice_Release(data->mmdev); data->mmdev = NULL; if(--deviceCount == 0) CoUninitialize(); req->result = S_OK; SetEvent(req->FinishedEvt); continue; case WM_USER_Enumerate: req = (ThreadRequest*)msg.wParam; hr = cohr = S_OK; if(++deviceCount == 1) hr = cohr = CoInitialize(NULL); if(SUCCEEDED(hr)) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { EDataFlow flowdir; DevMap **devlist; ALuint *numdevs; ALuint i; Enumerator = ptr; if(msg.lParam == CAPTURE_DEVICE_PROBE) { flowdir = eCapture; devlist = &CaptureDeviceList; numdevs = &NumCaptureDevices; } else { flowdir = eRender; devlist = &PlaybackDeviceList; numdevs = &NumPlaybackDevices; } for(i = 0;i < *numdevs;i++) { free((*devlist)[i].name); free((*devlist)[i].devid); } free(*devlist); *devlist = NULL; *numdevs = 0; *devlist = ProbeDevices(Enumerator, flowdir, numdevs); IMMDeviceEnumerator_Release(Enumerator); Enumerator = NULL; } if(--deviceCount == 0 && SUCCEEDED(cohr)) CoUninitialize(); req->result = S_OK; SetEvent(req->FinishedEvt); continue; default: ERR("Unexpected message: %u\n", msg.message); continue; } } TRACE("Message loop finished\n"); return 0; }
/* IMMDeviceCollection appears to have no QueryInterface method and instead forwards to mme */ static void test_collection(IMMDeviceEnumerator *mme, IMMDeviceCollection *col) { IMMDeviceCollection *col2; IMMDeviceEnumerator *mme2; IUnknown *unk; HRESULT hr; ULONG ref; UINT numdev; IMMDevice *dev; /* collection doesn't keep a ref on parent */ IMMDeviceEnumerator_AddRef(mme); ref = IMMDeviceEnumerator_Release(mme); ok(ref == 2, "Reference count on parent is %u\n", ref); ref = IMMDeviceCollection_AddRef(col); IMMDeviceCollection_Release(col); ok(ref == 2, "Invalid reference count %u on collection\n", ref); hr = IMMDeviceCollection_QueryInterface(col, &IID_IUnknown, NULL); ok(hr == E_POINTER, "Null ppv returns %08x\n", hr); hr = IMMDeviceCollection_QueryInterface(col, &IID_IUnknown, (void**)&unk); ok(hr == S_OK, "Cannot query for IID_IUnknown: 0x%08x\n", hr); if (hr == S_OK) { ok((IUnknown*)col == unk, "Pointers are not identical %p/%p/%p\n", col, unk, mme); IUnknown_Release(unk); } hr = IMMDeviceCollection_QueryInterface(col, &IID_IMMDeviceCollection, (void**)&col2); ok(hr == S_OK, "Cannot query for IID_IMMDeviceCollection: 0x%08x\n", hr); if (hr == S_OK) IMMDeviceCollection_Release(col2); hr = IMMDeviceCollection_QueryInterface(col, &IID_IMMDeviceEnumerator, (void**)&mme2); ok(hr == E_NOINTERFACE, "Query for IID_IMMDeviceEnumerator returned: 0x%08x\n", hr); if (hr == S_OK) IMMDeviceEnumerator_Release(mme2); hr = IMMDeviceCollection_GetCount(col, NULL); ok(hr == E_POINTER, "GetCount returned 0x%08x\n", hr); hr = IMMDeviceCollection_GetCount(col, &numdev); ok(hr == S_OK, "GetCount returned 0x%08x\n", hr); dev = (void*)(LONG_PTR)0x12345678; hr = IMMDeviceCollection_Item(col, numdev, &dev); ok(hr == E_INVALIDARG, "Asking for too high device returned 0x%08x\n", hr); ok(dev == NULL, "Returned non-null device\n"); if (numdev) { hr = IMMDeviceCollection_Item(col, 0, NULL); ok(hr == E_POINTER, "Query with null pointer returned 0x%08x\n", hr); hr = IMMDeviceCollection_Item(col, 0, &dev); ok(hr == S_OK, "Valid Item returned 0x%08x\n", hr); ok(dev != NULL, "Device is null!\n"); if (dev != NULL) { char temp[128]; WCHAR *id = NULL; if (IMMDevice_GetId(dev, &id) == S_OK) { IMMDevice *dev2; temp[sizeof(temp)-1] = 0; WideCharToMultiByte(CP_ACP, 0, id, -1, temp, sizeof(temp)-1, NULL, NULL); trace("Device found: %s\n", temp); hr = IMMDeviceEnumerator_GetDevice(mme, id, &dev2); ok(hr == S_OK, "GetDevice failed: %08x\n", hr); IMMDevice_Release(dev2); CoTaskMemFree(id); } } if (dev) IMMDevice_Release(dev); } IMMDeviceCollection_Release(col); }