Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1952 lines
60 KiB

  1. /* Copyright (c) 1998-2001 Microsoft Corporation */
  2. #define UNICODE
  3. #define _UNICODE
  4. #include "nt.h"
  5. #include "ntrtl.h"
  6. #include "nturtl.h"
  7. #include "winmmi.h"
  8. #include <mmreg.h>
  9. #include <regstr.h>
  10. #include <stdlib.h>
  11. #include <tchar.h>
  12. #include "audiosrvc.h"
  13. extern PCWSTR waveReferenceDevInterfaceById(IN PWAVEDRV pdrvZ, IN UINT_PTR id);
  14. extern PCWSTR midiReferenceDevInterfaceById(IN PMIDIDRV pdrvZ, IN UINT_PTR id);
  15. #define REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER TEXT("Software\\Microsoft\\Multimedia\\Sound Mapper")
  16. #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PLAYBACK TEXT("Playback")
  17. #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_RECORD TEXT("Record")
  18. #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_PLAYBACK TEXT("ConsoleVoiceComPlayback")
  19. #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_RECORD TEXT("ConsoleVoiceComRecord")
  20. #define REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY TEXT("PreferredOnly")
  21. #define REGSTR_PATH_MEDIARESOURCES_MIDI REGSTR_PATH_MEDIARESOURCES TEXT("\\MIDI")
  22. #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_ACTIVE TEXT("Active")
  23. #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DESCRIPTION TEXT("Description")
  24. #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DEVICEINTERFACE TEXT("DeviceInterface")
  25. #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PHYSDEVID TEXT("PhysDevID")
  26. #define REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PORT TEXT("Port")
  27. #define REGSTR_PATH_MULTIMEDIA_MIDIMAP REGSTR_PATH_MULTIMEDIA TEXT("\\MIDIMap")
  28. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_CONFIGURECOUNT TEXT("ConfigureCount")
  29. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_USESCHEME TEXT("UseScheme")
  30. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_DRIVERLIST TEXT("DriverList")
  31. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_AUTOSCHEME TEXT("AutoScheme")
  32. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_CURRENTINSTRUMENT TEXT("CurrentInstrument")
  33. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_DEVICEINTERFACE TEXT("DeviceInterface")
  34. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_RELATIVEINDEX TEXT("RelativeIndex")
  35. #define REGSTR_VAL_MULTIMEDIA_MIDIMAP_SZPNAME TEXT("szPname")
  36. #define REGSTR_VAL_SETUPPREFERREDAUDIODEVICES TEXT("SetupPreferredAudioDevices")
  37. #define REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT TEXT("SetupPreferredAudioDevicesCount")
  38. extern BOOL WaveMapperInitialized; // in winmm.c
  39. extern BOOL MidiMapperInitialized; // in winmm.c
  40. // Preferred Ids. Setting these to *_MAPPER indicates no setting.
  41. PWSTR gpstrWoDefaultStringId = NULL;
  42. PWSTR gpstrWiDefaultStringId = NULL;
  43. PWSTR gpstrWoConsoleVoiceComStringId = NULL;
  44. PWSTR gpstrWiConsoleVoiceComStringId = NULL;
  45. BOOL gfUsePreferredWaveOnly = TRUE;
  46. PWSTR gpstrMoDefaultStringId = NULL;
  47. // These will be TRUE if we sent the preferred device change
  48. // to sysaudio.
  49. BOOL gfWaveOutPreferredMessageSent = FALSE;
  50. BOOL gfWaveInPreferredMessageSent = FALSE;
  51. BOOL gfMidiOutPreferredMessageSent = FALSE;
  52. //------------------------------------------------------------------------------
  53. //
  54. //
  55. // Registry helpers
  56. //
  57. //
  58. //------------------------------------------------------------------------------
  59. LONG RegQuerySzValue(HKEY hkey, PCTSTR pValueName, PTSTR *ppstrValue)
  60. {
  61. LONG result;
  62. DWORD typeValue;
  63. DWORD cbstrValue = 0;
  64. BOOL f;
  65. result = RegQueryValueEx(hkey, pValueName, 0, &typeValue, NULL, &cbstrValue);
  66. if (ERROR_SUCCESS == result)
  67. {
  68. if (REG_SZ == typeValue)
  69. {
  70. PTSTR pstrValue;
  71. pstrValue = HeapAlloc(hHeap, 0, cbstrValue);
  72. if (pstrValue)
  73. {
  74. result = RegQueryValueEx(hkey, pValueName, 0, &typeValue, (PBYTE)pstrValue, &cbstrValue);
  75. if (ERROR_SUCCESS == result)
  76. {
  77. if (REG_SZ == typeValue)
  78. {
  79. *ppstrValue = pstrValue;
  80. } else {
  81. result = ERROR_FILE_NOT_FOUND;
  82. f = HeapFree(hHeap, 0, pstrValue);
  83. WinAssert(f);
  84. }
  85. } else {
  86. f = HeapFree(hHeap, 0, pstrValue);
  87. WinAssert(f);
  88. }
  89. } else {
  90. result = ERROR_OUTOFMEMORY;
  91. }
  92. } else {
  93. result = ERROR_FILE_NOT_FOUND;
  94. }
  95. }
  96. return result;
  97. }
  98. LONG RegQueryDwordValue(HKEY hkey, PCTSTR pValueName, PDWORD pdwValue)
  99. {
  100. DWORD cbdwValue;
  101. LONG result;
  102. cbdwValue = sizeof(*pdwValue);
  103. result = RegQueryValueEx(hkey, pValueName, 0, NULL, (PBYTE)pdwValue, &cbdwValue);
  104. return result;
  105. }
  106. LONG RegSetSzValue(HKEY hkey, PCTSTR pValueName, PCTSTR pstrValue)
  107. {
  108. DWORD cbstrValue = (lstrlen(pstrValue) + 1) * sizeof(pstrValue[0]);
  109. return RegSetValueEx(hkey, pValueName, 0, REG_SZ, (PBYTE)pstrValue, cbstrValue);
  110. }
  111. LONG RegSetDwordValue(HKEY hkey, PCTSTR pValueName, DWORD dwValue)
  112. {
  113. return RegSetValueEx(hkey, pValueName, 0, REG_DWORD, (PBYTE)&dwValue, sizeof(dwValue));
  114. }
  115. //------------------------------------------------------------------------------
  116. //
  117. //
  118. // AutoSetupPreferredAudio functions
  119. //
  120. //
  121. //------------------------------------------------------------------------------
  122. //--------------------------------------------------------------------------;
  123. //
  124. // DWORD GetCurrentSetupPreferredAudioCount
  125. //
  126. // Arguments:
  127. //
  128. // Return value:
  129. //
  130. // History:
  131. // 1/19/99 FrankYe Created
  132. //
  133. //--------------------------------------------------------------------------;
  134. DWORD GetCurrentSetupPreferredAudioCount(void)
  135. {
  136. HKEY hkeySetupPreferredAudioDevices;
  137. DWORD SetupCount = 0;
  138. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES TEXT("\\") REGSTR_VAL_SETUPPREFERREDAUDIODEVICES, 0, KEY_QUERY_VALUE, &hkeySetupPreferredAudioDevices))
  139. {
  140. if (ERROR_SUCCESS != RegQueryDwordValue(hkeySetupPreferredAudioDevices, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount)) {
  141. Squirt("GCSPATS: Couldn't read hklm\\...\\SetupPreferredAudioDevicesCount");
  142. }
  143. if (ERROR_SUCCESS != RegCloseKey(hkeySetupPreferredAudioDevices)) {
  144. WinAssert(!"GCSPATS: unexpected failure of RegCloseKey");
  145. }
  146. } else {
  147. Squirt("GCSPATS: Couldn't open hklm\\...\\SetupPreferredAudioDevices");
  148. }
  149. return SetupCount;
  150. }
  151. //--------------------------------------------------------------------------;
  152. //
  153. // DWORD GetDeviceInterfaceSetupPreferredAudioCount
  154. //
  155. // Arguments:
  156. //
  157. // Return value:
  158. //
  159. // History:
  160. // 1/19/99 FrankYe Created
  161. //
  162. //--------------------------------------------------------------------------;
  163. DWORD GetDeviceInterfaceSetupPreferredAudioCount(PCWSTR DeviceInterface)
  164. {
  165. PMMDEVICEINTERFACEINFO pdii;
  166. PMMPNPINFO pPnpInfo;
  167. LONG cbPnpInfo;
  168. DWORD count;
  169. int ii;
  170. // Handle empty DeviceInterface names in case of legacy drivers
  171. if (0 == lstrlen(DeviceInterface)) return 0;
  172. if (ERROR_SUCCESS != winmmGetPnpInfo(&cbPnpInfo, &pPnpInfo)) return 0;
  173. pdii = (PMMDEVICEINTERFACEINFO)&(pPnpInfo[1]);
  174. pdii = PAD_POINTER(pdii);
  175. for (ii = pPnpInfo->cDevInterfaces; ii; ii--)
  176. {
  177. // Searching for the device interface...
  178. if (0 == lstrcmpi(pdii->szName, DeviceInterface)) break;
  179. pdii = (PMMDEVICEINTERFACEINFO)(pdii->szName + lstrlenW(pdii->szName) + 1);
  180. pdii = PAD_POINTER(pdii);
  181. }
  182. WinAssert(ii);
  183. count = pdii->SetupPreferredAudioCount;
  184. HeapFree(hHeap, 0, pPnpInfo);
  185. return count;
  186. }
  187. //------------------------------------------------------------------------------
  188. //
  189. //
  190. // NotifyServerPreferredDeviceChange
  191. //
  192. //
  193. //------------------------------------------------------------------------------
  194. void NotifyServerPreferredDeviceChange(void)
  195. {
  196. winmmAdvisePreferredDeviceChange();
  197. }
  198. //------------------------------------------------------------------------------
  199. //
  200. //
  201. // Wave
  202. //
  203. //
  204. //------------------------------------------------------------------------------
  205. MMRESULT waveWritePersistentConsoleVoiceCom(BOOL fOut, PTSTR pstrPref, BOOL fPrefOnly)
  206. {
  207. HKEY hkcu;
  208. HKEY hkSoundMapper;
  209. LONG result;
  210. BOOL fSuccess;
  211. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_WRITE, &hkcu))) return MMSYSERR_WRITEERROR;
  212. result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, TEXT("\0"), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkSoundMapper, NULL);
  213. if (ERROR_SUCCESS == result)
  214. {
  215. DWORD cbstrPref;
  216. cbstrPref = (lstrlen(pstrPref) + 1) * sizeof(pstrPref[0]);
  217. if (fOut)
  218. {
  219. result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_PLAYBACK, pstrPref);
  220. }
  221. else
  222. {
  223. result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_RECORD, pstrPref);
  224. }
  225. if (ERROR_SUCCESS == result)
  226. {
  227. fSuccess = TRUE;
  228. result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, (DWORD)fPrefOnly);
  229. if (ERROR_SUCCESS != result) {
  230. Squirt("wWPCVC: Could not write hkcu\\...\\Sound Mapper\\PreferredOnly");
  231. }
  232. result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, GetCurrentSetupPreferredAudioCount());
  233. if (ERROR_SUCCESS != result) {
  234. Squirt("wWPCVC: Could not write hkcu\\...\\Sound Mapper\\SetupPreferredAudioCount");
  235. }
  236. }
  237. result = RegCloseKey(hkSoundMapper);
  238. WinAssert(ERROR_SUCCESS == result);
  239. }
  240. NtClose(hkcu);
  241. return MMSYSERR_NOERROR;
  242. }
  243. BOOL waveReadPersistentConsoleVoiceCom(BOOL fOut, PTSTR *ppstrPref, PBOOL pfPrefOnly, PDWORD pSetupCount)
  244. {
  245. HKEY hkcu;
  246. HKEY hkSoundMapper;
  247. LONG result;
  248. BOOL fSuccess;
  249. fSuccess = FALSE;
  250. *ppstrPref = NULL;
  251. *pfPrefOnly = FALSE;
  252. *pSetupCount = 0;
  253. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return FALSE;
  254. result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, KEY_QUERY_VALUE, &hkSoundMapper);
  255. if (ERROR_SUCCESS == result)
  256. {
  257. DWORD SetupCount;
  258. result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
  259. SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0;
  260. if (ERROR_SUCCESS == result)
  261. {
  262. PTSTR pstrPref;
  263. BOOL fPrefOnly;
  264. DWORD dwPrefOnly;
  265. result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, &dwPrefOnly);
  266. fPrefOnly = (ERROR_SUCCESS == result) ? (0 != dwPrefOnly) : FALSE;
  267. if (fOut)
  268. {
  269. result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_PLAYBACK, &pstrPref);
  270. }
  271. else
  272. {
  273. result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_CONSOLEVOICECOM_RECORD, &pstrPref);
  274. }
  275. if (ERROR_SUCCESS != result) pstrPref = NULL;
  276. *ppstrPref = pstrPref;
  277. *pfPrefOnly = fPrefOnly;
  278. *pSetupCount = SetupCount;
  279. fSuccess = TRUE;
  280. }
  281. result = RegCloseKey(hkSoundMapper);
  282. WinAssert(ERROR_SUCCESS == result);
  283. }
  284. NtClose(hkcu);
  285. return fSuccess;
  286. }
  287. MMRESULT wavePickBestConsoleVoiceComId(BOOL fOut, PUINT pPrefId, PDWORD pdwFlags)
  288. {
  289. PTSTR pstrPref;
  290. UINT cWaveId;
  291. UINT WaveId;
  292. UINT UserSelectedId;
  293. UINT NonConsoleId;
  294. UINT PreferredId;
  295. DWORD UserSelectedIdSetupCount;
  296. BOOL fPrefOnly;
  297. BOOL f;
  298. UserSelectedId = WAVE_MAPPER;
  299. if (fOut)
  300. {
  301. waveOutGetCurrentPreferredId(&NonConsoleId, NULL);
  302. cWaveId = waveOutGetNumDevs();
  303. waveReadPersistentConsoleVoiceCom(fOut, &pstrPref, &fPrefOnly, &UserSelectedIdSetupCount);
  304. *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  305. for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--)
  306. {
  307. WAVEOUTCAPS wc;
  308. MMRESULT mmr;
  309. mmr = waveOutGetDevCaps(WaveId, &wc, sizeof(wc));
  310. if (mmr) continue;
  311. wc.szPname[MAXPNAMELEN-1] = TEXT('\0');
  312. if (pstrPref && !lstrcmp(wc.szPname, pstrPref))
  313. {
  314. UserSelectedId = WaveId;
  315. break;
  316. }
  317. }
  318. }
  319. else
  320. {
  321. waveInGetCurrentPreferredId(&NonConsoleId, NULL);
  322. cWaveId = waveInGetNumDevs();
  323. waveReadPersistentConsoleVoiceCom(fOut, &pstrPref, &fPrefOnly, &UserSelectedIdSetupCount);
  324. *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  325. for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--)
  326. {
  327. WAVEINCAPS wc;
  328. MMRESULT mmr;
  329. mmr = waveInGetDevCaps(WaveId, &wc, sizeof(wc));
  330. if (mmr) continue;
  331. wc.szPname[MAXPNAMELEN-1] = TEXT('\0');
  332. if (pstrPref && !lstrcmp(wc.szPname, pstrPref))
  333. {
  334. UserSelectedId = WaveId;
  335. break;
  336. }
  337. }
  338. }
  339. if (pstrPref) {
  340. f = HeapFree(hHeap, 0, pstrPref);
  341. WinAssert(f);
  342. pstrPref = NULL;
  343. }
  344. PreferredId = ((WAVE_MAPPER == UserSelectedId)?NonConsoleId:UserSelectedId);
  345. *pPrefId = PreferredId;
  346. return MMSYSERR_NOERROR;
  347. }
  348. //------------------------------------------------------------------------------
  349. //
  350. //
  351. // WaveOut
  352. //
  353. //
  354. //------------------------------------------------------------------------------
  355. DWORD waveOutGetSetupPreferredAudioCount(UINT WaveId)
  356. {
  357. PCWSTR DeviceInterface;
  358. DWORD dwCount;
  359. DeviceInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, WaveId);
  360. if(DeviceInterface == NULL) {
  361. return 0;
  362. }
  363. dwCount = GetDeviceInterfaceSetupPreferredAudioCount(DeviceInterface);
  364. wdmDevInterfaceDec(DeviceInterface);
  365. return dwCount;
  366. }
  367. MMRESULT waveOutSendPreferredMessage(BOOL fClear)
  368. {
  369. PCWSTR DeviceInterface;
  370. UINT WaveId, Flags;
  371. MMRESULT mmr;
  372. if(!gfLogon) {
  373. return MMSYSERR_NOERROR;
  374. }
  375. waveOutGetCurrentPreferredId(&WaveId, &Flags);
  376. //Squirt("waveOutSendPreferredMessage: id %d f %d", WaveId, fClear);
  377. if(WaveId == WAVE_MAPPER) {
  378. return MMSYSERR_NOERROR;
  379. }
  380. DeviceInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, WaveId);
  381. if(DeviceInterface == NULL) {
  382. return MMSYSERR_NOERROR;
  383. }
  384. gfWaveOutPreferredMessageSent = TRUE;
  385. mmr = waveOutMessage((HWAVEOUT)(UINT_PTR)WaveId, WODM_PREFERRED, (DWORD_PTR)fClear, (DWORD_PTR)DeviceInterface);
  386. wdmDevInterfaceDec(DeviceInterface);
  387. return mmr;
  388. }
  389. BOOL waveOutReadPersistentPref(PTSTR *ppstrPref, PBOOL pfPrefOnly, PDWORD pSetupCount)
  390. {
  391. HKEY hkcu;
  392. HKEY hkSoundMapper;
  393. LONG result;
  394. BOOL fSuccess;
  395. fSuccess = FALSE;
  396. *ppstrPref = NULL;
  397. *pfPrefOnly = FALSE;
  398. *pSetupCount = 0;
  399. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return FALSE;
  400. result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, KEY_QUERY_VALUE, &hkSoundMapper);
  401. if (ERROR_SUCCESS == result)
  402. {
  403. DWORD SetupCount;
  404. result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
  405. SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0;
  406. if (ERROR_SUCCESS == result)
  407. {
  408. PTSTR pstrPref;
  409. BOOL fPrefOnly;
  410. DWORD dwPrefOnly;
  411. result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, &dwPrefOnly);
  412. fPrefOnly = (ERROR_SUCCESS == result) ? (0 != dwPrefOnly) : FALSE;
  413. result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PLAYBACK, &pstrPref);
  414. if (ERROR_SUCCESS != result) pstrPref = NULL;
  415. *ppstrPref = pstrPref;
  416. *pfPrefOnly = fPrefOnly;
  417. *pSetupCount = SetupCount;
  418. fSuccess = TRUE;
  419. }
  420. result = RegCloseKey(hkSoundMapper);
  421. WinAssert(ERROR_SUCCESS == result);
  422. }
  423. NtClose(hkcu);
  424. return fSuccess;
  425. }
  426. MMRESULT waveOutPickBestId(PUINT pPrefId, PDWORD pdwFlags)
  427. {
  428. PTSTR pstrPref;
  429. UINT cWaveId;
  430. UINT WaveId;
  431. UINT MappableId;
  432. UINT MixableId;
  433. UINT UserSelectedId;
  434. UINT PreferredId;
  435. DWORD WaveIdSetupCount;
  436. DWORD MappableIdSetupCount;
  437. DWORD MixableIdSetupCount;
  438. DWORD UserSelectedIdSetupCount;
  439. DWORD PreferredIdSetupCount;
  440. BOOL fPrefOnly;
  441. BOOL f;
  442. MappableId = WAVE_MAPPER;
  443. MixableId = WAVE_MAPPER;
  444. UserSelectedId = WAVE_MAPPER;
  445. PreferredId = WAVE_MAPPER;
  446. MappableIdSetupCount = 0;
  447. MixableIdSetupCount = 0;
  448. UserSelectedIdSetupCount = 0;
  449. PreferredIdSetupCount = 0;
  450. cWaveId = waveOutGetNumDevs();
  451. waveOutReadPersistentPref(&pstrPref, &fPrefOnly, &UserSelectedIdSetupCount);
  452. *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  453. for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--)
  454. {
  455. WAVEOUTCAPS wc;
  456. UINT uMixerId;
  457. MMRESULT mmr;
  458. PWAVEDRV pdrv;
  459. BOOL fThisSession;
  460. //
  461. // check the protocol name
  462. // mask all inappropriate TS/non-TS drivers
  463. //
  464. if (waveReferenceDriverById(&waveoutdrvZ, WaveId, &pdrv, NULL)) continue;
  465. fThisSession = !lstrcmpW(pdrv->wszSessProtocol, SessionProtocolName);
  466. mregDecUsagePtr(pdrv);
  467. if (!fThisSession) continue;
  468. mmr = waveOutGetDevCaps(WaveId, &wc, sizeof(wc));
  469. if (mmr) continue;
  470. wc.szPname[MAXPNAMELEN-1] = TEXT('\0');
  471. if (pstrPref && !lstrcmp(wc.szPname, pstrPref)) UserSelectedId = WaveId;
  472. WaveIdSetupCount = waveOutGetSetupPreferredAudioCount(WaveId);
  473. mmr = waveOutMessage((HWAVEOUT)(UINT_PTR)WaveId, DRV_QUERYMAPPABLE, 0L, 0L);
  474. if (mmr) continue;
  475. if (WaveIdSetupCount >= MappableIdSetupCount) {
  476. MappableId = WaveId;
  477. MappableIdSetupCount = WaveIdSetupCount;
  478. }
  479. mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)WaveId, &uMixerId, MIXER_OBJECTF_WAVEOUT);
  480. if (mmr) continue;
  481. if (WaveIdSetupCount >= MixableIdSetupCount) {
  482. MixableId = WaveId;
  483. MixableIdSetupCount = WaveIdSetupCount;
  484. }
  485. }
  486. if (pstrPref) {
  487. f = HeapFree(hHeap, 0, pstrPref);
  488. WinAssert(f);
  489. pstrPref = NULL;
  490. }
  491. PreferredId = MappableId;
  492. PreferredIdSetupCount = MappableIdSetupCount;
  493. if ((MixableIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != MixableId))
  494. {
  495. PreferredId = MixableId;
  496. PreferredIdSetupCount = MixableIdSetupCount;
  497. }
  498. if ((UserSelectedIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != UserSelectedId))
  499. {
  500. PreferredId = UserSelectedId;
  501. PreferredIdSetupCount = UserSelectedIdSetupCount;
  502. }
  503. *pPrefId = PreferredId;
  504. return MMSYSERR_NOERROR;
  505. }
  506. void waveOutGetCurrentPreferredId(PUINT pPrefId, PDWORD pdwFlags)
  507. {
  508. *pPrefId = WAVE_MAPPER;
  509. if (pdwFlags) *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  510. if (gpstrWoDefaultStringId) mregGetIdFromStringId(&waveoutdrvZ, gpstrWoDefaultStringId, pPrefId);
  511. return;
  512. }
  513. BOOL waveOutWritePersistentPref(PTSTR pstrPref, BOOL fPrefOnly)
  514. {
  515. HKEY hkcu;
  516. HKEY hkSoundMapper;
  517. LONG result;
  518. BOOL fSuccess;
  519. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_WRITE, &hkcu))) return MMSYSERR_WRITEERROR;
  520. result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, TEXT("\0"), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkSoundMapper, NULL);
  521. if (ERROR_SUCCESS == result)
  522. {
  523. DWORD cbstrPref;
  524. cbstrPref = (lstrlen(pstrPref) + 1) * sizeof(pstrPref[0]);
  525. result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PLAYBACK, pstrPref);
  526. if (ERROR_SUCCESS == result)
  527. {
  528. fSuccess = TRUE;
  529. result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, (DWORD)fPrefOnly);
  530. if (ERROR_SUCCESS != result) {
  531. Squirt("wOWPP: Could not write hkcu\\...\\Sound Mapper\\PreferredOnly");
  532. }
  533. result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, GetCurrentSetupPreferredAudioCount());
  534. if (ERROR_SUCCESS != result) {
  535. Squirt("wOWPP: Could not write hkcu\\...\\Sound Mapper\\SetupPreferredAudioCount");
  536. }
  537. }
  538. result = RegCloseKey(hkSoundMapper);
  539. WinAssert(ERROR_SUCCESS == result);
  540. }
  541. NtClose(hkcu);
  542. return MMSYSERR_NOERROR;
  543. }
  544. MMRESULT waveOutSetCurrentPreferredId(UINT PrefId, DWORD dwFlags)
  545. {
  546. MMRESULT mmr;
  547. WinAssert(PrefId < wTotalWaveOutDevs || PrefId == WAVE_MAPPER);
  548. mmr = MMSYSERR_NOERROR;
  549. if (gpstrWoDefaultStringId) HeapFree(hHeap, 0, gpstrWoDefaultStringId);
  550. gpstrWoDefaultStringId = NULL;
  551. if (wTotalWaveOutDevs)
  552. {
  553. UINT mixerId;
  554. PWAVEDRV pwavedrv;
  555. UINT port;
  556. mmr = waveReferenceDriverById(&waveoutdrvZ, PrefId, &pwavedrv, &port);
  557. if (!mmr)
  558. {
  559. mmr = mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWoDefaultStringId, NULL);
  560. if (!mmr)
  561. {
  562. if (!gfDisablePreferredDeviceReordering)
  563. {
  564. // Rearrange some of the driver list so that the preferred waveOut
  565. // device and its associated mixer device have a good chance of
  566. // having device ID 0
  567. mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)PrefId, &mixerId, MIXER_OBJECTF_WAVEOUT);
  568. if (mmr) mixerId = 0;
  569. if (0 != PrefId)
  570. {
  571. // Move the wave driver to the head of this list. This usually
  572. // makes the preferred device have ID 0.
  573. EnterNumDevs("waveOutSetCurrentPreferredId");
  574. pwavedrv->Prev->Next = pwavedrv->Next;
  575. pwavedrv->Next->Prev = pwavedrv->Prev;
  576. pwavedrv->Next = waveoutdrvZ.Next;
  577. pwavedrv->Prev = &waveoutdrvZ;
  578. waveoutdrvZ.Next->Prev = pwavedrv;
  579. waveoutdrvZ.Next = pwavedrv;
  580. LeaveNumDevs("waveOutSetCurrentPreferredId");
  581. mregDecUsagePtr(pwavedrv);
  582. }
  583. if (0 != mixerId)
  584. {
  585. PMIXERDRV pmixerdrv;
  586. mmr = mixerReferenceDriverById(mixerId, &pmixerdrv, NULL);
  587. if (!mmr)
  588. {
  589. EnterNumDevs("waveOutSetCurrentPreferredId");
  590. pmixerdrv->Prev->Next = pmixerdrv->Next;
  591. pmixerdrv->Next->Prev = pmixerdrv->Prev;
  592. pmixerdrv->Next = mixerdrvZ.Next;
  593. pmixerdrv->Prev = &mixerdrvZ;
  594. mixerdrvZ.Next->Prev = pmixerdrv;
  595. mixerdrvZ.Next = pmixerdrv;
  596. LeaveNumDevs("waveOutSetCurrentPreferredId");
  597. mregDecUsagePtr(pmixerdrv);
  598. }
  599. }
  600. }
  601. // Errors in this body are not critical
  602. mmr = MMSYSERR_NOERROR;
  603. }
  604. }
  605. }
  606. if (!mmr)
  607. {
  608. gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY));
  609. // Reconfigure the mapper only if it was already loaded. Don't cause it to
  610. // load simply so that we can reconfigure it!
  611. if (WaveMapperInitialized) waveOutMessage((HWAVEOUT)(UINT_PTR)WAVE_MAPPER, DRVM_MAPPER_RECONFIGURE, 0, 0);
  612. }
  613. return mmr;
  614. }
  615. MMRESULT waveOutSetPersistentPreferredId(UINT PrefId, DWORD dwFlags)
  616. {
  617. MMRESULT mmr;
  618. WAVEOUTCAPS woc;
  619. if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM;
  620. mmr = waveOutGetDevCaps(PrefId, &woc, sizeof(woc));
  621. if (!mmr)
  622. {
  623. woc.szPname[MAXPNAMELEN-1] = TEXT('\0');
  624. mmr = waveOutWritePersistentPref(woc.szPname, 0 != (dwFlags & 0x00000001));
  625. if (!mmr) {
  626. NotifyServerPreferredDeviceChange();
  627. } else {
  628. Squirt("waveOutSetPersistentPreferredId: waveOutWritePersistenPref failed, mmr=%08Xh", mmr);
  629. }
  630. }
  631. return mmr;
  632. }
  633. void waveOutGetCurrentConsoleVoiceComId(PUINT pPrefId, PDWORD pdwFlags)
  634. {
  635. *pPrefId = WAVE_MAPPER;
  636. *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  637. if (gpstrWoConsoleVoiceComStringId) mregGetIdFromStringId(&waveoutdrvZ, gpstrWoConsoleVoiceComStringId, pPrefId);
  638. return;
  639. }
  640. MMRESULT waveOutSetPersistentConsoleVoiceComId(UINT PrefId, DWORD dwFlags)
  641. {
  642. MMRESULT mmr;
  643. WAVEOUTCAPS woc;
  644. if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM;
  645. mmr = waveOutGetDevCaps(PrefId, &woc, sizeof(woc));
  646. if (!mmr)
  647. {
  648. woc.szPname[MAXPNAMELEN-1] = TEXT('\0');
  649. mmr = waveWritePersistentConsoleVoiceCom(TRUE, woc.szPname, 0 != (dwFlags & 0x00000001));
  650. if (!mmr) {
  651. NotifyServerPreferredDeviceChange();
  652. } else {
  653. Squirt("waveOutSetPersistentConsoleVoiceComId: waveWritePersistentConsoleVoiceCom failed, mmr=%08Xh", mmr);
  654. }
  655. }
  656. return mmr;
  657. }
  658. MMRESULT waveOutSetCurrentConsoleVoiceComId(UINT PrefId, DWORD dwFlags)
  659. {
  660. MMRESULT mmr;
  661. WinAssert(PrefId < wTotalWaveOutDevs || PrefId == WAVE_MAPPER);
  662. mmr = MMSYSERR_NOERROR;
  663. if (gpstrWoConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWoConsoleVoiceComStringId);
  664. gpstrWoConsoleVoiceComStringId = NULL;
  665. if (wTotalWaveOutDevs)
  666. {
  667. PWAVEDRV pwavedrv;
  668. UINT port;
  669. mmr = waveReferenceDriverById(&waveoutdrvZ, PrefId, &pwavedrv, &port);
  670. if (!mmr)
  671. {
  672. mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWoConsoleVoiceComStringId, NULL);
  673. gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY));
  674. }
  675. }
  676. return mmr;
  677. }
  678. //------------------------------------------------------------------------------
  679. //
  680. //
  681. // WaveIn
  682. //
  683. //
  684. //------------------------------------------------------------------------------
  685. DWORD waveInGetSetupPreferredAudioCount(UINT WaveId)
  686. {
  687. PCWSTR DeviceInterface;
  688. DWORD dwCount;
  689. DeviceInterface = waveReferenceDevInterfaceById(&waveindrvZ, WaveId);
  690. if(DeviceInterface == NULL) {
  691. return 0;
  692. }
  693. dwCount = GetDeviceInterfaceSetupPreferredAudioCount(DeviceInterface);
  694. wdmDevInterfaceDec(DeviceInterface);
  695. return dwCount;
  696. }
  697. MMRESULT waveInSendPreferredMessage(BOOL fClear)
  698. {
  699. PCWSTR DeviceInterface;
  700. UINT WaveId, Flags;
  701. MMRESULT mmr;
  702. if(!gfLogon) {
  703. return MMSYSERR_NOERROR;
  704. }
  705. waveInGetCurrentPreferredId(&WaveId, &Flags);
  706. //Squirt("waveInSendPreferredMessage: id %d f %d", WaveId, fClear);
  707. if(WaveId == WAVE_MAPPER) {
  708. return MMSYSERR_NOERROR;
  709. }
  710. DeviceInterface = waveReferenceDevInterfaceById(&waveindrvZ, WaveId);
  711. if(DeviceInterface == NULL) {
  712. return MMSYSERR_NOERROR;
  713. }
  714. gfWaveInPreferredMessageSent = TRUE;
  715. mmr = waveInMessage((HWAVEIN)(UINT_PTR)WaveId, WIDM_PREFERRED, (DWORD_PTR)fClear, (DWORD_PTR)DeviceInterface);
  716. wdmDevInterfaceDec(DeviceInterface);
  717. return mmr;
  718. }
  719. BOOL waveInReadPersistentPref(PTSTR *ppstrPref, PBOOL pfPrefOnly, PDWORD pSetupCount)
  720. {
  721. HKEY hkcu;
  722. HKEY hkSoundMapper;
  723. LONG result;
  724. BOOL fSuccess;
  725. fSuccess = FALSE;
  726. *ppstrPref = NULL;
  727. *pfPrefOnly = FALSE;
  728. *pSetupCount = 0;
  729. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return FALSE;
  730. result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, KEY_QUERY_VALUE, &hkSoundMapper);
  731. if (ERROR_SUCCESS == result)
  732. {
  733. DWORD SetupCount;
  734. result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
  735. SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0;
  736. if (ERROR_SUCCESS == result)
  737. {
  738. PTSTR pstrPref;
  739. BOOL fPrefOnly;
  740. DWORD dwPrefOnly;
  741. result = RegQueryDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, &dwPrefOnly);
  742. fPrefOnly = (ERROR_SUCCESS == result) ? (0 != dwPrefOnly) : FALSE;
  743. result = RegQuerySzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_RECORD, &pstrPref);
  744. if (ERROR_SUCCESS != result) pstrPref = NULL;
  745. *ppstrPref = pstrPref;
  746. *pfPrefOnly = fPrefOnly;
  747. *pSetupCount = SetupCount;
  748. fSuccess = TRUE;
  749. }
  750. result = RegCloseKey(hkSoundMapper);
  751. WinAssert(ERROR_SUCCESS == result);
  752. }
  753. NtClose(hkcu);
  754. return fSuccess;
  755. }
  756. MMRESULT waveInPickBestId(PUINT pPrefId, PDWORD pdwFlags)
  757. {
  758. PTSTR pstrPref;
  759. UINT cWaveId;
  760. UINT WaveId;
  761. UINT MappableId;
  762. UINT MixableId;
  763. UINT UserSelectedId;
  764. UINT PreferredId;
  765. DWORD WaveIdSetupCount;
  766. DWORD MappableIdSetupCount;
  767. DWORD MixableIdSetupCount;
  768. DWORD UserSelectedIdSetupCount;
  769. DWORD PreferredIdSetupCount;
  770. BOOL fPrefOnly;
  771. BOOL f;
  772. MappableId = WAVE_MAPPER;
  773. MixableId = WAVE_MAPPER;
  774. UserSelectedId = WAVE_MAPPER;
  775. PreferredId = WAVE_MAPPER;
  776. MappableIdSetupCount = 0;
  777. MixableIdSetupCount = 0;
  778. UserSelectedIdSetupCount = 0;
  779. PreferredIdSetupCount = 0;
  780. cWaveId = waveInGetNumDevs();
  781. waveInReadPersistentPref(&pstrPref, &fPrefOnly, &UserSelectedIdSetupCount);
  782. *pdwFlags = fPrefOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  783. for (WaveId = cWaveId-1; ((int)WaveId) >= 0; WaveId--)
  784. {
  785. WAVEINCAPS wic;
  786. UINT uMixerId;
  787. MMRESULT mmr;
  788. mmr = waveInGetDevCaps(WaveId, &wic, sizeof(wic));
  789. if (MMSYSERR_NOERROR != mmr) continue;
  790. wic.szPname[MAXPNAMELEN-1] = TEXT('\0');
  791. if (pstrPref && !lstrcmp(wic.szPname, pstrPref)) UserSelectedId = WaveId;
  792. WaveIdSetupCount = waveInGetSetupPreferredAudioCount(WaveId);
  793. mmr = waveInMessage((HWAVEIN)(UINT_PTR)WaveId, DRV_QUERYMAPPABLE, 0L, 0L);
  794. if (MMSYSERR_NOERROR != mmr) continue;
  795. if (WaveIdSetupCount >= MappableIdSetupCount) {
  796. MappableId = WaveId;
  797. MappableIdSetupCount = WaveIdSetupCount;
  798. }
  799. mmr = mixerGetID((HMIXEROBJ)(UINT_PTR)WaveId, &uMixerId, MIXER_OBJECTF_WAVEIN);
  800. if (MMSYSERR_NOERROR != mmr) continue;
  801. if (WaveIdSetupCount >= MixableIdSetupCount) {
  802. MixableId = WaveId;
  803. MixableIdSetupCount = WaveIdSetupCount;
  804. }
  805. }
  806. if (pstrPref) {
  807. f = HeapFree(hHeap, 0, pstrPref);
  808. WinAssert(f);
  809. pstrPref = NULL;
  810. }
  811. PreferredId = MappableId;
  812. PreferredIdSetupCount = MappableIdSetupCount;
  813. if ((MixableIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != MixableId)) {
  814. PreferredId = MixableId;
  815. PreferredIdSetupCount = MixableIdSetupCount;
  816. }
  817. if ((UserSelectedIdSetupCount >= PreferredIdSetupCount) && (WAVE_MAPPER != UserSelectedId))
  818. {
  819. PreferredId = UserSelectedId;
  820. PreferredIdSetupCount = UserSelectedIdSetupCount;
  821. }
  822. *pPrefId = PreferredId;
  823. return MMSYSERR_NOERROR;
  824. }
  825. void waveInGetCurrentPreferredId(PUINT pPrefId, PDWORD pdwFlags)
  826. {
  827. *pPrefId = WAVE_MAPPER;
  828. if (pdwFlags) *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  829. if (gpstrWiDefaultStringId) mregGetIdFromStringId(&waveindrvZ, gpstrWiDefaultStringId, pPrefId);
  830. return;
  831. }
  832. BOOL waveInWritePersistentPref(PTSTR pstrPref, BOOL fPrefOnly)
  833. {
  834. HKEY hkcu;
  835. HKEY hkSoundMapper;
  836. LONG result;
  837. BOOL fSuccess;
  838. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_WRITE, &hkcu))) return MMSYSERR_WRITEERROR;
  839. result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_SOUNDMAPPER, 0, TEXT("\0"), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkSoundMapper, NULL);
  840. if (ERROR_SUCCESS == result)
  841. {
  842. DWORD cbstrPref;
  843. cbstrPref = (lstrlen(pstrPref) + 1) * sizeof(pstrPref[0]);
  844. result = RegSetSzValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_RECORD, pstrPref);
  845. if (ERROR_SUCCESS == result)
  846. {
  847. fSuccess = TRUE;
  848. result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_MULTIMEDIA_SOUNDMAPPER_PREFERREDONLY, (DWORD)fPrefOnly);
  849. if (ERROR_SUCCESS != result) {
  850. Squirt("wiWPP: Could not write hkcu\\...\\Sound Mapper\\PreferredOnly");
  851. }
  852. result = RegSetDwordValue(hkSoundMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, GetCurrentSetupPreferredAudioCount());
  853. if (ERROR_SUCCESS != result) {
  854. Squirt("wiWPP: Could not write hkcu\\...\\Sound Mapper\\SetupPreferredAudioCount");
  855. }
  856. }
  857. result = RegCloseKey(hkSoundMapper);
  858. WinAssert(ERROR_SUCCESS == result);
  859. }
  860. NtClose(hkcu);
  861. return MMSYSERR_NOERROR;
  862. }
  863. MMRESULT waveInSetCurrentPreferredId(UINT PrefId, DWORD dwFlags)
  864. {
  865. MMRESULT mmr;
  866. WinAssert(PrefId < wTotalWaveInDevs || PrefId == WAVE_MAPPER);
  867. mmr = MMSYSERR_NOERROR;
  868. if (gpstrWiDefaultStringId) HeapFree(hHeap, 0, gpstrWiDefaultStringId);
  869. gpstrWiDefaultStringId = NULL;
  870. if (wTotalWaveInDevs)
  871. {
  872. PWAVEDRV pwavedrv;
  873. UINT port;
  874. mmr = waveReferenceDriverById(&waveindrvZ, PrefId, &pwavedrv, &port);
  875. if (!mmr)
  876. {
  877. mmr = mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWiDefaultStringId, NULL);
  878. if (!mmr)
  879. {
  880. if (!gfDisablePreferredDeviceReordering)
  881. {
  882. // Rearrange some of the driver list so that the preferred waveIn
  883. // device has a good chance of having device ID 0
  884. if (0 != PrefId)
  885. {
  886. // Move the wave driver to the head of this list. This usually
  887. // makes the preferred device have ID 0.
  888. EnterNumDevs("waveInSetCurrentPreferredId");
  889. pwavedrv->Prev->Next = pwavedrv->Next;
  890. pwavedrv->Next->Prev = pwavedrv->Prev;
  891. pwavedrv->Next = waveindrvZ.Next;
  892. pwavedrv->Prev = &waveindrvZ;
  893. waveindrvZ.Next->Prev = pwavedrv;
  894. waveindrvZ.Next = pwavedrv;
  895. LeaveNumDevs("waveInSetCurrentPreferredId");
  896. mregDecUsagePtr(pwavedrv);
  897. }
  898. }
  899. }
  900. }
  901. }
  902. if (!mmr)
  903. {
  904. gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY));
  905. // Reconfigure the mapper only if it was already loaded. Don't cause it to
  906. // load simply so that we can reconfigure it!
  907. if (WaveMapperInitialized) waveInMessage((HWAVEIN)(UINT_PTR)WAVE_MAPPER, DRVM_MAPPER_RECONFIGURE, 0, 0);
  908. }
  909. return mmr;
  910. }
  911. MMRESULT waveInSetPersistentPreferredId(UINT PrefId, DWORD dwFlags)
  912. {
  913. MMRESULT mmr;
  914. WAVEINCAPS wc;
  915. if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM;
  916. mmr = waveInGetDevCaps(PrefId, &wc, sizeof(wc));
  917. if (!mmr)
  918. {
  919. wc.szPname[MAXPNAMELEN-1] = TEXT('\0');
  920. mmr = waveInWritePersistentPref(wc.szPname, 0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY));
  921. if (!mmr) {
  922. NotifyServerPreferredDeviceChange();
  923. } else {
  924. Squirt("waveInSetPersistentPreferredId: waveInWritePersistenPref failed, mmr=%08Xh", mmr);
  925. }
  926. }
  927. return mmr;
  928. }
  929. void waveInGetCurrentConsoleVoiceComId(PUINT pPrefId, PDWORD pdwFlags)
  930. {
  931. *pPrefId = WAVE_MAPPER;
  932. *pdwFlags = gfUsePreferredWaveOnly ? DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY : 0;
  933. if (gpstrWiConsoleVoiceComStringId) mregGetIdFromStringId(&waveindrvZ, gpstrWiConsoleVoiceComStringId, pPrefId);
  934. return;
  935. }
  936. MMRESULT waveInSetPersistentConsoleVoiceComId(UINT PrefId, DWORD dwFlags)
  937. {
  938. MMRESULT mmr;
  939. WAVEINCAPS wic;
  940. if (0 != (dwFlags & ~DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY)) return MMSYSERR_INVALPARAM;
  941. mmr = waveInGetDevCaps(PrefId, &wic, sizeof(wic));
  942. if (!mmr)
  943. {
  944. wic.szPname[MAXPNAMELEN-1] = TEXT('\0');
  945. mmr = waveWritePersistentConsoleVoiceCom(FALSE, wic.szPname, 0 != (dwFlags & 0x00000001));
  946. if (!mmr) {
  947. NotifyServerPreferredDeviceChange();
  948. } else {
  949. Squirt("waveInSetPersistentConsoleVoiceComId: waveWritePersistentConsoleVoiceCom failed, mmr=%08Xh", mmr);
  950. }
  951. }
  952. return mmr;
  953. }
  954. MMRESULT waveInSetCurrentConsoleVoiceComId(UINT PrefId, DWORD dwFlags)
  955. {
  956. MMRESULT mmr;
  957. WinAssert(PrefId < wTotalWaveInDevs || PrefId == WAVE_MAPPER);
  958. mmr = MMSYSERR_NOERROR;
  959. if (gpstrWiConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWiConsoleVoiceComStringId);
  960. gpstrWiConsoleVoiceComStringId = NULL;
  961. if (wTotalWaveInDevs)
  962. {
  963. PWAVEDRV pwavedrv;
  964. UINT port;
  965. mmr = waveReferenceDriverById(&waveindrvZ, PrefId, &pwavedrv, &port);
  966. if (!mmr)
  967. {
  968. mregCreateStringIdFromDriverPort(pwavedrv, port, &gpstrWiConsoleVoiceComStringId, NULL);
  969. gfUsePreferredWaveOnly = (0 != (dwFlags & DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY));
  970. }
  971. }
  972. return mmr;
  973. }
  974. //------------------------------------------------------------------------------
  975. //
  976. //
  977. // MidiOut
  978. //
  979. //
  980. //------------------------------------------------------------------------------
  981. DWORD midiOutGetSetupPreferredAudioCount(UINT MidiId)
  982. {
  983. PCWSTR DeviceInterface;
  984. DWORD dwCount;
  985. DeviceInterface = midiReferenceDevInterfaceById(&midioutdrvZ, MidiId);
  986. if(DeviceInterface == NULL) {
  987. return 0;
  988. }
  989. dwCount = GetDeviceInterfaceSetupPreferredAudioCount(DeviceInterface);
  990. wdmDevInterfaceDec(DeviceInterface);
  991. return dwCount;
  992. }
  993. MMRESULT midiOutSendPreferredMessage(BOOL fClear)
  994. {
  995. PCWSTR DeviceInterface;
  996. UINT MidiId;
  997. MMRESULT mmr;
  998. if(!gfLogon) {
  999. return MMSYSERR_NOERROR;
  1000. }
  1001. midiOutGetCurrentPreferredId(&MidiId, NULL);
  1002. if(MidiId == WAVE_MAPPER) {
  1003. return MMSYSERR_NOERROR;
  1004. }
  1005. DeviceInterface = midiReferenceDevInterfaceById(&midioutdrvZ, MidiId);
  1006. if(DeviceInterface == NULL) {
  1007. return MMSYSERR_NOERROR;
  1008. }
  1009. gfMidiOutPreferredMessageSent = TRUE;
  1010. mmr = midiOutMessage((HMIDIOUT)(UINT_PTR)MidiId, MODM_PREFERRED, (DWORD_PTR)fClear, (DWORD_PTR)DeviceInterface);
  1011. wdmDevInterfaceDec(DeviceInterface);
  1012. return mmr;
  1013. }
  1014. MMRESULT midiOutWritePersistentPref(IN UINT MidiOutId, IN ULONG SetupCount)
  1015. {
  1016. HKEY hkMidiMapper;
  1017. HKEY hkcu;
  1018. MIDIOUTCAPS moc;
  1019. DWORD dwDisposition;
  1020. LONG result;
  1021. MMRESULT mmr;
  1022. mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc));
  1023. if (MMSYSERR_NOERROR != mmr) return mmr;
  1024. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_ALL, &hkcu))) return MMSYSERR_WRITEERROR;
  1025. result = RegCreateKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_MIDIMAP, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &hkMidiMapper, &dwDisposition);
  1026. if (ERROR_SUCCESS == result)
  1027. {
  1028. PCWSTR pstrDeviceInterface;
  1029. UINT RelativeIndex;
  1030. pstrDeviceInterface = midiReferenceDevInterfaceById(&midioutdrvZ, MidiOutId);
  1031. if (pstrDeviceInterface) {
  1032. UINT i;
  1033. RelativeIndex = 0;
  1034. for (i = 0; i < MidiOutId; i++) {
  1035. PCWSTR pstr = midiReferenceDevInterfaceById(&midioutdrvZ, i);
  1036. if (pstr && !lstrcmpi(pstrDeviceInterface, pstr)) RelativeIndex++;
  1037. if (pstr) wdmDevInterfaceDec(pstr);
  1038. }
  1039. } else {
  1040. RelativeIndex = 0;
  1041. }
  1042. result = RegSetSzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_SZPNAME, moc.szPname);
  1043. if (ERROR_SUCCESS == result) result = RegSetDwordValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_RELATIVEINDEX, RelativeIndex);
  1044. if (ERROR_SUCCESS == result) result = RegSetSzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_DEVICEINTERFACE, pstrDeviceInterface ? pstrDeviceInterface : TEXT(""));
  1045. if (ERROR_SUCCESS == result) result = RegSetDwordValue(hkMidiMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, SetupCount);
  1046. if (ERROR_SUCCESS == result) RegDeleteValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_CURRENTINSTRUMENT);
  1047. if (pstrDeviceInterface) wdmDevInterfaceDec(pstrDeviceInterface);
  1048. RegCloseKey(hkMidiMapper);
  1049. }
  1050. if (ERROR_SUCCESS != result) mmr = MMSYSERR_WRITEERROR;
  1051. NtClose(hkcu);
  1052. return mmr;
  1053. }
  1054. MMRESULT midiOutGetIdFromName(IN PTSTR pstrName, OUT UINT *pMidiOutId)
  1055. {
  1056. UINT MidiOutId;
  1057. UINT cMidiOutId;
  1058. MMRESULT mmr;
  1059. cMidiOutId = midiOutGetNumDevs();
  1060. for (MidiOutId = 0; MidiOutId < cMidiOutId; MidiOutId++)
  1061. {
  1062. MIDIOUTCAPS moc;
  1063. mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc));
  1064. if (MMSYSERR_NOERROR == mmr)
  1065. {
  1066. if (!lstrcmp(pstrName, moc.szPname))
  1067. {
  1068. mmr = MMSYSERR_NOERROR;
  1069. break;
  1070. }
  1071. }
  1072. }
  1073. if (MidiOutId == cMidiOutId)
  1074. {
  1075. mmr = MMSYSERR_NODRIVER;
  1076. }
  1077. if (MMSYSERR_NOERROR == mmr) *pMidiOutId = MidiOutId;
  1078. return mmr;
  1079. }
  1080. MMRESULT midiOutGetIdFromDiAndIndex(IN PTSTR pstrDeviceInterface, IN INT RelativeIndex, OUT UINT *pMidiOutId)
  1081. {
  1082. UINT cMidiOut;
  1083. UINT MidiOutId;
  1084. MMRESULT mmr;
  1085. mmr = MMSYSERR_NODRIVER;
  1086. cMidiOut = midiOutGetNumDevs();
  1087. if (0 == cMidiOut) return MMSYSERR_NODRIVER;
  1088. for (MidiOutId = 0; MidiOutId < cMidiOut; MidiOutId++) {
  1089. PCWSTR pstr = midiReferenceDevInterfaceById(&midioutdrvZ, MidiOutId);
  1090. if (pstr && !lstrcmpi(pstr, pstrDeviceInterface) && (0 == RelativeIndex--)) {
  1091. *pMidiOutId = MidiOutId;
  1092. wdmDevInterfaceDec(pstr);
  1093. mmr = MMSYSERR_NOERROR;
  1094. break;
  1095. }
  1096. if (pstr) wdmDevInterfaceDec(pstr);
  1097. }
  1098. return mmr;
  1099. }
  1100. MMRESULT midiOutGetInstrumentDriverData(IN PCTSTR pstrMidiSubkeyName, OUT PTSTR *ppstrDeviceInterface, OUT UINT *pDriverNum, OUT UINT *pPortNum, OUT PTSTR *ppstrPname)
  1101. {
  1102. HKEY hkMidi;
  1103. HKEY hkMidiSubkey;
  1104. LONG result;
  1105. MMRESULT mmr;
  1106. BOOL f;
  1107. mmr = MMSYSERR_ERROR;
  1108. result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_MEDIARESOURCES_MIDI, 0, KEY_QUERY_VALUE, &hkMidi);
  1109. if (ERROR_SUCCESS != result) return MMSYSERR_ERROR;
  1110. result = RegOpenKeyEx(hkMidi, pstrMidiSubkeyName, 0, KEY_QUERY_VALUE, &hkMidiSubkey);
  1111. if (ERROR_SUCCESS == result)
  1112. {
  1113. PTSTR pstrActive;
  1114. result = RegQuerySzValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_ACTIVE, &pstrActive);
  1115. if (ERROR_SUCCESS == result)
  1116. {
  1117. PTCHAR pchEnd;
  1118. BOOL fActive = _tcstol(pstrActive, &pchEnd, 10);
  1119. f = HeapFree(hHeap, 0, pstrActive);
  1120. WinAssert(f);
  1121. if (fActive)
  1122. {
  1123. PTSTR pstrDeviceInterface = NULL;
  1124. PTSTR pstrPname = NULL;
  1125. DWORD dwDriverNum;
  1126. DWORD dwPortNum;
  1127. result = RegQueryDwordValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PHYSDEVID, &dwDriverNum);
  1128. if (ERROR_SUCCESS == result) result = RegQueryDwordValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_PORT, &dwPortNum);
  1129. if (ERROR_SUCCESS == result) RegQuerySzValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DEVICEINTERFACE, &pstrDeviceInterface);
  1130. if (ERROR_SUCCESS == result) RegQuerySzValue(hkMidiSubkey, REGSTR_VAL_MEDIARESOURCES_MIDI_SUBKEY_DESCRIPTION, &pstrPname);
  1131. if (ERROR_SUCCESS == result)
  1132. {
  1133. *ppstrDeviceInterface = NULL;
  1134. *ppstrPname = NULL;
  1135. if (pstrDeviceInterface) {
  1136. if (lstrlen(pstrDeviceInterface)> 0) {
  1137. *ppstrDeviceInterface = pstrDeviceInterface;
  1138. } else {
  1139. HeapFree(hHeap, 0, pstrDeviceInterface);
  1140. }
  1141. }
  1142. if (pstrPname) {
  1143. if (lstrlen(pstrPname)> 0) {
  1144. *ppstrPname = pstrPname;
  1145. } else {
  1146. HeapFree(hHeap, 0, pstrPname);
  1147. }
  1148. }
  1149. *pDriverNum = dwDriverNum;
  1150. *pPortNum = dwPortNum;
  1151. mmr = MMSYSERR_NOERROR;
  1152. }
  1153. }
  1154. }
  1155. result = RegCloseKey(hkMidiSubkey);
  1156. WinAssert(ERROR_SUCCESS == result);
  1157. }
  1158. result = RegCloseKey(hkMidi);
  1159. WinAssert(ERROR_SUCCESS == result);
  1160. return mmr;
  1161. }
  1162. MMRESULT midiOutGetIdFromInstrument(IN PTSTR pstrMidiKeyName, OUT UINT *outMidiOutId)
  1163. {
  1164. PTSTR pstrDeviceInterface, pstrPname;
  1165. UINT DriverNum, PortNum;
  1166. UINT MidiOutId;
  1167. MMRESULT mmr;
  1168. mmr = midiOutGetInstrumentDriverData(pstrMidiKeyName, &pstrDeviceInterface, &DriverNum, &PortNum, &pstrPname);
  1169. if (MMSYSERR_NOERROR == mmr) {
  1170. if (pstrDeviceInterface) {
  1171. mmr = midiOutGetIdFromDiAndIndex(pstrDeviceInterface, PortNum, &MidiOutId);
  1172. } else if (pstrPname) {
  1173. mmr = midiOutGetIdFromName(pstrPname, &MidiOutId);
  1174. } else {
  1175. PMIDIDRV pmidioutdrv = midioutdrvZ.Next;
  1176. UINT DriverNum1 = DriverNum + 1;
  1177. MidiOutId = 0;
  1178. while ((pmidioutdrv != &midioutdrvZ) && (0 < DriverNum1))
  1179. {
  1180. MidiOutId += pmidioutdrv->NumDevs;
  1181. DriverNum1--;
  1182. pmidioutdrv = pmidioutdrv->Next;
  1183. }
  1184. if ((pmidioutdrv != &midioutdrvZ) && (PortNum < pmidioutdrv->NumDevs))
  1185. {
  1186. MidiOutId += PortNum;
  1187. } else {
  1188. MidiOutId = MIDI_MAPPER;
  1189. mmr = MMSYSERR_ERROR;
  1190. }
  1191. }
  1192. if (pstrDeviceInterface) HeapFree(hHeap, 0, pstrDeviceInterface);
  1193. if (pstrPname) HeapFree(hHeap, 0, pstrPname);
  1194. }
  1195. if (MMSYSERR_NOERROR == mmr) {
  1196. MIDIOUTCAPS moc;
  1197. WinAssert(MIDI_MAPPER != MidiOutId);
  1198. mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc));
  1199. }
  1200. if (MMSYSERR_NOERROR == mmr) *outMidiOutId = MidiOutId;
  1201. return mmr;
  1202. }
  1203. MMRESULT midiOutReadCurrentInstrument(OUT PTSTR *ppstrCurrentInstrument, OUT DWORD *pSetupCount)
  1204. {
  1205. HKEY hkcu;
  1206. HKEY hkMidiMapper;
  1207. LONG result;
  1208. MMRESULT mmr;
  1209. mmr = MMSYSERR_ERROR;
  1210. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return MMSYSERR_READERROR;
  1211. result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_MIDIMAP, 0, KEY_QUERY_VALUE, &hkMidiMapper);
  1212. if (ERROR_SUCCESS == result)
  1213. {
  1214. result = RegQuerySzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_CURRENTINSTRUMENT, ppstrCurrentInstrument);
  1215. if (ERROR_SUCCESS == result)
  1216. {
  1217. DWORD SetupCount;
  1218. result = RegQueryDwordValue(hkMidiMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &SetupCount);
  1219. SetupCount = (ERROR_SUCCESS == result) ? SetupCount : 0;
  1220. *pSetupCount = SetupCount;
  1221. mmr = MMSYSERR_NOERROR;
  1222. } else {
  1223. mmr = MMSYSERR_ERROR;
  1224. }
  1225. result = RegCloseKey(hkMidiMapper);
  1226. WinAssert(ERROR_SUCCESS == result);
  1227. }
  1228. NtClose(hkcu);
  1229. return mmr;
  1230. }
  1231. MMRESULT midiOutReadPreferredDeviceData(OUT PTSTR *ppstrDeviceInterface, OUT UINT *pRelativeIndex, OUT PTSTR *ppstrPname, OUT ULONG *pSetupCount)
  1232. {
  1233. HKEY hkcu;
  1234. HKEY hkMidiMapper;
  1235. LONG result;
  1236. MMRESULT mmr;
  1237. if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &hkcu))) return MMSYSERR_READERROR;
  1238. result = RegOpenKeyEx(hkcu, REGSTR_PATH_MULTIMEDIA_MIDIMAP, 0, KEY_QUERY_VALUE, &hkMidiMapper);
  1239. if (ERROR_SUCCESS == result)
  1240. {
  1241. PTSTR pstrDeviceInterface = NULL;
  1242. PTSTR pstrPname = NULL;
  1243. DWORD dwIndex;
  1244. DWORD dwSetupCount;
  1245. // See if we have a Pname. It is okay not to.
  1246. result = RegQuerySzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_SZPNAME, &pstrPname);
  1247. if (ERROR_FILE_NOT_FOUND == result) result = ERROR_SUCCESS;
  1248. // See if we have a device interface + relative index. It is okay not to.
  1249. if (ERROR_SUCCESS == result) result = RegQueryDwordValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_RELATIVEINDEX, &dwIndex);
  1250. if (ERROR_SUCCESS == result) result = RegQuerySzValue(hkMidiMapper, REGSTR_VAL_MULTIMEDIA_MIDIMAP_DEVICEINTERFACE, &pstrDeviceInterface);
  1251. if (ERROR_FILE_NOT_FOUND == result) result = ERROR_SUCCESS;
  1252. // The device interface value might be zero length. Act as thought it
  1253. // doesn't exist in this case.
  1254. if ((ERROR_SUCCESS == result) && (pstrDeviceInterface) && (0 == lstrlen(pstrDeviceInterface)))
  1255. {
  1256. HeapFree(hHeap, 0, pstrDeviceInterface);
  1257. pstrDeviceInterface = NULL;
  1258. dwIndex = 0;
  1259. }
  1260. if (ERROR_SUCCESS != RegQueryDwordValue(hkMidiMapper, REGSTR_VAL_SETUPPREFERREDAUDIODEVICESCOUNT, &dwSetupCount)) {
  1261. dwSetupCount = 0;
  1262. }
  1263. if (ERROR_SUCCESS == result) {
  1264. if (pstrPname || pstrDeviceInterface) {
  1265. *ppstrDeviceInterface = pstrDeviceInterface;
  1266. *ppstrPname = pstrPname;
  1267. *pRelativeIndex = dwIndex;
  1268. *pSetupCount = dwSetupCount;
  1269. mmr = MMSYSERR_NOERROR;
  1270. } else {
  1271. mmr = MMSYSERR_VALNOTFOUND;
  1272. }
  1273. } else {
  1274. mmr = MMSYSERR_READERROR;
  1275. }
  1276. if (MMSYSERR_NOERROR != mmr) {
  1277. if (pstrDeviceInterface) HeapFree(hHeap, 0, pstrDeviceInterface);
  1278. if (pstrPname) HeapFree(hHeap, 0, pstrPname);
  1279. }
  1280. RegCloseKey(hkMidiMapper);
  1281. } else {
  1282. if (ERROR_FILE_NOT_FOUND == result) mmr = MMSYSERR_KEYNOTFOUND;
  1283. else mmr = MMSYSERR_READERROR;
  1284. }
  1285. NtClose(hkcu);
  1286. return mmr;
  1287. }
  1288. MMRESULT midiOutReadPersistentPreferredId(OUT UINT *pMidiPrefId, OUT ULONG *pSetupCount)
  1289. {
  1290. PTSTR pstrDeviceInterface;
  1291. PTSTR pstrPname;
  1292. UINT RelativeIndex;
  1293. UINT MidiOutId;
  1294. ULONG SetupCount;
  1295. MMRESULT mmr;
  1296. mmr = midiOutReadPreferredDeviceData(&pstrDeviceInterface, &RelativeIndex, &pstrPname, &SetupCount);
  1297. if (MMSYSERR_NOERROR == mmr) {
  1298. WinAssert(pstrDeviceInterface || pstrPname);
  1299. if (pstrDeviceInterface) {
  1300. mmr = midiOutGetIdFromDiAndIndex(pstrDeviceInterface, RelativeIndex, &MidiOutId);
  1301. } else {
  1302. WinAssert(pstrPname);
  1303. mmr = midiOutGetIdFromName(pstrPname, &MidiOutId);
  1304. }
  1305. if (pstrDeviceInterface) HeapFree(hHeap, 0, pstrDeviceInterface);
  1306. if (pstrPname) HeapFree(hHeap, 0, pstrPname);
  1307. } else if (MMSYSERR_VALNOTFOUND == mmr || MMSYSERR_KEYNOTFOUND == mmr) {
  1308. PTSTR pstrMidiKeyName;
  1309. mmr = midiOutReadCurrentInstrument(&pstrMidiKeyName, &SetupCount);
  1310. if (MMSYSERR_NOERROR == mmr) {
  1311. mmr = midiOutGetIdFromInstrument(pstrMidiKeyName, &MidiOutId);
  1312. // Since this is older format for storing preference, let's
  1313. // rewrite it in newer format.
  1314. if (MMSYSERR_NOERROR == mmr)
  1315. {
  1316. midiOutWritePersistentPref(MidiOutId, SetupCount);
  1317. }
  1318. HeapFree(hHeap, 0, pstrMidiKeyName);
  1319. }
  1320. }
  1321. if (MMSYSERR_NOERROR == mmr) {
  1322. *pMidiPrefId = MidiOutId;
  1323. *pSetupCount = SetupCount;
  1324. }
  1325. return mmr;
  1326. }
  1327. MMRESULT midiOutPickBestId(PUINT pMidiPrefId, UINT WaveOutPrefId)
  1328. {
  1329. MIDIOUTCAPS moc;
  1330. UINT cMidiOutId;
  1331. UINT MidiOutId;
  1332. UINT UserSelectedMidiOutId;
  1333. UINT WavetableMidiOutId;
  1334. UINT SoftwareMidiOutId;
  1335. UINT OtherMidiOutId;
  1336. UINT FmMidiOutId;
  1337. UINT ExternalMidiOutId;
  1338. DWORD MidiOutIdCount;
  1339. DWORD UserSelectedMidiOutIdCount;
  1340. DWORD WavetableMidiOutIdCount;
  1341. DWORD SoftwareMidiOutIdCount;
  1342. DWORD OtherMidiOutIdCount;
  1343. DWORD FmMidiOutIdCount;
  1344. DWORD ExternalMidiOutIdCount;
  1345. MMRESULT mmrLastError;
  1346. MMRESULT mmr;
  1347. BOOL f;
  1348. UserSelectedMidiOutId = MIDI_MAPPER;
  1349. WavetableMidiOutId = MIDI_MAPPER;
  1350. SoftwareMidiOutId = MIDI_MAPPER;
  1351. OtherMidiOutId = MIDI_MAPPER;
  1352. FmMidiOutId = MIDI_MAPPER;
  1353. ExternalMidiOutId = MIDI_MAPPER;
  1354. MidiOutId = MIDI_MAPPER;
  1355. UserSelectedMidiOutIdCount = 0;
  1356. WavetableMidiOutIdCount = 0;
  1357. SoftwareMidiOutIdCount = 0;
  1358. OtherMidiOutIdCount = 0;
  1359. FmMidiOutIdCount = 0;
  1360. ExternalMidiOutIdCount = 0;
  1361. MidiOutIdCount = 0;
  1362. mmr = midiOutReadPersistentPreferredId(&UserSelectedMidiOutId, &UserSelectedMidiOutIdCount);
  1363. mmrLastError = MMSYSERR_NODRIVER;
  1364. cMidiOutId = midiOutGetNumDevs();
  1365. for (MidiOutId = 0; MidiOutId < cMidiOutId; MidiOutId++)
  1366. {
  1367. mmr = midiOutGetDevCaps(MidiOutId, &moc, sizeof(moc));
  1368. if (MMSYSERR_NOERROR == mmr)
  1369. {
  1370. MidiOutIdCount = midiOutGetSetupPreferredAudioCount(MidiOutId);
  1371. if (MOD_SWSYNTH == moc.wTechnology &&
  1372. MM_MSFT_WDMAUDIO_MIDIOUT == moc.wPid &&
  1373. MM_MICROSOFT == moc.wMid)
  1374. {
  1375. // We need to special case this synth, and get the count from
  1376. // the preferred audio device.
  1377. SoftwareMidiOutId = MidiOutId;
  1378. if ((-1) != WaveOutPrefId) {
  1379. SoftwareMidiOutIdCount = waveOutGetSetupPreferredAudioCount(WaveOutPrefId);
  1380. } else {
  1381. SoftwareMidiOutIdCount = 0;
  1382. }
  1383. } else if (MOD_FMSYNTH == moc.wTechnology) {
  1384. FmMidiOutId = MidiOutId;
  1385. FmMidiOutIdCount = MidiOutIdCount;
  1386. } else if (MOD_MIDIPORT == moc.wTechnology) {
  1387. ExternalMidiOutId = MidiOutId;
  1388. ExternalMidiOutIdCount = MidiOutIdCount;
  1389. } else if (MOD_WAVETABLE == moc.wTechnology) {
  1390. WavetableMidiOutId = MidiOutId;
  1391. WavetableMidiOutIdCount = MidiOutIdCount;
  1392. } else {
  1393. OtherMidiOutId = MidiOutId;
  1394. OtherMidiOutIdCount = MidiOutIdCount;
  1395. }
  1396. } else {
  1397. mmrLastError = mmr;
  1398. }
  1399. }
  1400. MidiOutId = ExternalMidiOutId;
  1401. MidiOutIdCount = ExternalMidiOutIdCount;
  1402. if ((FmMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != FmMidiOutId))
  1403. {
  1404. MidiOutId = FmMidiOutId;
  1405. MidiOutIdCount = FmMidiOutIdCount;
  1406. }
  1407. if ((OtherMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != OtherMidiOutId))
  1408. {
  1409. MidiOutId = OtherMidiOutId;
  1410. MidiOutIdCount = OtherMidiOutIdCount;
  1411. }
  1412. if ((SoftwareMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != SoftwareMidiOutId))
  1413. {
  1414. MidiOutId = SoftwareMidiOutId;
  1415. MidiOutIdCount = SoftwareMidiOutIdCount;
  1416. }
  1417. if ((WavetableMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != WavetableMidiOutId))
  1418. {
  1419. MidiOutId = WavetableMidiOutId;
  1420. MidiOutIdCount = WavetableMidiOutIdCount;
  1421. }
  1422. if ((UserSelectedMidiOutIdCount >= MidiOutIdCount) && (MIDI_MAPPER != UserSelectedMidiOutId))
  1423. {
  1424. MidiOutId = UserSelectedMidiOutId;
  1425. MidiOutIdCount = UserSelectedMidiOutIdCount;
  1426. }
  1427. if ((-1) != MidiOutId) {
  1428. mmr = MMSYSERR_NOERROR;
  1429. } else {
  1430. mmr = mmrLastError;
  1431. }
  1432. if (MMSYSERR_NOERROR == mmr) *pMidiPrefId = MidiOutId;
  1433. return mmr;
  1434. }
  1435. void midiOutGetCurrentPreferredId(PUINT pPrefId, PDWORD pdwFlags)
  1436. {
  1437. *pPrefId = WAVE_MAPPER;
  1438. if (pdwFlags) *pdwFlags = 0;;
  1439. if (gpstrMoDefaultStringId) mregGetIdFromStringId(&midioutdrvZ, gpstrMoDefaultStringId, pPrefId);
  1440. return;
  1441. }
  1442. MMRESULT midiOutSetCurrentPreferredId(UINT PrefId)
  1443. {
  1444. MMRESULT mmr;
  1445. WinAssert(PrefId < wTotalMidiOutDevs || PrefId == MIDI_MAPPER);
  1446. mmr = MMSYSERR_NOERROR;
  1447. if (gpstrMoDefaultStringId) HeapFree(hHeap, 0, gpstrMoDefaultStringId);
  1448. gpstrMoDefaultStringId = NULL;
  1449. if (wTotalMidiOutDevs)
  1450. {
  1451. PMIDIDRV pmididrv;
  1452. UINT port;
  1453. mmr = midiReferenceDriverById(&midioutdrvZ, PrefId, &pmididrv, &port);
  1454. if (!mmr)
  1455. {
  1456. mmr = mregCreateStringIdFromDriverPort(pmididrv, port, &gpstrMoDefaultStringId, NULL);
  1457. if (!mmr)
  1458. {
  1459. if (!gfDisablePreferredDeviceReordering)
  1460. {
  1461. // Rearrange some of the driver list so that the preferred midiOut
  1462. // device has a good chance of having device ID 0
  1463. if (0 != PrefId)
  1464. {
  1465. // Move the midi driver to the head of this list. This usually
  1466. // makes the preferred device have ID 0.
  1467. EnterNumDevs("midiOutSetCurrentPreferredId");
  1468. pmididrv->Prev->Next = pmididrv->Next;
  1469. pmididrv->Next->Prev = pmididrv->Prev;
  1470. pmididrv->Next = midioutdrvZ.Next;
  1471. pmididrv->Prev = &midioutdrvZ;
  1472. midioutdrvZ.Next->Prev = pmididrv;
  1473. midioutdrvZ.Next = pmididrv;
  1474. LeaveNumDevs("midiOutSetCurrentPreferredId");
  1475. mregDecUsagePtr(pmididrv);
  1476. }
  1477. }
  1478. }
  1479. }
  1480. }
  1481. if (!mmr)
  1482. {
  1483. // Reconfigure the mapper only if it was already loaded. Don't cause it to
  1484. // load simply so that we can reconfigure it!
  1485. if (MidiMapperInitialized) midiOutMessage((HMIDIOUT)(UINT_PTR)MIDI_MAPPER, DRVM_MAPPER_RECONFIGURE, 0, 0);
  1486. }
  1487. return mmr;
  1488. }
  1489. MMRESULT midiOutSetPersistentPreferredId(UINT PrefId, DWORD dwFlags)
  1490. {
  1491. MMRESULT mmr;
  1492. mmr = midiOutWritePersistentPref(PrefId, GetCurrentSetupPreferredAudioCount());
  1493. if (!mmr) NotifyServerPreferredDeviceChange();
  1494. return mmr;
  1495. }
  1496. //------------------------------------------------------------------------------
  1497. //
  1498. //
  1499. // RefreshPreferredDevices
  1500. //
  1501. //
  1502. //------------------------------------------------------------------------------
  1503. void RefreshPreferredDevices(void)
  1504. {
  1505. UINT WaveOutPreferredId;
  1506. DWORD WaveOutPreferredFlags;
  1507. UINT WaveInPreferredId;
  1508. DWORD WaveInPreferredFlags;
  1509. UINT WaveOutConsoleVoiceComId;
  1510. DWORD WaveOutConsoleVoiceComFlags;
  1511. UINT WaveInConsoleVoiceComId;
  1512. DWORD WaveInConsoleVoiceComFlags;
  1513. UINT MidiOutPreferredId;
  1514. UINT OldWaveOutPreferredId;
  1515. DWORD OldWaveOutPreferredFlags;
  1516. UINT OldWaveInPreferredId;
  1517. DWORD OldWaveInPreferredFlags;
  1518. UINT OldWaveOutConsoleVoiceComId;
  1519. DWORD OldWaveOutConsoleVoiceComFlags;
  1520. UINT OldWaveInConsoleVoiceComId;
  1521. DWORD OldWaveInConsoleVoiceComFlags;
  1522. UINT OldMidiOutPreferredId;
  1523. // Squirt("RefreshPreferredDevices");
  1524. BOOL fImpersonate = FALSE;
  1525. waveOutGetCurrentPreferredId(&OldWaveOutPreferredId, &OldWaveOutPreferredFlags);
  1526. if (!waveOutPickBestId(&WaveOutPreferredId, &WaveOutPreferredFlags)) {
  1527. if ((WaveOutPreferredId != OldWaveOutPreferredId) ||
  1528. (WaveOutPreferredFlags != OldWaveOutPreferredFlags) ||
  1529. !gfWaveOutPreferredMessageSent)
  1530. {
  1531. // Squirt("RefreshPreferredDevices: different waveOut preference %d -> %d", OldWaveOutPreferredId, WaveOutPreferredId);
  1532. waveOutSendPreferredMessage(TRUE);
  1533. waveOutSetCurrentPreferredId(WaveOutPreferredId, WaveOutPreferredFlags);
  1534. waveOutSendPreferredMessage(FALSE);
  1535. }
  1536. }
  1537. waveOutGetCurrentConsoleVoiceComId(&OldWaveOutConsoleVoiceComId, &OldWaveOutConsoleVoiceComFlags);
  1538. if (!wavePickBestConsoleVoiceComId(TRUE, &WaveOutConsoleVoiceComId, &WaveOutConsoleVoiceComFlags)) {
  1539. if ((WaveOutConsoleVoiceComId != OldWaveOutConsoleVoiceComId) ||
  1540. (WaveOutConsoleVoiceComFlags != OldWaveOutConsoleVoiceComFlags))
  1541. {
  1542. // Squirt("RefreshPreferredDevices: different waveOut preference %d -> %d", OldWaveOutConsoleVoiceComId, WaveOutConsoleVoiceComId);
  1543. waveOutSetCurrentConsoleVoiceComId(WaveOutConsoleVoiceComId, WaveOutConsoleVoiceComFlags);
  1544. }
  1545. }
  1546. waveInGetCurrentPreferredId(&OldWaveInPreferredId, &OldWaveInPreferredFlags);
  1547. if (!waveInPickBestId(&WaveInPreferredId, &WaveInPreferredFlags)) {
  1548. if ((WaveInPreferredId != OldWaveInPreferredId) ||
  1549. (WaveInPreferredFlags != OldWaveInPreferredFlags) ||
  1550. !gfWaveInPreferredMessageSent)
  1551. {
  1552. // Squirt("RefreshPreferredDevices: different waveIn preference %d -> %d", OldWaveInPreferredId, WaveInPreferredId);
  1553. waveInSendPreferredMessage(TRUE);
  1554. waveInSetCurrentPreferredId(WaveInPreferredId, WaveInPreferredFlags);
  1555. waveInSendPreferredMessage(FALSE);
  1556. }
  1557. }
  1558. waveInGetCurrentConsoleVoiceComId(&OldWaveInConsoleVoiceComId, &OldWaveInConsoleVoiceComFlags);
  1559. if (!wavePickBestConsoleVoiceComId(FALSE, &WaveInConsoleVoiceComId, &WaveInConsoleVoiceComFlags)) {
  1560. if ((WaveInConsoleVoiceComId != OldWaveInConsoleVoiceComId) ||
  1561. (WaveInConsoleVoiceComFlags != OldWaveInConsoleVoiceComFlags))
  1562. {
  1563. // Squirt("RefreshPreferredDevices: different waveIn preference %d -> %d", OldWaveInConsoleVoiceComId, WaveInConsoleVoiceComId);
  1564. waveInSetCurrentConsoleVoiceComId(WaveInConsoleVoiceComId, WaveInConsoleVoiceComFlags);
  1565. }
  1566. }
  1567. midiOutGetCurrentPreferredId(&OldMidiOutPreferredId, NULL);
  1568. if (!midiOutPickBestId(&MidiOutPreferredId, WaveOutPreferredId)) {
  1569. if (MidiOutPreferredId != OldMidiOutPreferredId ||
  1570. !gfMidiOutPreferredMessageSent)
  1571. {
  1572. // Squirt("RefreshPreferredDevices: different midiOut preference %d -> %d", OldMidiOutPreferredId, MidiOutPreferredId);
  1573. midiOutSendPreferredMessage(TRUE);
  1574. midiOutSetCurrentPreferredId(MidiOutPreferredId);
  1575. midiOutSendPreferredMessage(FALSE);
  1576. }
  1577. }
  1578. // Squirt("RefreshPreferredDevices: return");
  1579. return;
  1580. }
  1581. void InvalidatePreferredDevices(void)
  1582. {
  1583. if (gpstrWoDefaultStringId) HeapFree(hHeap, 0, gpstrWoDefaultStringId);
  1584. if (gpstrWiDefaultStringId) HeapFree(hHeap, 0, gpstrWiDefaultStringId);
  1585. gpstrWoDefaultStringId = NULL;
  1586. gpstrWiDefaultStringId = NULL;
  1587. if (gpstrWoConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWoConsoleVoiceComStringId);
  1588. if (gpstrWiConsoleVoiceComStringId) HeapFree(hHeap, 0, gpstrWiConsoleVoiceComStringId);
  1589. gpstrWoConsoleVoiceComStringId = NULL;
  1590. gpstrWiConsoleVoiceComStringId = NULL;
  1591. if (gpstrMoDefaultStringId) HeapFree(hHeap, 0, gpstrMoDefaultStringId);
  1592. gpstrMoDefaultStringId = NULL;
  1593. }