Leaked source code of windows server 2003
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.

2741 lines
95 KiB

  1. /*****************************************************************************
  2. midi.c
  3. Level 1 kitchen sink DLL midi support module
  4. Copyright (c) 1990-2001 Microsoft Corporation
  5. *****************************************************************************/
  6. #include "winmmi.h"
  7. #define DO_DEFAULT_MIDI_MAPPER
  8. /*****************************************************************************
  9. local structures
  10. *****************************************************************************/
  11. /*****************************************************************************
  12. internal prototypes
  13. *****************************************************************************/
  14. /*****************************************************************************
  15. segmentation
  16. *****************************************************************************/
  17. /*****************************************************************************
  18. * @doc INTERNAL MIDI
  19. *
  20. * @api MMRESULT | midiPrepareHeader | This function prepares the header and data
  21. * if the driver returns MMSYSERR_NOTSUPPORTED.
  22. *
  23. * @rdesc Currently always returns MMSYSERR_NOERROR.
  24. ****************************************************************************/
  25. STATIC MMRESULT midiPrepareHeader(LPMIDIHDR lpMidiHdr, UINT wSize)
  26. {
  27. if (!HugePageLock(lpMidiHdr, (DWORD)sizeof(MIDIHDR)))
  28. return MMSYSERR_NOMEM;
  29. if (!HugePageLock(lpMidiHdr->lpData, lpMidiHdr->dwBufferLength)) {
  30. HugePageUnlock(lpMidiHdr, (DWORD)sizeof(MIDIHDR));
  31. return MMSYSERR_NOMEM;
  32. }
  33. lpMidiHdr->dwFlags |= MHDR_PREPARED;
  34. return MMSYSERR_NOERROR;
  35. }
  36. /*****************************************************************************
  37. * @doc INTERNAL MIDI
  38. *
  39. * @api MMRESULT | midiUnprepareHeader | This function unprepares the header and
  40. * data if the driver returns MMSYSERR_NOTSUPPORTED.
  41. *
  42. * @rdesc Currently always returns MMSYSERR_NOERROR.
  43. ****************************************************************************/
  44. STATIC MMRESULT midiUnprepareHeader(LPMIDIHDR lpMidiHdr, UINT wSize)
  45. {
  46. HugePageUnlock(lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
  47. HugePageUnlock(lpMidiHdr, (DWORD)sizeof(MIDIHDR));
  48. lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
  49. return MMSYSERR_NOERROR;
  50. }
  51. /***************************************************************************
  52. * @doc INTERNAL MIDI
  53. *
  54. * @api MMRESULT | midiReferenceDriverById | This function maps a logical
  55. * id to a device driver table index and physical id.
  56. *
  57. * @parm IN MIDIDRV | pmididrvZ | The list of midi drivers.
  58. *
  59. * @parm IN UINT | id | The logical id to be mapped.
  60. *
  61. * @parm OUT PMIDIDRV* OPTIONAL | ppmididrv | Pointer to MIDIDRV structure
  62. * describing the driver supporting the id.
  63. *
  64. * @parm OUT UINT* OPTIONAL | pport | The driver-relative device number. If
  65. * the caller supplies this buffer then it must also supply ppmididrv.
  66. *
  67. * @comm If the caller specifies ppmididrv then this function increments
  68. * the mididrv's usage before returning. The caller must ensure
  69. * the usage is eventually decremented.
  70. *
  71. * @rdesc The return value is zero if successful, MMSYSERR_BADDEVICEID if
  72. * the id is out of range.
  73. *
  74. * @rdesc The return value contains the dev[] array element in the high UINT and
  75. * the driver physical device number in the low UINT.
  76. *
  77. * @comm Out of range values map to FFFF:FFFF
  78. ***************************************************************************/
  79. MMRESULT midiReferenceDriverById(IN PMIDIDRV pmididrvZ, IN UINT id, OUT PMIDIDRV *ppmididrv OPTIONAL, OUT UINT *pport)
  80. {
  81. PMIDIDRV pmididrv;
  82. MMRESULT mmr;
  83. // Should not be called asking for port but not mididrv
  84. WinAssert(!(pport && !ppmididrv));
  85. if (id == MIDI_MAPPER) {
  86. /*
  87. ** Make sure we tried to load the mapper
  88. */
  89. MidiMapperInit();
  90. }
  91. EnterNumDevs("midiReferenceDriverById");
  92. if (MIDI_MAPPER == id)
  93. {
  94. id = 0;
  95. for (pmididrv = pmididrvZ->Next; pmididrv != pmididrvZ; pmididrv = pmididrv->Next)
  96. {
  97. if (pmididrv->fdwDriver & MMDRV_MAPPER) break;
  98. }
  99. } else {
  100. for (pmididrv = pmididrvZ->Next; pmididrv != pmididrvZ; pmididrv = pmididrv->Next)
  101. {
  102. if (pmididrv->fdwDriver & MMDRV_MAPPER) continue;
  103. if (pmididrv->NumDevs > id) break;
  104. id -= pmididrv->NumDevs;
  105. }
  106. }
  107. if (pmididrv != pmididrvZ)
  108. {
  109. if (ppmididrv)
  110. {
  111. mregIncUsagePtr(pmididrv);
  112. *ppmididrv = pmididrv;
  113. if (pport) *pport = id;
  114. }
  115. mmr = MMSYSERR_NOERROR;
  116. } else {
  117. mmr = MMSYSERR_BADDEVICEID;
  118. }
  119. LeaveNumDevs("midiReferenceDriverById");
  120. return mmr;
  121. }
  122. PCWSTR midiReferenceDevInterfaceById(PMIDIDRV pdrvZ, UINT_PTR id)
  123. {
  124. PMIDIDRV pdrv;
  125. PCWSTR DeviceInterface;
  126. if ((pdrvZ == &midioutdrvZ && ValidateHandle((HANDLE)id, TYPE_MIDIOUT)) ||
  127. (pdrvZ == &midiindrvZ && ValidateHandle((HANDLE)id, TYPE_MIDIIN)))
  128. {
  129. DeviceInterface = ((PMIDIDEV)id)->mididrv->cookie;
  130. if (DeviceInterface) wdmDevInterfaceInc(DeviceInterface);
  131. return DeviceInterface;
  132. }
  133. if (!midiReferenceDriverById(pdrvZ, (UINT)id, &pdrv, NULL))
  134. {
  135. DeviceInterface = pdrv->cookie;
  136. if (DeviceInterface) wdmDevInterfaceInc(DeviceInterface);
  137. mregDecUsagePtr(pdrv);
  138. return DeviceInterface;
  139. }
  140. return NULL;
  141. }
  142. /****************************************************************************
  143. * @doc INTERNAL MIDI
  144. *
  145. * @api MMRESULT | midiMessage | This function sends messages to the MIDI device
  146. * drivers.
  147. *
  148. * @parm HMIDI | hMidi | The handle to the MIDI device.
  149. *
  150. * @parm UINT | wMsg | The message to send.
  151. *
  152. * @parm DWORD | dwP1 | Parameter 1.
  153. *
  154. * @parm DWORD | dwP2 | Parameter 2.
  155. *
  156. * @rdesc Returns the value of the message sent.
  157. ***************************************************************************/
  158. STATIC MMRESULT midiMessage(HMIDI hMidi, UINT msg, DWORD_PTR dwP1, DWORD_PTR dwP2)
  159. {
  160. MMRESULT mrc;
  161. ENTER_MM_HANDLE(hMidi);
  162. ReleaseHandleListResource();
  163. // Is handle deserted?
  164. if (IsHandleDeserted(hMidi))
  165. {
  166. LEAVE_MM_HANDLE(hMidi);
  167. return (MMSYSERR_NODRIVER);
  168. }
  169. // Are we busy (in the middle of an open/close)?
  170. if (IsHandleBusy(hMidi))
  171. {
  172. LEAVE_MM_HANDLE(hMidi);
  173. return (MMSYSERR_HANDLEBUSY);
  174. }
  175. if (BAD_HANDLE(hMidi, TYPE_MIDIOUT) && BAD_HANDLE(hMidi, TYPE_MIDISTRM) &&
  176. BAD_HANDLE(hMidi, TYPE_MIDIIN) ) {
  177. WinAssert(!"Bad Handle within midiMessage");
  178. mrc = MMSYSERR_INVALHANDLE;
  179. } else {
  180. mrc = (*(((PMIDIDEV)hMidi)->mididrv->drvMessage))
  181. (((PMIDIDEV)hMidi)->wDevice, msg, ((PMIDIDEV)hMidi)->dwDrvUser, dwP1, dwP2);
  182. }
  183. LEAVE_MM_HANDLE(hMidi);
  184. return mrc;
  185. }
  186. /****************************************************************************
  187. * @doc INTERNAL MIDI
  188. *
  189. * @func MMRESULT | midiIDMessage | This function sends a message to the device
  190. * ID specified. It also performs error checking on the ID passed.
  191. *
  192. * @parm PMIDIDRV | mididrv | Pointer to the input or output device list.
  193. *
  194. * @parm UINT | wTotalNumDevs | Total number of devices in device list.
  195. *
  196. * @parm UINT | uDeviceID | Device ID to send message to.
  197. *
  198. * @parm UINT | wMessage | The message to send.
  199. *
  200. * @parm DWORD | dwParam1 | Parameter 1.
  201. *
  202. * @parm DWORD | dwParam2 | Parameter 2.
  203. *
  204. * @rdesc The return value is the low UINT of the returned message.
  205. ***************************************************************************/
  206. STATIC MMRESULT midiIDMessage(
  207. PMIDIDRV pmididrvZ,
  208. UINT wTotalNumDevs,
  209. UINT_PTR uDeviceID,
  210. UINT wMessage,
  211. DWORD_PTR dwParam1,
  212. DWORD_PTR dwParam2)
  213. {
  214. PMIDIDRV mididrv;
  215. UINT port;
  216. DWORD mmr;
  217. DWORD dwClass;
  218. if (uDeviceID>=wTotalNumDevs && uDeviceID!=MIDI_MAPPER) {
  219. // this cannot be a device ID.
  220. // it could be a device handle. Try it.
  221. // First we have to verify which type of handle it is (OUT or IN)
  222. // We can work this out as midiIDMessage is only ever called with
  223. // mididrv== midioutdrv or midiindrv
  224. if ((pmididrvZ == &midioutdrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_MIDIOUT))
  225. || (pmididrvZ == &midiindrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_MIDIIN) )) {
  226. // to preserve as much compatibility with previous code paths
  227. // we do NOT call midiMessage as that calls ENTER_MM_HANDLE
  228. return (MMRESULT)(*(((PMIDIDEV)uDeviceID)->mididrv->drvMessage))
  229. (((PMIDIDEV)uDeviceID)->wDevice,
  230. wMessage,
  231. ((PMIDIDEV)uDeviceID)->dwDrvUser, dwParam1, dwParam2);
  232. } else {
  233. return(MMSYSERR_BADDEVICEID);
  234. }
  235. }
  236. // Get Physical Device, and Port
  237. mmr = midiReferenceDriverById(pmididrvZ, (UINT)uDeviceID, &mididrv, &port);
  238. if (mmr)
  239. {
  240. return mmr;
  241. }
  242. if (pmididrvZ == &midiindrvZ)
  243. dwClass = TYPE_MIDIIN;
  244. else if (pmididrvZ == &midioutdrvZ)
  245. dwClass = TYPE_MIDIOUT;
  246. else
  247. dwClass = TYPE_UNKNOWN;
  248. if (!mididrv->drvMessage)
  249. return MMSYSERR_NODRIVER;
  250. // Handle Internal Messages
  251. if (!mregHandleInternalMessages (mididrv, dwClass, port, wMessage, dwParam1, dwParam2, &mmr))
  252. {
  253. // Call Physical Device at Port
  254. mmr = (MMRESULT)((*(mididrv->drvMessage))(port, wMessage, 0L, dwParam1, dwParam2));
  255. }
  256. mregDecUsagePtr(mididrv);
  257. return mmr;
  258. }
  259. /*****************************************************************************
  260. * @doc EXTERNAL MIDI
  261. *
  262. * @api UINT | midiOutGetNumDevs | This function retrieves the number of MIDI
  263. * output devices present in the system.
  264. *
  265. * @rdesc Returns the number of MIDI output devices present in the system.
  266. *
  267. * @xref midiOutGetDevCaps
  268. ****************************************************************************/
  269. UINT APIENTRY midiOutGetNumDevs(void)
  270. {
  271. UINT cDevs;
  272. ClientUpdatePnpInfo();
  273. EnterNumDevs("midiOutGetNumDevs");
  274. cDevs = wTotalMidiOutDevs;
  275. LeaveNumDevs("midiOutGetNumDevs");
  276. return cDevs;
  277. }
  278. /****************************************************************************
  279. * @doc EXTERNAL MIDI
  280. *
  281. * @api MMRESULT | midiOutMessage | This function sends messages to the MIDI device
  282. * drivers.
  283. *
  284. * @parm HMIDIOUT | hMidiOut | The handle to the MIDI device.
  285. *
  286. * @parm UINT | msg | The message to send.
  287. *
  288. * @parm DWORD | dw1 | Parameter 1.
  289. *
  290. * @parm DWORD | dw2 | Parameter 2.
  291. *
  292. * @rdesc Returns the value of the message sent.
  293. ***************************************************************************/
  294. MMRESULT APIENTRY midiOutMessage(HMIDIOUT hMidiOut, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
  295. {
  296. ClientUpdatePnpInfo();
  297. AcquireHandleListResourceShared();
  298. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  299. {
  300. ReleaseHandleListResource();
  301. return midiIDMessage(&midioutdrvZ, wTotalMidiOutDevs, (UINT_PTR)hMidiOut, msg, dw1, dw2);
  302. }
  303. switch(GetHandleType(hMidiOut))
  304. {
  305. case TYPE_MIDIOUT:
  306. return midiMessage((HMIDI)hMidiOut, msg, dw1, dw2);
  307. case TYPE_MIDISTRM:
  308. ReleaseHandleListResource();
  309. return midiStreamBroadcast(HtoPT(PMIDISTRM, hMidiOut), msg, dw1, dw2);
  310. }
  311. ReleaseHandleListResource();
  312. Squirt("We should never get here.");
  313. WinAssert(FALSE);
  314. // Getting rid of warning.
  315. return MMSYSERR_INVALHANDLE;
  316. }
  317. /*****************************************************************************
  318. * @doc EXTERNAL MIDI
  319. *
  320. * @api MMRESULT | midiOutGetDevCaps | This function queries a specified
  321. * MIDI output device to determine its capabilities.
  322. *
  323. * @parm UINT | uDeviceID | Identifies the MIDI output device.
  324. *
  325. * @parm LPMIDIOUTCAPS | lpCaps | Specifies a far pointer to a <t MIDIOUTCAPS>
  326. * structure. This structure is filled with information about the
  327. * capabilities of the device.
  328. *
  329. * @parm UINT | wSize | Specifies the size of the <t MIDIOUTCAPS> structure.
  330. *
  331. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  332. * an error number. Possible error returns are:
  333. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  334. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  335. * @flag MMSYSERR_NOMEM | Unable load mapper string description.
  336. *
  337. * @comm Use <f midiOutGetNumDevs> to determine the number of MIDI output
  338. * devices present in the system. The device ID specified by <p uDeviceID>
  339. * varies from zero to one less than the number of devices present.
  340. * The MIDI_MAPPER constant may also be used as a device id. Only
  341. * <p wSize> bytes (or less) of information is copied to the location
  342. * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied,
  343. * and the function returns zero.
  344. *
  345. * @xref midiOutGetNumDevs
  346. ****************************************************************************/
  347. MMRESULT APIENTRY midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT wSize)
  348. {
  349. DWORD_PTR dwParam1, dwParam2;
  350. MDEVICECAPSEX mdCaps;
  351. PMIDIDRV midioutdrv;
  352. PCWSTR DevInterface;
  353. MMRESULT mmr;
  354. if (wSize == 0)
  355. return MMSYSERR_NOERROR;
  356. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  357. ClientUpdatePnpInfo();
  358. DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, uDeviceID);
  359. dwParam2 = (DWORD_PTR)DevInterface;
  360. if (0 == dwParam2)
  361. {
  362. dwParam1 = (DWORD_PTR)lpCaps;
  363. dwParam2 = (DWORD)wSize;
  364. }
  365. else
  366. {
  367. mdCaps.cbSize = (DWORD)wSize;
  368. mdCaps.pCaps = lpCaps;
  369. dwParam1 = (DWORD_PTR)&mdCaps;
  370. }
  371. //
  372. // Don't allow non proper drivers in TS environement
  373. //
  374. // ISSUE-2001/01/09-FrankYe Instead of cast to UINT. Should check whether
  375. // this is a handle and get wavedrv from handle if it is.
  376. midioutdrv = NULL;
  377. if ((!midiReferenceDriverById(&midioutdrvZ, (UINT)uDeviceID, &midioutdrv, NULL)) &&
  378. lstrcmpW(midioutdrv->wszSessProtocol, SessionProtocolName))
  379. {
  380. mmr = MMSYSERR_NODRIVER;
  381. }
  382. else
  383. {
  384. AcquireHandleListResourceShared();
  385. if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIOUT))
  386. {
  387. ReleaseHandleListResource();
  388. mmr = midiIDMessage( &midioutdrvZ, wTotalMidiOutDevs, uDeviceID, MODM_GETDEVCAPS, dwParam1, dwParam2 );
  389. }
  390. else
  391. {
  392. mmr = (MMRESULT)midiMessage((HMIDI)uDeviceID, MODM_GETDEVCAPS, dwParam1, dwParam2);
  393. }
  394. }
  395. if (midioutdrv) mregDecUsagePtr(midioutdrv);
  396. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  397. return mmr;
  398. }
  399. MMRESULT APIENTRY midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT wSize)
  400. {
  401. MIDIOUTCAPS2W wDevCaps2;
  402. MIDIOUTCAPS2A aDevCaps2;
  403. DWORD_PTR dwParam1, dwParam2;
  404. MDEVICECAPSEX mdCaps;
  405. MMRESULT mmRes;
  406. PMIDIDRV midioutdrv;
  407. CHAR chTmp[ MAXPNAMELEN * sizeof(WCHAR) ];
  408. PCWSTR DevInterface;
  409. if (wSize == 0)
  410. return MMSYSERR_NOERROR;
  411. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  412. ClientUpdatePnpInfo();
  413. DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, uDeviceID);
  414. dwParam2 = (DWORD_PTR)DevInterface;
  415. memset(&wDevCaps2, 0, sizeof(wDevCaps2));
  416. if (0 == dwParam2)
  417. {
  418. dwParam1 = (DWORD_PTR)&wDevCaps2;
  419. dwParam2 = (DWORD)sizeof(wDevCaps2);
  420. }
  421. else
  422. {
  423. mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
  424. mdCaps.pCaps = &wDevCaps2;
  425. dwParam1 = (DWORD_PTR)&mdCaps;
  426. }
  427. //
  428. // Don't allow non proper drivers in TS environement
  429. //
  430. // ISSUE-2001/01/09-FrankYe Bad cast to UINT. Should check whether this
  431. // is a handle and get wavedrv from handle if it is.
  432. midioutdrv = NULL;
  433. if ( uDeviceID < wTotalMidiOutDevs &&
  434. !midiReferenceDriverById(&midioutdrvZ, (UINT)uDeviceID, &midioutdrv, NULL) &&
  435. lstrcmpW(midioutdrv->wszSessProtocol, SessionProtocolName) )
  436. {
  437. mregDecUsagePtr(midioutdrv);
  438. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  439. return MMSYSERR_NODRIVER;
  440. }
  441. AcquireHandleListResourceShared();
  442. if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIOUT))
  443. {
  444. ReleaseHandleListResource();
  445. mmRes = midiIDMessage( &midioutdrvZ, wTotalMidiOutDevs, (UINT)uDeviceID,
  446. MODM_GETDEVCAPS, dwParam1,
  447. dwParam2);
  448. }
  449. else
  450. {
  451. mmRes = midiMessage((HMIDI)uDeviceID, MODM_GETDEVCAPS,
  452. dwParam1, dwParam2);
  453. }
  454. if (midioutdrv) mregDecUsagePtr(midioutdrv);
  455. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  456. //
  457. // Make sure the call worked before proceeding with the thunk.
  458. //
  459. if ( mmRes != MMSYSERR_NOERROR ) {
  460. return mmRes;
  461. }
  462. aDevCaps2.wMid = wDevCaps2.wMid;
  463. aDevCaps2.wPid = wDevCaps2.wPid;
  464. aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
  465. aDevCaps2.wTechnology = wDevCaps2.wTechnology;
  466. aDevCaps2.wVoices = wDevCaps2.wVoices;
  467. aDevCaps2.wNotes = wDevCaps2.wNotes;
  468. aDevCaps2.wChannelMask = wDevCaps2.wChannelMask;
  469. aDevCaps2.dwSupport = wDevCaps2.dwSupport;
  470. aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
  471. aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
  472. aDevCaps2.NameGuid = wDevCaps2.NameGuid;
  473. // copy and convert lpwText to lpText here.
  474. UnicodeStrToAsciiStr( chTmp, chTmp + sizeof( chTmp ), wDevCaps2.szPname );
  475. strcpy( aDevCaps2.szPname, chTmp );
  476. //
  477. // now copy the required amount into the callers buffer.
  478. //
  479. CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
  480. return mmRes;
  481. }
  482. /*****************************************************************************
  483. * @doc EXTERNAL MIDI
  484. *
  485. * @api MMRESULT | midiOutGetVolume | This function returns the current volume
  486. * setting of a MIDI output device.
  487. *
  488. * @parm UINT | uDeviceID | Identifies the MIDI output device.
  489. *
  490. * @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location
  491. * to be filled with the current volume setting. The low-order UINT of
  492. * this location contains the left channel volume setting, and the high-order
  493. * UINT contains the right channel setting. A value of 0xFFFF represents
  494. * full volume, and a value of 0x0000 is silence.
  495. *
  496. * If a device does not support both left and right volume
  497. * control, the low-order UINT of the specified location contains
  498. * the mono volume level.
  499. *
  500. * The full 16-bit setting(s)
  501. * set with <f midiOutSetVolume> is returned, regardless of whether
  502. * the device supports the full 16 bits of volume level control.
  503. *
  504. *
  505. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  506. * an error number. Possible error returns are:
  507. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  508. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  509. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  510. *
  511. * @comm Not all devices support volume control. To determine whether the
  512. * device supports volume control, use the MIDICAPS_VOLUME
  513. * flag to test the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
  514. * structure (filled by <f midiOutGetDevCaps>).
  515. *
  516. * To determine whether the device supports volume control on both the
  517. * left and right channels, use the MIDICAPS_LRVOLUME flag to test
  518. * the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
  519. * structure (filled by <f midiOutGetDevCaps>).
  520. *
  521. * @xref midiOutSetVolume
  522. ****************************************************************************/
  523. MMRESULT APIENTRY midiOutGetVolume(HMIDIOUT hmo, LPDWORD lpdwVolume)
  524. {
  525. PCWSTR DevInterface;
  526. MMRESULT mmr;
  527. V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
  528. ClientUpdatePnpInfo();
  529. DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, (UINT_PTR)hmo);
  530. AcquireHandleListResourceShared();
  531. if (BAD_HANDLE(hmo, TYPE_MIDIOUT) && BAD_HANDLE(hmo, TYPE_MIDISTRM))
  532. {
  533. ReleaseHandleListResource();
  534. mmr = midiIDMessage(&midioutdrvZ, wTotalMidiOutDevs, (UINT_PTR)hmo, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
  535. }
  536. else
  537. {
  538. switch(GetHandleType(hmo))
  539. {
  540. case TYPE_MIDIOUT:
  541. mmr = (MMRESULT)midiMessage((HMIDI)hmo, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
  542. break;
  543. case TYPE_MIDISTRM:
  544. ENTER_MM_HANDLE((HMIDI)hmo);
  545. ReleaseHandleListResource();
  546. mmr = (MMRESULT)midiStreamMessage(HtoPT(PMIDISTRM, hmo)->rgIds, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
  547. LEAVE_MM_HANDLE((HMIDI)hmo);
  548. break;
  549. default:
  550. WinAssert(FALSE);
  551. ReleaseHandleListResource();
  552. mmr = MMSYSERR_INVALHANDLE;
  553. break;
  554. }
  555. }
  556. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  557. return mmr;
  558. }
  559. /*****************************************************************************
  560. * @doc EXTERNAL MIDI
  561. *
  562. * @api MMRESULT | midiOutSetVolume | This function sets the volume of a
  563. * MIDI output device.
  564. *
  565. * @parm UINT | uDeviceID | Identifies the MIDI output device.
  566. *
  567. * @parm DWORD | dwVolume | Specifies the new volume setting.
  568. * The low-order UINT contains the left channel volume setting, and the
  569. * high-order UINT contains the right channel setting. A value of
  570. * 0xFFFF represents full volume, and a value of 0x0000 is silence.
  571. *
  572. * If a device does not support both left and right volume
  573. * control, the low-order UINT of <p dwVolume> specifies the volume
  574. * level, and the high-order UINT is ignored.
  575. *
  576. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  577. * an error number. Possible error returns are:
  578. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  579. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  580. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  581. *
  582. * @comm Not all devices support volume changes. To determine whether the
  583. * device supports volume control, use the MIDICAPS_VOLUME
  584. * flag to test the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
  585. * structure (filled by <f midiOutGetDevCaps>).
  586. *
  587. * To determine whether the device supports volume control on both the
  588. * left and right channels, use the MIDICAPS_LRVOLUME flag to test
  589. * the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
  590. * structure (filled by <f midiOutGetDevCaps>).
  591. *
  592. * Most devices do not support the full 16 bits of volume level control
  593. * and will use only the high-order bits of the requested volume setting.
  594. * For example, for a device that supports 4 bits of volume control,
  595. * requested volume level values of 0x4000, 0x4fff, and 0x43be will
  596. * all produce the same physical volume setting, 0x4000. The
  597. * <f midiOutGetVolume> function will return the full 16-bit setting set
  598. * with <f midiOutSetVolume>.
  599. *
  600. * Volume settings are interpreted logarithmically. This means the
  601. * perceived increase in volume is the same when increasing the
  602. * volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
  603. *
  604. * @xref midiOutGetVolume
  605. ****************************************************************************/
  606. MMRESULT APIENTRY midiOutSetVolume(HMIDIOUT hmo, DWORD dwVolume)
  607. {
  608. PCWSTR DevInterface;
  609. MMRESULT mmr;
  610. ClientUpdatePnpInfo();
  611. DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, (UINT_PTR)hmo);
  612. AcquireHandleListResourceShared();
  613. if (BAD_HANDLE(hmo, TYPE_MIDIOUT) && BAD_HANDLE(hmo, TYPE_MIDISTRM))
  614. {
  615. ReleaseHandleListResource();
  616. mmr = midiIDMessage(&midioutdrvZ, wTotalMidiOutDevs, (UINT_PTR)hmo, MODM_SETVOLUME, dwVolume, (DWORD_PTR)DevInterface);
  617. }
  618. else
  619. {
  620. switch(GetHandleType(hmo))
  621. {
  622. case TYPE_MIDIOUT:
  623. mmr = (MMRESULT)midiMessage((HMIDI)hmo, MODM_SETVOLUME, (DWORD)dwVolume, (DWORD_PTR)DevInterface);
  624. break;
  625. case TYPE_MIDISTRM:
  626. ReleaseHandleListResource();
  627. mmr = (MMRESULT)midiStreamBroadcast(HtoPT(PMIDISTRM, hmo), MODM_SETVOLUME, (DWORD)dwVolume, (DWORD_PTR)DevInterface);
  628. break;
  629. default:
  630. ReleaseHandleListResource();
  631. WinAssert(FALSE);
  632. mmr = MMSYSERR_INVALHANDLE;
  633. break;
  634. }
  635. }
  636. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  637. return mmr;
  638. }
  639. /*****************************************************************************
  640. * @doc INTERNAL MIDI
  641. *
  642. * @func MMRESULT | midiGetErrorText | This function retrieves a textual
  643. * description of the error identified by the specified error number.
  644. *
  645. * @parm UINT | wError | Specifies the error number.
  646. *
  647. * @parm LPTSTR | lpText | Specifies a far pointer to a buffer which
  648. * is filled with the textual error description.
  649. *
  650. * @parm UINT | wSize | Specifies the length in characters of the buffer
  651. * pointed to by <p lpText>.
  652. *
  653. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  654. * an error number. Possible error returns are:
  655. * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
  656. *
  657. * @comm If the textual error description is longer than the specified buffer,
  658. * the description is truncated. The returned error string is always
  659. * null-terminated. If <p wSize> is zero, nothing is copied and MMSYSERR_NOERROR
  660. * is returned. All error descriptions are less than 80 characters long.
  661. ****************************************************************************/
  662. STATIC MMRESULT midiGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
  663. {
  664. lpText[0] = 0;
  665. #if MMSYSERR_BASE
  666. if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
  667. #else
  668. if ((wError > MMSYSERR_LASTERROR) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
  669. #endif
  670. return MMSYSERR_BADERRNUM;
  671. if (wSize > 1)
  672. {
  673. if (!LoadStringW(ghInst, wError, lpText, wSize))
  674. return MMSYSERR_BADERRNUM;
  675. }
  676. return MMSYSERR_NOERROR;
  677. }
  678. STATIC MMRESULT midiGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
  679. {
  680. lpText[0] = 0;
  681. #if MMSYSERR_BASE
  682. if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
  683. #else
  684. if ((wError > MMSYSERR_LASTERROR) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
  685. #endif
  686. return MMSYSERR_BADERRNUM;
  687. if (wSize > 1)
  688. {
  689. if (!LoadStringA(ghInst, wError, lpText, wSize))
  690. return MMSYSERR_BADERRNUM;
  691. }
  692. return MMSYSERR_NOERROR;
  693. }
  694. /*****************************************************************************
  695. * @doc EXTERNAL MIDI
  696. *
  697. * @api MMRESULT | midiOutGetErrorText | This function retrieves a textual
  698. * description of the error identified by the specified error number.
  699. *
  700. * @parm UINT | wError | Specifies the error number.
  701. *
  702. * @parm LPTSTR | lpText | Specifies a far pointer to a buffer to be
  703. * filled with the textual error description.
  704. *
  705. * @parm UINT | wSize | Specifies the length in characters of the buffer
  706. * pointed to by <p lpText>.
  707. *
  708. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  709. * an error number. Possible error returns are:
  710. * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
  711. *
  712. * @comm If the textual error description is longer than the specified buffer,
  713. * the description is truncated. The returned error string is always
  714. * null-terminated. If <p wSize> is zero, nothing is copied, and the
  715. * function returns MMSYSERR_NOERROR. All error descriptions are
  716. * less than MAXERRORLENGTH characters long.
  717. ****************************************************************************/
  718. MMRESULT APIENTRY midiOutGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
  719. {
  720. if(wSize == 0)
  721. return MMSYSERR_NOERROR;
  722. V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
  723. return midiGetErrorTextW(wError, lpText, wSize);
  724. }
  725. MMRESULT APIENTRY midiOutGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
  726. {
  727. if(wSize == 0)
  728. return MMSYSERR_NOERROR;
  729. V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
  730. return midiGetErrorTextA(wError, lpText, wSize);
  731. }
  732. /*****************************************************************************
  733. * @doc EXTERNAL MIDI
  734. *
  735. * @api MMRESULT | midiOutOpen | This function opens a specified MIDI
  736. * output device for playback.
  737. *
  738. * @parm LPHMIDIOUT | lphMidiOut | Specifies a far pointer to an HMIDIOUT
  739. * handle. This location is filled with a handle identifying the opened
  740. * MIDI output device. Use the handle to identify the device when calling
  741. * other MIDI output functions.
  742. *
  743. * @parm UINT | uDeviceID | Identifies the MIDI output device that is
  744. * to be opened.
  745. *
  746. * @parm DWORD | dwCallback | Specifies the address of a fixed callback
  747. * function or
  748. * a handle to a window called during MIDI playback to process
  749. * messages related to the progress of the playback. Specify NULL
  750. * for this parameter if no callback is desired.
  751. *
  752. * @parm DWORD | dwCallbackInstance | Specifies user instance data
  753. * passed to the callback. This parameter is not used with
  754. * window callbacks.
  755. *
  756. * @parm DWORD | dwFlags | Specifies a callback flag for opening the device.
  757. * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
  758. * assumed to be a window handle.
  759. * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
  760. * assumed to be a callback procedure address.
  761. *
  762. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  763. * an error number. Possible error returns are as follows:
  764. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  765. * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
  766. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  767. * @flag MIDIERR_NOMAP | There is no current MIDI map. This occurs only
  768. * when opening the mapper.
  769. * @flag MIDIERR_NODEVICE | A port in the current MIDI map doesn't exist.
  770. * This occurs only when opening the mapper.
  771. *
  772. * @comm Use <f midiOutGetNumDevs> to determine the number of MIDI output
  773. * devices present in the system. The device ID specified by <p uDeviceID>
  774. * varies from zero to one less than the number of devices present.
  775. * You may also specify MIDI_MAPPER as the device ID to open the MIDI mapper.
  776. *
  777. * If a window is chosen to receive callback information, the following
  778. * messages are sent to the window procedure function to indicate the
  779. * progress of MIDI output: <m MM_MOM_OPEN>, <m MM_MOM_CLOSE>,
  780. * <m MM_MOM_DONE>.
  781. *
  782. * If a function is chosen to receive callback information, the following
  783. * messages are sent to the function to indicate the progress of MIDI
  784. * output: <m MOM_OPEN>, <m MOM_CLOSE>, <m MOM_DONE>. The callback function
  785. * must reside in a DLL. You do not have to use <f MakeProcInstance> to
  786. * get a procedure-instance address for the callback function.
  787. *
  788. * @cb void CALLBACK | MidiOutFunc | <f MidiOutFunc> is a placeholder for
  789. * the application-supplied function name. The actual name must be
  790. * exported by including it in an EXPORTS statement in the DLL's
  791. * module-definition file.
  792. *
  793. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI device
  794. * associated with the callback.
  795. *
  796. * @parm UINT | wMsg | Specifies a MIDI output message.
  797. *
  798. * @parm DWORD | dwInstance | Specifies the instance data
  799. * supplied with <f midiOutOpen>.
  800. *
  801. * @parm DWORD | dwParam1 | Specifies a parameter for the message.
  802. *
  803. * @parm DWORD | dwParam2 | Specifies a parameter for the message.
  804. *
  805. * @comm Because the callback is accessed at interrupt time, it must reside
  806. * in a DLL and its code segment must be specified as FIXED in the
  807. * module-definition file for the DLL. Any data that the callback accesses
  808. * must be in a FIXED data segment as well. The callback may not make any
  809. * system calls except for <f PostMessage>, <f timeGetSystemTime>,
  810. * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
  811. * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
  812. *
  813. * @xref midiOutClose
  814. ****************************************************************************/
  815. MMRESULT APIENTRY midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
  816. DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
  817. {
  818. MIDIOPENDESC mo;
  819. PMIDIDEV pdev;
  820. PMIDIDRV mididrv;
  821. UINT port;
  822. MMRESULT wRet;
  823. V_WPOINTER(lphMidiOut, sizeof(HMIDIOUT), MMSYSERR_INVALPARAM);
  824. if (uDeviceID == MIDI_MAPPER) {
  825. V_FLAGS(LOWORD(dwFlags), MIDI_O_VALID & ~LOWORD(MIDI_IO_SHARED | MIDI_IO_COOKED), midiOutOpen, MMSYSERR_INVALFLAG);
  826. } else {
  827. V_FLAGS(LOWORD(dwFlags), MIDI_O_VALID & ~LOWORD(MIDI_IO_COOKED), midiOutOpen, MMSYSERR_INVALFLAG);
  828. }
  829. V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
  830. *lphMidiOut = NULL;
  831. ClientUpdatePnpInfo();
  832. wRet = midiReferenceDriverById(&midioutdrvZ, uDeviceID, &mididrv, &port);
  833. if (wRet)
  834. {
  835. return wRet;
  836. }
  837. //
  838. // check if the device is appropriate for the current TS session
  839. //
  840. if (!(mididrv->fdwDriver & MMDRV_MAPPER) &&
  841. lstrcmpW(mididrv->wszSessProtocol, SessionProtocolName))
  842. {
  843. mregDecUsagePtr(mididrv);
  844. return MMSYSERR_NODRIVER;
  845. }
  846. #ifdef DO_DEFAULT_MIDI_MAPPER
  847. /* Default midi mapper :
  848. *
  849. * If a midi mapper is installed as a separate DLL then all midi mapper
  850. * messages are routed to it. If no midi mapper is installed, simply
  851. * loop through the midi devices looking for a match.
  852. */
  853. if ((uDeviceID == MIDI_MAPPER && !mididrv->drvMessage)) {
  854. UINT wErr = MMSYSERR_NODRIVER;
  855. UINT cMax;
  856. mregDecUsagePtr(mididrv);
  857. cMax = wTotalMidiOutDevs;
  858. for (uDeviceID=0; uDeviceID<cMax; uDeviceID++) {
  859. wErr = midiOutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
  860. if (wErr == MMSYSERR_NOERROR)
  861. break;
  862. }
  863. return wErr;
  864. }
  865. #endif // DO_DEFAULT_MIDI_MAPPER
  866. if (!mididrv->drvMessage)
  867. {
  868. mregDecUsagePtr(mididrv);
  869. return MMSYSERR_NODRIVER;
  870. }
  871. pdev = (PMIDIDEV)NewHandle(TYPE_MIDIOUT, mididrv->cookie, sizeof(MIDIDEV));
  872. if( pdev == NULL)
  873. {
  874. mregDecUsagePtr(mididrv);
  875. return MMSYSERR_NOMEM;
  876. }
  877. ENTER_MM_HANDLE(pdev);
  878. SetHandleFlag(pdev, MMHANDLE_BUSY);
  879. ReleaseHandleListResource();
  880. pdev->mididrv = mididrv;
  881. pdev->wDevice = port;
  882. pdev->uDeviceID = uDeviceID;
  883. pdev->fdwHandle = 0;
  884. mo.hMidi = (HMIDI)pdev;
  885. mo.dwInstance = dwInstance;
  886. mo.dwCallback = dwCallback;
  887. mo.dnDevNode = (DWORD_PTR)pdev->mididrv->cookie;
  888. wRet = (MMRESULT)((*(mididrv->drvMessage))
  889. (pdev->wDevice, MODM_OPEN, (DWORD_PTR)&pdev->dwDrvUser, (DWORD_PTR)(LPMIDIOPENDESC)&mo, dwFlags));
  890. // Mark as not busy on successful open...
  891. if (!wRet)
  892. ClearHandleFlag(pdev, MMHANDLE_BUSY);
  893. LEAVE_MM_HANDLE(pdev);
  894. if (wRet)
  895. FreeHandle((HMIDIOUT)pdev);
  896. else {
  897. // Workaround for Bug#330817
  898. mregIncUsagePtr(mididrv);
  899. *lphMidiOut = (HMIDIOUT)pdev;
  900. }
  901. mregDecUsagePtr(mididrv);
  902. return wRet;
  903. }
  904. /*****************************************************************************
  905. * @doc EXTERNAL MIDI
  906. *
  907. * @api MMRESULT | midiOutClose | This function closes the specified MIDI
  908. * output device.
  909. *
  910. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output device.
  911. * If the function is successful, the handle is no longer
  912. * valid after this call.
  913. *
  914. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  915. * an error number. Possible error returns are:
  916. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  917. * @flag MIDIERR_STILLPLAYING | There are still buffers in the queue.
  918. *
  919. * @comm If there are output buffers that have been sent with
  920. * <f midiOutLongMsg> and haven't been returned to the application,
  921. * the close operation will fail. Call <f midiOutReset> to mark all
  922. * pending buffers as being done.
  923. *
  924. * @xref midiOutOpen midiOutReset
  925. ****************************************************************************/
  926. MMRESULT APIENTRY midiOutClose(HMIDIOUT hMidiOut)
  927. {
  928. MMRESULT wRet;
  929. PMIDIDRV pmididrv;
  930. PMIDIDEV pDev = (PMIDIDEV)hMidiOut;
  931. ClientUpdatePnpInfo();
  932. V_HANDLE_ACQ(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
  933. ENTER_MM_HANDLE((HMIDI)hMidiOut);
  934. ReleaseHandleListResource();
  935. if (IsHandleDeserted(hMidiOut))
  936. {
  937. // This handle has been deserted. Let's just free it.
  938. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  939. FreeHandle(hMidiOut);
  940. return MMSYSERR_NOERROR;
  941. }
  942. if (IsHandleBusy(hMidiOut))
  943. {
  944. // Not quite invalid, but marked as closed.
  945. LEAVE_MM_HANDLE(hMidiOut);
  946. return (MMSYSERR_HANDLEBUSY);
  947. }
  948. // Marking handle as 'invalid/closed'.
  949. SetHandleFlag(hMidiOut, MMHANDLE_BUSY);
  950. pmididrv = pDev->mididrv;
  951. wRet = (MMRESULT)(*pmididrv->drvMessage)(pDev->wDevice, MODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  952. if (MMSYSERR_NOERROR != wRet)
  953. {
  954. // Error closing, set the flag as valid.
  955. ClearHandleFlag(hMidiOut, MMHANDLE_BUSY);
  956. }
  957. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  958. if (!wRet)
  959. {
  960. FreeHandle(hMidiOut);
  961. mregDecUsagePtr(pmididrv);
  962. return wRet;
  963. }
  964. return wRet;
  965. }
  966. /*****************************************************************************
  967. * @doc EXTERNAL MIDI
  968. *
  969. * @api MMRESULT | midiOutPrepareHeader | This function prepares a MIDI
  970. * system-exclusive data block for output.
  971. *
  972. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
  973. * device.
  974. *
  975. * @parm LPMIDIHDR | lpMidiOutHdr | Specifies a far pointer to a <t MIDIHDR>
  976. * structure that identifies the data block to be prepared.
  977. *
  978. * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
  979. *
  980. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  981. * an error number. Possible error returns are:
  982. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  983. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  984. *
  985. * @comm The <t MIDIHDR> data structure and the data block pointed to by its
  986. * <e MIDIHDR.lpData> field must be allocated with <f GlobalAlloc> using the
  987. * GMEM_MOVEABLE and GMEM_SHARE flags and locked with <f GlobalLock>.
  988. * Preparing a header that has already been prepared has no effect, and
  989. * the function returns zero.
  990. *
  991. * @xref midiOutUnprepareHeader
  992. ****************************************************************************/
  993. MMRESULT APIENTRY midiOutPrepareHeader(HMIDIOUT hMidiOut, LPMIDIHDR lpMidiOutHdr, UINT wSize)
  994. {
  995. MMRESULT wRet;
  996. LPMIDIHDR lpmh;
  997. PMIDISTRM pms;
  998. PMIDISTRMID pmsi;
  999. DWORD idx;
  1000. #ifdef DEBUG
  1001. DWORD cDrvrs;
  1002. #endif
  1003. DWORD dwSaveFlags;
  1004. V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
  1005. if (lpMidiOutHdr->dwFlags & MHDR_PREPARED)
  1006. return MMSYSERR_NOERROR;
  1007. lpMidiOutHdr->dwFlags = 0;
  1008. ClientUpdatePnpInfo();
  1009. AcquireHandleListResourceShared();
  1010. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1011. {
  1012. ReleaseHandleListResource();
  1013. return MMSYSERR_INVALHANDLE;
  1014. }
  1015. switch(GetHandleType(hMidiOut))
  1016. {
  1017. case TYPE_MIDIOUT:
  1018. dwSaveFlags = lpMidiOutHdr->dwFlags & MHDR_SAVE;
  1019. wRet = midiMessage((HMIDI)hMidiOut, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, (DWORD)wSize);
  1020. lpMidiOutHdr->dwFlags &= ~MHDR_SAVE;
  1021. lpMidiOutHdr->dwFlags |= dwSaveFlags;
  1022. if (MMSYSERR_NOTSUPPORTED == wRet)
  1023. return midiPrepareHeader(lpMidiOutHdr, wSize);
  1024. return wRet;
  1025. case TYPE_MIDISTRM:
  1026. ENTER_MM_HANDLE((HMIDI)hMidiOut);
  1027. ReleaseHandleListResource();
  1028. pms = HtoPT(PMIDISTRM, hMidiOut);
  1029. if (lpMidiOutHdr->dwBufferLength > 65536L)
  1030. {
  1031. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1032. return MMSYSERR_INVALPARAM;
  1033. }
  1034. lpmh = (LPMIDIHDR)winmmAlloc(sizeof(MIDIHDR) *
  1035. pms->cDrvrs);
  1036. if (NULL == lpmh)
  1037. {
  1038. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1039. return MMSYSERR_NOMEM;
  1040. }
  1041. lpMidiOutHdr->dwReserved[MH_SHADOW] = (DWORD_PTR)lpmh;
  1042. // assert ((HIWORD(lpmh) & 0xFFFE) != (HIWORD(lpMidiOutHdr) & 0xFFFE));
  1043. #ifdef DEBUG
  1044. cDrvrs = 0;
  1045. #endif
  1046. wRet = MMSYSERR_ERROR;
  1047. for (idx = 0, pmsi = pms->rgIds; idx < pms->cIds; idx++, pmsi++)
  1048. if (pmsi->fdwId & MSI_F_FIRST)
  1049. {
  1050. *lpmh = *lpMidiOutHdr;
  1051. lpmh->dwReserved[MH_PARENT] = (DWORD_PTR)lpMidiOutHdr;
  1052. lpmh->dwReserved[MH_SHADOW] = 0;
  1053. lpmh->dwFlags =
  1054. (lpMidiOutHdr->dwFlags & MHDR_MAPPED) | MHDR_SHADOWHDR;
  1055. dwSaveFlags = lpmh->dwFlags & MHDR_SAVE;
  1056. wRet = (MMRESULT)midiStreamMessage(pmsi, MODM_PREPARE, (DWORD_PTR)lpmh, (DWORD)sizeof(MIDIHDR));
  1057. lpmh->dwFlags &= ~MHDR_SAVE;
  1058. lpmh->dwFlags |= dwSaveFlags;
  1059. if (MMSYSERR_NOTSUPPORTED == wRet)
  1060. wRet = midiPrepareHeader(lpmh, sizeof(MIDIHDR));
  1061. if (MMSYSERR_NOERROR != wRet)
  1062. break;
  1063. lpmh++;
  1064. #ifdef DEBUG
  1065. ++cDrvrs;
  1066. if (cDrvrs > pms->cDrvrs)
  1067. dprintf1(("!Too many drivers in midiOutPrepareHeader()!!!"));
  1068. #endif
  1069. }
  1070. if (MMSYSERR_NOERROR == wRet)
  1071. wRet = midiPrepareHeader(lpMidiOutHdr, wSize);
  1072. else
  1073. {
  1074. for (idx = 0, pmsi = pms->rgIds; idx < pms->cIds; idx++, pmsi++)
  1075. if (pmsi->fdwId & MSI_F_FIRST)
  1076. {
  1077. dwSaveFlags = lpmh->dwFlags & MHDR_SAVE;
  1078. wRet = (MMRESULT)midiStreamMessage(pmsi, MODM_UNPREPARE, (DWORD_PTR)lpmh, (DWORD)sizeof(MIDIHDR));
  1079. lpmh->dwFlags &= ~MHDR_SAVE;
  1080. lpmh->dwFlags |= dwSaveFlags;
  1081. if (MMSYSERR_NOTSUPPORTED == wRet)
  1082. wRet = midiUnprepareHeader(lpmh, sizeof(MIDIHDR));
  1083. }
  1084. }
  1085. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1086. return wRet;
  1087. default:
  1088. ReleaseHandleListResource();
  1089. break;
  1090. }
  1091. return MMSYSERR_INVALHANDLE;
  1092. }
  1093. /*****************************************************************************
  1094. * @doc EXTERNAL MIDI
  1095. *
  1096. * @api MMRESULT | midiOutUnprepareHeader | This function cleans up the
  1097. * preparation performed by <f midiOutPrepareHeader>. The
  1098. * <f midiOutUnprepareHeader> function must be called
  1099. * after the device driver fills a data buffer and returns it to the
  1100. * application. You must call this function before freeing the data
  1101. * buffer.
  1102. *
  1103. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
  1104. * device.
  1105. *
  1106. * @parm LPMIDIHDR | lpMidiOutHdr | Specifies a pointer to a <t MIDIHDR>
  1107. * structure identifying the buffer to be cleaned up.
  1108. *
  1109. * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
  1110. *
  1111. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1112. * an error number. Possible error returns are:
  1113. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1114. * @flag MIDIERR_STILLPLAYING | <p lpMidiOutHdr> is still in the queue.
  1115. *
  1116. * @comm This function is the complementary function to
  1117. * <f midiOutPrepareHeader>.
  1118. * You must call this function before freeing the data buffer with
  1119. * <f GlobalFree>.
  1120. * After passing a buffer to the device driver with <f midiOutLongMsg>, you
  1121. * must wait until the driver is finished with the buffer before calling
  1122. * <f midiOutUnprepareHeader>.
  1123. *
  1124. * Unpreparing a buffer that has not been
  1125. * prepared has no effect, and the function returns zero.
  1126. *
  1127. * @xref midiOutPrepareHeader
  1128. ****************************************************************************/
  1129. MMRESULT APIENTRY midiOutUnprepareHeader(HMIDIOUT hMidiOut, LPMIDIHDR lpMidiOutHdr, UINT wSize)
  1130. {
  1131. MMRESULT wRet;
  1132. MMRESULT mmrc;
  1133. PMIDISTRM pms;
  1134. PMIDISTRMID pmsi;
  1135. DWORD idx;
  1136. LPMIDIHDR lpmh;
  1137. DWORD dwSaveFlags;
  1138. V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
  1139. if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED))
  1140. return MMSYSERR_NOERROR;
  1141. if(lpMidiOutHdr->dwFlags & MHDR_INQUEUE)
  1142. {
  1143. DebugErr(DBF_WARNING, "midiOutUnprepareHeader: header still in queue\r\n");
  1144. return MIDIERR_STILLPLAYING;
  1145. }
  1146. ClientUpdatePnpInfo();
  1147. AcquireHandleListResourceShared();
  1148. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1149. {
  1150. ReleaseHandleListResource();
  1151. return MMSYSERR_INVALHANDLE;
  1152. }
  1153. switch(GetHandleType(hMidiOut))
  1154. {
  1155. case TYPE_MIDIOUT:
  1156. dwSaveFlags = lpMidiOutHdr->dwFlags & MHDR_SAVE;
  1157. wRet = midiMessage((HMIDI)hMidiOut, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, (DWORD)wSize);
  1158. lpMidiOutHdr->dwFlags &= ~MHDR_SAVE;
  1159. lpMidiOutHdr->dwFlags |= dwSaveFlags;
  1160. if (wRet == MMSYSERR_NOTSUPPORTED)
  1161. return midiUnprepareHeader(lpMidiOutHdr, wSize);
  1162. if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiOut)))
  1163. {
  1164. // if the driver for the handle has been removed, succeed
  1165. // the call.
  1166. wRet = MMSYSERR_NOERROR;
  1167. }
  1168. return wRet;
  1169. case TYPE_MIDISTRM:
  1170. ENTER_MM_HANDLE((HMIDI)hMidiOut);
  1171. ReleaseHandleListResource();
  1172. pms = HtoPT(PMIDISTRM, hMidiOut);
  1173. wRet = MMSYSERR_NOERROR;
  1174. lpmh = (LPMIDIHDR)lpMidiOutHdr->dwReserved[MH_SHADOW];
  1175. // assert ((HIWORD(lpmh) & 0xFFFE) != (HIWORD(lpMidiOutHdr) & 0xFFFE));
  1176. for (idx = 0, pmsi = pms->rgIds; idx < pms->cIds; idx++, pmsi++)
  1177. if (pmsi->fdwId & MSI_F_FIRST)
  1178. {
  1179. dwSaveFlags = lpmh->dwFlags & MHDR_SAVE;
  1180. mmrc = (MMRESULT)midiStreamMessage(pmsi, MODM_UNPREPARE, (DWORD_PTR)lpmh, (DWORD)sizeof(MIDIHDR));
  1181. lpmh->dwFlags &= ~MHDR_SAVE;
  1182. lpmh->dwFlags |= dwSaveFlags;
  1183. if (MMSYSERR_NOTSUPPORTED == mmrc)
  1184. mmrc = midiUnprepareHeader(lpmh, sizeof(MIDIHDR));
  1185. if (MMSYSERR_NOERROR != mmrc)
  1186. wRet = mmrc;
  1187. lpmh++;
  1188. }
  1189. // assert (HIWORD(lpmh) == HIWORD(lpMidiOutHdr->dwReserved[MH_SHADOW]));
  1190. GlobalFree(GlobalHandle((LPMIDIHDR)lpMidiOutHdr->dwReserved[MH_SHADOW]));
  1191. lpMidiOutHdr->dwReserved[MH_SHADOW] = 0;
  1192. mmrc = midiUnprepareHeader(lpMidiOutHdr, wSize);
  1193. if (MMSYSERR_NOERROR != mmrc)
  1194. wRet = mmrc;
  1195. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1196. return wRet;
  1197. default:
  1198. ReleaseHandleListResource();
  1199. break;
  1200. }
  1201. return MMSYSERR_INVALHANDLE;
  1202. }
  1203. /*****************************************************************************
  1204. * @doc EXTERNAL MIDI
  1205. *
  1206. * @api MMRESULT | midiOutShortMsg | This function sends a short MIDI message to
  1207. * the specified MIDI output device. Use this function to send any MIDI
  1208. * message except for system-exclusive messages.
  1209. *
  1210. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
  1211. * device.
  1212. *
  1213. * @parm DWORD | dwMsg | Specifies the MIDI message. The message is packed
  1214. * into a DWORD with the first byte of the message in the low-order byte.
  1215. *
  1216. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1217. * an error number. Possible error returns are:
  1218. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1219. * @flag MIDIERR_NOTREADY | The hardware is busy with other data.
  1220. *
  1221. * @comm This function may not return until the message has been sent to the
  1222. * output device.
  1223. *
  1224. * @xref midiOutLongMsg
  1225. ****************************************************************************/
  1226. MMRESULT APIENTRY midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
  1227. {
  1228. MMRESULT mmr;
  1229. ClientUpdatePnpInfo();
  1230. AcquireHandleListResourceShared();
  1231. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1232. {
  1233. ReleaseHandleListResource();
  1234. return MMSYSERR_INVALHANDLE;
  1235. }
  1236. switch(GetHandleType(hMidiOut))
  1237. {
  1238. case TYPE_MIDIOUT:
  1239. return (MMRESULT)midiMessage((HMIDI)hMidiOut, MODM_DATA, dwMsg, 0L);
  1240. case TYPE_MIDISTRM:
  1241. ENTER_MM_HANDLE((HMIDI)hMidiOut);
  1242. ReleaseHandleListResource();
  1243. mmr = (MMRESULT)midiStreamMessage(HtoPT(PMIDISTRM, hMidiOut)->rgIds, MODM_DATA, dwMsg, 0L);
  1244. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1245. return (mmr);
  1246. }
  1247. ReleaseHandleListResource();
  1248. return MMSYSERR_INVALHANDLE;
  1249. }
  1250. /*****************************************************************************
  1251. * @doc EXTERNAL MIDI
  1252. *
  1253. * @api MMRESULT | midiOutLongMsg | This function sends a system-exclusive
  1254. * MIDI message to the specified MIDI output device.
  1255. *
  1256. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
  1257. * device.
  1258. *
  1259. * @parm LPMIDIHDR | lpMidiOutHdr | Specifies a far pointer to a <t MIDIHDR>
  1260. * structure that identifies the MIDI data buffer.
  1261. *
  1262. * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
  1263. *
  1264. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1265. * an error number. Possible error returns are:
  1266. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1267. * @flag MIDIERR_UNPREPARED | <p lpMidiOutHdr> hasn't been prepared.
  1268. * @flag MIDIERR_NOTREADY | The hardware is busy with other data.
  1269. *
  1270. * @comm The data buffer must be prepared with <f midiOutPrepareHeader>
  1271. * before it is passed to <f midiOutLongMsg>. The <t MIDIHDR> data
  1272. * structure and the data buffer pointed to by its <e MIDIHDR.lpData>
  1273. * field must be allocated with <f GlobalAlloc> using the GMEM_MOVEABLE
  1274. * and GMEM_SHARE flags, and locked with <f GlobalLock>. The MIDI output
  1275. * device driver determines whether the data is sent synchronously or
  1276. * asynchronously.
  1277. *
  1278. * @xref midiOutShortMsg midiOutPrepareHeader
  1279. ****************************************************************************/
  1280. MMRESULT APIENTRY midiOutLongMsg(HMIDIOUT hMidiOut, LPMIDIHDR lpMidiOutHdr, UINT wSize)
  1281. {
  1282. V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
  1283. if (lpMidiOutHdr->dwFlags & ~MHDR_VALID)
  1284. return MMSYSERR_INVALFLAG;
  1285. if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED))
  1286. return MIDIERR_UNPREPARED;
  1287. if (lpMidiOutHdr->dwFlags & MHDR_INQUEUE)
  1288. return MIDIERR_STILLPLAYING;
  1289. if (!lpMidiOutHdr->dwBufferLength)
  1290. return MMSYSERR_INVALPARAM;
  1291. lpMidiOutHdr->dwFlags &= ~MHDR_ISSTRM;
  1292. ClientUpdatePnpInfo();
  1293. AcquireHandleListResourceShared();
  1294. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1295. {
  1296. ReleaseHandleListResource();
  1297. return MMSYSERR_INVALHANDLE;
  1298. }
  1299. switch(GetHandleType(hMidiOut))
  1300. {
  1301. case TYPE_MIDIOUT:
  1302. return (MMRESULT)midiMessage((HMIDI)hMidiOut, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, (DWORD)wSize);
  1303. case TYPE_MIDISTRM:
  1304. ReleaseHandleListResource();
  1305. return MMSYSERR_NOTSUPPORTED;
  1306. default:
  1307. ReleaseHandleListResource();
  1308. break;
  1309. }
  1310. return MMSYSERR_INVALHANDLE;
  1311. }
  1312. /*****************************************************************************
  1313. * @doc EXTERNAL MIDI
  1314. *
  1315. * @api MMRESULT | midiOutReset | This function turns off all notes on all MIDI
  1316. * channels for the specified MIDI output device. Any pending
  1317. * system-exclusive output buffers are marked as done and
  1318. * returned to the application.
  1319. *
  1320. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
  1321. * device.
  1322. *
  1323. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1324. * an error number. Possible error returns are:
  1325. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1326. *
  1327. * @comm To turn off all notes, a note-off message for each note for each
  1328. * channel is sent. In addition, the sustain controller is turned off for
  1329. * each channel.
  1330. *
  1331. * @xref midiOutLongMsg midiOutClose
  1332. ****************************************************************************/
  1333. MMRESULT APIENTRY midiOutReset(HMIDIOUT hMidiOut)
  1334. {
  1335. PMIDISTRM pms;
  1336. MMRESULT mmr;
  1337. ClientUpdatePnpInfo();
  1338. AcquireHandleListResourceShared();
  1339. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1340. {
  1341. ReleaseHandleListResource();
  1342. return MMSYSERR_INVALHANDLE;
  1343. }
  1344. switch(GetHandleType(hMidiOut))
  1345. {
  1346. case TYPE_MIDIOUT:
  1347. mmr = (MMRESULT)midiMessage((HMIDI)hMidiOut, MODM_RESET, 0, 0);
  1348. break;
  1349. case TYPE_MIDISTRM:
  1350. pms = HtoPT(PMIDISTRM, hMidiOut);
  1351. ReleaseHandleListResource();
  1352. mmr = (MMRESULT)midiStreamBroadcast(pms, MODM_RESET, 0, 0);
  1353. break;
  1354. default:
  1355. ReleaseHandleListResource();
  1356. mmr = MMSYSERR_INVALHANDLE;
  1357. break;
  1358. }
  1359. if ((mmr == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiOut)))
  1360. {
  1361. mmr = MMSYSERR_NOERROR;
  1362. }
  1363. return mmr;
  1364. }
  1365. /*****************************************************************************
  1366. * @doc EXTERNAL MIDI
  1367. *
  1368. * @api MMRESULT | midiOutCachePatches | This function requests that an internal
  1369. * MIDI synthesizer device preload a specified set of patches. Some
  1370. * synthesizers are not capable of keeping all patches loaded simultaneously
  1371. * and must load data from disk when they receive MIDI program change
  1372. * messages. Caching patches ensures specified patches are immediately
  1373. * available.
  1374. *
  1375. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the opened MIDI output
  1376. * device. This device must be an internal MIDI synthesizer.
  1377. *
  1378. * @parm UINT | wBank | Specifies which bank of patches should be used.
  1379. * This parameter should be set to zero to cache the default patch bank.
  1380. *
  1381. * @parm LPWORD | lpPatchArray | Specifies a pointer to a <t PATCHARRAY>
  1382. * array indicating the patches to be cached or uncached.
  1383. *
  1384. * @parm UINT | wFlags | Specifies options for the cache operation. Only one
  1385. * of the following flags can be specified:
  1386. * @flag MIDI_CACHE_ALL | Cache all of the specified patches. If they
  1387. * can't all be cached, cache none, clear the <t PATCHARRAY> array,
  1388. * and return MMSYSERR_NOMEM.
  1389. * @flag MIDI_CACHE_BESTFIT | Cache all of the specified patches.
  1390. * If all patches can't be cached, cache as many patches as
  1391. * possible, change the <t PATCHARRAY> array to reflect which
  1392. * patches were cached, and return MMSYSERR_NOMEM.
  1393. * @flag MIDI_CACHE_QUERY | Change the <t PATCHARRAY> array to indicate
  1394. * which patches are currently cached.
  1395. * @flag MIDI_UNCACHE | Uncache the specified patches and clear the
  1396. * <t PATCHARRAY> array.
  1397. *
  1398. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1399. * one of the following error codes:
  1400. * @flag MMSYSERR_INVALHANDLE | The specified device handle is invalid.
  1401. * @flag MMSYSERR_NOTSUPPORTED | The specified device does not support
  1402. * patch caching.
  1403. * @flag MMSYSERR_NOMEM | The device does not have enough memory to cache
  1404. * all of the requested patches.
  1405. *
  1406. * @comm The <t PATCHARRAY> data type is defined as:
  1407. *
  1408. * typedef UINT PATCHARRAY[MIDIPATCHSIZE];
  1409. *
  1410. * Each element of the array represents one of the 128 patches and
  1411. * has bits set for
  1412. * each of the 16 MIDI channels that use that particular patch. The
  1413. * least-significant bit represents physical channel 0; the
  1414. * most-significant bit represents physical channel 15 (0x0F). For
  1415. * example, if patch 0 is used by physical channels 0 and 8, element 0
  1416. * would be set to 0x0101.
  1417. *
  1418. * This function only applies to internal MIDI synthesizer devices.
  1419. * Not all internal synthesizers support patch caching. Use the
  1420. * MIDICAPS_CACHE flag to test the <e MIDIOUTCAPS.dwSupport> field of the
  1421. * <t MIDIOUTCAPS> structure filled by <f midiOutGetDevCaps> to see if the
  1422. * device supports patch caching.
  1423. *
  1424. * @xref midiOutCacheDrumPatches
  1425. ****************************************************************************/
  1426. MMRESULT APIENTRY midiOutCachePatches(HMIDIOUT hMidiOut, UINT wBank,
  1427. LPWORD lpPatchArray, UINT wFlags)
  1428. {
  1429. V_WPOINTER(lpPatchArray, sizeof(PATCHARRAY), MMSYSERR_INVALPARAM);
  1430. V_FLAGS(wFlags, MIDI_CACHE_VALID, midiOutCacheDrumPatches, MMSYSERR_INVALFLAG);
  1431. ClientUpdatePnpInfo();
  1432. AcquireHandleListResourceShared();
  1433. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1434. {
  1435. ReleaseHandleListResource();
  1436. return MMSYSERR_INVALHANDLE;
  1437. }
  1438. switch(GetHandleType(hMidiOut))
  1439. {
  1440. case TYPE_MIDIOUT:
  1441. return (MMRESULT)midiMessage((HMIDI)hMidiOut,
  1442. MODM_CACHEPATCHES,
  1443. (DWORD_PTR)lpPatchArray,
  1444. MAKELONG(wFlags, wBank));
  1445. case TYPE_MIDISTRM:
  1446. ReleaseHandleListResource();
  1447. return (MMRESULT)midiStreamBroadcast((PMIDISTRM)hMidiOut,
  1448. MODM_CACHEPATCHES,
  1449. (DWORD_PTR)lpPatchArray,
  1450. MAKELONG(wFlags, wBank));
  1451. default:
  1452. ReleaseHandleListResource();
  1453. break;
  1454. }
  1455. return MMSYSERR_INVALHANDLE;
  1456. }
  1457. /*****************************************************************************
  1458. * @doc EXTERNAL MIDI
  1459. *
  1460. * @api MMRESULT | midiOutCacheDrumPatches | This function requests that an
  1461. * internal MIDI synthesizer device preload a specified set of key-based
  1462. * percussion patches. Some synthesizers are not capable of keeping all
  1463. * percussion patches loaded simultaneously. Caching patches ensures
  1464. * specified patches are available.
  1465. *
  1466. * @parm HMIDIOUT | hMidiOut | Specifies a handle to the opened MIDI output
  1467. * device. This device should be an internal MIDI synthesizer.
  1468. *
  1469. * @parm UINT | wPatch | Specifies which drum patch number should be used.
  1470. * This parameter should be set to zero to cache the default drum patch.
  1471. *
  1472. * @parm LPWORD | lpKeyArray | Specifies a pointer to a <t KEYARRAY>
  1473. * array indicating the key numbers of the specified percussion patches
  1474. * to be cached or uncached.
  1475. *
  1476. * @parm UINT | wFlags | Specifies options for the cache operation. Only one
  1477. * of the following flags can be specified:
  1478. * @flag MIDI_CACHE_ALL | Cache all of the specified patches. If they
  1479. * can't all be cached, cache none, clear the <t KEYARRAY> array,
  1480. * and return MMSYSERR_NOMEM.
  1481. * @flag MIDI_CACHE_BESTFIT | Cache all of the specified patches.
  1482. * If all patches can't be cached, cache as many patches as
  1483. * possible, change the <t KEYARRAY> array to reflect which
  1484. * patches were cached, and return MMSYSERR_NOMEM.
  1485. * @flag MIDI_CACHE_QUERY | Change the <t KEYARRAY> array to indicate
  1486. * which patches are currently cached.
  1487. * @flag MIDI_UNCACHE | Uncache the specified patches and clear the
  1488. * <t KEYARRAY> array.
  1489. *
  1490. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1491. * one of the following error codes:
  1492. * @flag MMSYSERR_INVALHANDLE | The specified device handle is invalid.
  1493. * @flag MMSYSERR_NOTSUPPORTED | The specified device does not support
  1494. * patch caching.
  1495. * @flag MMSYSERR_NOMEM | The device does not have enough memory to cache
  1496. * all of the requested patches.
  1497. *
  1498. * @comm The <t KEYARRAY> data type is defined as:
  1499. *
  1500. * typedef UINT KEYARRAY[MIDIPATCHSIZE];
  1501. *
  1502. * Each element of the array represents one of the 128 key-based percussion
  1503. * patches and has bits set for
  1504. * each of the 16 MIDI channels that use that particular patch. The
  1505. * least-significant bit represents physical channel 0; the
  1506. * most-significant bit represents physical channel 15. For
  1507. * example, if the patch on key number 60 is used by physical channels 9
  1508. * and 15, element 60 would be set to 0x8200.
  1509. *
  1510. * This function applies only to internal MIDI synthesizer devices.
  1511. * Not all internal synthesizers support patch caching. Use the
  1512. * MIDICAPS_CACHE flag to test the <e MIDIOUTCAPS.dwSupport> field of the
  1513. * <t MIDIOUTCAPS> structure filled by <f midiOutGetDevCaps> to see if the
  1514. * device supports patch caching.
  1515. *
  1516. * @xref midiOutCachePatches
  1517. ****************************************************************************/
  1518. MMRESULT APIENTRY midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT wPatch,
  1519. LPWORD lpKeyArray, UINT wFlags)
  1520. {
  1521. V_WPOINTER(lpKeyArray, sizeof(KEYARRAY), MMSYSERR_INVALPARAM);
  1522. V_FLAGS(wFlags, MIDI_CACHE_VALID, midiOutCacheDrumPatches, MMSYSERR_INVALFLAG);
  1523. ClientUpdatePnpInfo();
  1524. AcquireHandleListResourceShared();
  1525. if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
  1526. {
  1527. ReleaseHandleListResource();
  1528. return MMSYSERR_INVALHANDLE;
  1529. }
  1530. switch(GetHandleType(hMidiOut))
  1531. {
  1532. case TYPE_MIDIOUT:
  1533. return (MMRESULT)midiMessage((HMIDI)hMidiOut,
  1534. MODM_CACHEDRUMPATCHES,
  1535. (DWORD_PTR)lpKeyArray,
  1536. MAKELONG(wFlags, wPatch));
  1537. case TYPE_MIDISTRM:
  1538. ReleaseHandleListResource();
  1539. return (MMRESULT)midiStreamBroadcast((PMIDISTRM)hMidiOut,
  1540. MODM_CACHEDRUMPATCHES,
  1541. (DWORD_PTR)lpKeyArray,
  1542. MAKELONG(wFlags, wPatch));
  1543. default:
  1544. ReleaseHandleListResource();
  1545. break;
  1546. }
  1547. return MMSYSERR_INVALHANDLE;
  1548. }
  1549. //--------------------------------------------------------------------------;
  1550. //
  1551. // MMRESULT midiOutDesertHandle
  1552. //
  1553. // Description:
  1554. // Cleans up the midi out handle and marks it as deserted.
  1555. //
  1556. // Arguments:
  1557. // HMIDIOUT hMidiOut: MIDI out handle.
  1558. //
  1559. // Return (MMRESULT): Error code.
  1560. //
  1561. // History:
  1562. // 01/25/99 Fwong Adding Pnp Support.
  1563. //
  1564. //--------------------------------------------------------------------------;
  1565. MMRESULT midiOutDesertHandle
  1566. (
  1567. HMIDIOUT hMidiOut
  1568. )
  1569. {
  1570. MMRESULT mmr;
  1571. PMIDIDEV pDev = (PMIDIDEV)hMidiOut;
  1572. V_HANDLE_ACQ(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
  1573. ENTER_MM_HANDLE((HMIDI)hMidiOut);
  1574. ReleaseHandleListResource();
  1575. if (IsHandleDeserted(hMidiOut))
  1576. {
  1577. // Handle has already been deserted...
  1578. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1579. return(MMSYSERR_NOERROR);
  1580. }
  1581. if (IsHandleBusy(hMidiOut))
  1582. {
  1583. // Not quite invalid, but marked as closed.
  1584. LEAVE_MM_HANDLE(hMidiOut);
  1585. return (MMSYSERR_HANDLEBUSY);
  1586. }
  1587. // Marking handle as deserted
  1588. SetHandleFlag(hMidiOut, MMHANDLE_DESERTED);
  1589. // Since the handle was invalidated, we have to send the message ourselves...
  1590. (*(pDev->mididrv->drvMessage))(pDev->wDevice, MODM_RESET, pDev->dwDrvUser, 0L, 0L);
  1591. (*(pDev->mididrv->drvMessage))(pDev->wDevice, MODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  1592. LEAVE_MM_HANDLE((HMIDI)hMidiOut);
  1593. // ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
  1594. // dec on close instead.
  1595. mregDecUsage(PTtoH(HMD, pDev->mididrv));
  1596. // Mark handle as deserted, but not freeing.
  1597. return MMSYSERR_NOERROR;
  1598. } // midiOutDesertHandle()
  1599. /*****************************************************************************
  1600. * @doc EXTERNAL MIDI
  1601. *
  1602. * @api UINT | midiInGetNumDevs | This function retrieves the number of MIDI
  1603. * input devices in the system.
  1604. *
  1605. * @rdesc Returns the number of MIDI input devices present in the system.
  1606. *
  1607. * @xref midiInGetDevCaps
  1608. ****************************************************************************/
  1609. UINT APIENTRY midiInGetNumDevs(void)
  1610. {
  1611. UINT cDevs;
  1612. ClientUpdatePnpInfo();
  1613. EnterNumDevs("midiInGetNumDevs");
  1614. cDevs = wTotalMidiInDevs;
  1615. LeaveNumDevs("midiInGetNumDevs");
  1616. return cDevs;
  1617. }
  1618. /****************************************************************************
  1619. * @doc EXTERNAL MIDI
  1620. *
  1621. * @api MMRESULT | midiInMessage | This function sends messages to the MIDI device
  1622. * drivers.
  1623. *
  1624. * @parm HMIDIIN | hMidiIn | The handle to the MIDI device.
  1625. *
  1626. * @parm UINT | msg | The message to send.
  1627. *
  1628. * @parm DWORD | dw1 | Parameter 1.
  1629. *
  1630. * @parm DWORD | dw2 | Parameter 2.
  1631. *
  1632. * @rdesc Returns the value of the message sent.
  1633. ***************************************************************************/
  1634. MMRESULT APIENTRY midiInMessage(HMIDIIN hMidiIn, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
  1635. {
  1636. ClientUpdatePnpInfo();
  1637. AcquireHandleListResourceShared();
  1638. if (BAD_HANDLE(hMidiIn, TYPE_MIDIIN))
  1639. {
  1640. ReleaseHandleListResource();
  1641. return midiIDMessage(&midiindrvZ, wTotalMidiInDevs, (UINT_PTR)hMidiIn, msg, dw1, dw2);
  1642. }
  1643. return midiMessage((HMIDI)hMidiIn, msg, dw1, dw2);
  1644. }
  1645. /*****************************************************************************
  1646. * @doc EXTERNAL MIDI
  1647. *
  1648. * @api MMRESULT | midiInGetDevCaps | This function queries a specified MIDI input
  1649. * device to determine its capabilities.
  1650. *
  1651. * @parm UINT | uDeviceID | Identifies the MIDI input device.
  1652. *
  1653. * @parm LPMIDIINCAPS | lpCaps | Specifies a far pointer to a <t MIDIINCAPS>
  1654. * data structure. This structure is filled with information about
  1655. * the capabilities of the device.
  1656. *
  1657. * @parm UINT | wSize | Specifies the size of the <t MIDIINCAPS> structure.
  1658. *
  1659. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1660. * an error number. Possible error returns are:
  1661. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  1662. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  1663. *
  1664. * @comm Use <f midiInGetNumDevs> to determine the number of MIDI input
  1665. * devices present in the system. The device ID specified by <p uDeviceID>
  1666. * varies from zero to one less than the number of devices present.
  1667. * The MIDI_MAPPER constant may also be used as a device id. Only
  1668. * <p wSize> bytes (or less) of information is copied to the location
  1669. * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied,
  1670. * and the function returns zero.
  1671. *
  1672. * @xref midiInGetNumDevs
  1673. ****************************************************************************/
  1674. MMRESULT APIENTRY midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT wSize)
  1675. {
  1676. DWORD_PTR dwParam1, dwParam2;
  1677. MDEVICECAPSEX mdCaps;
  1678. PCWSTR DevInterface;
  1679. MMRESULT mmr;
  1680. if (wSize == 0)
  1681. return MMSYSERR_NOERROR;
  1682. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  1683. ClientUpdatePnpInfo();
  1684. DevInterface = midiReferenceDevInterfaceById(&midiindrvZ, uDeviceID);
  1685. dwParam2 = (DWORD_PTR)DevInterface;
  1686. if (0 == dwParam2)
  1687. {
  1688. dwParam1 = (DWORD_PTR)lpCaps;
  1689. dwParam2 = (DWORD)wSize;
  1690. }
  1691. else
  1692. {
  1693. mdCaps.cbSize = (DWORD)wSize;
  1694. mdCaps.pCaps = lpCaps;
  1695. dwParam1 = (DWORD_PTR)&mdCaps;
  1696. }
  1697. AcquireHandleListResourceShared();
  1698. if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIIN))
  1699. {
  1700. ReleaseHandleListResource();
  1701. mmr = midiIDMessage(&midiindrvZ, wTotalMidiInDevs, uDeviceID, MIDM_GETDEVCAPS, dwParam1, dwParam2);
  1702. }
  1703. else
  1704. {
  1705. mmr = (MMRESULT)midiMessage((HMIDI)uDeviceID, MIDM_GETDEVCAPS, dwParam1, dwParam2);
  1706. }
  1707. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  1708. return mmr;
  1709. }
  1710. MMRESULT APIENTRY midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT wSize)
  1711. {
  1712. MIDIINCAPS2W wDevCaps2;
  1713. MIDIINCAPS2A aDevCaps2;
  1714. DWORD_PTR dwParam1, dwParam2;
  1715. MDEVICECAPSEX mdCaps;
  1716. PCWSTR DevInterface;
  1717. MMRESULT mmRes;
  1718. CHAR chTmp[ MAXPNAMELEN * sizeof(WCHAR) ];
  1719. if (wSize == 0)
  1720. return MMSYSERR_NOERROR;
  1721. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  1722. ClientUpdatePnpInfo();
  1723. DevInterface = midiReferenceDevInterfaceById(&midiindrvZ, uDeviceID);
  1724. dwParam2 = (DWORD_PTR)DevInterface;
  1725. memset(&wDevCaps2, 0, sizeof(wDevCaps2));
  1726. if (0 == dwParam2)
  1727. {
  1728. dwParam1 = (DWORD_PTR)&wDevCaps2;
  1729. dwParam2 = (DWORD)sizeof(wDevCaps2);
  1730. }
  1731. else
  1732. {
  1733. mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
  1734. mdCaps.pCaps = &wDevCaps2;
  1735. dwParam1 = (DWORD_PTR)&mdCaps;
  1736. }
  1737. AcquireHandleListResourceShared();
  1738. if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIIN))
  1739. {
  1740. ReleaseHandleListResource();
  1741. mmRes = midiIDMessage( &midiindrvZ, wTotalMidiInDevs, uDeviceID,
  1742. MIDM_GETDEVCAPS, dwParam1, dwParam2);
  1743. }
  1744. else
  1745. {
  1746. mmRes = midiMessage((HMIDI)uDeviceID, MIDM_GETDEVCAPS,
  1747. (DWORD)dwParam1, (DWORD)dwParam2);
  1748. }
  1749. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  1750. //
  1751. // Make sure the call worked before proceeding with the thunk.
  1752. //
  1753. if ( mmRes != MMSYSERR_NOERROR ) {
  1754. return mmRes;
  1755. }
  1756. aDevCaps2.wMid = wDevCaps2.wMid;
  1757. aDevCaps2.wPid = wDevCaps2.wPid;
  1758. aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
  1759. aDevCaps2.dwSupport = wDevCaps2.dwSupport;
  1760. aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
  1761. aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
  1762. aDevCaps2.NameGuid = wDevCaps2.NameGuid;
  1763. // copy and convert unicode to ascii here.
  1764. UnicodeStrToAsciiStr( chTmp, chTmp + sizeof( chTmp ), wDevCaps2.szPname );
  1765. strcpy( aDevCaps2.szPname, chTmp );
  1766. //
  1767. // now copy the required amount into the callers buffer.
  1768. //
  1769. CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
  1770. return mmRes;
  1771. }
  1772. /*****************************************************************************
  1773. * @doc EXTERNAL MIDI
  1774. *
  1775. * @api MMRESULT | midiInGetErrorText | This function retrieves a textual
  1776. * description of the error identified by the specified error number.
  1777. *
  1778. * @parm UINT | wError | Specifies the error number.
  1779. *
  1780. * @parm LPTSTR | lpText | Specifies a far pointer to the buffer to be
  1781. * filled with the textual error description.
  1782. *
  1783. * @parm UINT | wSize | Specifies the length in characters of the buffer
  1784. * pointed to by <p lpText>.
  1785. *
  1786. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1787. * an error number. Possible error returns are:
  1788. * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
  1789. *
  1790. * @comm If the textual error description is longer than the specified buffer,
  1791. * the description is truncated. The returned error string is always
  1792. * null-terminated. If <p wSize> is zero, nothing is copied, and
  1793. * the function returns zero. All error descriptions are
  1794. * less than MAXERRORLENGTH characters long.
  1795. ****************************************************************************/
  1796. MMRESULT APIENTRY midiInGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
  1797. {
  1798. if(wSize == 0)
  1799. return MMSYSERR_NOERROR;
  1800. V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
  1801. return midiGetErrorTextW(wError, lpText, wSize);
  1802. }
  1803. MMRESULT APIENTRY midiInGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
  1804. {
  1805. if(wSize == 0)
  1806. return MMSYSERR_NOERROR;
  1807. V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
  1808. return midiGetErrorTextA(wError, lpText, wSize);
  1809. }
  1810. /*****************************************************************************
  1811. * @doc EXTERNAL MIDI
  1812. *
  1813. * @api MMRESULT | midiInOpen | This function opens a specified MIDI input device.
  1814. *
  1815. * @parm LPHMIDIIN | lphMidiIn | Specifies a far pointer to an HMIDIIN handle.
  1816. * This location is filled with a handle identifying the opened MIDI
  1817. * input device. Use the handle to identify the device when calling
  1818. * other MIDI input functions.
  1819. *
  1820. * @parm UINT | uDeviceID | Identifies the MIDI input device to be
  1821. * opened.
  1822. *
  1823. * @parm DWORD | dwCallback | Specifies the address of a fixed callback
  1824. * function or a handle to a window called with information
  1825. * about incoming MIDI messages.
  1826. *
  1827. * @parm DWORD | dwCallbackInstance | Specifies user instance data
  1828. * passed to the callback function. This parameter is not
  1829. * used with window callbacks.
  1830. *
  1831. * @parm DWORD | dwFlags | Specifies a callback flag for opening the device.
  1832. * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
  1833. * assumed to be a window handle.
  1834. * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
  1835. * assumed to be a callback procedure address.
  1836. *
  1837. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1838. * an error number. Possible error returns are:
  1839. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  1840. * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
  1841. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  1842. *
  1843. * @comm Use <f midiInGetNumDevs> to determine the number of MIDI input
  1844. * devices present in the system. The device ID specified by <p uDeviceID>
  1845. * varies from zero to one less than the number of devices present.
  1846. * The MIDI_MAPPER constant may also be used as a device id.
  1847. *
  1848. * If a window is chosen to receive callback information, the following
  1849. * messages are sent to the window procedure function to indicate the
  1850. * progress of MIDI input: <m MM_MIM_OPEN>, <m MM_MIM_CLOSE>,
  1851. * <m MM_MIM_DATA>, <m MM_MIM_LONGDATA>, <m MM_MIM_ERROR>,
  1852. * <m MM_MIM_LONGERROR>.
  1853. *
  1854. * If a function is chosen to receive callback information, the following
  1855. * messages are sent to the function to indicate the progress of MIDI
  1856. * input: <m MIM_OPEN>, <m MIM_CLOSE>, <m MIM_DATA>, <m MIM_LONGDATA>,
  1857. * <m MIM_ERROR>, <m MIM_LONGERROR>. The callback function must reside in
  1858. * a DLL. You do not have to use <f MakeProcInstance> to get a
  1859. * procedure-instance address for the callback function.
  1860. *
  1861. * @cb void CALLBACK | MidiInFunc | <f MidiInFunc> is a placeholder for
  1862. * the application-supplied function name. The actual name must be
  1863. * exported by including it in an EXPORTS statement in the DLL's module
  1864. * definition file.
  1865. *
  1866. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
  1867. *
  1868. * @parm UINT | wMsg | Specifies a MIDI input message.
  1869. *
  1870. * @parm DWORD | dwInstance | Specifies the instance data supplied
  1871. * with <f midiInOpen>.
  1872. *
  1873. * @parm DWORD | dwParam1 | Specifies a parameter for the message.
  1874. *
  1875. * @parm DWORD | dwParam2 | Specifies a parameter for the message.
  1876. *
  1877. * @comm Because the callback is accessed at interrupt time, it must reside
  1878. * in a DLL, and its code segment must be specified as FIXED in the
  1879. * module-definition file for the DLL. Any data that the callback accesses
  1880. * must be in a FIXED data segment as well. The callback may not make any
  1881. * system calls except for <f PostMessage>, <f timeGetSystemTime>,
  1882. * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
  1883. * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
  1884. *
  1885. * @xref midiInClose
  1886. ****************************************************************************/
  1887. MMRESULT APIENTRY midiInOpen(LPHMIDIIN lphMidiIn, UINT uDeviceID,
  1888. DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
  1889. {
  1890. MIDIOPENDESC mo;
  1891. PMIDIDEV pdev;
  1892. PMIDIDRV mididrv;
  1893. UINT port;
  1894. MMRESULT wRet;
  1895. V_WPOINTER(lphMidiIn, sizeof(HMIDIIN), MMSYSERR_INVALPARAM);
  1896. if (uDeviceID == MIDI_MAPPER) {
  1897. V_FLAGS(LOWORD(dwFlags), MIDI_I_VALID & ~LOWORD(MIDI_IO_COOKED | MIDI_IO_SHARED), midiInOpen, MMSYSERR_INVALFLAG);
  1898. } else {
  1899. V_FLAGS(LOWORD(dwFlags), MIDI_I_VALID & ~LOWORD(MIDI_IO_COOKED) , midiInOpen, MMSYSERR_INVALFLAG);
  1900. }
  1901. V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
  1902. *lphMidiIn = NULL;
  1903. ClientUpdatePnpInfo();
  1904. wRet = midiReferenceDriverById(&midiindrvZ, uDeviceID, &mididrv, &port);
  1905. if (wRet)
  1906. {
  1907. return wRet;
  1908. }
  1909. if (!mididrv->drvMessage)
  1910. {
  1911. mregDecUsagePtr(mididrv);
  1912. return MMSYSERR_NODRIVER;
  1913. }
  1914. pdev = (PMIDIDEV)NewHandle(TYPE_MIDIIN, mididrv->cookie, sizeof(MIDIDEV));
  1915. if( pdev == NULL)
  1916. {
  1917. mregDecUsagePtr(mididrv);
  1918. return MMSYSERR_NOMEM;
  1919. }
  1920. ENTER_MM_HANDLE(pdev);
  1921. SetHandleFlag(pdev, MMHANDLE_BUSY);
  1922. ReleaseHandleListResource();
  1923. pdev->mididrv = mididrv;
  1924. pdev->wDevice = port;
  1925. pdev->uDeviceID = uDeviceID;
  1926. pdev->fdwHandle = 0;
  1927. mo.hMidi = (HMIDI)pdev;
  1928. mo.dwCallback = dwCallback;
  1929. mo.dwInstance = dwInstance;
  1930. mo.dnDevNode = (DWORD_PTR)pdev->mididrv->cookie;
  1931. wRet = (MMRESULT)((*(mididrv->drvMessage))
  1932. (pdev->wDevice, MIDM_OPEN, (DWORD_PTR)&pdev->dwDrvUser, (DWORD_PTR)(LPMIDIOPENDESC)&mo, dwFlags));
  1933. if (!wRet)
  1934. ClearHandleFlag(pdev, MMHANDLE_BUSY);
  1935. LEAVE_MM_HANDLE(pdev);
  1936. if (wRet)
  1937. FreeHandle((HMIDIIN)pdev);
  1938. else {
  1939. mregIncUsagePtr(mididrv);
  1940. *lphMidiIn = (HMIDIIN)pdev;
  1941. }
  1942. mregDecUsagePtr(mididrv);
  1943. return wRet;
  1944. }
  1945. /*****************************************************************************
  1946. * @doc EXTERNAL MIDI
  1947. *
  1948. * @api MMRESULT | midiInClose | This function closes the specified MIDI input
  1949. * device.
  1950. *
  1951. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
  1952. * If the function is successful, the handle is no longer
  1953. * valid after this call.
  1954. *
  1955. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1956. * an error number. Possible error returns are:
  1957. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1958. * @flag MIDIERR_STILLPLAYING | There are still buffers in the queue.
  1959. *
  1960. * @comm If there are input buffers that have been sent with
  1961. * <f midiInAddBuffer> and haven't been returned to the application,
  1962. * the close operation will fail. Call <f midiInReset> to mark all
  1963. * pending buffers as being done.
  1964. *
  1965. * @xref midiInOpen midiInReset
  1966. ****************************************************************************/
  1967. MMRESULT APIENTRY midiInClose(HMIDIIN hMidiIn)
  1968. {
  1969. MMRESULT wRet;
  1970. PMIDIDRV pmididrv;
  1971. PMIDIDEV pDev = (PMIDIDEV)hMidiIn;
  1972. ClientUpdatePnpInfo();
  1973. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  1974. ENTER_MM_HANDLE((HMIDI)hMidiIn);
  1975. ReleaseHandleListResource();
  1976. if (IsHandleDeserted(hMidiIn))
  1977. {
  1978. // This handle has been deserted. Let's just free it.
  1979. LEAVE_MM_HANDLE((HMIDI)hMidiIn);
  1980. FreeHandle(hMidiIn);
  1981. return MMSYSERR_NOERROR;
  1982. }
  1983. if (IsHandleBusy(hMidiIn))
  1984. {
  1985. // Not quite invalid, but marked as closed.
  1986. LEAVE_MM_HANDLE(hMidiIn);
  1987. return (MMSYSERR_HANDLEBUSY);
  1988. }
  1989. // Marking handle as 'invalid/closed'.
  1990. SetHandleFlag(hMidiIn, MMHANDLE_BUSY);
  1991. pmididrv = pDev->mididrv;
  1992. wRet = (MMRESULT)(*(pmididrv->drvMessage))(pDev->wDevice, MIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  1993. if (MMSYSERR_NOERROR != wRet)
  1994. {
  1995. ClearHandleFlag(hMidiIn, MMHANDLE_BUSY);
  1996. }
  1997. LEAVE_MM_HANDLE((HWAVE)hMidiIn);
  1998. if (!wRet)
  1999. {
  2000. FreeHandle(hMidiIn);
  2001. mregDecUsagePtr(pmididrv);
  2002. return wRet;
  2003. }
  2004. return wRet;
  2005. }
  2006. /*****************************************************************************
  2007. * @doc EXTERNAL MIDI
  2008. *
  2009. * @api MMRESULT | midiInPrepareHeader | This function prepares a buffer for
  2010. * MIDI input.
  2011. *
  2012. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input
  2013. * device.
  2014. *
  2015. * @parm LPMIDIHDR | lpMidiInHdr | Specifies a pointer to a <t MIDIHDR>
  2016. * structure that identifies the buffer to be prepared.
  2017. *
  2018. * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
  2019. *
  2020. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2021. * an error number. Possible error returns are:
  2022. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2023. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  2024. *
  2025. * @comm The <t MIDIHDR> data structure and the data block pointed to by its
  2026. * <e MIDIHDR.lpData> field must be allocated with <f GlobalAlloc> using the
  2027. * GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
  2028. * Preparing a header that has already been prepared has no effect,
  2029. * and the function returns zero.
  2030. *
  2031. * @xref midiInUnprepareHeader
  2032. ****************************************************************************/
  2033. MMRESULT APIENTRY midiInPrepareHeader(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr, UINT wSize)
  2034. {
  2035. MMRESULT wRet;
  2036. V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
  2037. if (lpMidiInHdr->dwFlags & MHDR_PREPARED)
  2038. return MMSYSERR_NOERROR;
  2039. lpMidiInHdr->dwFlags = 0;
  2040. ClientUpdatePnpInfo();
  2041. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2042. wRet = midiMessage((HMIDI)hMidiIn, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, (DWORD)wSize);
  2043. if (wRet == MMSYSERR_NOTSUPPORTED)
  2044. return midiPrepareHeader(lpMidiInHdr, wSize);
  2045. return wRet;
  2046. }
  2047. /*****************************************************************************
  2048. * @doc EXTERNAL MIDI
  2049. *
  2050. * @api MMRESULT | midiInUnprepareHeader | This function cleans up the
  2051. * preparation performed by <f midiInPrepareHeader>. The
  2052. * <f midiInUnprepareHeader> function must be called
  2053. * after the device driver fills a data buffer and returns it to the
  2054. * application. You must call this function before freeing the data
  2055. * buffer.
  2056. *
  2057. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input
  2058. * device.
  2059. *
  2060. * @parm LPMIDIHDR | lpMidiInHdr | Specifies a pointer to a <t MIDIHDR>
  2061. * structure identifying the data buffer to be cleaned up.
  2062. *
  2063. * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
  2064. *
  2065. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2066. * an error number. Possible error returns are:
  2067. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2068. * @flag MIDIERR_STILLPLAYING | <p lpMidiInHdr> is still in the queue.
  2069. *
  2070. * @comm This function is the complementary function to <f midiInPrepareHeader>.
  2071. * You must call this function before freeing the data buffer with
  2072. * <f GlobalFree>.
  2073. * After passing a buffer to the device driver with <f midiInAddBuffer>, you
  2074. * must wait until the driver is finished with the buffer before calling
  2075. * <f midiInUnprepareHeader>. Unpreparing a buffer that has not been
  2076. * prepared has no effect, and the function returns zero.
  2077. *
  2078. * @xref midiInPrepareHeader
  2079. ****************************************************************************/
  2080. MMRESULT APIENTRY midiInUnprepareHeader(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr, UINT wSize)
  2081. {
  2082. MMRESULT wRet;
  2083. V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
  2084. if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED))
  2085. return MMSYSERR_NOERROR;
  2086. if(lpMidiInHdr->dwFlags & MHDR_INQUEUE)
  2087. {
  2088. DebugErr(DBF_WARNING, "midiInUnprepareHeader: header still in queue\r\n");
  2089. return MIDIERR_STILLPLAYING;
  2090. }
  2091. ClientUpdatePnpInfo();
  2092. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2093. wRet = midiMessage((HMIDI)hMidiIn, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, (DWORD)wSize);
  2094. if (wRet == MMSYSERR_NOTSUPPORTED)
  2095. return midiUnprepareHeader(lpMidiInHdr, wSize);
  2096. if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiIn)))
  2097. {
  2098. // if the driver for the handle has been removed, succeed the call.
  2099. wRet = MMSYSERR_NOERROR;
  2100. }
  2101. return wRet;
  2102. }
  2103. /******************************************************************************
  2104. * @doc EXTERNAL MIDI
  2105. *
  2106. * @api MMRESULT | midiInAddBuffer | This function sends an input buffer
  2107. * to a specified opened MIDI input device. When the buffer is filled,
  2108. * it is sent back to the application. Input buffers are
  2109. * used only for system-exclusive messages.
  2110. *
  2111. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
  2112. *
  2113. * @parm LPMIDIHDR | lpMidiInHdr | Specifies a far pointer to a <t MIDIHDR>
  2114. * structure that identifies the buffer.
  2115. *
  2116. * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
  2117. *
  2118. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2119. * an error number. Possible error returns are:
  2120. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2121. * @flag MIDIERR_UNPREPARED | <p lpMidiInHdr> hasn't been prepared.
  2122. *
  2123. * @comm The data buffer must be prepared with <f midiInPrepareHeader> before
  2124. * it is passed to <f midiInAddBuffer>. The <t MIDIHDR> data structure
  2125. * and the data buffer pointed to by its <e MIDIHDR.lpData> field must be allocated
  2126. * with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
  2127. * locked with <f GlobalLock>.
  2128. *
  2129. * @xref midiInPrepareHeader
  2130. *****************************************************************************/
  2131. MMRESULT APIENTRY midiInAddBuffer(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr, UINT wSize)
  2132. {
  2133. V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
  2134. if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED))
  2135. {
  2136. DebugErr(DBF_WARNING, "midiInAddBuffer: buffer not prepared\r\n");
  2137. return MIDIERR_UNPREPARED;
  2138. }
  2139. if (lpMidiInHdr->dwFlags & MHDR_INQUEUE)
  2140. {
  2141. DebugErr(DBF_WARNING, "midiInAddBuffer: buffer already in queue\r\n");
  2142. return MIDIERR_STILLPLAYING;
  2143. }
  2144. ClientUpdatePnpInfo();
  2145. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2146. return midiMessage((HMIDI)hMidiIn, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, (DWORD)wSize);
  2147. }
  2148. /*****************************************************************************
  2149. * @doc EXTERNAL MIDI
  2150. *
  2151. * @api MMRESULT | midiInStart | This function starts MIDI input on the
  2152. * specified MIDI input device.
  2153. *
  2154. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
  2155. *
  2156. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2157. * an error number. Possible error returns are:
  2158. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2159. *
  2160. * @comm This function resets the timestamps to zero; timestamp values for
  2161. * subsequently received messages are relative to the time this
  2162. * function was called.
  2163. *
  2164. * All messages other than system-exclusive messages are sent
  2165. * directly to the client when received. System-exclusive
  2166. * messages are placed in the buffers supplied by <f midiInAddBuffer>;
  2167. * if there are no buffers in the queue,
  2168. * the data is thrown away without notification to the client, and input
  2169. * continues.
  2170. *
  2171. * Buffers are returned to the client when full, when a
  2172. * complete system-exclusive message has been received,
  2173. * or when <f midiInReset> is
  2174. * called. The <e MIDIHDR.dwBytesRecorded> field in the header will contain the
  2175. * actual length of data received.
  2176. *
  2177. * Calling this function when input is already started has no effect, and
  2178. * the function returns zero.
  2179. *
  2180. * @xref midiInStop midiInReset
  2181. ****************************************************************************/
  2182. MMRESULT APIENTRY midiInStart(HMIDIIN hMidiIn)
  2183. {
  2184. ClientUpdatePnpInfo();
  2185. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2186. return midiMessage((HMIDI)hMidiIn, MIDM_START, 0L, 0L);
  2187. }
  2188. /*****************************************************************************
  2189. * @doc EXTERNAL MIDI
  2190. *
  2191. * @api MMRESULT | midiInStop | This function terminates MIDI input on the
  2192. * specified MIDI input device.
  2193. *
  2194. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
  2195. *
  2196. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2197. * an error number. Possible error returns are:
  2198. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2199. *
  2200. * @comm Current status (running status, parsing state, etc.) is maintained
  2201. * across calls to <f midiInStop> and <f midiInStart>.
  2202. * If there are any system-exclusive message buffers in the queue,
  2203. * the current buffer
  2204. * is marked as done (the <e MIDIHDR.dwBytesRecorded> field in the header will
  2205. * contain the actual length of data), but any empty buffers in the queue
  2206. * remain there. Calling this function when input is not started has no
  2207. * no effect, and the function returns zero.
  2208. *
  2209. * @xref midiInStart midiInReset
  2210. ****************************************************************************/
  2211. MMRESULT APIENTRY midiInStop(HMIDIIN hMidiIn)
  2212. {
  2213. ClientUpdatePnpInfo();
  2214. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2215. return midiMessage((HMIDI)hMidiIn, MIDM_STOP, 0L, 0L);
  2216. }
  2217. /*****************************************************************************
  2218. * @doc EXTERNAL MIDI
  2219. *
  2220. * @api MMRESULT | midiInReset | This function stops input on a given MIDI
  2221. * input device and marks all pending input buffers as done.
  2222. *
  2223. * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
  2224. *
  2225. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2226. * an error number. Possible error returns are:
  2227. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2228. *
  2229. * @xref midiInStart midiInStop midiInAddBuffer midiInClose
  2230. ****************************************************************************/
  2231. MMRESULT APIENTRY midiInReset(HMIDIIN hMidiIn)
  2232. {
  2233. MMRESULT mmr;
  2234. ClientUpdatePnpInfo();
  2235. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2236. mmr = midiMessage((HMIDI)hMidiIn, MIDM_RESET, 0L, 0L);
  2237. if ((mmr == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiIn)))
  2238. {
  2239. mmr = MMSYSERR_NOERROR;
  2240. }
  2241. return mmr;
  2242. }
  2243. //--------------------------------------------------------------------------;
  2244. //
  2245. // MMRESULT midiInDesertHandle
  2246. //
  2247. // Description:
  2248. // Cleans up the midi in handle and marks it as deserted.
  2249. //
  2250. // Arguments:
  2251. // HMIDIIN hMidiIn: MIDI in handle.
  2252. //
  2253. // Return (MMRESULT): Error code.
  2254. //
  2255. // History:
  2256. // 01/25/99 Fwong Adding Pnp Support.
  2257. //
  2258. //--------------------------------------------------------------------------;
  2259. MMRESULT midiInDesertHandle
  2260. (
  2261. HMIDIIN hMidiIn
  2262. )
  2263. {
  2264. MMRESULT mmr;
  2265. PMIDIDEV pDev = (PMIDIDEV)hMidiIn;
  2266. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2267. ENTER_MM_HANDLE((HMIDI)hMidiIn);
  2268. ReleaseHandleListResource();
  2269. if (IsHandleDeserted(hMidiIn))
  2270. {
  2271. LEAVE_MM_HANDLE((HMIDI)hMidiIn);
  2272. return (MMSYSERR_NOERROR);
  2273. }
  2274. if (IsHandleBusy(hMidiIn))
  2275. {
  2276. // Not quite invalid, but marked as closed.
  2277. LEAVE_MM_HANDLE(hMidiIn);
  2278. return (MMSYSERR_HANDLEBUSY);
  2279. }
  2280. // Marking handle as deserted
  2281. SetHandleFlag(hMidiIn, MMHANDLE_DESERTED);
  2282. // Since the handle was invalidated, we have to send the message ourselves...
  2283. (*(pDev->mididrv->drvMessage))(pDev->wDevice, MIDM_RESET, pDev->dwDrvUser, 0L, 0L);
  2284. (*(pDev->mididrv->drvMessage))(pDev->wDevice, MIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  2285. LEAVE_MM_HANDLE((HWAVE)hMidiIn);
  2286. // ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
  2287. // dec on close instead.
  2288. mregDecUsage(PTtoH(HMD, pDev->mididrv));
  2289. return MMSYSERR_NOERROR;
  2290. } // midiInDesertHandle()
  2291. /*****************************************************************************
  2292. * @doc EXTERNAL MIDI
  2293. *
  2294. * @api MMRESULT | midiInGetID | This function gets the device ID for a
  2295. * MIDI input device.
  2296. *
  2297. * @parm HMIDIIN | hMidiIn | Specifies the handle to the MIDI input
  2298. * device.
  2299. * @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized
  2300. * memory location to be filled with the device ID.
  2301. *
  2302. * @rdesc Returns zero if successful. Otherwise, returns
  2303. * an error number. Possible error returns are:
  2304. *
  2305. * @flag MMSYSERR_INVALHANDLE | The <p hMidiIn> parameter specifies an
  2306. * invalid handle.
  2307. *
  2308. ****************************************************************************/
  2309. MMRESULT APIENTRY midiInGetID(HMIDIIN hMidiIn, PUINT lpuDeviceID)
  2310. {
  2311. V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
  2312. V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
  2313. *lpuDeviceID = ((PMIDIDEV)hMidiIn)->uDeviceID;
  2314. ReleaseHandleListResource();
  2315. return MMSYSERR_NOERROR;
  2316. }
  2317. /*****************************************************************************
  2318. * @doc EXTERNAL MIDI
  2319. *
  2320. * @api MMRESULT | midiOutGetID | This function gets the device ID for a
  2321. * MIDI output device.
  2322. *
  2323. * @parm HMIDIOUT | hMidiOut | Specifies the handle to the MIDI output
  2324. * device.
  2325. * @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized
  2326. * memory location to be filled with the device ID.
  2327. *
  2328. * @rdesc Returns MMSYSERR_NOERROR if successful. Otherwise, returns
  2329. * an error number. Possible error returns are:
  2330. *
  2331. * @flag MMSYSERR_INVALHANDLE | The <p hMidiOut> parameter specifies an
  2332. * invalid handle.
  2333. *
  2334. ****************************************************************************/
  2335. MMRESULT APIENTRY midiOutGetID(HMIDIOUT hMidiOut, PUINT lpuDeviceID)
  2336. {
  2337. V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
  2338. V_HANDLE_ACQ(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
  2339. *lpuDeviceID = ((PMIDIDEV)hMidiOut)->uDeviceID;
  2340. ReleaseHandleListResource();
  2341. return MMSYSERR_NOERROR;
  2342. }