/************************************************************************** * midiOutGetDevCapsA [WINMM.@] */ UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT uSize) { MIDIOUTCAPSW mocW; UINT ret; if (lpCaps == NULL) return MMSYSERR_INVALPARAM; ret = midiOutGetDevCapsW(uDeviceID, &mocW, sizeof(mocW)); if (ret == MMSYSERR_NOERROR) { MIDIOUTCAPSA mocA; mocA.wMid = mocW.wMid; mocA.wPid = mocW.wPid; mocA.vDriverVersion = mocW.vDriverVersion; WideCharToMultiByte( CP_ACP, 0, mocW.szPname, -1, mocA.szPname, sizeof(mocA.szPname), NULL, NULL ); mocA.wTechnology = mocW.wTechnology; mocA.wVoices = mocW.wVoices; mocA.wNotes = mocW.wNotes; mocA.wChannelMask = mocW.wChannelMask; mocA.dwSupport = mocW.dwSupport; memcpy(lpCaps, &mocA, min(uSize, sizeof(mocA))); } return ret; }
/************************************************************************** * MIDIMAP_drvOpen [internal] */ static LRESULT MIDIMAP_drvOpen(LPSTR str) { MIDIOUTCAPSW moc; unsigned dev, i; if (midiOutPorts) return 0; numMidiOutPorts = midiOutGetNumDevs(); midiOutPorts = HeapAlloc(GetProcessHeap(), 0, numMidiOutPorts * sizeof(MIDIOUTPORT)); for (dev = 0; dev < numMidiOutPorts; dev++) { if (midiOutGetDevCapsW(dev, &moc, sizeof(moc)) == 0L) { strcpyW(midiOutPorts[dev].name, moc.szPname); midiOutPorts[dev].loaded = 0; midiOutPorts[dev].hMidi = 0; midiOutPorts[dev].uDevID = dev; midiOutPorts[dev].lpbPatch = NULL; for (i = 0; i < 16; i++) midiOutPorts[dev].aChn[i] = i; } else { midiOutPorts[dev].loaded = -1; } } return 1; }
/********************************************************************** * DEVENUM_CreateSpecialCategories (INTERNAL) * * Creates the keys in the registry for the dynamic categories */ static HRESULT DEVENUM_CreateSpecialCategories(void) { HRESULT res; WCHAR szDSoundNameFormat[MAX_PATH + 1]; WCHAR szDSoundName[MAX_PATH + 1]; DWORD iDefaultDevice = -1; UINT numDevs; IFilterMapper2 * pMapper = NULL; REGFILTER2 rf2; REGFILTERPINS2 rfp2; WCHAR path[MAX_PATH]; HKEY basekey; if (DEVENUM_populate_handle) return S_OK; DEVENUM_populate_handle = CreateEventW(NULL, TRUE, FALSE, DEVENUM_populate_handle_nameW); if (GetLastError() == ERROR_ALREADY_EXISTS) { /* Webcams can take some time to scan if the driver is badly written and it enables them, * so have a 10 s timeout here */ if (WaitForSingleObject(DEVENUM_populate_handle, 10000) == WAIT_TIMEOUT) WARN("Waiting for object timed out\n"); TRACE("No need to rescan\n"); return S_OK; } TRACE("Scanning for devices\n"); /* Since devices can change between session, for example because you just plugged in a webcam * or switched from pulseaudio to alsa, delete all old devices first */ if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioRendererCategory, &basekey, path, MAX_PATH))) RegDeleteTreeW(basekey, path); if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_AudioInputDeviceCategory, &basekey, path, MAX_PATH))) RegDeleteTreeW(basekey, path); if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_VideoInputDeviceCategory, &basekey, path, MAX_PATH))) RegDeleteTreeW(basekey, path); if (SUCCEEDED(DEVENUM_GetCategoryKey(&CLSID_MidiRendererCategory, &basekey, path, MAX_PATH))) RegDeleteTreeW(basekey, path); rf2.dwVersion = 2; rf2.dwMerit = MERIT_PREFERRED; rf2.u.s1.cPins2 = 1; rf2.u.s1.rgPins2 = &rfp2; rfp2.cInstances = 1; rfp2.nMediums = 0; rfp2.lpMedium = NULL; rfp2.clsPinCategory = &IID_NULL; if (!LoadStringW(DEVENUM_hInstance, IDS_DEVENUM_DS, szDSoundNameFormat, sizeof(szDSoundNameFormat)/sizeof(szDSoundNameFormat[0])-1)) { ERR("Couldn't get string resource (GetLastError() is %d)\n", GetLastError()); return HRESULT_FROM_WIN32(GetLastError()); } res = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC, &IID_IFilterMapper2, (void **) &pMapper); /* * Fill in info for devices */ if (SUCCEEDED(res)) { UINT i; WAVEOUTCAPSW wocaps; WAVEINCAPSW wicaps; MIDIOUTCAPSW mocaps; REGPINTYPES * pTypes; numDevs = waveOutGetNumDevs(); res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory); if (FAILED(res)) /* can't register any devices in this category */ numDevs = 0; rfp2.dwFlags = REG_PINFLAG_B_RENDERER; for (i = 0; i < numDevs; i++) { if (waveOutGetDevCapsW(i, &wocaps, sizeof(WAVEOUTCAPSW)) == MMSYSERR_NOERROR) { IMoniker * pMoniker = NULL; rfp2.nMediaTypes = 1; pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); if (!pTypes) { IFilterMapper2_Release(pMapper); return E_OUTOFMEMORY; } /* FIXME: Native devenum seems to register a lot more types for * DSound than we do. Not sure what purpose they serve */ pTypes[0].clsMajorType = &MEDIATYPE_Audio; pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM; rfp2.lpMediaType = pTypes; res = IFilterMapper2_RegisterFilter(pMapper, &CLSID_AudioRender, wocaps.szPname, &pMoniker, &CLSID_AudioRendererCategory, wocaps.szPname, &rf2); /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ if (pMoniker) { IMoniker_Release(pMoniker); pMoniker = NULL; } wsprintfW(szDSoundName, szDSoundNameFormat, wocaps.szPname); res = IFilterMapper2_RegisterFilter(pMapper, &CLSID_DSoundRender, szDSoundName, &pMoniker, &CLSID_AudioRendererCategory, szDSoundName, &rf2); /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ if (pMoniker) IMoniker_Release(pMoniker); if (i == iDefaultDevice) { FIXME("Default device\n"); } CoTaskMemFree(pTypes); } } numDevs = waveInGetNumDevs(); res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioInputDeviceCategory); if (FAILED(res)) /* can't register any devices in this category */ numDevs = 0; rfp2.dwFlags = REG_PINFLAG_B_OUTPUT; for (i = 0; i < numDevs; i++) { if (waveInGetDevCapsW(i, &wicaps, sizeof(WAVEINCAPSW)) == MMSYSERR_NOERROR) { IMoniker * pMoniker = NULL; rfp2.nMediaTypes = 1; pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); if (!pTypes) { IFilterMapper2_Release(pMapper); return E_OUTOFMEMORY; } /* FIXME: Not sure if these are correct */ pTypes[0].clsMajorType = &MEDIATYPE_Audio; pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM; rfp2.lpMediaType = pTypes; res = IFilterMapper2_RegisterFilter(pMapper, &CLSID_AudioRecord, wicaps.szPname, &pMoniker, &CLSID_AudioInputDeviceCategory, wicaps.szPname, &rf2); /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ if (pMoniker) IMoniker_Release(pMoniker); CoTaskMemFree(pTypes); } } numDevs = midiOutGetNumDevs(); res = DEVENUM_CreateAMCategoryKey(&CLSID_MidiRendererCategory); if (FAILED(res)) /* can't register any devices in this category */ numDevs = 0; rfp2.dwFlags = REG_PINFLAG_B_RENDERER; for (i = 0; i < numDevs; i++) { if (midiOutGetDevCapsW(i, &mocaps, sizeof(MIDIOUTCAPSW)) == MMSYSERR_NOERROR) { IMoniker * pMoniker = NULL; rfp2.nMediaTypes = 1; pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); if (!pTypes) { IFilterMapper2_Release(pMapper); return E_OUTOFMEMORY; } /* FIXME: Not sure if these are correct */ pTypes[0].clsMajorType = &MEDIATYPE_Midi; pTypes[0].clsMinorType = &MEDIASUBTYPE_None; rfp2.lpMediaType = pTypes; res = IFilterMapper2_RegisterFilter(pMapper, &CLSID_AVIMIDIRender, mocaps.szPname, &pMoniker, &CLSID_MidiRendererCategory, mocaps.szPname, &rf2); /* FIXME: do additional stuff with IMoniker here, depending on what RegisterFilter does */ /* Native version sets MidiOutId */ if (pMoniker) IMoniker_Release(pMoniker); if (i == iDefaultDevice) { FIXME("Default device\n"); } CoTaskMemFree(pTypes); } } res = DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory); if (SUCCEEDED(res)) for (i = 0; i < 10; i++) { WCHAR szDeviceName[32], szDeviceVersion[32], szDevicePath[10]; if (capGetDriverDescriptionW ((WORD) i, szDeviceName, sizeof(szDeviceName)/sizeof(WCHAR), szDeviceVersion, sizeof(szDeviceVersion)/sizeof(WCHAR))) { IMoniker * pMoniker = NULL; IPropertyBag * pPropBag = NULL; WCHAR dprintf[] = { 'v','i','d','e','o','%','d',0 }; snprintfW(szDevicePath, sizeof(szDevicePath)/sizeof(WCHAR), dprintf, i); /* The above code prevents 1 device with a different ID overwriting another */ rfp2.nMediaTypes = 1; pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES)); if (!pTypes) { IFilterMapper2_Release(pMapper); return E_OUTOFMEMORY; } pTypes[0].clsMajorType = &MEDIATYPE_Video; pTypes[0].clsMinorType = &MEDIASUBTYPE_None; rfp2.lpMediaType = pTypes; res = IFilterMapper2_RegisterFilter(pMapper, &CLSID_VfwCapture, szDeviceName, &pMoniker, &CLSID_VideoInputDeviceCategory, szDevicePath, &rf2); if (pMoniker) { OLECHAR wszVfwIndex[] = { 'V','F','W','I','n','d','e','x',0 }; VARIANT var; V_VT(&var) = VT_I4; V_UNION(&var, ulVal) = i; res = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID)&pPropBag); if (SUCCEEDED(res)) res = IPropertyBag_Write(pPropBag, wszVfwIndex, &var); IMoniker_Release(pMoniker); } if (i == iDefaultDevice) FIXME("Default device\n"); CoTaskMemFree(pTypes); } } } if (pMapper) IFilterMapper2_Release(pMapper); SetEvent(DEVENUM_populate_handle); return res; }
static void create_system_ports_list(IDirectMusic8Impl* object) { port_info * port; const WCHAR emulated[] = {' ','[','E','m','u','l','a','t','e','d',']',0}; ULONG nb_ports; ULONG nb_midi_out; ULONG nb_midi_in; MIDIOUTCAPSW caps_out; MIDIINCAPSW caps_in; IDirectMusicSynth8* synth; HRESULT hr; ULONG i; TRACE("(%p)\n", object); /* NOTE: - it seems some native versions get the rest of devices through dmusic32.EnumLegacyDevices...*sigh*...which is undocumented - should we enum wave devices ? Native does not seem to */ nb_midi_out = midiOutGetNumDevs(); nb_midi_in = midiInGetNumDevs(); nb_ports = 1 /* midi mapper */ + nb_midi_out + nb_midi_in + 1 /* synth port */; port = object->system_ports = HeapAlloc(GetProcessHeap(), 0, nb_ports * sizeof(port_info)); if (!object->system_ports) return; /* Fill common port caps for all winmm ports */ for (i = 0; i < (nb_ports - 1 /* synth port*/); i++) { object->system_ports[i].caps.dwSize = sizeof(DMUS_PORTCAPS); object->system_ports[i].caps.dwType = DMUS_PORT_WINMM_DRIVER; object->system_ports[i].caps.dwMemorySize = 0; object->system_ports[i].caps.dwMaxChannelGroups = 1; object->system_ports[i].caps.dwMaxVoices = 0; object->system_ports[i].caps.dwMaxAudioChannels = 0; object->system_ports[i].caps.dwEffectFlags = DMUS_EFFECT_NONE; /* Fake port GUID */ object->system_ports[i].caps.guidPort = IID_IUnknown; object->system_ports[i].caps.guidPort.Data1 = i + 1; } /* Fill midi mapper port info */ port->device = MIDI_MAPPER; port->create = DMUSIC_CreateMidiOutPortImpl; midiOutGetDevCapsW(MIDI_MAPPER, &caps_out, sizeof(caps_out)); strcpyW(port->caps.wszDescription, caps_out.szPname); strcatW(port->caps.wszDescription, emulated); port->caps.dwFlags = DMUS_PC_SHAREABLE; port->caps.dwClass = DMUS_PC_OUTPUTCLASS; port++; /* Fill midi out port info */ for (i = 0; i < nb_midi_out; i++) { port->device = i; port->create = DMUSIC_CreateMidiOutPortImpl; midiOutGetDevCapsW(i, &caps_out, sizeof(caps_out)); strcpyW(port->caps.wszDescription, caps_out.szPname); strcatW(port->caps.wszDescription, emulated); port->caps.dwFlags = DMUS_PC_SHAREABLE | DMUS_PC_EXTERNAL; port->caps.dwClass = DMUS_PC_OUTPUTCLASS; port++; } /* Fill midi in port info */ for (i = 0; i < nb_midi_in; i++) { port->device = i; port->create = DMUSIC_CreateMidiInPortImpl; midiInGetDevCapsW(i, &caps_in, sizeof(caps_in)); strcpyW(port->caps.wszDescription, caps_in.szPname); strcatW(port->caps.wszDescription, emulated); port->caps.dwFlags = DMUS_PC_EXTERNAL; port->caps.dwClass = DMUS_PC_INPUTCLASS; port++; } /* Fill synth port info */ port->create = DMUSIC_CreateSynthPortImpl; hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth8, (void**)&synth); if (SUCCEEDED(hr)) { port->caps.dwSize = sizeof(port->caps); hr = IDirectMusicSynth8_GetPortCaps(synth, &port->caps); IDirectMusicSynth8_Release(synth); } if (FAILED(hr)) nb_ports--; object->nb_system_ports = nb_ports; }