/* Copyright (c) 1998-2001 Microsoft Corporation */ #define UNICODE #define _UNICODE #include "nt.h" #include "ntrtl.h" #include "nturtl.h" #include "winmmi.h" #include #include #include #include #include "audiosrvc.h" extern PCWSTR waveReferenceDevInterfaceById(IN PWAVEDRV pdrvZ, IN UINT_PTR id); extern PCWSTR midiReferenceDevInterfaceById(IN PMIDIDRV pdrvZ, IN UINT_PTR id); #define REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER TEXT("Software\\Microsoft\\Multimedia\\Sound Mapper") #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PLAYBACK TEXT("Playback") #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_RECORD TEXT("Record") #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_PLAYBACK TEXT("ConsoleVoiceComPlayback") #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_RECORD TEXT("ConsoleVoiceComRecord") #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY TEXT("PreferredOnly") #define REGSTR_PATH_MEDIARESOURCES_MIDI REGSTR_PATH_MEDIARESOURCES TEXT("\\MIDI") #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_ACTIVE TEXT("Active") #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DESCRIPTION TEXT("Description") #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DEVICEINTERFACE TEXT("DeviceInterface") #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PHYSDEVID TEXT("PhysDevID") #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PORT TEXT("Port") #define REGSTR_PATH_MULTIMEDIA_MIDIMAP REGSTR_PATH_MULTIMEDIA TEXT("\\MIDIMap") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_CONFIGURECOUNT TEXT("ConfigureCount") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_USESCHEME TEXT("UseScheme") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_DRIVERLIST TEXT("DriverList") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_AUTOSCHEME TEXT("AutoScheme") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_CURRENTINSTRUMENT TEXT("CurrentInstrument") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_DEVICEINTERFACE TEXT("DeviceInterface") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_RELATIVEINDEX TEXT("RelativeIndex") #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_SZPNAME TEXT("szPname") #define REGSTR_VAL_SETUPPREFERREDAUDIODEVICES TEXT("SetupPreferredAudioDevices") #define REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT TEXT("SetupPreferredAudioDevicesCount") extern BOOL WaveMapperInitialized; // in winmm.c extern BOOL MidiMapperInitialized; // in winmm.c // Preferred Ids. Setting these to *_MAPPER indicates no setting. PWSTR gpstrWoDefaultStringId = NULL; PWSTR gpstrWiDefaultStringId = NULL; PWSTR gpstrWoConsoleVoiceComStringId = NULL; PWSTR gpstrWiConsoleVoiceComStringId = NULL; BOOL gfUsePreferredWaveOnly = TRUE; PWSTR gpstrMoDefaultStringId = NULL; // These will be TRUE if we sent the preferred device change // to sysaudio. BOOL gfWaveOutPreferredMessageSent = FALSE; BOOL gfWaveInPreferredMessageSent = FALSE; BOOL gfMidiOutPreferredMessageSent = FALSE; //------------------------------------------------------------------------------ // // // Registry helpers // // //------------------------------------------------------------------------------ LONG RegQuerySzValue(HKEY hkey, PCTSTR pValueName, PTSTR *ppstrValue) { LONG result; DWORD typeValue; DWORD cbstrValue = 0; BOOL f; result = RegQueryValueEx(hkey, pValueName, 0, &typeValue, NULL, &cbstrValue); if (ERROR_SUCCESS == result) { if (REG_SZ == typeValue) { PTSTR pstrValue; pstrValue = HeapAlloc(hHeap, 0, cbstrValue); if (pstrValue) { result = RegQueryValueEx(hkey, pValueName, 0, &typeValue, (PBYTE)pstrValue, &cbstrValue); if (ERROR_SUCCESS == result) { if (REG_SZ == typeValue) { *ppstrValue = pstrValue; } else { result = ERROR_FILE_NOT_FOUND; f = HeapFree(hHeap, 0, pstrValue); WinAssert(f); } } else { f = HeapFree(hHeap, 0, pstrValue); WinAssert(f); } } else { result = ERROR_OUTOFMEMORY; } } else { result = ERROR_FILE_NOT_FOUND; } } return result; } LONG RegQueryDwordValue(HKEY hkey, PCTSTR pValueName, PDWORD pdwValue) { DWORD cbdwValue; LONG result; cbdwValue = sizeof(*pdwValue); result = RegQueryValueEx(hkey, pValueName, 0, NULL, (PBYTE)pdwValue, &cbdwValue); return result; } LONG RegSetSzValue(HKEY hkey, PCTSTR pValueName, PCTSTR pstrValue) { DWORD cbstrValue = (lstrlen(pstrValue) + 1) * sizeof(pstrValue[0]); return RegSetValueEx(hkey, pValueName, 0, REG_SZ, (PBYTE)pstrValue, cbstrValue); } LONG RegSetDwordValue(HKEY hkey, PCTSTR pValueName, DWORD dwValue) { return RegSetValueEx(hkey, pValueName, 0, REG_DWORD, (PBYTE)&dwValue, sizeof(dwValue)); } //------------------------------------------------------------------------------ // // // AutoSetupPreferredAudio functions // // //------------------------------------------------------------------------------ //--------------------------------------------------------------------------; // // DWORD GetCurrentSetupPreferredAudioCount // // Arguments: // // Return value: // // History: // 1/19/99 FrankYe Created // //--------------------------------------------------------------------------; DWORD GetCurrentSetupPreferredAudioCount(void) { HKEY hkeySetupPreferredAudioDevices; DWORD SetupCount = 0; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES TEXT("\\") REGSTR_VAL_SETUPPREFERREDAUDIODEVICES, 0, KEY_QUERY_VALUE, &hkeySetupPreferredAudioDevices)) { if (ERROR_SUCCESS != RegQueryDwordValue(hkeySetupPreferredAudioDevices, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount)) { Squirt("GCSPATS: Couldn't read hklm\\...\\SetupPreferredAudioDevicesCount"); } if (ERROR_SUCCESS != RegCloseKey(hkeySetupPreferredAudioDevices)) { WinAssert(!"GCSPATS: unexpected failure of RegCloseKey"); } } else { Squirt("GCSPATS: Couldn't open hklm\\...\\SetupPreferredAudioDevices"); } return SetupCount; } //--------------------------------------------------------------------------; // // DWORD GetDeviceInterfaceSetupPreferredAudioCount // // Arguments: // // Return value: // // History: // 1/19/99 FrankYe Created // //--------------------------------------------------------------------------; DWORD GetDeviceInterfaceSetupPreferredAudioCount(PCWSTR DeviceInterface) { PMMDEVICEINTERFACEINFO pdii; PMMPNPINFO pPnpInfo; LONG cbPnpInfo; DWORD count; int ii; // Handle empty DeviceInterface names in case of legacy drivers if (0 == lstrlen(DeviceInterface)) return 0; if (ERROR_SUCCESS != winmmGetPnpInfo(&cbPnpInfo, &pPnpInfo)) return 0; pdii = (PMMDEVICEINTERFACEINFO)&(pPnpInfo[1]); pdii = PAD_POINTER(pdii); for (ii = pPnpInfo->cDevInterfaces; ii; ii--) { // Searching for the device interface... if (0 == lstrcmpi(pdii->szName, DeviceInterface)) break; pdii = (PMMDEVICEINTERFACEINFO)(pdii->szName + lstrlenW(pdii->szName) + 1); pdii = PAD_POINTER(pdii); } WinAssert(ii); count = pdii->SetupPreferredAudioCount; HeapFree(hHeap, 0, pPnpInfo); return count; } //------------------------------------------------------------------------------ // // // NotifyServerPreferredDeviceChange // // //------------------------------------------------------------------------------ void NotifyServerPreferredDeviceChange(void) { winmmAdvisePreferredDeviceChange(); } //------------------------------------------------------------------------------ // // // Wave // // //------------------------------------------------------------------------------ MMRESULT waveWritePersistentConsoleVoiceCom(BOOL fOut, PTSTR pstrPref, BOOL fPrefOnly) { HKEY hkcu; HKEY hkSoundMapper; LONG result; BOOL fSuccess; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_WRITE, &hkcu))) return MMSYSERR_WRITEERROR; result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, TEXT("\0"), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkSoundMapper, NULL); if (ERROR_SUCCESS == result) { DWORD cbstrPref; cbstrPref = (lstrlen(pstrPref) + 1) * sizeof(pstrPref[0]); if (fOut) { result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_PLAYBACK, pstrPref); } else { result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_RECORD, pstrPref); } if (ERROR_SUCCESS == result) { fSuccess = TRUE; result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, (DWORD)fPrefOnly); if (ERROR_SUCCESS != result) { Squirt("wWPCVC: Could not write hkcu\\...\\Sound Mapper\\PreferredOnly"); } result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, GetCurrentSetupPreferredAudioCount()); if (ERROR_SUCCESS != result) { Squirt("wWPCVC: Could not write hkcu\\...\\Sound Mapper\\SetupPreferredAudioCount"); } } result = RegCloseKey(hkSoundMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return MMSYSERR_NOERROR; } BOOL waveReadPersistentConsoleVoiceCom(BOOL fOut, PTSTR *ppstrPref, PBOOL pfPrefOnly, PDWORD pSetupCount) { HKEY hkcu; HKEY hkSoundMapper; LONG result; BOOL fSuccess; fSuccess = FALSE; *ppstrPref = NULL; *pfPrefOnly = FALSE; *pSetupCount = 0; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return FALSE; result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, KEY_QUERY_VALUE, &hkSoundMapper); if (ERROR_SUCCESS == result) { DWORD SetupCount; result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount); SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0; if (ERROR_SUCCESS == result) { PTSTR pstrPref; BOOL fPrefOnly; DWORD dwPrefOnly; result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, &dwPrefOnly); fPrefOnly = (ERROR_SUCCESS == result) ? (0 != dwPrefOnly) : FALSE; if (fOut) { result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_PLAYBACK, &pstrPref); } else { result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_RECORD, &pstrPref); } if (ERROR_SUCCESS != result) pstrPref = NULL; *ppstrPref = pstrPref; *pfPrefOnly = fPrefOnly; *pSetupCount = SetupCount; fSuccess = TRUE; } result = RegCloseKey(hkSoundMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return fSuccess; } MMRESULT wavePickBestConsoleVoiceComId(BOOL fOut, PUINT pPrefId, PDWORD pdwFlags) { PTSTR pstrPref; UINT cWaveId; UINT WaveId; UINT UserSelectedId; UINT NonConsoleId; UINT PreferredId; DWORD UserSelectedIdSetupCount; BOOL fPrefOnly; BOOL f; UserSelectedId = WAVE_MAPPER; if (fOut) { waveOutGetCurrentPreferredId(&NonConsoleId, NULL); cWaveId = waveOutGetNumDevs(); waveReadPersistentConsoleVoiceCom(fOut, &pstrPref, &fPrefOnly, &UserSelectedIdSetupCount); *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--) { WAVEOUTCAPS wc; MMRESULT mmr; mmr = waveOutGetDevCaps(WaveId, &wc, sizeof(wc)); if (mmr) continue; wc.szPname[MAXPNAMELEN-1] = TEXT('\0'); if (pstrPref && !lstrcmp(wc.szPname, pstrPref)) { UserSelectedId = WaveId; break; } } } else { waveInGetCurrentPreferredId(&NonConsoleId, NULL); cWaveId = waveInGetNumDevs(); waveReadPersistentConsoleVoiceCom(fOut, &pstrPref, &fPrefOnly, &UserSelectedIdSetupCount); *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--) { WAVEINCAPS wc; MMRESULT mmr; mmr = waveInGetDevCaps(WaveId, &wc, sizeof(wc)); if (mmr) continue; wc.szPname[MAXPNAMELEN-1] = TEXT('\0'); if (pstrPref && !lstrcmp(wc.szPname, pstrPref)) { UserSelectedId = WaveId; break; } } } if (pstrPref) { f = HeapFree(hHeap, 0, pstrPref); WinAssert(f); pstrPref = NULL; } PreferredId = ((WAVE_MAPPER == UserSelectedId)?NonConsoleId:UserSelectedId); *pPrefId = PreferredId; return MMSYSERR_NOERROR; } //------------------------------------------------------------------------------ // // // WaveOut // // //------------------------------------------------------------------------------ DWORD waveOutGetSetupPreferredAudioCount(UINT WaveId) { PCWSTR DeviceInterface; DWORD dwCount; DeviceInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, WaveId); if(DeviceInterface == NULL) { return 0; } dwCount = GetDeviceInterfaceSetupPreferredAudioCount(DeviceInterface); wdmDevInterfaceDec(DeviceInterface); return dwCount; } MMRESULT waveOutSendPreferredMessage(BOOL fClear) { PCWSTR DeviceInterface; UINT WaveId, Flags; MMRESULT mmr; if(!gfLogon) { return MMSYSERR_NOERROR; } waveOutGetCurrentPreferredId(&WaveId, &Flags); //Squirt("waveOutSendPreferredMessage: id %d f %d", WaveId, fClear); if(WaveId == WAVE_MAPPER) { return MMSYSERR_NOERROR; } DeviceInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, WaveId); if(DeviceInterface == NULL) { return MMSYSERR_NOERROR; } gfWaveOutPreferredMessageSent = TRUE; mmr = waveOutMessage((HWAVEOUT)(UINT_PTR)WaveId, WODM_PREFERRED, (DWORD_PTR)fClear, (DWORD_PTR)DeviceInterface); wdmDevInterfaceDec(DeviceInterface); return mmr; } BOOL waveOutReadPersistentPref(PTSTR *ppstrPref, PBOOL pfPrefOnly, PDWORD pSetupCount) { HKEY hkcu; HKEY hkSoundMapper; LONG result; BOOL fSuccess; fSuccess = FALSE; *ppstrPref = NULL; *pfPrefOnly = FALSE; *pSetupCount = 0; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return FALSE; result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, KEY_QUERY_VALUE, &hkSoundMapper); if (ERROR_SUCCESS == result) { DWORD SetupCount; result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount); SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0; if (ERROR_SUCCESS == result) { PTSTR pstrPref; BOOL fPrefOnly; DWORD dwPrefOnly; result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, &dwPrefOnly); fPrefOnly = (ERROR_SUCCESS == result) ? (0 != dwPrefOnly) : FALSE; result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PLAYBACK, &pstrPref); if (ERROR_SUCCESS != result) pstrPref = NULL; *ppstrPref = pstrPref; *pfPrefOnly = fPrefOnly; *pSetupCount = SetupCount; fSuccess = TRUE; } result = RegCloseKey(hkSoundMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return fSuccess; } MMRESULT waveOutPickBestId(PUINT pPrefId, PDWORD pdwFlags) { PTSTR pstrPref; UINT cWaveId; UINT WaveId; UINT MappableId; UINT MixableId; UINT UserSelectedId; UINT PreferredId; DWORD WaveIdSetupCount; DWORD MappableIdSetupCount; DWORD MixableIdSetupCount; DWORD UserSelectedIdSetupCount; DWORD PreferredIdSetupCount; BOOL fPrefOnly; BOOL f; MappableId = WAVE_MAPPER; MixableId = WAVE_MAPPER; UserSelectedId = WAVE_MAPPER; PreferredId = WAVE_MAPPER; MappableIdSetupCount = 0; MixableIdSetupCount = 0; UserSelectedIdSetupCount = 0; PreferredIdSetupCount = 0; cWaveId = waveOutGetNumDevs(); waveOutReadPersistentPref(&pstrPref, &fPrefOnly, &UserSelectedIdSetupCount); *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--) { WAVEOUTCAPS wc; UINT uMixerId; MMRESULT mmr; PWAVEDRV pdrv; BOOL fThisSession; // // check the protocol name // mask all inappropriate TS/non-TS drivers // if (waveReferenceDriverById(&waveoutdrvZ, WaveId, &pdrv, NULL)) continue; fThisSession = !lstrcmpW(pdrv->wszSessProtocol, SessionProtocolName); mregDecUsagePtr(pdrv); if (!fThisSession) continue; mmr = waveOutGetDevCaps(WaveId, &wc, sizeof(wc)); if (mmr) continue; wc.szPname[MAXPNAMELEN-1] = TEXT('\0'); if (pstrPref && !lstrcmp(wc.szPname, pstrPref)) UserSelectedId = WaveId; WaveIdSetupCount = waveOutGetSetupPreferredAudioCount(WaveId); mmr = waveOutMessage((HWAVEOUT)(UINT_PTR)WaveId, DRV_QUERYMAPPABLE, 0L, 0L); if (mmr) continue; if (WaveIdSetupCount >= MappableIdSetupCount) { MappableId = WaveId; MappableIdSetupCount = WaveIdSetupCount; } mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)WaveId, &uMixerId, MIXER_OBJECTF_WAVEOUT); if (mmr) continue; if (WaveIdSetupCount >= MixableIdSetupCount) { MixableId = WaveId; MixableIdSetupCount = WaveIdSetupCount; } } if (pstrPref) { f = HeapFree(hHeap, 0, pstrPref); WinAssert(f); pstrPref = NULL; } PreferredId = MappableId; PreferredIdSetupCount = MappableIdSetupCount; if ((MixableIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != MixableId)) { PreferredId = MixableId; PreferredIdSetupCount = MixableIdSetupCount; } if ((UserSelectedIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != UserSelectedId)) { PreferredId = UserSelectedId; PreferredIdSetupCount = UserSelectedIdSetupCount; } *pPrefId = PreferredId; return MMSYSERR_NOERROR; } void waveOutGetCurrentPreferredId(PUINT pPrefId, PDWORD pdwFlags) { *pPrefId = WAVE_MAPPER; if (pdwFlags) *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; if (gpstrWoDefaultStringId) mregGetIdFromStringId(&waveoutdrvZ, gpstrWoDefaultStringId, pPrefId); return; } BOOL waveOutWritePersistentPref(PTSTR pstrPref, BOOL fPrefOnly) { HKEY hkcu; HKEY hkSoundMapper; LONG result; BOOL fSuccess; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_WRITE, &hkcu))) return MMSYSERR_WRITEERROR; result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, TEXT("\0"), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkSoundMapper, NULL); if (ERROR_SUCCESS == result) { DWORD cbstrPref; cbstrPref = (lstrlen(pstrPref) + 1) * sizeof(pstrPref[0]); result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PLAYBACK, pstrPref); if (ERROR_SUCCESS == result) { fSuccess = TRUE; result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, (DWORD)fPrefOnly); if (ERROR_SUCCESS != result) { Squirt("wOWPP: Could not write hkcu\\...\\Sound Mapper\\PreferredOnly"); } result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, GetCurrentSetupPreferredAudioCount()); if (ERROR_SUCCESS != result) { Squirt("wOWPP: Could not write hkcu\\...\\Sound Mapper\\SetupPreferredAudioCount"); } } result = RegCloseKey(hkSoundMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return MMSYSERR_NOERROR; } MMRESULT waveOutSetCurrentPreferredId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WinAssert(PrefId < wTotalWaveOutDevs || PrefId == WAVE_MAPPER); mmr = MMSYSERR_NOERROR; if (gpstrWoDefaultStringId) HeapFree(hHeap, 0, gpstrWoDefaultStringId); gpstrWoDefaultStringId = NULL; if (wTotalWaveOutDevs) { UINT mixerId; PWAVEDRV pwavedrv; UINT port; mmr = waveReferenceDriverById(&waveoutdrvZ, PrefId, &pwavedrv, &port); if (!mmr) { mmr = mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWoDefaultStringId, NULL); if (!mmr) { if (!gfDisablePreferredDeviceReordering) { // Rearrange some of the driver list so that the preferred waveOut // device and its associated mixer device have a good chance of // having device ID 0 mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)PrefId, &mixerId, MIXER_OBJECTF_WAVEOUT); if (mmr) mixerId = 0; if (0 != PrefId) { // Move the wave driver to the head of this list. This usually // makes the preferred device have ID 0. EnterNumDevs("waveOutSetCurrentPreferredId"); pwavedrv->Prev->Next = pwavedrv->Next; pwavedrv->Next->Prev = pwavedrv->Prev; pwavedrv->Next = waveoutdrvZ.Next; pwavedrv->Prev = &waveoutdrvZ; waveoutdrvZ.Next->Prev = pwavedrv; waveoutdrvZ.Next = pwavedrv; LeaveNumDevs("waveOutSetCurrentPreferredId"); mregDecUsagePtr(pwavedrv); } if (0 != mixerId) { PMIXERDRV pmixerdrv; mmr = mixerReferenceDriverById(mixerId, &pmixerdrv, NULL); if (!mmr) { EnterNumDevs("waveOutSetCurrentPreferredId"); pmixerdrv->Prev->Next = pmixerdrv->Next; pmixerdrv->Next->Prev = pmixerdrv->Prev; pmixerdrv->Next = mixerdrvZ.Next; pmixerdrv->Prev = &mixerdrvZ; mixerdrvZ.Next->Prev = pmixerdrv; mixerdrvZ.Next = pmixerdrv; LeaveNumDevs("waveOutSetCurrentPreferredId"); mregDecUsagePtr(pmixerdrv); } } } // Errors in this body are not critical mmr = MMSYSERR_NOERROR; } } } if (!mmr) { gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)); // Reconfigure the mapper only if it was already loaded. Don't cause it to // load simply so that we can reconfigure it! if (WaveMapperInitialized) waveOutMessage((HWAVEOUT)(UINT_PTR)WAVE_MAPPER, DRVM_MAPPER_RECONFIGURE, 0, 0); } return mmr; } MMRESULT waveOutSetPersistentPreferredId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WAVEOUTCAPS woc; if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM; mmr = waveOutGetDevCaps(PrefId, &woc, sizeof(woc)); if (!mmr) { woc.szPname[MAXPNAMELEN-1] = TEXT('\0'); mmr = waveOutWritePersistentPref(woc.szPname, 0 != (dwFlags & 0x00000001)); if (!mmr) { NotifyServerPreferredDeviceChange(); } else { Squirt("waveOutSetPersistentPreferredId: waveOutWritePersistenPref failed, mmr=%08Xh", mmr); } } return mmr; } void waveOutGetCurrentConsoleVoiceComId(PUINT pPrefId, PDWORD pdwFlags) { *pPrefId = WAVE_MAPPER; *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; if (gpstrWoConsoleVoiceComStringId) mregGetIdFromStringId(&waveoutdrvZ, gpstrWoConsoleVoiceComStringId, pPrefId); return; } MMRESULT waveOutSetPersistentConsoleVoiceComId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WAVEOUTCAPS woc; if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM; mmr = waveOutGetDevCaps(PrefId, &woc, sizeof(woc)); if (!mmr) { woc.szPname[MAXPNAMELEN-1] = TEXT('\0'); mmr = waveWritePersistentConsoleVoiceCom(TRUE, woc.szPname, 0 != (dwFlags & 0x00000001)); if (!mmr) { NotifyServerPreferredDeviceChange(); } else { Squirt("waveOutSetPersistentConsoleVoiceComId: waveWritePersistentConsoleVoiceCom failed, mmr=%08Xh", mmr); } } return mmr; } MMRESULT waveOutSetCurrentConsoleVoiceComId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WinAssert(PrefId < wTotalWaveOutDevs || PrefId == WAVE_MAPPER); mmr = MMSYSERR_NOERROR; if (gpstrWoConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWoConsoleVoiceComStringId); gpstrWoConsoleVoiceComStringId = NULL; if (wTotalWaveOutDevs) { PWAVEDRV pwavedrv; UINT port; mmr = waveReferenceDriverById(&waveoutdrvZ, PrefId, &pwavedrv, &port); if (!mmr) { mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWoConsoleVoiceComStringId, NULL); gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)); } } return mmr; } //------------------------------------------------------------------------------ // // // WaveIn // // //------------------------------------------------------------------------------ DWORD waveInGetSetupPreferredAudioCount(UINT WaveId) { PCWSTR DeviceInterface; DWORD dwCount; DeviceInterface = waveReferenceDevInterfaceById(&waveindrvZ, WaveId); if(DeviceInterface == NULL) { return 0; } dwCount = GetDeviceInterfaceSetupPreferredAudioCount(DeviceInterface); wdmDevInterfaceDec(DeviceInterface); return dwCount; } MMRESULT waveInSendPreferredMessage(BOOL fClear) { PCWSTR DeviceInterface; UINT WaveId, Flags; MMRESULT mmr; if(!gfLogon) { return MMSYSERR_NOERROR; } waveInGetCurrentPreferredId(&WaveId, &Flags); //Squirt("waveInSendPreferredMessage: id %d f %d", WaveId, fClear); if(WaveId == WAVE_MAPPER) { return MMSYSERR_NOERROR; } DeviceInterface = waveReferenceDevInterfaceById(&waveindrvZ, WaveId); if(DeviceInterface == NULL) { return MMSYSERR_NOERROR; } gfWaveInPreferredMessageSent = TRUE; mmr = waveInMessage((HWAVEIN)(UINT_PTR)WaveId, WIDM_PREFERRED, (DWORD_PTR)fClear, (DWORD_PTR)DeviceInterface); wdmDevInterfaceDec(DeviceInterface); return mmr; } BOOL waveInReadPersistentPref(PTSTR *ppstrPref, PBOOL pfPrefOnly, PDWORD pSetupCount) { HKEY hkcu; HKEY hkSoundMapper; LONG result; BOOL fSuccess; fSuccess = FALSE; *ppstrPref = NULL; *pfPrefOnly = FALSE; *pSetupCount = 0; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return FALSE; result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, KEY_QUERY_VALUE, &hkSoundMapper); if (ERROR_SUCCESS == result) { DWORD SetupCount; result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount); SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0; if (ERROR_SUCCESS == result) { PTSTR pstrPref; BOOL fPrefOnly; DWORD dwPrefOnly; result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, &dwPrefOnly); fPrefOnly = (ERROR_SUCCESS == result) ? (0 != dwPrefOnly) : FALSE; result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_RECORD, &pstrPref); if (ERROR_SUCCESS != result) pstrPref = NULL; *ppstrPref = pstrPref; *pfPrefOnly = fPrefOnly; *pSetupCount = SetupCount; fSuccess = TRUE; } result = RegCloseKey(hkSoundMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return fSuccess; } MMRESULT waveInPickBestId(PUINT pPrefId, PDWORD pdwFlags) { PTSTR pstrPref; UINT cWaveId; UINT WaveId; UINT MappableId; UINT MixableId; UINT UserSelectedId; UINT PreferredId; DWORD WaveIdSetupCount; DWORD MappableIdSetupCount; DWORD MixableIdSetupCount; DWORD UserSelectedIdSetupCount; DWORD PreferredIdSetupCount; BOOL fPrefOnly; BOOL f; MappableId = WAVE_MAPPER; MixableId = WAVE_MAPPER; UserSelectedId = WAVE_MAPPER; PreferredId = WAVE_MAPPER; MappableIdSetupCount = 0; MixableIdSetupCount = 0; UserSelectedIdSetupCount = 0; PreferredIdSetupCount = 0; cWaveId = waveInGetNumDevs(); waveInReadPersistentPref(&pstrPref, &fPrefOnly, &UserSelectedIdSetupCount); *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--) { WAVEINCAPS wic; UINT uMixerId; MMRESULT mmr; mmr = waveInGetDevCaps(WaveId, &wic, sizeof(wic)); if (MMSYSERR_NOERROR != mmr) continue; wic.szPname[MAXPNAMELEN-1] = TEXT('\0'); if (pstrPref && !lstrcmp(wic.szPname, pstrPref)) UserSelectedId = WaveId; WaveIdSetupCount = waveInGetSetupPreferredAudioCount(WaveId); mmr = waveInMessage((HWAVEIN)(UINT_PTR)WaveId, DRV_QUERYMAPPABLE, 0L, 0L); if (MMSYSERR_NOERROR != mmr) continue; if (WaveIdSetupCount >= MappableIdSetupCount) { MappableId = WaveId; MappableIdSetupCount = WaveIdSetupCount; } mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)WaveId, &uMixerId, MIXER_OBJECTF_WAVEIN); if (MMSYSERR_NOERROR != mmr) continue; if (WaveIdSetupCount >= MixableIdSetupCount) { MixableId = WaveId; MixableIdSetupCount = WaveIdSetupCount; } } if (pstrPref) { f = HeapFree(hHeap, 0, pstrPref); WinAssert(f); pstrPref = NULL; } PreferredId = MappableId; PreferredIdSetupCount = MappableIdSetupCount; if ((MixableIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != MixableId)) { PreferredId = MixableId; PreferredIdSetupCount = MixableIdSetupCount; } if ((UserSelectedIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != UserSelectedId)) { PreferredId = UserSelectedId; PreferredIdSetupCount = UserSelectedIdSetupCount; } *pPrefId = PreferredId; return MMSYSERR_NOERROR; } void waveInGetCurrentPreferredId(PUINT pPrefId, PDWORD pdwFlags) { *pPrefId = WAVE_MAPPER; if (pdwFlags) *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; if (gpstrWiDefaultStringId) mregGetIdFromStringId(&waveindrvZ, gpstrWiDefaultStringId, pPrefId); return; } BOOL waveInWritePersistentPref(PTSTR pstrPref, BOOL fPrefOnly) { HKEY hkcu; HKEY hkSoundMapper; LONG result; BOOL fSuccess; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_WRITE, &hkcu))) return MMSYSERR_WRITEERROR; result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, TEXT("\0"), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkSoundMapper, NULL); if (ERROR_SUCCESS == result) { DWORD cbstrPref; cbstrPref = (lstrlen(pstrPref) + 1) * sizeof(pstrPref[0]); result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_RECORD, pstrPref); if (ERROR_SUCCESS == result) { fSuccess = TRUE; result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, (DWORD)fPrefOnly); if (ERROR_SUCCESS != result) { Squirt("wiWPP: Could not write hkcu\\...\\Sound Mapper\\PreferredOnly"); } result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, GetCurrentSetupPreferredAudioCount()); if (ERROR_SUCCESS != result) { Squirt("wiWPP: Could not write hkcu\\...\\Sound Mapper\\SetupPreferredAudioCount"); } } result = RegCloseKey(hkSoundMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return MMSYSERR_NOERROR; } MMRESULT waveInSetCurrentPreferredId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WinAssert(PrefId < wTotalWaveInDevs || PrefId == WAVE_MAPPER); mmr = MMSYSERR_NOERROR; if (gpstrWiDefaultStringId) HeapFree(hHeap, 0, gpstrWiDefaultStringId); gpstrWiDefaultStringId = NULL; if (wTotalWaveInDevs) { PWAVEDRV pwavedrv; UINT port; mmr = waveReferenceDriverById(&waveindrvZ, PrefId, &pwavedrv, &port); if (!mmr) { mmr = mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWiDefaultStringId, NULL); if (!mmr) { if (!gfDisablePreferredDeviceReordering) { // Rearrange some of the driver list so that the preferred waveIn // device has a good chance of having device ID 0 if (0 != PrefId) { // Move the wave driver to the head of this list. This usually // makes the preferred device have ID 0. EnterNumDevs("waveInSetCurrentPreferredId"); pwavedrv->Prev->Next = pwavedrv->Next; pwavedrv->Next->Prev = pwavedrv->Prev; pwavedrv->Next = waveindrvZ.Next; pwavedrv->Prev = &waveindrvZ; waveindrvZ.Next->Prev = pwavedrv; waveindrvZ.Next = pwavedrv; LeaveNumDevs("waveInSetCurrentPreferredId"); mregDecUsagePtr(pwavedrv); } } } } } if (!mmr) { gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)); // Reconfigure the mapper only if it was already loaded. Don't cause it to // load simply so that we can reconfigure it! if (WaveMapperInitialized) waveInMessage((HWAVEIN)(UINT_PTR)WAVE_MAPPER, DRVM_MAPPER_RECONFIGURE, 0, 0); } return mmr; } MMRESULT waveInSetPersistentPreferredId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WAVEINCAPS wc; if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM; mmr = waveInGetDevCaps(PrefId, &wc, sizeof(wc)); if (!mmr) { wc.szPname[MAXPNAMELEN-1] = TEXT('\0'); mmr = waveInWritePersistentPref(wc.szPname, 0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)); if (!mmr) { NotifyServerPreferredDeviceChange(); } else { Squirt("waveInSetPersistentPreferredId: waveInWritePersistenPref failed, mmr=%08Xh", mmr); } } return mmr; } void waveInGetCurrentConsoleVoiceComId(PUINT pPrefId, PDWORD pdwFlags) { *pPrefId = WAVE_MAPPER; *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0; if (gpstrWiConsoleVoiceComStringId) mregGetIdFromStringId(&waveindrvZ, gpstrWiConsoleVoiceComStringId, pPrefId); return; } MMRESULT waveInSetPersistentConsoleVoiceComId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WAVEINCAPS wic; if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM; mmr = waveInGetDevCaps(PrefId, &wic, sizeof(wic)); if (!mmr) { wic.szPname[MAXPNAMELEN-1] = TEXT('\0'); mmr = waveWritePersistentConsoleVoiceCom(FALSE, wic.szPname, 0 != (dwFlags & 0x00000001)); if (!mmr) { NotifyServerPreferredDeviceChange(); } else { Squirt("waveInSetPersistentConsoleVoiceComId: waveWritePersistentConsoleVoiceCom failed, mmr=%08Xh", mmr); } } return mmr; } MMRESULT waveInSetCurrentConsoleVoiceComId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; WinAssert(PrefId < wTotalWaveInDevs || PrefId == WAVE_MAPPER); mmr = MMSYSERR_NOERROR; if (gpstrWiConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWiConsoleVoiceComStringId); gpstrWiConsoleVoiceComStringId = NULL; if (wTotalWaveInDevs) { PWAVEDRV pwavedrv; UINT port; mmr = waveReferenceDriverById(&waveindrvZ, PrefId, &pwavedrv, &port); if (!mmr) { mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWiConsoleVoiceComStringId, NULL); gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)); } } return mmr; } //------------------------------------------------------------------------------ // // // MidiOut // // //------------------------------------------------------------------------------ DWORD midiOutGetSetupPreferredAudioCount(UINT MidiId) { PCWSTR DeviceInterface; DWORD dwCount; DeviceInterface = midiReferenceDevInterfaceById(&midioutdrvZ, MidiId); if(DeviceInterface == NULL) { return 0; } dwCount = GetDeviceInterfaceSetupPreferredAudioCount(DeviceInterface); wdmDevInterfaceDec(DeviceInterface); return dwCount; } MMRESULT midiOutSendPreferredMessage(BOOL fClear) { PCWSTR DeviceInterface; UINT MidiId; MMRESULT mmr; if(!gfLogon) { return MMSYSERR_NOERROR; } midiOutGetCurrentPreferredId(&MidiId, NULL); if(MidiId == WAVE_MAPPER) { return MMSYSERR_NOERROR; } DeviceInterface = midiReferenceDevInterfaceById(&midioutdrvZ, MidiId); if(DeviceInterface == NULL) { return MMSYSERR_NOERROR; } gfMidiOutPreferredMessageSent = TRUE; mmr = midiOutMessage((HMIDIOUT)(UINT_PTR)MidiId, MODM_PREFERRED, (DWORD_PTR)fClear, (DWORD_PTR)DeviceInterface); wdmDevInterfaceDec(DeviceInterface); return mmr; } MMRESULT midiOutWritePersistentPref(IN UINT MidiOutId, IN ULONG SetupCount) { HKEY hkMidiMapper; HKEY hkcu; MIDIOUTCAPS moc; DWORD dwDisposition; LONG result; MMRESULT mmr; mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc)); if (MMSYSERR_NOERROR != mmr) return mmr; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_ALL, &hkcu))) return MMSYSERR_WRITEERROR; result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_MIDIMAP, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &hkMidiMapper, &dwDisposition); if (ERROR_SUCCESS == result) { PCWSTR pstrDeviceInterface; UINT RelativeIndex; pstrDeviceInterface = midiReferenceDevInterfaceById(&midioutdrvZ, MidiOutId); if (pstrDeviceInterface) { UINT i; RelativeIndex = 0; for (i = 0; i < MidiOutId; i++) { PCWSTR pstr = midiReferenceDevInterfaceById(&midioutdrvZ, i); if (pstr && !lstrcmpi(pstrDeviceInterface, pstr)) RelativeIndex++; if (pstr) wdmDevInterfaceDec(pstr); } } else { RelativeIndex = 0; } result = RegSetSzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_SZPNAME, moc.szPname); if (ERROR_SUCCESS == result) result = RegSetDwordValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_RELATIVEINDEX, RelativeIndex); if (ERROR_SUCCESS == result) result = RegSetSzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_DEVICEINTERFACE, pstrDeviceInterface ? pstrDeviceInterface : TEXT("")); if (ERROR_SUCCESS == result) result = RegSetDwordValue(hkMidiMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, SetupCount); if (ERROR_SUCCESS == result) RegDeleteValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_CURRENTINSTRUMENT); if (pstrDeviceInterface) wdmDevInterfaceDec(pstrDeviceInterface); RegCloseKey(hkMidiMapper); } if (ERROR_SUCCESS != result) mmr = MMSYSERR_WRITEERROR; NtClose(hkcu); return mmr; } MMRESULT midiOutGetIdFromName(IN PTSTR pstrName, OUT UINT *pMidiOutId) { UINT MidiOutId; UINT cMidiOutId; MMRESULT mmr; cMidiOutId = midiOutGetNumDevs(); for (MidiOutId = 0; MidiOutId < cMidiOutId; MidiOutId++) { MIDIOUTCAPS moc; mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc)); if (MMSYSERR_NOERROR == mmr) { if (!lstrcmp(pstrName, moc.szPname)) { mmr = MMSYSERR_NOERROR; break; } } } if (MidiOutId == cMidiOutId) { mmr = MMSYSERR_NODRIVER; } if (MMSYSERR_NOERROR == mmr) *pMidiOutId = MidiOutId; return mmr; } MMRESULT midiOutGetIdFromDiAndIndex(IN PTSTR pstrDeviceInterface, IN INT RelativeIndex, OUT UINT *pMidiOutId) { UINT cMidiOut; UINT MidiOutId; MMRESULT mmr; mmr = MMSYSERR_NODRIVER; cMidiOut = midiOutGetNumDevs(); if (0 == cMidiOut) return MMSYSERR_NODRIVER; for (MidiOutId = 0; MidiOutId < cMidiOut; MidiOutId++) { PCWSTR pstr = midiReferenceDevInterfaceById(&midioutdrvZ, MidiOutId); if (pstr && !lstrcmpi(pstr, pstrDeviceInterface) && (0 == RelativeIndex--)) { *pMidiOutId = MidiOutId; wdmDevInterfaceDec(pstr); mmr = MMSYSERR_NOERROR; break; } if (pstr) wdmDevInterfaceDec(pstr); } return mmr; } MMRESULT midiOutGetInstrumentDriverData(IN PCTSTR pstrMidiSubkeyName, OUT PTSTR *ppstrDeviceInterface, OUT UINT *pDriverNum, OUT UINT *pPortNum, OUT PTSTR *ppstrPname) { HKEY hkMidi; HKEY hkMidiSubkey; LONG result; MMRESULT mmr; BOOL f; mmr = MMSYSERR_ERROR; result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES_MIDI, 0, KEY_QUERY_VALUE, &hkMidi); if (ERROR_SUCCESS != result) return MMSYSERR_ERROR; result = RegOpenKeyEx(hkMidi, pstrMidiSubkeyName, 0, KEY_QUERY_VALUE, &hkMidiSubkey); if (ERROR_SUCCESS == result) { PTSTR pstrActive; result = RegQuerySzValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_ACTIVE, &pstrActive); if (ERROR_SUCCESS == result) { PTCHAR pchEnd; BOOL fActive = _tcstol(pstrActive, &pchEnd, 10); f = HeapFree(hHeap, 0, pstrActive); WinAssert(f); if (fActive) { PTSTR pstrDeviceInterface = NULL; PTSTR pstrPname = NULL; DWORD dwDriverNum; DWORD dwPortNum; result = RegQueryDwordValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PHYSDEVID, &dwDriverNum); if (ERROR_SUCCESS == result) result = RegQueryDwordValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PORT, &dwPortNum); if (ERROR_SUCCESS == result) RegQuerySzValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DEVICEINTERFACE, &pstrDeviceInterface); if (ERROR_SUCCESS == result) RegQuerySzValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DESCRIPTION, &pstrPname); if (ERROR_SUCCESS == result) { *ppstrDeviceInterface = NULL; *ppstrPname = NULL; if (pstrDeviceInterface) { if (lstrlen(pstrDeviceInterface)> 0) { *ppstrDeviceInterface = pstrDeviceInterface; } else { HeapFree(hHeap, 0, pstrDeviceInterface); } } if (pstrPname) { if (lstrlen(pstrPname)> 0) { *ppstrPname = pstrPname; } else { HeapFree(hHeap, 0, pstrPname); } } *pDriverNum = dwDriverNum; *pPortNum = dwPortNum; mmr = MMSYSERR_NOERROR; } } } result = RegCloseKey(hkMidiSubkey); WinAssert(ERROR_SUCCESS == result); } result = RegCloseKey(hkMidi); WinAssert(ERROR_SUCCESS == result); return mmr; } MMRESULT midiOutGetIdFromInstrument(IN PTSTR pstrMidiKeyName, OUT UINT *outMidiOutId) { PTSTR pstrDeviceInterface, pstrPname; UINT DriverNum, PortNum; UINT MidiOutId; MMRESULT mmr; mmr = midiOutGetInstrumentDriverData(pstrMidiKeyName, &pstrDeviceInterface, &DriverNum, &PortNum, &pstrPname); if (MMSYSERR_NOERROR == mmr) { if (pstrDeviceInterface) { mmr = midiOutGetIdFromDiAndIndex(pstrDeviceInterface, PortNum, &MidiOutId); } else if (pstrPname) { mmr = midiOutGetIdFromName(pstrPname, &MidiOutId); } else { PMIDIDRV pmidioutdrv = midioutdrvZ.Next; UINT DriverNum1 = DriverNum + 1; MidiOutId = 0; while ((pmidioutdrv != &midioutdrvZ) && (0 < DriverNum1)) { MidiOutId += pmidioutdrv->NumDevs; DriverNum1--; pmidioutdrv = pmidioutdrv->Next; } if ((pmidioutdrv != &midioutdrvZ) && (PortNum < pmidioutdrv->NumDevs)) { MidiOutId += PortNum; } else { MidiOutId = MIDI_MAPPER; mmr = MMSYSERR_ERROR; } } if (pstrDeviceInterface) HeapFree(hHeap, 0, pstrDeviceInterface); if (pstrPname) HeapFree(hHeap, 0, pstrPname); } if (MMSYSERR_NOERROR == mmr) { MIDIOUTCAPS moc; WinAssert(MIDI_MAPPER != MidiOutId); mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc)); } if (MMSYSERR_NOERROR == mmr) *outMidiOutId = MidiOutId; return mmr; } MMRESULT midiOutReadCurrentInstrument(OUT PTSTR *ppstrCurrentInstrument, OUT DWORD *pSetupCount) { HKEY hkcu; HKEY hkMidiMapper; LONG result; MMRESULT mmr; mmr = MMSYSERR_ERROR; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return MMSYSERR_READERROR; result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_MIDIMAP, 0, KEY_QUERY_VALUE, &hkMidiMapper); if (ERROR_SUCCESS == result) { result = RegQuerySzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_CURRENTINSTRUMENT, ppstrCurrentInstrument); if (ERROR_SUCCESS == result) { DWORD SetupCount; result = RegQueryDwordValue(hkMidiMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount); SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0; *pSetupCount = SetupCount; mmr = MMSYSERR_NOERROR; } else { mmr = MMSYSERR_ERROR; } result = RegCloseKey(hkMidiMapper); WinAssert(ERROR_SUCCESS == result); } NtClose(hkcu); return mmr; } MMRESULT midiOutReadPreferredDeviceData(OUT PTSTR *ppstrDeviceInterface, OUT UINT *pRelativeIndex, OUT PTSTR *ppstrPname, OUT ULONG *pSetupCount) { HKEY hkcu; HKEY hkMidiMapper; LONG result; MMRESULT mmr; if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return MMSYSERR_READERROR; result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_MIDIMAP, 0, KEY_QUERY_VALUE, &hkMidiMapper); if (ERROR_SUCCESS == result) { PTSTR pstrDeviceInterface = NULL; PTSTR pstrPname = NULL; DWORD dwIndex; DWORD dwSetupCount; // See if we have a Pname. It is okay not to. result = RegQuerySzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_SZPNAME, &pstrPname); if (ERROR_FILE_NOT_FOUND == result) result = ERROR_SUCCESS; // See if we have a device interface + relative index. It is okay not to. if (ERROR_SUCCESS == result) result = RegQueryDwordValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_RELATIVEINDEX, &dwIndex); if (ERROR_SUCCESS == result) result = RegQuerySzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_DEVICEINTERFACE, &pstrDeviceInterface); if (ERROR_FILE_NOT_FOUND == result) result = ERROR_SUCCESS; // The device interface value might be zero length. Act as thought it // doesn't exist in this case. if ((ERROR_SUCCESS == result) && (pstrDeviceInterface) && (0 == lstrlen(pstrDeviceInterface))) { HeapFree(hHeap, 0, pstrDeviceInterface); pstrDeviceInterface = NULL; dwIndex = 0; } if (ERROR_SUCCESS != RegQueryDwordValue(hkMidiMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &dwSetupCount)) { dwSetupCount = 0; } if (ERROR_SUCCESS == result) { if (pstrPname || pstrDeviceInterface) { *ppstrDeviceInterface = pstrDeviceInterface; *ppstrPname = pstrPname; *pRelativeIndex = dwIndex; *pSetupCount = dwSetupCount; mmr = MMSYSERR_NOERROR; } else { mmr = MMSYSERR_VALNOTFOUND; } } else { mmr = MMSYSERR_READERROR; } if (MMSYSERR_NOERROR != mmr) { if (pstrDeviceInterface) HeapFree(hHeap, 0, pstrDeviceInterface); if (pstrPname) HeapFree(hHeap, 0, pstrPname); } RegCloseKey(hkMidiMapper); } else { if (ERROR_FILE_NOT_FOUND == result) mmr = MMSYSERR_KEYNOTFOUND; else mmr = MMSYSERR_READERROR; } NtClose(hkcu); return mmr; } MMRESULT midiOutReadPersistentPreferredId(OUT UINT *pMidiPrefId, OUT ULONG *pSetupCount) { PTSTR pstrDeviceInterface; PTSTR pstrPname; UINT RelativeIndex; UINT MidiOutId; ULONG SetupCount; MMRESULT mmr; mmr = midiOutReadPreferredDeviceData(&pstrDeviceInterface, &RelativeIndex, &pstrPname, &SetupCount); if (MMSYSERR_NOERROR == mmr) { WinAssert(pstrDeviceInterface || pstrPname); if (pstrDeviceInterface) { mmr = midiOutGetIdFromDiAndIndex(pstrDeviceInterface, RelativeIndex, &MidiOutId); } else { WinAssert(pstrPname); mmr = midiOutGetIdFromName(pstrPname, &MidiOutId); } if (pstrDeviceInterface) HeapFree(hHeap, 0, pstrDeviceInterface); if (pstrPname) HeapFree(hHeap, 0, pstrPname); } else if (MMSYSERR_VALNOTFOUND == mmr || MMSYSERR_KEYNOTFOUND == mmr) { PTSTR pstrMidiKeyName; mmr = midiOutReadCurrentInstrument(&pstrMidiKeyName, &SetupCount); if (MMSYSERR_NOERROR == mmr) { mmr = midiOutGetIdFromInstrument(pstrMidiKeyName, &MidiOutId); // Since this is older format for storing preference, let's // rewrite it in newer format. if (MMSYSERR_NOERROR == mmr) { midiOutWritePersistentPref(MidiOutId, SetupCount); } HeapFree(hHeap, 0, pstrMidiKeyName); } } if (MMSYSERR_NOERROR == mmr) { *pMidiPrefId = MidiOutId; *pSetupCount = SetupCount; } return mmr; } MMRESULT midiOutPickBestId(PUINT pMidiPrefId, UINT WaveOutPrefId) { MIDIOUTCAPS moc; UINT cMidiOutId; UINT MidiOutId; UINT UserSelectedMidiOutId; UINT WavetableMidiOutId; UINT SoftwareMidiOutId; UINT OtherMidiOutId; UINT FmMidiOutId; UINT ExternalMidiOutId; DWORD MidiOutIdCount; DWORD UserSelectedMidiOutIdCount; DWORD WavetableMidiOutIdCount; DWORD SoftwareMidiOutIdCount; DWORD OtherMidiOutIdCount; DWORD FmMidiOutIdCount; DWORD ExternalMidiOutIdCount; MMRESULT mmrLastError; MMRESULT mmr; BOOL f; UserSelectedMidiOutId = MIDI_MAPPER; WavetableMidiOutId = MIDI_MAPPER; SoftwareMidiOutId = MIDI_MAPPER; OtherMidiOutId = MIDI_MAPPER; FmMidiOutId = MIDI_MAPPER; ExternalMidiOutId = MIDI_MAPPER; MidiOutId = MIDI_MAPPER; UserSelectedMidiOutIdCount = 0; WavetableMidiOutIdCount = 0; SoftwareMidiOutIdCount = 0; OtherMidiOutIdCount = 0; FmMidiOutIdCount = 0; ExternalMidiOutIdCount = 0; MidiOutIdCount = 0; mmr = midiOutReadPersistentPreferredId(&UserSelectedMidiOutId, &UserSelectedMidiOutIdCount); mmrLastError = MMSYSERR_NODRIVER; cMidiOutId = midiOutGetNumDevs(); for (MidiOutId = 0; MidiOutId < cMidiOutId; MidiOutId++) { mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc)); if (MMSYSERR_NOERROR == mmr) { MidiOutIdCount = midiOutGetSetupPreferredAudioCount(MidiOutId); if (MOD_SWSYNTH == moc.wTechnology && MM_MSFT_WDMAUDIO_MIDIOUT == moc.wPid && MM_MICROSOFT == moc.wMid) { // We need to special case this synth, and get the count from // the preferred audio device. SoftwareMidiOutId = MidiOutId; if ((-1) != WaveOutPrefId) { SoftwareMidiOutIdCount = waveOutGetSetupPreferredAudioCount(WaveOutPrefId); } else { SoftwareMidiOutIdCount = 0; } } else if (MOD_FMSYNTH == moc.wTechnology) { FmMidiOutId = MidiOutId; FmMidiOutIdCount = MidiOutIdCount; } else if (MOD_MIDIPORT == moc.wTechnology) { ExternalMidiOutId = MidiOutId; ExternalMidiOutIdCount = MidiOutIdCount; } else if (MOD_WAVETABLE == moc.wTechnology) { WavetableMidiOutId = MidiOutId; WavetableMidiOutIdCount = MidiOutIdCount; } else { OtherMidiOutId = MidiOutId; OtherMidiOutIdCount = MidiOutIdCount; } } else { mmrLastError = mmr; } } MidiOutId = ExternalMidiOutId; MidiOutIdCount = ExternalMidiOutIdCount; if ((FmMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != FmMidiOutId)) { MidiOutId = FmMidiOutId; MidiOutIdCount = FmMidiOutIdCount; } if ((OtherMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != OtherMidiOutId)) { MidiOutId = OtherMidiOutId; MidiOutIdCount = OtherMidiOutIdCount; } if ((SoftwareMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != SoftwareMidiOutId)) { MidiOutId = SoftwareMidiOutId; MidiOutIdCount = SoftwareMidiOutIdCount; } if ((WavetableMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != WavetableMidiOutId)) { MidiOutId = WavetableMidiOutId; MidiOutIdCount = WavetableMidiOutIdCount; } if ((UserSelectedMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != UserSelectedMidiOutId)) { MidiOutId = UserSelectedMidiOutId; MidiOutIdCount = UserSelectedMidiOutIdCount; } if ((-1) != MidiOutId) { mmr = MMSYSERR_NOERROR; } else { mmr = mmrLastError; } if (MMSYSERR_NOERROR == mmr) *pMidiPrefId = MidiOutId; return mmr; } void midiOutGetCurrentPreferredId(PUINT pPrefId, PDWORD pdwFlags) { *pPrefId = WAVE_MAPPER; if (pdwFlags) *pdwFlags = 0;; if (gpstrMoDefaultStringId) mregGetIdFromStringId(&midioutdrvZ, gpstrMoDefaultStringId, pPrefId); return; } MMRESULT midiOutSetCurrentPreferredId(UINT PrefId) { MMRESULT mmr; WinAssert(PrefId < wTotalMidiOutDevs || PrefId == MIDI_MAPPER); mmr = MMSYSERR_NOERROR; if (gpstrMoDefaultStringId) HeapFree(hHeap, 0, gpstrMoDefaultStringId); gpstrMoDefaultStringId = NULL; if (wTotalMidiOutDevs) { PMIDIDRV pmididrv; UINT port; mmr = midiReferenceDriverById(&midioutdrvZ, PrefId, &pmididrv, &port); if (!mmr) { mmr = mregCreateStringIdFromDriverPort(pmididrv, port, &gpstrMoDefaultStringId, NULL); if (!mmr) { if (!gfDisablePreferredDeviceReordering) { // Rearrange some of the driver list so that the preferred midiOut // device has a good chance of having device ID 0 if (0 != PrefId) { // Move the midi driver to the head of this list. This usually // makes the preferred device have ID 0. EnterNumDevs("midiOutSetCurrentPreferredId"); pmididrv->Prev->Next = pmididrv->Next; pmididrv->Next->Prev = pmididrv->Prev; pmididrv->Next = midioutdrvZ.Next; pmididrv->Prev = &midioutdrvZ; midioutdrvZ.Next->Prev = pmididrv; midioutdrvZ.Next = pmididrv; LeaveNumDevs("midiOutSetCurrentPreferredId"); mregDecUsagePtr(pmididrv); } } } } } if (!mmr) { // Reconfigure the mapper only if it was already loaded. Don't cause it to // load simply so that we can reconfigure it! if (MidiMapperInitialized) midiOutMessage((HMIDIOUT)(UINT_PTR)MIDI_MAPPER, DRVM_MAPPER_RECONFIGURE, 0, 0); } return mmr; } MMRESULT midiOutSetPersistentPreferredId(UINT PrefId, DWORD dwFlags) { MMRESULT mmr; mmr = midiOutWritePersistentPref(PrefId, GetCurrentSetupPreferredAudioCount()); if (!mmr) NotifyServerPreferredDeviceChange(); return mmr; } //------------------------------------------------------------------------------ // // // RefreshPreferredDevices // // //------------------------------------------------------------------------------ void RefreshPreferredDevices(void) { UINT WaveOutPreferredId; DWORD WaveOutPreferredFlags; UINT WaveInPreferredId; DWORD WaveInPreferredFlags; UINT WaveOutConsoleVoiceComId; DWORD WaveOutConsoleVoiceComFlags; UINT WaveInConsoleVoiceComId; DWORD WaveInConsoleVoiceComFlags; UINT MidiOutPreferredId; UINT OldWaveOutPreferredId; DWORD OldWaveOutPreferredFlags; UINT OldWaveInPreferredId; DWORD OldWaveInPreferredFlags; UINT OldWaveOutConsoleVoiceComId; DWORD OldWaveOutConsoleVoiceComFlags; UINT OldWaveInConsoleVoiceComId; DWORD OldWaveInConsoleVoiceComFlags; UINT OldMidiOutPreferredId; // Squirt("RefreshPreferredDevices"); BOOL fImpersonate = FALSE; waveOutGetCurrentPreferredId(&OldWaveOutPreferredId, &OldWaveOutPreferredFlags); if (!waveOutPickBestId(&WaveOutPreferredId, &WaveOutPreferredFlags)) { if ((WaveOutPreferredId != OldWaveOutPreferredId) || (WaveOutPreferredFlags != OldWaveOutPreferredFlags) || !gfWaveOutPreferredMessageSent) { // Squirt("RefreshPreferredDevices: different waveOut preference %d -> %d", OldWaveOutPreferredId, WaveOutPreferredId); waveOutSendPreferredMessage(TRUE); waveOutSetCurrentPreferredId(WaveOutPreferredId, WaveOutPreferredFlags); waveOutSendPreferredMessage(FALSE); } } waveOutGetCurrentConsoleVoiceComId(&OldWaveOutConsoleVoiceComId, &OldWaveOutConsoleVoiceComFlags); if (!wavePickBestConsoleVoiceComId(TRUE, &WaveOutConsoleVoiceComId, &WaveOutConsoleVoiceComFlags)) { if ((WaveOutConsoleVoiceComId != OldWaveOutConsoleVoiceComId) || (WaveOutConsoleVoiceComFlags != OldWaveOutConsoleVoiceComFlags)) { // Squirt("RefreshPreferredDevices: different waveOut preference %d -> %d", OldWaveOutConsoleVoiceComId, WaveOutConsoleVoiceComId); waveOutSetCurrentConsoleVoiceComId(WaveOutConsoleVoiceComId, WaveOutConsoleVoiceComFlags); } } waveInGetCurrentPreferredId(&OldWaveInPreferredId, &OldWaveInPreferredFlags); if (!waveInPickBestId(&WaveInPreferredId, &WaveInPreferredFlags)) { if ((WaveInPreferredId != OldWaveInPreferredId) || (WaveInPreferredFlags != OldWaveInPreferredFlags) || !gfWaveInPreferredMessageSent) { // Squirt("RefreshPreferredDevices: different waveIn preference %d -> %d", OldWaveInPreferredId, WaveInPreferredId); waveInSendPreferredMessage(TRUE); waveInSetCurrentPreferredId(WaveInPreferredId, WaveInPreferredFlags); waveInSendPreferredMessage(FALSE); } } waveInGetCurrentConsoleVoiceComId(&OldWaveInConsoleVoiceComId, &OldWaveInConsoleVoiceComFlags); if (!wavePickBestConsoleVoiceComId(FALSE, &WaveInConsoleVoiceComId, &WaveInConsoleVoiceComFlags)) { if ((WaveInConsoleVoiceComId != OldWaveInConsoleVoiceComId) || (WaveInConsoleVoiceComFlags != OldWaveInConsoleVoiceComFlags)) { // Squirt("RefreshPreferredDevices: different waveIn preference %d -> %d", OldWaveInConsoleVoiceComId, WaveInConsoleVoiceComId); waveInSetCurrentConsoleVoiceComId(WaveInConsoleVoiceComId, WaveInConsoleVoiceComFlags); } } midiOutGetCurrentPreferredId(&OldMidiOutPreferredId, NULL); if (!midiOutPickBestId(&MidiOutPreferredId, WaveOutPreferredId)) { if (MidiOutPreferredId != OldMidiOutPreferredId || !gfMidiOutPreferredMessageSent) { // Squirt("RefreshPreferredDevices: different midiOut preference %d -> %d", OldMidiOutPreferredId, MidiOutPreferredId); midiOutSendPreferredMessage(TRUE); midiOutSetCurrentPreferredId(MidiOutPreferredId); midiOutSendPreferredMessage(FALSE); } } // Squirt("RefreshPreferredDevices: return"); return; } void InvalidatePreferredDevices(void) { if (gpstrWoDefaultStringId) HeapFree(hHeap, 0, gpstrWoDefaultStringId); if (gpstrWiDefaultStringId) HeapFree(hHeap, 0, gpstrWiDefaultStringId); gpstrWoDefaultStringId = NULL; gpstrWiDefaultStringId = NULL; if (gpstrWoConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWoConsoleVoiceComStringId); if (gpstrWiConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWiConsoleVoiceComStringId); gpstrWoConsoleVoiceComStringId = NULL; gpstrWiConsoleVoiceComStringId = NULL; if (gpstrMoDefaultStringId) HeapFree(hHeap, 0, gpstrMoDefaultStringId); gpstrMoDefaultStringId = NULL; }