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

2904 lines
103 KiB

  1. /****************************************************************************
  2. wave.c
  3. Level 1 kitchen sink DLL wave support module
  4. Copyright (c) 1990-2001 Microsoft Corporation
  5. Changes for NT :
  6. Change parameters for MapWaveId to return the driver index rather
  7. than a pointer
  8. change list of include files
  9. widen function parameters and return codes
  10. Change WINAPI to APIENTRY
  11. ****************************************************************************/
  12. #include "winmmi.h"
  13. /****************************************************************************
  14. local structures
  15. ****************************************************************************/
  16. typedef struct wavedev_tag {
  17. PWAVEDRV wavedrv;
  18. UINT wDevice;
  19. DWORD_PTR dwDrvUser;
  20. UINT uDeviceID;
  21. DWORD fdwHandle;
  22. } WAVEDEV, *PWAVEDEV;
  23. extern UINT gRealWaveOutPreferredId;
  24. extern UINT gRealWaveInPreferredId;
  25. extern BOOL WaveMapperInitialized; // Wave mapper safely loaded
  26. /*****************************************************************************
  27. * @doc INTERNAL WAVE validation code for WAVEHDRs
  28. *
  29. ****************************************************************************/
  30. #define IsWaveHeaderPrepared(hWave, lpwh) ((lpwh)->dwFlags & WHDR_PREPARED)
  31. #define MarkWaveHeaderPrepared(hWave, lpwh) ((lpwh)->dwFlags |= WHDR_PREPARED)
  32. #define MarkWaveHeaderUnprepared(hWave, lpwh) ((lpwh)->dwFlags &=~WHDR_PREPARED)
  33. /*****************************************************************************
  34. * @doc INTERNAL WAVE
  35. *
  36. * @api MMRESULT | wavePrepareHeader | This function prepares the header and data
  37. * if the driver returns MMSYSERR_NOTSUPPORTED.
  38. *
  39. * @rdesc Returns zero if the function was successful. Otherwise, it
  40. * specifies an error number.
  41. ****************************************************************************/
  42. STATIC MMRESULT wavePrepareHeader(LPWAVEHDR lpWaveHdr, UINT wSize)
  43. {
  44. if (!HugePageLock(lpWaveHdr, (DWORD)sizeof(WAVEHDR)))
  45. return MMSYSERR_NOMEM;
  46. if (!HugePageLock(lpWaveHdr->lpData, lpWaveHdr->dwBufferLength)) {
  47. HugePageUnlock(lpWaveHdr, (DWORD)sizeof(WAVEHDR));
  48. return MMSYSERR_NOMEM;
  49. }
  50. lpWaveHdr->dwFlags |= WHDR_PREPARED;
  51. return MMSYSERR_NOERROR;
  52. }
  53. /*****************************************************************************
  54. * @doc INTERNAL WAVE
  55. *
  56. * @api MMRESULT | waveUnprepareHeader | This function unprepares the header and
  57. * data if the driver returns MMSYSERR_NOTSUPPORTED.
  58. *
  59. * @rdesc Currently always returns MMSYSERR_NOERROR.
  60. ****************************************************************************/
  61. STATIC MMRESULT waveUnprepareHeader(LPWAVEHDR lpWaveHdr, UINT wSize)
  62. {
  63. HugePageUnlock(lpWaveHdr->lpData, lpWaveHdr->dwBufferLength);
  64. HugePageUnlock(lpWaveHdr, (DWORD)sizeof(WAVEHDR));
  65. lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
  66. return MMSYSERR_NOERROR;
  67. }
  68. /****************************************************************************
  69. * @doc INTERNAL WAVE
  70. *
  71. * @api MMRESULT | waveReferenceDriverById | This function maps a logical id
  72. * to a device driver and physical id.
  73. *
  74. * @parm IN PWAVEDRV | pwavedrvZ | The list of wave drivers.
  75. *
  76. * @parm IN UINT | id | The logical id to be mapped.
  77. *
  78. * @parm OUT PWAVEDRV* OPTIONAL | ppwavedrv | Pointer to WAVEDRV structure
  79. * describing the driver supporting the id.
  80. *
  81. * @parm OUT UINT* OPTIONAL | pport | The driver-relative device number. If
  82. * the caller supplies this buffer then it must also supply ppwavedrv.
  83. *
  84. * @rdesc The return value is zero if successful, MMSYSERR_BADDEVICEID if
  85. * the id is out of range.
  86. *
  87. * @comm If the caller specifies ppwavedrv then this function increments
  88. * the wavedrv's usage before returning. The caller must ensure
  89. * the usage is eventually decremented.
  90. *
  91. ****************************************************************************/
  92. MMRESULT waveReferenceDriverById(
  93. IN PWAVEDRV pwavedrvZ,
  94. IN UINT id,
  95. OUT PWAVEDRV *ppwavedrv OPTIONAL,
  96. OUT UINT *pport OPTIONAL
  97. )
  98. {
  99. PWAVEDRV pwavedrv;
  100. MMRESULT mmr;
  101. // Should not be called asking for port but not wavedrv
  102. WinAssert(!(pport && !ppwavedrv));
  103. if (id == WAVE_MAPPER) {
  104. /*
  105. ** Make sure we've tried to load it
  106. */
  107. WaveMapperInit();
  108. // WinAssert(((WaveMapperInitialized) || (0 == wTotalWaveInDevs + wTotalWaveOutDevs)));
  109. }
  110. EnterNumDevs("waveReferenceDriverById");
  111. if (WAVE_MAPPER == id)
  112. {
  113. id = 0;
  114. for (pwavedrv = pwavedrvZ->Next; pwavedrv != pwavedrvZ; pwavedrv = pwavedrv->Next)
  115. {
  116. if (pwavedrv->fdwDriver & MMDRV_MAPPER) break;
  117. }
  118. } else {
  119. for (pwavedrv = pwavedrvZ->Next; pwavedrv != pwavedrvZ; pwavedrv = pwavedrv->Next)
  120. {
  121. if (pwavedrv->fdwDriver & MMDRV_MAPPER) continue;
  122. if (pwavedrv->NumDevs > id) break;
  123. id -= pwavedrv->NumDevs;
  124. }
  125. }
  126. if (pwavedrv != pwavedrvZ)
  127. {
  128. if (ppwavedrv) {
  129. mregIncUsagePtr(pwavedrv);
  130. *ppwavedrv = pwavedrv;
  131. if (pport) *pport = id;
  132. }
  133. mmr = MMSYSERR_NOERROR;
  134. } else {
  135. mmr = MMSYSERR_BADDEVICEID;
  136. }
  137. LeaveNumDevs("waveReferenceDriverById");
  138. return mmr;
  139. }
  140. PCWSTR waveReferenceDevInterfaceById(PWAVEDRV pdrvZ, UINT_PTR id)
  141. {
  142. PWAVEDRV pdrv;
  143. PCWSTR DevInterface;
  144. if ((pdrvZ == &waveoutdrvZ && ValidateHandle((HANDLE)id, TYPE_WAVEOUT)) ||
  145. (pdrvZ == &waveindrvZ && ValidateHandle((HANDLE)id, TYPE_WAVEIN)))
  146. {
  147. DevInterface = ((PWAVEDEV)id)->wavedrv->cookie;
  148. if (DevInterface) wdmDevInterfaceInc(DevInterface);
  149. return DevInterface;
  150. }
  151. if (!waveReferenceDriverById(pdrvZ, (UINT)id, &pdrv, NULL))
  152. {
  153. DevInterface = pdrv->cookie;
  154. if (DevInterface) wdmDevInterfaceInc(DevInterface);
  155. mregDecUsagePtr(pdrv);
  156. return DevInterface;
  157. }
  158. return NULL;
  159. }
  160. /*****************************************************************************
  161. * @doc INTERNAL WAVE
  162. *
  163. * @func MMRESULT | waveMessage | This function sends messages to the waveform
  164. * output device drivers.
  165. *
  166. * @parm HWAVE | hWave | The handle to the audio device.
  167. *
  168. * @parm UINT | wMsg | The message to send.
  169. *
  170. * @parm DWORD | dwP1 | Parameter 1.
  171. *
  172. * @parm DWORD | dwP2 | Parameter 2.
  173. *
  174. * @rdesc Returns the value returned from the driver.
  175. ****************************************************************************/
  176. STATIC MMRESULT waveMessage(HWAVE hWave, UINT msg, DWORD_PTR dwP1, DWORD_PTR dwP2)
  177. {
  178. MMRESULT mrc;
  179. ENTER_MM_HANDLE(hWave); // Serialize on handle
  180. ReleaseHandleListResource();
  181. // Is handle deserted?
  182. if (IsHandleDeserted(hWave))
  183. {
  184. LEAVE_MM_HANDLE(hWave);
  185. return (MMSYSERR_NODRIVER);
  186. }
  187. // Are we busy (in the middle of an open/close)?
  188. if (IsHandleBusy(hWave))
  189. {
  190. LEAVE_MM_HANDLE(hWave);
  191. return (MMSYSERR_HANDLEBUSY);
  192. }
  193. // ISSUE: We should no longer have to check for invalid handle... every
  194. // function that calls this check with with a read lock on the handle
  195. // resource.
  196. if (BAD_HANDLE(hWave, TYPE_WAVEOUT) && BAD_HANDLE(hWave, TYPE_WAVEIN)) {
  197. WinAssert(!"Bad Handle within waveMessage");
  198. mrc = MMSYSERR_INVALHANDLE;
  199. } else {
  200. mrc = (MMRESULT)(*(((PWAVEDEV)hWave)->wavedrv->drvMessage))
  201. (((PWAVEDEV)hWave)->wDevice, msg, ((PWAVEDEV)hWave)->dwDrvUser, dwP1, dwP2);
  202. }
  203. LEAVE_MM_HANDLE(hWave);
  204. return mrc;
  205. }
  206. /****************************************************************************
  207. * @doc INTERNAL WAVE
  208. *
  209. * @func MMRESULT | waveIDMessage | This function sends a message to the device
  210. * ID specified. It also performs error checking on the ID passed.
  211. *
  212. * @parm PWAVEDRV | wavedrv | Pointer to the input or output device list.
  213. *
  214. * @parm UINT | wTotalNumDevs | Total number of devices in device list.
  215. *
  216. * @parm UINT | uDeviceID | Device ID to send message to.
  217. *
  218. * @parm UINT | wMessage | The message to send.
  219. *
  220. * @parm DWORD | dwParam1 | Parameter 1.
  221. *
  222. * @parm DWORD | dwParam2 | Parameter 2.
  223. *
  224. * @rdesc The return value is the low word of the returned message.
  225. ***************************************************************************/
  226. // ISSUE-2001/01/09-FrankYe This should take UINT_PTR uDeviceID if we expect
  227. // it to accept handles. If we change it, then review all calls to this
  228. // function.
  229. STATIC MMRESULT waveIDMessage(
  230. PWAVEDRV pwavedrvZ,
  231. UINT wTotalNumDevs,
  232. UINT_PTR uDeviceID,
  233. UINT wMessage,
  234. DWORD_PTR dwParam1,
  235. DWORD_PTR dwParam2)
  236. {
  237. DWORD mmr;
  238. DWORD dwClass;
  239. UINT port;
  240. PWAVEDRV wavedrv;
  241. if (uDeviceID>=wTotalNumDevs && uDeviceID!=WAVE_MAPPER) {
  242. // this cannot be a device ID.
  243. // it could be a wave handle. Try it.
  244. // First we have to verify which type of handle it is (OUT or IN)
  245. // We can work this out as waveIDMessage is only ever called with
  246. // pwavedrvZ == &waveoutdrvZ or &waveindrvZ
  247. if ((pwavedrvZ == &waveoutdrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_WAVEOUT))
  248. || (pwavedrvZ == &waveindrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_WAVEIN) ))
  249. {
  250. if (0 != (((PWAVEDEV)uDeviceID)->wavedrv->fdwDriver & MMDRV_DESERTED))
  251. {
  252. // The driver has been deserted, all calls should return
  253. // MMSYSERR_NODRIVER.
  254. return MMSYSERR_NODRIVER;
  255. }
  256. dprintf2(("waveIDMessage passed ID==%x, translating to handle", uDeviceID));
  257. // to preserve as much compatibility with previous code paths
  258. // we do NOT call waveMessage as that calls ENTER_MM_HANDLE
  259. return (MMRESULT)(*(((PWAVEDEV)uDeviceID)->wavedrv->drvMessage))
  260. (((PWAVEDEV)uDeviceID)->wDevice,
  261. wMessage,
  262. ((PWAVEDEV)uDeviceID)->dwDrvUser, dwParam1, dwParam2);
  263. } else {
  264. return(MMSYSERR_BADDEVICEID);
  265. }
  266. }
  267. mmr = waveReferenceDriverById(pwavedrvZ, (UINT)uDeviceID, &wavedrv, &port);
  268. if (mmr)
  269. {
  270. return mmr;
  271. }
  272. if (pwavedrvZ == &waveindrvZ)
  273. dwClass = TYPE_WAVEIN;
  274. else if (pwavedrvZ == &waveoutdrvZ)
  275. dwClass = TYPE_WAVEOUT;
  276. else
  277. dwClass = TYPE_UNKNOWN;
  278. if (!wavedrv->drvMessage)
  279. {
  280. mmr = MMSYSERR_NODRIVER;
  281. }
  282. else if (!mregHandleInternalMessages(wavedrv, dwClass, port, wMessage, dwParam1, dwParam2, &mmr))
  283. {
  284. mmr = (MMRESULT)((*(wavedrv->drvMessage))(port, wMessage, 0L, dwParam1, dwParam2));
  285. }
  286. mregDecUsagePtr(wavedrv);
  287. return mmr;
  288. }
  289. //////////////////////////////////////////////////////////////////////////
  290. //////////////////////////////////////////////////////////////////////////
  291. /*****************************************************************************
  292. * @doc EXTERNAL WAVE
  293. *
  294. * @api UINT | waveOutGetNumDevs | This function retrieves the number of
  295. * waveform output devices present in the system.
  296. *
  297. * @rdesc Returns the number of waveform output devices present in the system.
  298. *
  299. * @xref waveOutGetDevCaps
  300. ****************************************************************************/
  301. UINT APIENTRY waveOutGetNumDevs(void)
  302. {
  303. UINT cDevs;
  304. ClientUpdatePnpInfo();
  305. if (WinmmRunningInServer)
  306. {
  307. if (0 == wTotalWaveOutDevs)
  308. {
  309. Squirt("Returning 1 for CSRSS process.");
  310. return 1;
  311. }
  312. return wTotalWaveOutDevs;
  313. }
  314. EnterNumDevs("waveOutGetNumDevs");
  315. cDevs = wTotalWaveOutDevs;
  316. LeaveNumDevs("waveOutGetNumDevs");
  317. dprintf3(("waveOutGetNumDevs returning %d devices", wTotalWaveOutDevs));
  318. return cDevs;
  319. }
  320. /*****************************************************************************
  321. * @doc EXTERNAL WAVE
  322. *
  323. * @api MMRESULT | waveOutMessage | This function sends messages to the waveform
  324. * output device drivers.
  325. *
  326. * @parm HWAVEOUT | hWaveOut | The handle to the audio device.
  327. *
  328. * @parm UINT | msg | The message to send.
  329. *
  330. * @parm DWORD | dw1 | Parameter 1.
  331. *
  332. * @parm DWORD | dw2 | Parameter 2.
  333. *
  334. * @rdesc Returns the value returned from the driver.
  335. ****************************************************************************/
  336. MMRESULT APIENTRY waveOutMessage(HWAVEOUT hWaveOut, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
  337. {
  338. ClientUpdatePnpInfo();
  339. AcquireHandleListResourceShared();
  340. if (BAD_HANDLE((HWAVE)hWaveOut, TYPE_WAVEOUT))
  341. {
  342. ReleaseHandleListResource();
  343. return waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, (UINT)(UINT_PTR)hWaveOut, msg, dw1, dw2);
  344. }
  345. else
  346. {
  347. return waveMessage((HWAVE)hWaveOut, msg, dw1, dw2);
  348. }
  349. }
  350. /*****************************************************************************
  351. * @doc EXTERNAL WAVE
  352. *
  353. * @api MMRESULT | waveOutGetDevCaps | This function queries a specified waveform
  354. * device to determine its capabilities.
  355. *
  356. * @parm UINT | uDeviceID | Identifies the waveform output device.
  357. *
  358. * @parm LPWAVEOUTCAPS | lpCaps | Specifies a far pointer to a <t WAVEOUTCAPS>
  359. * structure. This structure is filled with information about the
  360. * capabilities of the device.
  361. *
  362. * @parm UINT | wSize | Specifies the size of the <t WAVEOUTCAPS> structure.
  363. *
  364. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  365. * an error number. Possible error returns are:
  366. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  367. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  368. *
  369. * @comm Use <f waveOutGetNumDevs> to determine the number of waveform output
  370. * devices present in the system. The device ID specified by <p uDeviceID>
  371. * varies from zero to one less than the number of devices present.
  372. * The WAVE_MAPPER constant may also be used as a device id. Only
  373. * <p wSize> bytes (or less) of information is copied to the location
  374. * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied, and
  375. * the function returns zero.
  376. *
  377. * @xref waveOutGetNumDevs
  378. ****************************************************************************/
  379. MMRESULT APIENTRY waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, UINT wSize)
  380. {
  381. DWORD_PTR dwParam1, dwParam2;
  382. MDEVICECAPSEX mdCaps;
  383. PWAVEDRV waveoutdrv;
  384. PCWSTR DevInterface;
  385. MMRESULT mmr;
  386. if (wSize == 0)
  387. return MMSYSERR_NOERROR;
  388. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  389. // Because some 32-bit applications use the value 0x0000FFFF for
  390. // WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
  391. // This just happened to work on Win9x because WinMM would thunk down
  392. // to MMSystem and send down the lower word to the 16-bit interface.
  393. if (uDeviceID == LOWORD(WAVE_MAPPER)) {
  394. uDeviceID = WAVE_MAPPER;
  395. }
  396. ClientUpdatePnpInfo();
  397. DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, uDeviceID);
  398. dwParam2 = (DWORD_PTR)DevInterface;
  399. if (0 == dwParam2)
  400. {
  401. dwParam1 = (DWORD_PTR)lpCaps;
  402. dwParam2 = (DWORD)wSize;
  403. }
  404. else
  405. {
  406. mdCaps.cbSize = (DWORD)wSize;
  407. mdCaps.pCaps = lpCaps;
  408. dwParam1 = (DWORD_PTR)&mdCaps;
  409. }
  410. //
  411. // Don't allow non proper drivers in TS environement
  412. //
  413. // ISSUE-2001/01/09-FrankYe Instead of cast to UINT. Should check whether
  414. // this is a handle and get wavedrv from handle if it is.
  415. waveoutdrv = NULL;
  416. if ((!waveReferenceDriverById(&waveoutdrvZ, (UINT)uDeviceID, &waveoutdrv, NULL)) &&
  417. lstrcmpW(waveoutdrv->wszSessProtocol, SessionProtocolName))
  418. {
  419. mmr = MMSYSERR_NODRIVER;
  420. }
  421. else
  422. {
  423. AcquireHandleListResourceShared();
  424. if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEOUT))
  425. {
  426. int cRecursion;
  427. ReleaseHandleListResource();
  428. // Unless it's the mapper, increment the recursion depth counter. Then,
  429. // check whether this thread is now recursing through waveOutGetDevCaps. If it
  430. // is, then disable preferred device reordering.
  431. cRecursion = PtrToInt(TlsGetValue(gTlsIndex));
  432. if ((uDeviceID != WAVE_MAPPER) && (waveoutdrv) && (waveoutdrv->fdwDriver & MMDRV_PREXP)) TlsSetValue(gTlsIndex, IntToPtr(cRecursion + 1));
  433. if (cRecursion) gfDisablePreferredDeviceReordering = TRUE;
  434. mmr = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, (UINT)uDeviceID, WODM_GETDEVCAPS, dwParam1, dwParam2);
  435. // Restore recursion counter
  436. TlsSetValue(gTlsIndex, IntToPtr(cRecursion));
  437. }
  438. else
  439. {
  440. mmr = (MMRESULT)waveMessage((HWAVE)uDeviceID, WODM_GETDEVCAPS, dwParam1, dwParam2);
  441. }
  442. }
  443. if (waveoutdrv) mregDecUsagePtr(waveoutdrv);
  444. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  445. return mmr;
  446. }
  447. MMRESULT APIENTRY waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, UINT wSize)
  448. {
  449. WAVEOUTCAPS2W wDevCaps2;
  450. WAVEOUTCAPS2A aDevCaps2;
  451. DWORD_PTR dwParam1, dwParam2;
  452. MDEVICECAPSEX mdCaps;
  453. MMRESULT mmRes;
  454. PWAVEDRV waveoutdrv;
  455. PCWSTR DevInterface;
  456. if (wSize == 0)
  457. return MMSYSERR_NOERROR;
  458. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  459. // Because some 32-bit applications use the value 0x0000FFFF for
  460. // WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
  461. // This just happened to work on Win9x because WinMM would thunk down
  462. // to MMSystem and send down the lower word to the 16-bit interface.
  463. if (uDeviceID == LOWORD(WAVE_MAPPER)) {
  464. uDeviceID = WAVE_MAPPER;
  465. }
  466. ClientUpdatePnpInfo();
  467. DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, uDeviceID);
  468. dwParam2 = (DWORD_PTR)DevInterface;
  469. memset(&wDevCaps2, 0, sizeof(wDevCaps2));
  470. if (0 == dwParam2)
  471. {
  472. dwParam1 = (DWORD_PTR)&wDevCaps2;
  473. dwParam2 = (DWORD)sizeof(wDevCaps2);
  474. }
  475. else
  476. {
  477. mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
  478. mdCaps.pCaps = &wDevCaps2;
  479. dwParam1 = (DWORD_PTR)&mdCaps;
  480. }
  481. //
  482. // Don't allow non proper drivers in TS environement
  483. //
  484. // ISSUE-2001/01/09-FrankYe Bad cast to UINT. Should check whether this
  485. // is a handle and get wavedrv from handle if it is.
  486. waveoutdrv = NULL;
  487. if ( uDeviceID < wTotalWaveOutDevs &&
  488. !waveReferenceDriverById(&waveoutdrvZ, (UINT)uDeviceID, &waveoutdrv, NULL) &&
  489. lstrcmpW(waveoutdrv->wszSessProtocol, SessionProtocolName) )
  490. {
  491. mregDecUsagePtr(waveoutdrv);
  492. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  493. return MMSYSERR_NODRIVER;
  494. }
  495. AcquireHandleListResourceShared();
  496. if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEOUT))
  497. {
  498. ReleaseHandleListResource();
  499. mmRes = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, (UINT)uDeviceID,
  500. WODM_GETDEVCAPS, dwParam1, dwParam2);
  501. }
  502. else
  503. {
  504. mmRes = waveMessage((HWAVE)uDeviceID,
  505. WODM_GETDEVCAPS,
  506. dwParam1,
  507. dwParam2);
  508. }
  509. if (waveoutdrv) mregDecUsagePtr(waveoutdrv);
  510. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  511. //
  512. // Make sure the call worked before proceeding with the thunk.
  513. //
  514. if ( mmRes != MMSYSERR_NOERROR ) {
  515. return mmRes;
  516. }
  517. aDevCaps2.wMid = wDevCaps2.wMid;
  518. aDevCaps2.wPid = wDevCaps2.wPid;
  519. aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
  520. aDevCaps2.dwFormats = wDevCaps2.dwFormats;
  521. aDevCaps2.wChannels = wDevCaps2.wChannels;
  522. aDevCaps2.dwSupport = wDevCaps2.dwSupport;
  523. aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
  524. aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
  525. aDevCaps2.NameGuid = wDevCaps2.NameGuid;
  526. // copy and convert lpwText to lpText here.
  527. Iwcstombs(aDevCaps2.szPname, wDevCaps2.szPname, MAXPNAMELEN);
  528. //
  529. // now copy the required amount into the callers buffer.
  530. //
  531. CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
  532. return mmRes;
  533. }
  534. /*****************************************************************************
  535. * @doc EXTERNAL WAVE
  536. *
  537. * @api MMRESULT | waveOutGetVolume | This function queries the current volume
  538. * setting of a waveform output device.
  539. *
  540. * @parm UINT | uDeviceID | Identifies the waveform output device.
  541. *
  542. * @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location to
  543. * be filled with the current volume setting. The low-order word of
  544. * this location contains the left channel volume setting, and the high-order
  545. * word contains the right channel setting. A value of 0xFFFF represents
  546. * full volume, and a value of 0x0000 is silence.
  547. *
  548. * If a device does not support both left and right volume
  549. * control, the low-order word of the specified location contains
  550. * the mono volume level.
  551. *
  552. * The full 16-bit setting(s)
  553. * set with <f waveOutSetVolume> is returned, regardless of whether
  554. * the device supports the full 16 bits of volume-level control.
  555. *
  556. *
  557. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  558. * an error number. Possible error returns are:
  559. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  560. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  561. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  562. *
  563. * @comm Not all devices support volume changes. To determine whether the
  564. * device supports volume control, use the WAVECAPS_VOLUME
  565. * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
  566. * structure (filled by <f waveOutGetDevCaps>).
  567. *
  568. * To determine whether the device supports volume control on both
  569. * the left and right channels, use the WAVECAPS_VOLUME
  570. * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
  571. * structure (filled by <f waveOutGetDevCaps>).
  572. *
  573. * @xref waveOutSetVolume
  574. ****************************************************************************/
  575. MMRESULT APIENTRY waveOutGetVolume(HWAVEOUT hwo, LPDWORD lpdwVolume)
  576. {
  577. PCWSTR DevInterface;
  578. MMRESULT mmr;
  579. V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
  580. // Because some 32-bit applications use the value 0x0000FFFF for
  581. // WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
  582. // This just happened to work on Win9x because WinMM would thunk down
  583. // to MMSystem and send down the lower word to the 16-bit interface.
  584. if ((UINT_PTR)hwo == LOWORD(WAVE_MAPPER)) {
  585. (UINT_PTR)hwo = WAVE_MAPPER;
  586. }
  587. ClientUpdatePnpInfo();
  588. DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, (UINT_PTR)hwo);
  589. AcquireHandleListResourceShared();
  590. if (BAD_HANDLE(hwo, TYPE_WAVEOUT))
  591. {
  592. ReleaseHandleListResource();
  593. mmr = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, PtrToUint(hwo), WODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
  594. }
  595. else
  596. {
  597. mmr = (MMRESULT)waveMessage((HWAVE)hwo, WODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
  598. }
  599. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  600. return mmr;
  601. }
  602. /*****************************************************************************
  603. * @doc EXTERNAL WAVE
  604. *
  605. * @api MMRESULT | waveOutSetVolume | This function sets the volume of a
  606. * waveform output device.
  607. *
  608. * @parm UINT | uDeviceID | Identifies the waveform output device.
  609. *
  610. * @parm DWORD | dwVolume | Specifies the new volume setting. The
  611. * low-order word contains the left channel volume setting, and the
  612. * high-order word contains the right channel setting. A value of
  613. * 0xFFFF represents full volume, and a value of 0x0000 is silence.
  614. *
  615. * If a device does
  616. * not support both left and right volume control, the low-order word of
  617. * <p dwVolume> specifies the volume level, and the high-order word is
  618. * ignored.
  619. *
  620. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  621. * an error number. Possible error returns are:
  622. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  623. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  624. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  625. *
  626. * @comm Not all devices support volume changes. To determine whether the
  627. * device supports volume control, use the WAVECAPS_VOLUME
  628. * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
  629. * structure (filled by <f waveOutGetDevCaps>).
  630. *
  631. * To determine whether the device supports volume control on both the
  632. * left and right channels, use the WAVECAPS_LRVOLUME flag
  633. * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
  634. * structure (filled by <f waveOutGetDevCaps>).
  635. *
  636. * Most devices don't support the full 16 bits of volume level control
  637. * and will not use the high-order bits of the requested volume setting.
  638. * For example, for a device that supports 4 bits of volume control,
  639. * requested volume level values of 0x4000, 0x4fff, and 0x43be
  640. * all produce the same physical volume setting, 0x4000. The
  641. * <f waveOutGetVolume> function returns the full 16-bit setting set
  642. * with <f waveOutSetVolume>.
  643. *
  644. * Volume settings are interpreted logarithmically. This means the
  645. * perceived increase in volume is the same when increasing the
  646. * volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
  647. *
  648. * @xref waveOutGetVolume
  649. ****************************************************************************/
  650. MMRESULT APIENTRY waveOutSetVolume(HWAVEOUT hwo, DWORD dwVolume)
  651. {
  652. PCWSTR DevInterface;
  653. MMRESULT mmr;
  654. ClientUpdatePnpInfo();
  655. // Because some 32-bit applications use the value 0x0000FFFF for
  656. // WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
  657. // This just happened to work on Win9x because WinMM would thunk down
  658. // to MMSystem and send down the lower word to the 16-bit interface.
  659. if ((UINT_PTR)hwo == LOWORD(WAVE_MAPPER)) {
  660. (UINT_PTR)hwo = WAVE_MAPPER;
  661. }
  662. DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, (UINT_PTR)hwo);
  663. AcquireHandleListResourceShared();
  664. if (BAD_HANDLE(hwo, TYPE_WAVEOUT))
  665. {
  666. ReleaseHandleListResource();
  667. mmr = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, PtrToUint(hwo), WODM_SETVOLUME, dwVolume, (DWORD_PTR)DevInterface);
  668. }
  669. else
  670. {
  671. mmr = (MMRESULT)waveMessage((HWAVE)hwo, WODM_SETVOLUME, dwVolume, (DWORD_PTR)DevInterface);
  672. }
  673. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  674. return mmr;
  675. }
  676. /*****************************************************************************
  677. * @doc INTERNAL WAVE
  678. *
  679. * @func UINT | waveGetErrorText | This function retrieves a textual
  680. * description of the error identified by the specified error number.
  681. *
  682. * @parm UINT | wError | Specifies the error number.
  683. *
  684. * @parm LPTSTR | lpText | Specifies a far pointer to a buffer which
  685. * is filled with the textual error description.
  686. *
  687. * @parm UINT | wSize | Specifies the length in characters of the buffer
  688. * pointed to by <p lpText>.
  689. *
  690. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  691. * an error number. Possible error returns are:
  692. * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
  693. *
  694. * @comm If the textual error description is longer than the specified buffer,
  695. * the description is truncated. The returned error string is always
  696. * null-terminated. If <p wSize> is zero, nothing is copied and MMSYSERR_NOERROR
  697. * is returned. All error descriptions are less than 80 characters long.
  698. ****************************************************************************/
  699. STATIC MMRESULT waveGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
  700. {
  701. lpText[0] = 0;
  702. #if MMSYSERR_BASE
  703. if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
  704. #else
  705. if ((wError > MMSYSERR_LASTERROR) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
  706. #endif
  707. return MMSYSERR_BADERRNUM;
  708. if (wSize > 1)
  709. {
  710. if (!LoadStringW(ghInst, wError, lpText, wSize))
  711. return MMSYSERR_BADERRNUM;
  712. }
  713. return MMSYSERR_NOERROR;
  714. }
  715. STATIC MMRESULT waveGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
  716. {
  717. lpText[0] = 0;
  718. #if MMSYSERR_BASE
  719. if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
  720. #else
  721. if ((wError > MMSYSERR_LASTERROR) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
  722. #endif
  723. return MMSYSERR_BADERRNUM;
  724. if (wSize > 1)
  725. {
  726. if (!LoadStringA(ghInst, wError, lpText, wSize))
  727. return MMSYSERR_BADERRNUM;
  728. }
  729. return MMSYSERR_NOERROR;
  730. }
  731. /*****************************************************************************
  732. * @doc EXTERNAL WAVE
  733. *
  734. * @api MMRESULT | waveOutGetErrorText | This function retrieves a
  735. * textual description of the error identified by the specified
  736. * error number.
  737. *
  738. * @parm UINT | wError | Specifies the error number.
  739. *
  740. * @parm LPTSTR | lpText | Specifies a far pointer to a buffer to be
  741. * filled with the textual error description.
  742. *
  743. * @parm UINT | wSize | Specifies the length in characters of the buffer
  744. * pointed to by <p lpText>.
  745. *
  746. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  747. * an error number. Possible error returns are:
  748. * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
  749. *
  750. * @comm If the textual error description is longer than the specified buffer,
  751. * the description is truncated. The returned error string is always
  752. * null-terminated. If <p wSize> is zero, nothing is copied, and the function
  753. * returns zero. All error descriptions are less than MAXERRORLENGTH characters long.
  754. ****************************************************************************/
  755. MMRESULT APIENTRY waveOutGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
  756. {
  757. if (wSize == 0)
  758. return MMSYSERR_NOERROR;
  759. V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
  760. return waveGetErrorTextW(wError, lpText, wSize);
  761. }
  762. MMRESULT APIENTRY waveOutGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
  763. {
  764. if (wSize == 0)
  765. return MMSYSERR_NOERROR;
  766. V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
  767. return waveGetErrorTextA(wError, lpText, wSize );
  768. }
  769. /****************************************************************************
  770. * @doc EXTERNAL WAVE
  771. *
  772. * @api MMRESULT | waveOutOpen | This function opens a specified waveform output
  773. * device for playback.
  774. *
  775. * @parm LPHWAVEOUT | lphWaveOut | Specifies a far pointer to an HWAVEOUT
  776. * handle. This location is filled with a handle identifying the opened
  777. * waveform output device. Use the handle to identify the device when
  778. * calling other waveform output functions. This parameter may be
  779. * NULL if the WAVE_FORMAT_QUERY flag is specified for <p dwFlags>.
  780. *
  781. * @parm UINT | uDeviceID | Identifies the waveform output device to open.
  782. * Use a valid device ID or the following flag:
  783. *
  784. * @flag WAVE_MAPPER | If this flag is specified, the function
  785. * selects a waveform output device
  786. * capable of playing the given format.
  787. *
  788. * @parm LPWAVEFORMATEX | lpFormat | Specifies a pointer to a <t WAVEFORMATEX>
  789. * structure that identifies the format of the waveform data
  790. * to be sent to the waveform output device.
  791. *
  792. * @parm DWORD | dwCallback | Specifies the address of a callback
  793. * function or a handle to a window called during waveform
  794. * playback to process messages related to the progress of the playback.
  795. * Specify NULL for this parameter if no callback is desired.
  796. *
  797. * @parm DWORD | dwCallbackInstance | Specifies user instance data
  798. * passed to the callback. This parameter is not used with
  799. * window callbacks.
  800. *
  801. * @parm DWORD | dwFlags | Specifies flags for opening the device.
  802. * @flag WAVE_FORMAT_QUERY | If this flag is specified, the device is
  803. * queried to determine if it supports the given format but is not
  804. * actually opened.
  805. * @flag WAVE_ALLOWSYNC | If this flag is not specified, then the
  806. * device will fail to open if it is a synchronous device.
  807. * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
  808. * assumed to be a window handle.
  809. * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
  810. * assumed to be a callback procedure address.
  811. *
  812. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  813. * an error number. Possible error returns are:
  814. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  815. * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
  816. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  817. * @flag WAVERR_BADFORMAT | Attempted to open with an unsupported wave format.
  818. *
  819. * @comm Use <f waveOutGetNumDevs> to determine the number of waveform output
  820. * devices present in the system. The device ID specified by <p uDeviceID>
  821. * varies from zero to one less than the number of devices present.
  822. * The WAVE_MAPPER constant may also be used as a device id.
  823. *
  824. * The <t WAVEFORMAT> structure pointed to by <p lpFormat> may be extended
  825. * to include type-specific information for certain data formats.
  826. * For example, for PCM data, an extra WORD is added to specify the number
  827. * of bits per sample. Use the <t PCMWAVEFORMAT> structure in this case.
  828. *
  829. * If a window is chosen to receive callback information, the following
  830. * messages are sent to the window procedure function to indicate the
  831. * progress of waveform output: <m MM_WOM_OPEN>, <m MM_WOM_CLOSE>,
  832. * <m MM_WOM_DONE>
  833. *
  834. * If a function is chosen to receive callback information, the following
  835. * messages are sent to the function to indicate the progress of waveform
  836. * output: <m WOM_OPEN>, <m WOM_CLOSE>, <m WOM_DONE>. The callback function
  837. * must reside in a DLL. You do not have to use <f MakeProcInstance> to get
  838. * a procedure-instance address for the callback function.
  839. *
  840. * @cb void CALLBACK | WaveOutFunc | <f WaveOutFunc> is a placeholder for the
  841. * application-supplied function name. The actual name must be exported by
  842. * including it in an EXPORTS statement in the DLL's module-definition file.
  843. *
  844. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform device
  845. * associated with the callback.
  846. *
  847. * @parm UINT | wMsg | Specifies a waveform output message.
  848. *
  849. * @parm DWORD | dwInstance | Specifies the user instance data
  850. * specified with <f waveOutOpen>.
  851. *
  852. * @parm DWORD | dwParam1 | Specifies a parameter for the message.
  853. *
  854. * @parm DWORD | dwParam2 | Specifies a parameter for the message.
  855. *
  856. * @comm Because the callback is accessed at interrupt time, it must reside
  857. * in a DLL and its code segment must be specified as FIXED in the
  858. * module-definition file for the DLL. Any data that the callback accesses
  859. * must be in a FIXED data segment as well. The callback may not make any
  860. * system calls except for <f PostMessage>, <f timeGetSystemTime>,
  861. * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
  862. * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
  863. *
  864. * @xref waveOutClose
  865. ****************************************************************************/
  866. MMRESULT APIENTRY waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
  867. LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
  868. DWORD_PTR dwInstance, DWORD dwFlags)
  869. {
  870. WAVEOPENDESC wo;
  871. PWAVEDEV pdev;
  872. PWAVEDRV wavedrv;
  873. UINT port;
  874. MMRESULT wRet;
  875. DWORD_PTR dwDrvUser;
  876. int cRecursion;
  877. V_RPOINTER(lpFormat, sizeof(WAVEFORMAT), MMSYSERR_INVALPARAM);
  878. V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
  879. // Because some 32-bit applications use the value 0x0000FFFF for
  880. // WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
  881. // This just happened to work on Win9x because WinMM would thunk down
  882. // to MMSystem and send down the lower word to the 16-bit interface.
  883. if (uDeviceID == LOWORD(WAVE_MAPPER)) {
  884. uDeviceID = WAVE_MAPPER;
  885. }
  886. if (uDeviceID == WAVE_MAPPER) {
  887. V_FLAGS(LOWORD(dwFlags), WAVE_VALID & ~(WAVE_MAPPED), waveOutOpen, MMSYSERR_INVALFLAG);
  888. } else {
  889. V_FLAGS(LOWORD(dwFlags), WAVE_VALID, waveOutOpen, MMSYSERR_INVALFLAG);
  890. }
  891. if ((lpFormat->wFormatTag != WAVE_FORMAT_PCM)) {
  892. V_RPOINTER(lpFormat, sizeof(WAVEFORMATEX), MMSYSERR_INVALPARAM);
  893. if ((lpFormat->cbSize)) {
  894. V_RPOINTER(lpFormat + 1, lpFormat->cbSize, MMSYSERR_INVALPARAM);
  895. }
  896. }
  897. if ((dwFlags & WAVE_FORMAT_QUERY)) {
  898. lphWaveOut = NULL;
  899. } else
  900. {
  901. V_WPOINTER(lphWaveOut, sizeof(HWAVEOUT), MMSYSERR_INVALPARAM);
  902. // WAVE_FORMAT_DIRECT was bounced on Win95. Now we
  903. // accept this flag.
  904. //
  905. // if (dwFlags & WAVE_FORMAT_DIRECT)
  906. // return MMSYSERR_INVALFLAG;
  907. *lphWaveOut = NULL;
  908. }
  909. ClientUpdatePnpInfo();
  910. if ((!wTotalWaveOutDevs) || waveReferenceDriverById(&waveoutdrvZ, (dwFlags & WAVE_MAPPED) ? WAVE_MAPPER : uDeviceID, &wavedrv, &port))
  911. {
  912. return MMSYSERR_BADDEVICEID;
  913. }
  914. //
  915. // check if the device is appropriate for the current TS session
  916. //
  917. if (!(wavedrv->fdwDriver & MMDRV_MAPPER) &&
  918. lstrcmpW(wavedrv->wszSessProtocol, SessionProtocolName))
  919. {
  920. mregDecUsagePtr(wavedrv);
  921. return MMSYSERR_NODRIVER;
  922. }
  923. /* Default wave mapper :
  924. *
  925. * If a wave mapper is installed as a separate DLL then all wave mapper
  926. * messages are routed to it. If no wave mapper is installed, simply
  927. * loop through the wave devices looking for a match.
  928. */
  929. // ISSUE-2001/01/06-FrankYe This logic looks broken for the WAVE_MAPPER case
  930. if ((uDeviceID == WAVE_MAPPER) && !wavedrv->drvMessage) {
  931. MMRESULT wErr;
  932. mregDecUsagePtr(wavedrv);
  933. wErr = MMSYSERR_ALLOCATED;
  934. if (dwFlags & WAVE_MAPPED)
  935. {
  936. if (wErr = waveReferenceDriverById(&waveoutdrvZ, uDeviceID, &wavedrv, &port))
  937. return wErr;
  938. if (mregHandleInternalMessages(wavedrv,
  939. MMDRVI_WAVEOUT,
  940. port,
  941. DRV_QUERYMAPPABLE,
  942. 0, 0, &wErr) ||
  943. (MMSYSERR_NOERROR != wErr))
  944. {
  945. mregDecUsagePtr(wavedrv);
  946. return wErr;
  947. }
  948. wErr = waveOutOpen(lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags & ~WAVE_MAPPED);
  949. mregDecUsagePtr(wavedrv);
  950. }
  951. else
  952. {
  953. for (uDeviceID=0; uDeviceID<wTotalWaveOutDevs; uDeviceID++) {
  954. wErr = waveOutOpen(lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
  955. if (!wErr)
  956. break;
  957. }
  958. }
  959. return wErr;
  960. }
  961. if (dwFlags & WAVE_FORMAT_QUERY)
  962. pdev = NULL;
  963. else {
  964. if (!(pdev = (PWAVEDEV)NewHandle(TYPE_WAVEOUT, wavedrv->cookie, sizeof(WAVEDEV))))
  965. {
  966. mregDecUsagePtr(wavedrv);
  967. return MMSYSERR_NOMEM;
  968. }
  969. ENTER_MM_HANDLE(pdev);
  970. SetHandleFlag(pdev, MMHANDLE_BUSY);
  971. ReleaseHandleListResource();
  972. pdev->wavedrv = wavedrv;
  973. pdev->wDevice = port;
  974. pdev->uDeviceID = uDeviceID;
  975. pdev->fdwHandle = 0;
  976. }
  977. wo.hWave = (HWAVE)pdev;
  978. wo.dwCallback = dwCallback;
  979. wo.dwInstance = dwInstance;
  980. wo.uMappedDeviceID = uDeviceID;
  981. wo.lpFormat = (LPWAVEFORMAT)lpFormat; // cast away the CONST to eliminate wng
  982. wo.dnDevNode = (DWORD_PTR)wavedrv->cookie;
  983. // Unless it's the mapper, increment the recursion depth counter. Then,
  984. // check whether this thread is now recursing through waveOutOpen. If it
  985. // is, then disable preferred device reordering.
  986. cRecursion = PtrToInt(TlsGetValue(gTlsIndex));
  987. if (uDeviceID != WAVE_MAPPER) TlsSetValue(gTlsIndex, IntToPtr(cRecursion + 1));
  988. if ((uDeviceID != WAVE_MAPPER) && (wavedrv->fdwDriver & MMDRV_PREXP)) TlsSetValue(gTlsIndex, IntToPtr(cRecursion + 1));
  989. if (cRecursion) gfDisablePreferredDeviceReordering = TRUE;
  990. wRet = ((*(wavedrv->drvMessage))
  991. (port, WODM_OPEN, (DWORD_PTR)&dwDrvUser, (DWORD_PTR)(LPWAVEOPENDESC)&wo, dwFlags));
  992. // Restore recursion counter
  993. TlsSetValue(gTlsIndex, IntToPtr(cRecursion));
  994. if (pdev) {
  995. // Mark as not busy on successful open...
  996. if (!wRet)
  997. ClearHandleFlag(pdev, MMHANDLE_BUSY);
  998. LEAVE_MM_HANDLE(pdev);
  999. if (wRet)
  1000. FreeHandle((HWAVEOUT)pdev);
  1001. else {
  1002. // Inc usage since we opened a handle on it
  1003. mregIncUsagePtr(wavedrv);
  1004. *lphWaveOut = (HWAVEOUT)pdev;
  1005. pdev->dwDrvUser = dwDrvUser;
  1006. }
  1007. }
  1008. mregDecUsagePtr(wavedrv);
  1009. return wRet;
  1010. }
  1011. /*****************************************************************************
  1012. * @doc EXTERNAL WAVE
  1013. *
  1014. * @api MMRESULT | waveOutClose | This function closes the specified waveform
  1015. * output device.
  1016. *
  1017. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1018. * device. If the function is successful, the handle is no
  1019. * longer valid after this call.
  1020. *
  1021. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1022. * an error number. Possible error returns are:
  1023. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1024. * @flag WAVERR_STILLPLAYING | There are still buffers in the queue.
  1025. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1026. * thread.
  1027. *
  1028. * @comm If the device is still playing a waveform, the close
  1029. * operation will fail. Use <f waveOutReset> to terminate waveform
  1030. * playback before calling <f waveOutClose>.
  1031. *
  1032. * @xref waveOutOpen waveOutReset
  1033. ****************************************************************************/
  1034. MMRESULT APIENTRY waveOutClose(HWAVEOUT hWaveOut)
  1035. {
  1036. MMRESULT wRet;
  1037. PWAVEDRV pwavedrv;
  1038. PWAVEDEV pDev = (PWAVEDEV)hWaveOut;
  1039. ClientUpdatePnpInfo();
  1040. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1041. ENTER_MM_HANDLE((HWAVE)hWaveOut);
  1042. ReleaseHandleListResource();
  1043. if (IsHandleDeserted(hWaveOut))
  1044. {
  1045. // This handle has been deserted. Let's just free it.
  1046. LEAVE_MM_HANDLE((HWAVE)hWaveOut);
  1047. FreeHandle(hWaveOut);
  1048. return MMSYSERR_NOERROR;
  1049. }
  1050. if (IsHandleBusy(hWaveOut))
  1051. {
  1052. // Not quite invalid, but marked as closed.
  1053. LEAVE_MM_HANDLE(hWaveOut);
  1054. return (MMSYSERR_HANDLEBUSY);
  1055. }
  1056. // Marking handle as 'invalid/closed'.
  1057. SetHandleFlag(hWaveOut, MMHANDLE_BUSY);
  1058. pwavedrv = pDev->wavedrv;
  1059. wRet = (MMRESULT)(*(pwavedrv->drvMessage))(pDev->wDevice, WODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  1060. if (MMSYSERR_NOERROR != wRet)
  1061. {
  1062. // Error closing, set the flag as valid.
  1063. ClearHandleFlag(hWaveOut, MMHANDLE_BUSY);
  1064. }
  1065. LEAVE_MM_HANDLE((HWAVE)hWaveOut);
  1066. if (!wRet)
  1067. {
  1068. FreeHandle(hWaveOut);
  1069. mregDecUsagePtr(pwavedrv);
  1070. return wRet;
  1071. }
  1072. return wRet;
  1073. }
  1074. /*****************************************************************************
  1075. * @doc EXTERNAL WAVE
  1076. *
  1077. * @api MMRESULT | waveOutPrepareHeader | This function prepares a
  1078. * waveform data block for playback.
  1079. *
  1080. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1081. * device.
  1082. *
  1083. * @parm LPWAVEHDR | lpWaveOutHdr | Specifies a pointer to a
  1084. * <t WAVEHDR> structure that identifies the data block to be prepared.
  1085. *
  1086. * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
  1087. *
  1088. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1089. * an error number. Possible error returns are:
  1090. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1091. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  1092. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1093. * thread.
  1094. *
  1095. * @comm The <t WAVEHDR> data structure and the data block pointed to by its
  1096. * <e WAVEHDR.lpData> field must be allocated with <f GlobalAlloc> using the
  1097. * GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
  1098. * Preparing a header that has already been prepared has no effect, and
  1099. * the function returns zero.
  1100. *
  1101. * @xref waveOutUnprepareHeader
  1102. ****************************************************************************/
  1103. MMRESULT APIENTRY waveOutPrepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT wSize)
  1104. {
  1105. MMRESULT wRet;
  1106. V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
  1107. if (IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr))
  1108. {
  1109. DebugErr(DBF_WARNING,"waveOutPrepareHeader: header is already prepared.");
  1110. return MMSYSERR_NOERROR;
  1111. }
  1112. ClientUpdatePnpInfo();
  1113. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1114. lpWaveOutHdr->dwFlags &= (WHDR_BEGINLOOP | WHDR_ENDLOOP);
  1115. wRet = waveMessage((HWAVE)hWaveOut, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, (DWORD)wSize);
  1116. if (wRet == MMSYSERR_NOTSUPPORTED)
  1117. wRet = wavePrepareHeader(lpWaveOutHdr, wSize);
  1118. if (wRet == MMSYSERR_NOERROR)
  1119. MarkWaveHeaderPrepared(hWaveOut, lpWaveOutHdr);
  1120. return wRet;
  1121. }
  1122. /*****************************************************************************
  1123. * @doc EXTERNAL WAVE
  1124. *
  1125. * @api MMRESULT | waveOutUnprepareHeader | This function cleans up the
  1126. * preparation performed by <f waveOutPrepareHeader>. The function
  1127. * must be called after
  1128. * the device driver is finished with a data block. You must call this
  1129. * function before freeing the data buffer.
  1130. *
  1131. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1132. * device.
  1133. *
  1134. * @parm LPWAVEHDR | lpWaveOutHdr | Specifies a pointer to a <t WAVEHDR>
  1135. * structure identifying the data block to be cleaned up.
  1136. *
  1137. * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
  1138. *
  1139. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1140. * an error number. Possible error returns are:
  1141. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1142. * @flag WAVERR_STILLPLAYING | <p lpWaveOutHdr> is still in the queue.
  1143. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1144. * thread.
  1145. *
  1146. * @comm This function is the complementary function to
  1147. * <f waveOutPrepareHeader>. You must call this function before freeing the
  1148. * data buffer with <f GlobalFree>.
  1149. * After passing a buffer to the device driver with <f waveOutWrite>, you
  1150. * must wait until the driver is finished with the buffer before calling
  1151. * <f waveOutUnprepareHeader>.
  1152. *
  1153. * Unpreparing a buffer that has not been
  1154. * prepared has no effect, and the function returns zero.
  1155. *
  1156. * @xref waveOutPrepareHeader
  1157. ****************************************************************************/
  1158. MMRESULT APIENTRY waveOutUnprepareHeader(HWAVEOUT hWaveOut,
  1159. LPWAVEHDR lpWaveOutHdr, UINT wSize)
  1160. {
  1161. MMRESULT wRet;
  1162. V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
  1163. if(lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
  1164. {
  1165. DebugErr(DBF_WARNING,"waveOutUnprepareHeader: header still in queue.");
  1166. return WAVERR_STILLPLAYING;
  1167. }
  1168. if (!IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr))
  1169. {
  1170. DebugErr(DBF_WARNING,"waveOutUnprepareHeader: header is not prepared.");
  1171. return MMSYSERR_NOERROR;
  1172. }
  1173. ClientUpdatePnpInfo();
  1174. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1175. wRet = waveMessage((HWAVE)hWaveOut, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, (DWORD)wSize);
  1176. if (wRet == MMSYSERR_NOTSUPPORTED)
  1177. wRet = waveUnprepareHeader(lpWaveOutHdr, wSize);
  1178. if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hWaveOut)))
  1179. {
  1180. wRet = MMSYSERR_NOERROR;
  1181. }
  1182. if (wRet == MMSYSERR_NOERROR)
  1183. MarkWaveHeaderUnprepared(hWaveOut, lpWaveOutHdr);
  1184. return wRet;
  1185. }
  1186. /*****************************************************************************
  1187. * @doc EXTERNAL WAVE
  1188. *
  1189. * @api MMRESULT | waveOutWrite | This function sends a data block to the
  1190. * specified waveform output device.
  1191. *
  1192. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1193. * device.
  1194. *
  1195. * @parm LPWAVEHDR | lpWaveOutHdr | Specifies a far pointer to a <t WAVEHDR>
  1196. * structure containing information about the data block.
  1197. *
  1198. * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
  1199. *
  1200. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1201. * an error number. Possible error returns are:
  1202. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1203. * @flag WAVERR_UNPREPARED | <p lpWaveOutHdr> hasn't been prepared.
  1204. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1205. * thread.
  1206. *
  1207. * @comm The data buffer must be prepared with <f waveOutPrepareHeader> before
  1208. * it is passed to <f waveOutWrite>. The <t WAVEHDR> data structure
  1209. * and the data buffer pointed to by its <e WAVEHDR.lpData> field must be allocated
  1210. * with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
  1211. * locked with <f GlobalLock>. Unless the device is paused by calling
  1212. * <f waveOutPause>, playback begins when the first data block is sent to
  1213. * the device.
  1214. *
  1215. * @xref waveOutPrepareHeader waveOutPause waveOutReset waveOutRestart
  1216. ****************************************************************************/
  1217. MMRESULT APIENTRY waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT wSize)
  1218. {
  1219. V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
  1220. if (!IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr))
  1221. {
  1222. DebugErr(DBF_WARNING,"waveOutWrite: header not prepared");
  1223. return WAVERR_UNPREPARED;
  1224. }
  1225. if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
  1226. {
  1227. DebugErr(DBF_WARNING,"waveOutWrite: header is still in queue");
  1228. return WAVERR_STILLPLAYING;
  1229. }
  1230. ClientUpdatePnpInfo();
  1231. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1232. lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
  1233. return waveMessage((HWAVE)hWaveOut, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, (DWORD)wSize);
  1234. }
  1235. /*****************************************************************************
  1236. * @doc EXTERNAL WAVE
  1237. *
  1238. * @api MMRESULT | waveOutPause | This function pauses playback on a specified
  1239. * waveform output device. The current playback position is saved. Use
  1240. * <f waveOutRestart> to resume playback from the current playback position.
  1241. *
  1242. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1243. * device.
  1244. *
  1245. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1246. * an error number. Possible error returns are:
  1247. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1248. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1249. * thread.
  1250. *
  1251. * @comm Calling this function when the output is already paused has no
  1252. * effect, and the function returns zero.
  1253. *
  1254. * @xref waveOutRestart waveOutBreakLoop
  1255. ****************************************************************************/
  1256. MMRESULT APIENTRY waveOutPause(HWAVEOUT hWaveOut)
  1257. {
  1258. ClientUpdatePnpInfo();
  1259. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1260. return waveMessage((HWAVE)hWaveOut, WODM_PAUSE, 0L, 0L);
  1261. }
  1262. /*****************************************************************************
  1263. * @doc EXTERNAL WAVE
  1264. *
  1265. * @api MMRESULT | waveOutRestart | This function restarts a paused waveform
  1266. * output device.
  1267. *
  1268. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1269. * device.
  1270. *
  1271. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1272. * an error number. Possible error returns are:
  1273. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1274. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1275. * thread.
  1276. *
  1277. * @comm Calling this function when the output is not paused has no
  1278. * effect, and the function returns zero.
  1279. *
  1280. * @xref waveOutPause waveOutBreakLoop
  1281. ****************************************************************************/
  1282. MMRESULT APIENTRY waveOutRestart(HWAVEOUT hWaveOut)
  1283. {
  1284. ClientUpdatePnpInfo();
  1285. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1286. return waveMessage((HWAVE)hWaveOut, WODM_RESTART, 0L, 0L);
  1287. }
  1288. /*****************************************************************************
  1289. * @doc EXTERNAL WAVE
  1290. *
  1291. * @api MMRESULT | waveOutReset | This function stops playback on a given waveform
  1292. * output device and resets the current position to 0. All pending
  1293. * playback buffers are marked as done and returned to the application.
  1294. *
  1295. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1296. * device.
  1297. *
  1298. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1299. * an error number. Possible error returns are:
  1300. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1301. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1302. * thread.
  1303. *
  1304. * @xref waveOutWrite waveOutClose
  1305. /****************************************************************************/
  1306. MMRESULT APIENTRY waveOutReset(HWAVEOUT hWaveOut)
  1307. {
  1308. MMRESULT mmr;
  1309. ClientUpdatePnpInfo();
  1310. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1311. mmr = waveMessage((HWAVE)hWaveOut, WODM_RESET, 0L, 0L);
  1312. if ((MMSYSERR_NODRIVER == mmr) && (IsHandleDeserted(hWaveOut)))
  1313. {
  1314. mmr = MMSYSERR_NOERROR;
  1315. }
  1316. return (mmr);
  1317. }
  1318. /*****************************************************************************
  1319. * @doc EXTERNAL WAVE
  1320. *
  1321. * @api MMRESULT | waveOutBreakLoop | This function breaks a loop on a
  1322. * given waveform output device and allows playback to continue with the
  1323. * next block in the driver list.
  1324. *
  1325. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1326. * device.
  1327. *
  1328. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1329. * an error number. Possible error returns are:
  1330. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1331. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1332. * thread.
  1333. *
  1334. * @comm Waveform looping is controlled by the <e WAVEHDR.dwLoops> and
  1335. * <e WAVEHDR.dwFlags> fields in the <t WAVEHDR> structures passed to the device
  1336. * with <f waveOutWrite>. Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags
  1337. * in the <e WAVEHDR.dwFlags> field to specify the beginning and ending data
  1338. * blocks for looping.
  1339. *
  1340. * To loop on a single block, specify both flags for the same block.
  1341. * To specify the number of loops, use the <e WAVEHDR.dwLoops> field in
  1342. * the <t WAVEHDR> structure for the first block in the loop.
  1343. *
  1344. * The blocks making up the loop are played to the end before the loop
  1345. * is terminated.
  1346. *
  1347. * Calling this function when the nothing is playing or looping has no
  1348. * effect, and the function returns zero.
  1349. *
  1350. * @xref waveOutWrite waveOutPause waveOutRestart
  1351. /****************************************************************************/
  1352. MMRESULT APIENTRY waveOutBreakLoop(HWAVEOUT hWaveOut)
  1353. {
  1354. ClientUpdatePnpInfo();
  1355. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1356. return waveMessage((HWAVE)hWaveOut, WODM_BREAKLOOP, 0L, 0L);
  1357. }
  1358. /*****************************************************************************
  1359. * @doc EXTERNAL WAVE
  1360. *
  1361. * @api MMRESULT | waveOutGetPosition | This function retrieves the current
  1362. * playback position of the specified waveform output device.
  1363. *
  1364. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1365. * device.
  1366. *
  1367. * @parm LPMMTIME | lpInfo | Specifies a far pointer to an <t MMTIME>
  1368. * structure.
  1369. *
  1370. * @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
  1371. *
  1372. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1373. * an error number. Possible error returns are:
  1374. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1375. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1376. * thread.
  1377. *
  1378. * @comm Before calling <f waveOutGetPosition>, set the <e MMTIME.wType> field of the
  1379. * MMTIME structure to indicate the time format that you desire. After
  1380. * calling <f waveOutGetPosition>, check the <e MMTIME.wType> field
  1381. * to determine if the desired time format is supported. If the desired
  1382. * format is not supported, <e MMTIME.wType> will specify an alternative format.
  1383. *
  1384. * The position is set to zero when the device is opened or reset.
  1385. ****************************************************************************/
  1386. MMRESULT APIENTRY waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpInfo,
  1387. UINT wSize)
  1388. {
  1389. V_WPOINTER(lpInfo, wSize, MMSYSERR_INVALPARAM);
  1390. ClientUpdatePnpInfo();
  1391. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1392. return waveMessage((HWAVE)hWaveOut, WODM_GETPOS, (DWORD_PTR)lpInfo, (DWORD)wSize);
  1393. }
  1394. /*****************************************************************************
  1395. * @doc EXTERNAL WAVE
  1396. *
  1397. * @api MMRESULT | waveOutGetPitch | This function queries the the current pitch
  1398. * setting of a waveform output device.
  1399. *
  1400. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1401. * device.
  1402. *
  1403. * @parm LPDWORD | lpdwPitch | Specifies a far pointer to a location
  1404. * to be filled with the current pitch multiplier setting. The pitch
  1405. * multiplier indicates the current change in pitch from the original
  1406. * authored setting. The pitch multiplier must be a positive value.
  1407. *
  1408. * The pitch multiplier is specified as a fixed-point value. The high-order word
  1409. * of the DWORD location contains the signed integer part of the number,
  1410. * and the low-order word contains the fractional part. The fraction is
  1411. * expressed as a WORD in which a value of 0x8000 represents one half,
  1412. * and 0x4000 represents one quarter. For example, the value 0x00010000
  1413. * specifies a multiplier of 1.0 (no pitch change), and a value of
  1414. * 0x000F8000 specifies a multiplier of 15.5.
  1415. *
  1416. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1417. * an error number. Possible error returns are:
  1418. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1419. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  1420. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1421. * thread.
  1422. *
  1423. * @comm Changing the pitch does not change the playback rate, sample
  1424. * rate, or playback time. Not all devices support
  1425. * pitch changes. To determine whether the device supports pitch control,
  1426. * use the WAVECAPS_PITCH flag to test the <e WAVEOUTCAPS.dwSupport>
  1427. * field of the <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
  1428. *
  1429. * @xref waveOutSetPitch waveOutGetPlaybackRate waveOutSetPlaybackRate
  1430. ****************************************************************************/
  1431. MMRESULT APIENTRY waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdwPitch)
  1432. {
  1433. V_WPOINTER(lpdwPitch, sizeof(DWORD), MMSYSERR_INVALPARAM);
  1434. ClientUpdatePnpInfo();
  1435. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1436. return waveMessage((HWAVE)hWaveOut, WODM_GETPITCH, (DWORD_PTR)lpdwPitch, 0L);
  1437. }
  1438. /*****************************************************************************
  1439. * @doc EXTERNAL WAVE
  1440. *
  1441. * @api MMRESULT | waveOutSetPitch | This function sets the pitch of a waveform
  1442. * output device.
  1443. *
  1444. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform
  1445. * output device.
  1446. *
  1447. * @parm DWORD | dwPitch | Specifies the new pitch multiplier setting.
  1448. * The pitch multiplier setting indicates the current change in pitch
  1449. * from the original authored setting. The pitch multiplier must be a
  1450. * positive value.
  1451. *
  1452. * The pitch multiplier is specified as a fixed-point value. The high-order word
  1453. * location contains the signed integer part of the number,
  1454. * and the low-order word contains the fractional part. The fraction is
  1455. * expressed as a WORD in which a value of 0x8000 represents one half,
  1456. * and 0x4000 represents one quarter.
  1457. * For example, the value 0x00010000 specifies a multiplier
  1458. * of 1.0 (no pitch change), and a value of 0x000F8000 specifies a
  1459. * multiplier of 15.5.
  1460. *
  1461. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1462. * an error number. Possible error returns are:
  1463. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1464. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  1465. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1466. * thread.
  1467. *
  1468. * @comm Changing the pitch does not change the playback rate or the sample
  1469. * rate. The playback time is also unchanged. Not all devices support
  1470. * pitch changes. To determine whether the device supports pitch control,
  1471. * use the WAVECAPS_PITCH flag to test the <e WAVEOUTCAPS.dwSupport>
  1472. * field of the <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
  1473. *
  1474. * @xref waveOutGetPitch waveOutSetPlaybackRate waveOutGetPlaybackRate
  1475. ****************************************************************************/
  1476. MMRESULT APIENTRY waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dwPitch)
  1477. {
  1478. ClientUpdatePnpInfo();
  1479. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1480. return waveMessage((HWAVE)hWaveOut, WODM_SETPITCH, dwPitch, 0L);
  1481. }
  1482. /*****************************************************************************
  1483. * @doc EXTERNAL WAVE
  1484. *
  1485. * @api MMRESULT | waveOutGetPlaybackRate | This function queries the
  1486. * current playback rate setting of a waveform output device.
  1487. *
  1488. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
  1489. * device.
  1490. *
  1491. * @parm LPDWORD | lpdwRate | Specifies a far pointer to a location
  1492. * to be filled with the current playback rate. The playback rate setting
  1493. * is a multiplier indicating the current change in playback rate from
  1494. * the original authored setting. The playback rate multiplier must be
  1495. * a positive value.
  1496. *
  1497. * The rate is specified as a fixed-point value. The high-order word
  1498. * of the DWORD location contains the signed integer part of the number,
  1499. * and the low-order word contains the fractional part. The fraction is
  1500. * expressed as a WORD in which a value of 0x8000 represents one half,
  1501. * and 0x4000 represents one quarter. For example, the value 0x00010000
  1502. * specifies a multiplier of 1.0 (no playback rate change), and a value
  1503. * of 0x000F8000 specifies a multiplier of 15.5.
  1504. *
  1505. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1506. * an error number. Possible error returns are:
  1507. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1508. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  1509. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1510. * thread.
  1511. *
  1512. * @comm Changing the playback rate does not change the sample rate but does
  1513. * change the playback time.
  1514. *
  1515. * Not all devices support playback rate changes. To determine whether a
  1516. * device supports playback rate changes, use
  1517. * the WAVECAPS_PLAYBACKRATE flag to test the <e WAVEOUTCAPS.dwSupport> field of the
  1518. * <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
  1519. *
  1520. * @xref waveOutSetPlaybackRate waveOutSetPitch waveOutGetPitch
  1521. ****************************************************************************/
  1522. MMRESULT APIENTRY waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdwRate)
  1523. {
  1524. V_WPOINTER(lpdwRate, sizeof(DWORD), MMSYSERR_INVALPARAM);
  1525. ClientUpdatePnpInfo();
  1526. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1527. return waveMessage((HWAVE)hWaveOut, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdwRate, 0L);
  1528. }
  1529. /*****************************************************************************
  1530. * @doc EXTERNAL WAVE
  1531. *
  1532. * @api MMRESULT | waveOutSetPlaybackRate | This function sets the
  1533. * playback rate of a waveform output device.
  1534. *
  1535. * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform
  1536. * output device.
  1537. *
  1538. * @parm DWORD | dwRate | Specifies the new playback rate setting.
  1539. * The playback rate setting is a multiplier indicating the current
  1540. * change in playback rate from the original authored setting. The playback
  1541. * rate multiplier must be a positive value.
  1542. *
  1543. * The rate is specified as a fixed-point value. The high-order word
  1544. * contains the signed integer part of the number,
  1545. * and the low-order word contains the fractional part. The fraction is
  1546. * expressed as a WORD in which a value of 0x8000 represents one half,
  1547. * and 0x4000 represents one quarter.
  1548. * For example, the value 0x00010000 specifies a multiplier of 1.0 (no
  1549. * playback rate change), and a value of 0x000F8000 specifies a
  1550. * multiplier of 15.5.
  1551. *
  1552. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1553. * an error number. Possible error returns are:
  1554. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  1555. * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
  1556. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  1557. * thread.
  1558. *
  1559. * @comm Changing the playback rate does not change the sample rate but does
  1560. * change the playback time.
  1561. *
  1562. * Not all devices support playback rate changes. To determine whether a
  1563. * device supports playback rate changes,
  1564. * use the WAVECAPS_PLAYBACKRATE flag to test the <e WAVEOUTCAPS.dwSupport> field of the
  1565. * <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
  1566. *
  1567. * @xref waveOutGetPlaybackRate waveOutSetPitch waveOutGetPitch
  1568. ****************************************************************************/
  1569. MMRESULT APIENTRY waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dwRate)
  1570. {
  1571. ClientUpdatePnpInfo();
  1572. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1573. return waveMessage((HWAVE)hWaveOut, WODM_SETPLAYBACKRATE, dwRate, 0L);
  1574. }
  1575. /////////////////////////////////////////////////////////////////////////////
  1576. /////////////////////////////////////////////////////////////////////////////
  1577. /*****************************************************************************
  1578. * @doc EXTERNAL WAVE
  1579. *
  1580. * @api UINT | waveInGetNumDevs | This function returns the number of waveform
  1581. * input devices.
  1582. *
  1583. * @rdesc Returns the number of waveform input devices present in the system.
  1584. *
  1585. * @xref waveInGetDevCaps
  1586. ****************************************************************************/
  1587. UINT APIENTRY waveInGetNumDevs(void)
  1588. {
  1589. ClientUpdatePnpInfo();
  1590. dprintf3(("waveInGetNumDevs returning %d devices", wTotalWaveInDevs));
  1591. // EnterNumDevs("waveInGetNumDevs");
  1592. return wTotalWaveInDevs;
  1593. // LeaveNumDevs("waveInGetNumDevs");
  1594. }
  1595. //--------------------------------------------------------------------------;
  1596. //
  1597. // MMRESULT waveOutDesertHandle
  1598. //
  1599. // Description:
  1600. // Cleans up the wave out handle and marks it as deserted.
  1601. //
  1602. // Arguments:
  1603. // HWAVEOUT hWaveOut: Wave out handle
  1604. //
  1605. // Return (MMRESULT): Error code.
  1606. //
  1607. // History:
  1608. // 01/25/99 Fwong Adding Pnp Support.
  1609. //
  1610. //--------------------------------------------------------------------------;
  1611. MMRESULT waveOutDesertHandle
  1612. (
  1613. HWAVEOUT hWaveOut
  1614. )
  1615. {
  1616. MMRESULT mmr;
  1617. PWAVEDEV pDev = (PWAVEDEV)hWaveOut;
  1618. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  1619. ENTER_MM_HANDLE((HWAVE)hWaveOut);
  1620. ReleaseHandleListResource();
  1621. if (IsHandleDeserted(hWaveOut))
  1622. {
  1623. LEAVE_MM_HANDLE((HWAVE)hWaveOut);
  1624. return (MMSYSERR_NOERROR);
  1625. }
  1626. if (IsHandleBusy(hWaveOut))
  1627. {
  1628. // Not quite invalid, but marked as closed.
  1629. LEAVE_MM_HANDLE(hWaveOut);
  1630. return (MMSYSERR_HANDLEBUSY);
  1631. }
  1632. // Marking handle as deserted
  1633. SetHandleFlag(hWaveOut, MMHANDLE_DESERTED);
  1634. // Since the handle was invalidated, we have to send the message ourselves...
  1635. (*(pDev->wavedrv->drvMessage))(pDev->wDevice, WODM_RESET, pDev->dwDrvUser, 0L, 0L);
  1636. (*(pDev->wavedrv->drvMessage))(pDev->wDevice, WODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  1637. LEAVE_MM_HANDLE((HWAVE)hWaveOut);
  1638. // ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
  1639. // dec on close instead.
  1640. mregDecUsagePtr(pDev->wavedrv);
  1641. return MMSYSERR_NOERROR;
  1642. } // waveOutDesertHandle()
  1643. /*****************************************************************************
  1644. * @doc EXTERNAL WAVE
  1645. *
  1646. * @api MMRESULT | waveInMessage | This function sends messages to the waveform
  1647. * output device drivers.
  1648. *
  1649. * @parm HWAVEIN | hWave | The handle to the audio device.
  1650. *
  1651. * @parm UINT | wMsg | The message to send.
  1652. *
  1653. * @parm DWORD | dw1 | Parameter 1.
  1654. *
  1655. * @parm DWORD | dw2 | Parameter 2.
  1656. *
  1657. * @rdesc Returns the value returned from the driver.
  1658. ****************************************************************************/
  1659. MMRESULT APIENTRY waveInMessage(HWAVEIN hWaveIn, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
  1660. {
  1661. ClientUpdatePnpInfo();
  1662. AcquireHandleListResourceShared();
  1663. if (BAD_HANDLE((HWAVE)hWaveIn, TYPE_WAVEIN))
  1664. {
  1665. ReleaseHandleListResource();
  1666. return waveIDMessage(&waveindrvZ, wTotalWaveInDevs, PtrToUint(hWaveIn), msg, dw1, dw2);
  1667. }
  1668. else
  1669. {
  1670. return waveMessage((HWAVE)hWaveIn, msg, dw1, dw2);
  1671. }
  1672. }
  1673. /*****************************************************************************
  1674. * @doc EXTERNAL WAVE
  1675. *
  1676. * @api MMRESULT | waveInGetDevCaps | This function queries a specified waveform
  1677. * input device to determine its capabilities.
  1678. *
  1679. * @parm UINT | uDeviceID | Identifies the waveform input device.
  1680. *
  1681. * @parm LPWAVEINCAPS | lpCaps | Specifies a far pointer to a <t WAVEINCAPS>
  1682. * structure. This structure is filled with information about the
  1683. * capabilities of the device.
  1684. *
  1685. * @parm UINT | wSize | Specifies the size of the <t WAVEINCAPS> structure.
  1686. *
  1687. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1688. * an error number. Possible error returns are:
  1689. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  1690. * @flag MMSYSERR_NODRIVER | The driver was not installed.
  1691. *
  1692. * @comm Use <f waveInGetNumDevs> to determine the number of waveform input
  1693. * devices present in the system. The device ID specified by <p uDeviceID>
  1694. * varies from zero to one less than the number of devices present.
  1695. * The WAVE_MAPPER constant may also be used as a device id. Only
  1696. * <p wSize> bytes (or less) of information is copied to the location
  1697. * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied, and
  1698. * the function returns zero.
  1699. *
  1700. * @xref waveInGetNumDevs
  1701. ****************************************************************************/
  1702. MMRESULT APIENTRY waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps,UINT wSize)
  1703. {
  1704. DWORD_PTR dwParam1, dwParam2;
  1705. MDEVICECAPSEX mdCaps;
  1706. PWAVEDRV waveindrv;
  1707. PCWSTR DevInterface;
  1708. MMRESULT mmr;
  1709. if (wSize == 0)
  1710. return MMSYSERR_NOERROR;
  1711. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  1712. ClientUpdatePnpInfo();
  1713. DevInterface = waveReferenceDevInterfaceById(&waveindrvZ, uDeviceID);
  1714. dwParam2 = (DWORD_PTR)DevInterface;
  1715. if (0 == dwParam2)
  1716. {
  1717. dwParam1 = (DWORD_PTR)lpCaps;
  1718. dwParam2 = (DWORD)wSize;
  1719. }
  1720. else
  1721. {
  1722. mdCaps.cbSize = (DWORD)wSize;
  1723. mdCaps.pCaps = lpCaps;
  1724. dwParam1 = (DWORD_PTR)&mdCaps;
  1725. }
  1726. //
  1727. // Don't allow non proper drivers in TS environement
  1728. //
  1729. // ISSUE-2001/01/09-FrankYe Instead of cast to UINT. Should check whether
  1730. // this is a handle and get wavedrv from handle if it is.
  1731. waveindrv = NULL;
  1732. if ((!waveReferenceDriverById(&waveindrvZ, (UINT)uDeviceID, &waveindrv, NULL)) &&
  1733. lstrcmpW(waveindrv->wszSessProtocol, SessionProtocolName))
  1734. {
  1735. mmr = MMSYSERR_NODRIVER;
  1736. }
  1737. else
  1738. {
  1739. AcquireHandleListResourceShared();
  1740. if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEIN))
  1741. {
  1742. ReleaseHandleListResource();
  1743. mmr = waveIDMessage(&waveindrvZ, wTotalWaveInDevs, (UINT)uDeviceID, WIDM_GETDEVCAPS, dwParam1, dwParam2);
  1744. }
  1745. else
  1746. {
  1747. mmr = (MMRESULT)waveMessage((HWAVE)uDeviceID, WIDM_GETDEVCAPS, dwParam1, dwParam2);
  1748. }
  1749. }
  1750. if (waveindrv) mregDecUsagePtr(waveindrv);
  1751. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  1752. return mmr;
  1753. }
  1754. MMRESULT APIENTRY waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps,UINT wSize)
  1755. {
  1756. WAVEINCAPS2W wDevCaps2;
  1757. WAVEINCAPS2A aDevCaps2;
  1758. DWORD_PTR dwParam1, dwParam2;
  1759. MDEVICECAPSEX mdCaps;
  1760. PCWSTR DevInterface;
  1761. PWAVEDRV waveindrv;
  1762. MMRESULT mmRes;
  1763. if (wSize == 0)
  1764. return MMSYSERR_NOERROR;
  1765. V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
  1766. ClientUpdatePnpInfo();
  1767. DevInterface = waveReferenceDevInterfaceById(&waveindrvZ, uDeviceID);
  1768. dwParam2 = (DWORD_PTR)DevInterface;
  1769. memset(&wDevCaps2, 0, sizeof(wDevCaps2));
  1770. if (0 == dwParam2)
  1771. {
  1772. dwParam1 = (DWORD_PTR)&wDevCaps2;
  1773. dwParam2 = (DWORD)sizeof(wDevCaps2);
  1774. }
  1775. else
  1776. {
  1777. mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
  1778. mdCaps.pCaps = &wDevCaps2;
  1779. dwParam1 = (DWORD_PTR)&mdCaps;
  1780. }
  1781. //
  1782. // Don't allow non proper drivers in TS environement
  1783. //
  1784. // ISSUE-2001/01/09-FrankYe Bad cast to UINT. Should check whether this
  1785. // is a handle and get wavedrv from handle if it is.
  1786. waveindrv = NULL;
  1787. if ( uDeviceID < wTotalWaveInDevs &&
  1788. !waveReferenceDriverById(&waveindrvZ, (UINT)uDeviceID, &waveindrv, NULL) &&
  1789. lstrcmpW(waveindrv->wszSessProtocol, SessionProtocolName) )
  1790. {
  1791. mregDecUsagePtr(waveindrv);
  1792. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  1793. return MMSYSERR_NODRIVER;
  1794. }
  1795. AcquireHandleListResourceShared();
  1796. if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEIN))
  1797. {
  1798. ReleaseHandleListResource();
  1799. mmRes = waveIDMessage( &waveindrvZ, wTotalWaveInDevs, (UINT)uDeviceID,
  1800. WIDM_GETDEVCAPS, dwParam1, dwParam2);
  1801. }
  1802. else
  1803. {
  1804. mmRes = waveMessage((HWAVE)uDeviceID, WIDM_GETDEVCAPS,
  1805. dwParam1, dwParam2);
  1806. }
  1807. if (waveindrv) mregDecUsagePtr(waveindrv);
  1808. if (DevInterface) wdmDevInterfaceDec(DevInterface);
  1809. //
  1810. // Make sure the call worked before proceeding with the thunk.
  1811. //
  1812. if ( mmRes != MMSYSERR_NOERROR ) {
  1813. return mmRes;
  1814. }
  1815. aDevCaps2.wMid = wDevCaps2.wMid;
  1816. aDevCaps2.wPid = wDevCaps2.wPid;
  1817. aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
  1818. aDevCaps2.dwFormats = wDevCaps2.dwFormats;
  1819. aDevCaps2.wChannels = wDevCaps2.wChannels;
  1820. aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
  1821. aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
  1822. aDevCaps2.NameGuid = wDevCaps2.NameGuid;
  1823. // copy and convert unicode to ascii here.
  1824. Iwcstombs(aDevCaps2.szPname, wDevCaps2.szPname, MAXPNAMELEN);
  1825. //
  1826. // now copy the required amount into the callers buffer.
  1827. //
  1828. CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
  1829. return mmRes;
  1830. }
  1831. /*****************************************************************************
  1832. * @doc EXTERNAL WAVE
  1833. *
  1834. * @api MMRESULT | waveInGetErrorText | This function retrieves a textual
  1835. * description of the error identified by the specified error number.
  1836. *
  1837. * @parm UINT | wError | Specifies the error number.
  1838. *
  1839. * @parm LPTSTR | lpText | Specifies a far pointer to the buffer to be
  1840. * filled with the textual error description.
  1841. *
  1842. * @parm UINT | wSize | Specifies the length in characters of the buffer
  1843. * pointed to by <p lpText>.
  1844. *
  1845. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1846. * an error number. Possible error returns are:
  1847. * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
  1848. *
  1849. * @comm If the textual error description is longer than the specified buffer,
  1850. * the description is truncated. The returned error string is always
  1851. * null-terminated. If <p wSize> is zero, nothing is copied, and the function
  1852. * returns zero. All error descriptions are less than MAXERRORLENGTH characters long.
  1853. ****************************************************************************/
  1854. MMRESULT APIENTRY waveInGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
  1855. {
  1856. if (wSize == 0)
  1857. return MMSYSERR_NOERROR;
  1858. V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
  1859. return waveGetErrorTextW(wError, lpText, wSize);
  1860. }
  1861. MMRESULT APIENTRY waveInGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
  1862. {
  1863. if (wSize == 0)
  1864. return MMSYSERR_NOERROR;
  1865. V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
  1866. return waveGetErrorTextA(wError, lpText, wSize );
  1867. }
  1868. /*****************************************************************************
  1869. * @doc EXTERNAL WAVE
  1870. *
  1871. * @api MMRESULT | waveInOpen | This function opens a specified waveform
  1872. * input device for recording.
  1873. *
  1874. * @parm LPHWAVEIN | lphWaveIn | Specifies a far pointer to a HWAVEIN
  1875. * handle. This location is filled with a handle identifying the opened
  1876. * waveform input device. Use this handle to identify the device when
  1877. * calling other waveform input functions. This parameter may be NULL
  1878. * if the WAVE_FORMAT_QUERY flag is specified for <p dwFlags>.
  1879. *
  1880. * @parm UINT | uDeviceID | Identifies the waveform input device to open. Use
  1881. * a valid device ID or the following flag:
  1882. *
  1883. * @flag WAVE_MAPPER | If this flag is specified, the function
  1884. * selects a waveform input device capable of recording in the
  1885. * given format.
  1886. *
  1887. * @parm LPWAVEFORMATEX | lpFormat | Specifies a pointer to a <t WAVEFORMATEX>
  1888. * data structure that identifies the desired format for recording
  1889. * waveform data.
  1890. *
  1891. * @parm DWORD | dwCallback | Specifies the address of a callback
  1892. * function or a handle to a window called during waveform
  1893. * recording to process messages related to the progress of recording.
  1894. *
  1895. * @parm DWORD | dwCallbackInstance | Specifies user
  1896. * instance data passed to the callback. This parameter is not
  1897. * used with window callbacks.
  1898. *
  1899. * @parm DWORD | dwFlags | Specifies flags for opening the device.
  1900. * @flag WAVE_FORMAT_QUERY | If this flag is specified, the device will
  1901. * be queried to determine if it supports the given format but will not
  1902. * actually be opened.
  1903. * @flag WAVE_ALLOWSYNC | If this flag is not specified, then the
  1904. * device will fail to open if it is a synchronous device.
  1905. * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
  1906. * assumed to be a window handle.
  1907. * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
  1908. * assumed to be a callback procedure address.
  1909. *
  1910. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1911. * an error number. Possible error returns are:
  1912. * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
  1913. * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
  1914. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  1915. * @flag WAVERR_BADFORMAT | Attempted to open with an unsupported wave format.
  1916. *
  1917. * @comm Use <f waveInGetNumDevs> to determine the number of waveform input
  1918. * devices present in the system. The device ID specified by <p uDeviceID>
  1919. * varies from zero to one less than the number of devices present.
  1920. * The WAVE_MAPPER constant may also be used as a device id.
  1921. *
  1922. * If a window is chosen to receive callback information, the following
  1923. * messages are sent to the window procedure function to indicate the
  1924. * progress of waveform input: <m MM_WIM_OPEN>, <m MM_WIM_CLOSE>,
  1925. * <m MM_WIM_DATA>
  1926. *
  1927. * If a function is chosen to receive callback information, the following
  1928. * messages are sent to the function to indicate the progress of waveform
  1929. * input: <m WIM_OPEN>, <m WIM_CLOSE>, <m WIM_DATA>. The callback function
  1930. * must reside in a DLL. You do not have to use <f MakeProcInstance> to get
  1931. * a procedure-instance address for the callback function.
  1932. *
  1933. * @cb void CALLBACK | WaveInFunc | <f WaveInFunc> is a placeholder for the
  1934. * application-supplied function name. The actual name must be exported by
  1935. * including it in an EXPORTS statement in the DLL's module-definition file.
  1936. *
  1937. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform device
  1938. * associated with the callback.
  1939. *
  1940. * @parm UINT | wMsg | Specifies a waveform input device.
  1941. *
  1942. * @parm DWORD | dwInstance | Specifies the user instance
  1943. * data specified with <f waveInOpen>.
  1944. *
  1945. * @parm DWORD | dwParam1 | Specifies a parameter for the message.
  1946. *
  1947. * @parm DWORD | dwParam2 | Specifies a parameter for the message.
  1948. *
  1949. * @comm Because the callback is accessed at interrupt time, it must reside
  1950. * in a DLL and its code segment must be specified as FIXED in the
  1951. * module-definition file for the DLL. Any data that the callback accesses
  1952. * must be in a FIXED data segment as well. The callback may not make any
  1953. * system calls except for <f PostMessage>, <f timeGetSystemTime>,
  1954. * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
  1955. * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
  1956. *
  1957. * @xref waveInClose
  1958. ****************************************************************************/
  1959. MMRESULT APIENTRY waveInOpen(LPHWAVEIN lphWaveIn, UINT uDeviceID,
  1960. LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
  1961. DWORD_PTR dwInstance, DWORD dwFlags)
  1962. {
  1963. WAVEOPENDESC wo;
  1964. UINT port;
  1965. PWAVEDEV pdev;
  1966. PWAVEDRV wavedrv;
  1967. MMRESULT wRet;
  1968. DWORD_PTR dwDrvUser;
  1969. V_RPOINTER(lpFormat, sizeof(WAVEFORMAT), MMSYSERR_INVALPARAM);
  1970. V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
  1971. // Because some 32-bit applications use the value 0x0000FFFF for
  1972. // WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
  1973. // This just happened to work on Win9x because WinMM would thunk down
  1974. // to MMSystem and send down the lower word to the 16-bit interface.
  1975. if (uDeviceID == LOWORD(WAVE_MAPPER)) {
  1976. uDeviceID = WAVE_MAPPER;
  1977. }
  1978. if (uDeviceID == WAVE_MAPPER) {
  1979. V_FLAGS(LOWORD(dwFlags), WAVE_VALID & ~(WAVE_MAPPED), waveInOpen, MMSYSERR_INVALFLAG);
  1980. } else {
  1981. V_FLAGS(LOWORD(dwFlags), WAVE_VALID, waveInOpen, MMSYSERR_INVALFLAG);
  1982. }
  1983. if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
  1984. V_RPOINTER(lpFormat, sizeof(WAVEFORMATEX), MMSYSERR_INVALPARAM);
  1985. if (lpFormat->cbSize) {
  1986. V_RPOINTER(lpFormat + 1, lpFormat->cbSize, MMSYSERR_INVALPARAM);
  1987. }
  1988. }
  1989. if (dwFlags & WAVE_FORMAT_QUERY) {
  1990. lphWaveIn = NULL;
  1991. } else {
  1992. V_WPOINTER((LPVOID)lphWaveIn, sizeof(HWAVEIN), MMSYSERR_INVALPARAM);
  1993. // WAVE_FORMAT_DIRECT was bounced on Win95. Now we
  1994. // accept this flag
  1995. //
  1996. // if (dwFlags & WAVE_FORMAT_DIRECT)
  1997. // return MMSYSERR_INVALFLAG;
  1998. *lphWaveIn = NULL;
  1999. }
  2000. ClientUpdatePnpInfo();
  2001. if ((!wTotalWaveInDevs) || waveReferenceDriverById(&waveindrvZ, (dwFlags & WAVE_MAPPED) ? WAVE_MAPPER : uDeviceID, &wavedrv, &port))
  2002. {
  2003. return MMSYSERR_BADDEVICEID;
  2004. }
  2005. //
  2006. // check if the device is appropriate for the current TS session
  2007. //
  2008. if (!(wavedrv->fdwDriver & MMDRV_MAPPER) &&
  2009. lstrcmpW(wavedrv->wszSessProtocol, SessionProtocolName))
  2010. {
  2011. mregDecUsagePtr(wavedrv);
  2012. return MMSYSERR_NODRIVER;
  2013. }
  2014. /* Default wave mapper :
  2015. *
  2016. * If a wave mapper is installed as a separate DLL then all wave mapper
  2017. * messages are routed to it. If no wave mapper is installed, simply
  2018. * loop through the wave devices looking for a match.
  2019. */
  2020. // ISSUE-2001/01/06-FrankYe This logic looks broken for the WAVE_MAPPED case
  2021. if ((uDeviceID == WAVE_MAPPER && !wavedrv->drvMessage)) {
  2022. UINT wErr;
  2023. mregDecUsagePtr(wavedrv);
  2024. wErr = MMSYSERR_ALLOCATED;
  2025. if (dwFlags & WAVE_MAPPED)
  2026. {
  2027. if (wErr = waveReferenceDriverById(&waveindrvZ, uDeviceID, &wavedrv, &port))
  2028. return wErr;
  2029. if (mregHandleInternalMessages(wavedrv,
  2030. MMDRVI_WAVEIN,
  2031. port,
  2032. DRV_QUERYMAPPABLE,
  2033. 0, 0, &wErr) ||
  2034. (MMSYSERR_NOERROR != wErr))
  2035. {
  2036. mregDecUsagePtr(wavedrv);
  2037. return wErr;
  2038. }
  2039. wErr = waveInOpen(lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags & ~WAVE_MAPPED);
  2040. mregDecUsagePtr(wavedrv);
  2041. }
  2042. else
  2043. {
  2044. for (uDeviceID=0; uDeviceID<wTotalWaveInDevs; uDeviceID++) {
  2045. wErr = waveInOpen(lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
  2046. if (!wErr)
  2047. break;
  2048. }
  2049. }
  2050. return wErr;
  2051. }
  2052. if (dwFlags & WAVE_FORMAT_QUERY)
  2053. pdev = NULL;
  2054. else {
  2055. if (!(pdev = (PWAVEDEV)NewHandle(TYPE_WAVEIN, wavedrv->cookie, sizeof(WAVEDEV))))
  2056. return MMSYSERR_NOMEM;
  2057. ENTER_MM_HANDLE(pdev);
  2058. SetHandleFlag(pdev, MMHANDLE_BUSY);
  2059. ReleaseHandleListResource();
  2060. pdev->wavedrv = wavedrv;
  2061. pdev->wDevice = port;
  2062. pdev->uDeviceID = uDeviceID;
  2063. pdev->fdwHandle = 0;
  2064. }
  2065. wo.hWave = (HWAVE)pdev;
  2066. wo.dwCallback = dwCallback;
  2067. wo.dwInstance = dwInstance;
  2068. wo.uMappedDeviceID = uDeviceID;
  2069. wo.lpFormat = (LPWAVEFORMAT)lpFormat; // cast away the CONST to eliminate wng
  2070. wo.dnDevNode = (DWORD_PTR)wavedrv->cookie;
  2071. wRet = (MMRESULT)((*(wavedrv->drvMessage))
  2072. (port, WIDM_OPEN, (DWORD_PTR)&dwDrvUser, (DWORD_PTR)(LPWAVEOPENDESC)&wo, dwFlags));
  2073. if (pdev) {
  2074. // Mark as not busy on successful open...
  2075. if (!wRet)
  2076. ClearHandleFlag(pdev, MMHANDLE_BUSY);
  2077. LEAVE_MM_HANDLE(pdev);
  2078. if (wRet)
  2079. FreeHandle((HWAVEIN)pdev);
  2080. else {
  2081. // Inc usage since we opened a handle on it
  2082. mregIncUsagePtr(wavedrv);
  2083. *lphWaveIn = (HWAVEIN)pdev;
  2084. pdev->dwDrvUser = dwDrvUser;
  2085. }
  2086. }
  2087. mregDecUsagePtr(wavedrv);
  2088. return wRet;
  2089. }
  2090. /*****************************************************************************
  2091. * @doc EXTERNAL WAVE
  2092. *
  2093. * @api MMRESULT | waveInClose | This function closes the specified waveform
  2094. * input device.
  2095. *
  2096. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
  2097. * If the function is successful, the handle is no longer
  2098. * valid after this call.
  2099. *
  2100. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2101. * an error number. Possible error returns are:
  2102. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2103. * @flag WAVERR_STILLPLAYING | There are still buffers in the queue.
  2104. *
  2105. * @comm If there are input buffers that have been sent with
  2106. * <f waveInAddBuffer>, and haven't been returned to the application,
  2107. * the close operation will fail. Call <f waveInReset> to mark all
  2108. * pending buffers as done.
  2109. *
  2110. * @xref waveInOpen waveInReset
  2111. ****************************************************************************/
  2112. MMRESULT APIENTRY waveInClose(HWAVEIN hWaveIn)
  2113. {
  2114. MMRESULT wRet;
  2115. PWAVEDRV pwavedrv;
  2116. PWAVEDEV pDev = (PWAVEDEV)hWaveIn;
  2117. ClientUpdatePnpInfo();
  2118. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2119. ENTER_MM_HANDLE((HWAVE)hWaveIn);
  2120. ReleaseHandleListResource();
  2121. if (IsHandleDeserted(hWaveIn))
  2122. {
  2123. // This handle has been deserted. Let's just free it.
  2124. LEAVE_MM_HANDLE((HWAVE)hWaveIn);
  2125. FreeHandle(hWaveIn);
  2126. return MMSYSERR_NOERROR;
  2127. }
  2128. if (IsHandleBusy(hWaveIn))
  2129. {
  2130. // Not quite invalid, but marked as closed.
  2131. LEAVE_MM_HANDLE(hWaveIn);
  2132. return (MMSYSERR_HANDLEBUSY);
  2133. }
  2134. // Marking handle as 'invalid/closed'.
  2135. SetHandleFlag(hWaveIn, MMHANDLE_BUSY);
  2136. pwavedrv = pDev->wavedrv;
  2137. wRet = (MMRESULT)(*(pwavedrv->drvMessage))(pDev->wDevice, WIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  2138. if (MMSYSERR_NOERROR != wRet)
  2139. {
  2140. ClearHandleFlag(hWaveIn, MMHANDLE_BUSY);
  2141. }
  2142. LEAVE_MM_HANDLE((HWAVE)hWaveIn);
  2143. if (!wRet)
  2144. {
  2145. FreeHandle(hWaveIn);
  2146. mregDecUsagePtr(pwavedrv);
  2147. return wRet;
  2148. }
  2149. return wRet;
  2150. }
  2151. /*****************************************************************************
  2152. * @doc EXTERNAL WAVE
  2153. *
  2154. * @api MMRESULT | waveInPrepareHeader | This function prepares a buffer
  2155. * for waveform input.
  2156. *
  2157. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
  2158. * device.
  2159. *
  2160. * @parm LPWAVEHDR | lpWaveInHdr | Specifies a pointer to a
  2161. * <t WAVEHDR> structure that identifies the buffer to be prepared.
  2162. *
  2163. * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
  2164. *
  2165. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2166. * an error number. Possible error returns are:
  2167. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2168. * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
  2169. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2170. * thread.
  2171. *
  2172. * @comm The <t WAVEHDR> data structure and the data block pointed to by its
  2173. * <e WAVEHDR.lpData> field must be allocated with <f GlobalAlloc> using the
  2174. * GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
  2175. * Preparing a header that has already been prepared will have no effect,
  2176. * and the function will return zero.
  2177. *
  2178. * @xref waveInUnprepareHeader
  2179. ****************************************************************************/
  2180. MMRESULT APIENTRY waveInPrepareHeader(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr,
  2181. UINT wSize)
  2182. {
  2183. MMRESULT wRet;
  2184. V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
  2185. if (IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr))
  2186. {
  2187. DebugErr(DBF_WARNING,"waveInPrepareHeader: header is already prepared.");
  2188. return MMSYSERR_NOERROR;
  2189. }
  2190. lpWaveInHdr->dwFlags = 0;
  2191. ClientUpdatePnpInfo();
  2192. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2193. wRet = waveMessage((HWAVE)hWaveIn, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, (DWORD)wSize);
  2194. if (wRet == MMSYSERR_NOTSUPPORTED)
  2195. wRet = wavePrepareHeader(lpWaveInHdr, wSize);
  2196. if (wRet == MMSYSERR_NOERROR)
  2197. MarkWaveHeaderPrepared(hWaveIn, lpWaveInHdr);
  2198. return wRet;
  2199. }
  2200. /*****************************************************************************
  2201. * @doc EXTERNAL WAVE
  2202. *
  2203. * @api MMRESULT | waveInUnprepareHeader | This function cleans up the
  2204. * preparation performed by <f waveInPrepareHeader>. The function must
  2205. * be called after the device
  2206. * driver fills a data buffer and returns it to the application. You
  2207. * must call this function before freeing the data buffer.
  2208. *
  2209. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
  2210. * device.
  2211. *
  2212. * @parm LPWAVEHDR | lpWaveInHdr | Specifies a pointer to a <t WAVEHDR>
  2213. * structure identifying the data buffer to be cleaned up.
  2214. *
  2215. * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
  2216. *
  2217. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2218. * an error number. Possible error returns are:
  2219. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2220. * @flag WAVERR_STILLPLAYING | <p lpWaveInHdr> is still in the queue.
  2221. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2222. * thread.
  2223. *
  2224. * @comm This function is the complementary function to <f waveInPrepareHeader>.
  2225. * You must call this function before freeing the data buffer with <f GlobalFree>.
  2226. * After passing a buffer to the device driver with <f waveInAddBuffer>, you
  2227. * must wait until the driver is finished with the buffer before calling
  2228. * <f waveInUnprepareHeader>. Unpreparing a buffer that has not been
  2229. * prepared has no effect, and the function returns zero.
  2230. *
  2231. * @xref waveInPrepareHeader
  2232. ****************************************************************************/
  2233. MMRESULT APIENTRY waveInUnprepareHeader(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr, UINT wSize)
  2234. {
  2235. MMRESULT wRet;
  2236. V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
  2237. if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
  2238. {
  2239. DebugErr(DBF_WARNING, "waveInUnprepareHeader: buffer still in queue.");
  2240. return WAVERR_STILLPLAYING;
  2241. }
  2242. if (!IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr))
  2243. {
  2244. DebugErr(DBF_WARNING,"waveInUnprepareHeader: header is not prepared.");
  2245. return MMSYSERR_NOERROR;
  2246. }
  2247. ClientUpdatePnpInfo();
  2248. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2249. wRet = waveMessage((HWAVE)hWaveIn, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, (DWORD)wSize);
  2250. if (wRet == MMSYSERR_NOTSUPPORTED)
  2251. wRet = waveUnprepareHeader(lpWaveInHdr, wSize);
  2252. if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hWaveIn)))
  2253. {
  2254. wRet = MMSYSERR_NOERROR;
  2255. }
  2256. if (wRet == MMSYSERR_NOERROR)
  2257. MarkWaveHeaderUnprepared(hWaveIn, lpWaveInHdr);
  2258. return wRet;
  2259. }
  2260. /*****************************************************************************
  2261. * @doc EXTERNAL WAVE
  2262. *
  2263. * @api MMRESULT | waveInAddBuffer | This function sends an input buffer to a
  2264. * waveform input device. When the buffer is filled, it is sent back
  2265. * to the application.
  2266. *
  2267. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
  2268. *
  2269. * @parm LPWAVEHDR | lpWaveInHdr | Specifies a far pointer to a <t WAVEHDR>
  2270. * structure that identifies the buffer.
  2271. *
  2272. * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
  2273. *
  2274. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2275. * an error number. Possible error returns are:
  2276. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2277. * @flag WAVERR_UNPREPARED | <p lpWaveInHdr> hasn't been prepared.
  2278. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2279. * thread.
  2280. *
  2281. * @comm The data buffer must be prepared with <f waveInPrepareHeader> before
  2282. * it is passed to <f waveInAddBuffer>. The <t WAVEHDR> data structure
  2283. * and the data buffer pointed to by its <e WAVEHDR.lpData> field must be allocated
  2284. * with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
  2285. * locked with <f GlobalLock>.
  2286. *
  2287. * @xref waveInPrepareHeader
  2288. ****************************************************************************/
  2289. MMRESULT APIENTRY waveInAddBuffer(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr,
  2290. UINT wSize)
  2291. {
  2292. V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
  2293. if (!IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr))
  2294. {
  2295. DebugErr(DBF_WARNING, "waveInAddBuffer: buffer not prepared.");
  2296. return WAVERR_UNPREPARED;
  2297. }
  2298. if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
  2299. {
  2300. DebugErr(DBF_WARNING, "waveInAddBuffer: buffer already in queue.");
  2301. return WAVERR_STILLPLAYING;
  2302. }
  2303. ClientUpdatePnpInfo();
  2304. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2305. return waveMessage((HWAVE)hWaveIn, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, (DWORD)wSize);
  2306. }
  2307. /*****************************************************************************
  2308. * @doc EXTERNAL WAVE
  2309. *
  2310. * @api MMRESULT | waveInStart | This function starts input on the specified
  2311. * waveform input device.
  2312. *
  2313. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
  2314. *
  2315. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2316. * an error number. Possible error returns are:
  2317. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2318. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2319. * thread.
  2320. *
  2321. * @comm Buffers are returned to the client when full or when <f waveInReset>
  2322. * is called (the <e WAVEHDR.dwBytesRecorded> field in the header will contain the
  2323. * actual length of data). If there are no buffers in the queue, the data is
  2324. * thrown away without notification to the client, and input continues.
  2325. *
  2326. * Calling this function when input is already started has no effect, and
  2327. * the function returns zero.
  2328. *
  2329. * @xref waveInStop waveInReset
  2330. ****************************************************************************/
  2331. MMRESULT APIENTRY waveInStart(HWAVEIN hWaveIn)
  2332. {
  2333. ClientUpdatePnpInfo();
  2334. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2335. return waveMessage((HWAVE)hWaveIn, WIDM_START, 0L, 0L);
  2336. }
  2337. /*****************************************************************************
  2338. * @doc EXTERNAL WAVE
  2339. *
  2340. * @api MMRESULT | waveInStop | This function stops waveform input.
  2341. *
  2342. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
  2343. * device.
  2344. *
  2345. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2346. * an error number. Possible error returns are:
  2347. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2348. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2349. * thread.
  2350. *
  2351. * @comm If there are any buffers in the queue, the current buffer will be
  2352. * marked as done (the <e WAVEHDR.dwBytesRecorded> field in the header will contain
  2353. * the actual length of data), but any empty buffers in the queue will remain
  2354. * there. Calling this function when input is not started has no effect,
  2355. * and the function returns zero.
  2356. *
  2357. * @xref waveInStart waveInReset
  2358. ****************************************************************************/
  2359. MMRESULT APIENTRY waveInStop(HWAVEIN hWaveIn)
  2360. {
  2361. ClientUpdatePnpInfo();
  2362. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2363. return waveMessage((HWAVE)hWaveIn, WIDM_STOP, 0L, 0L);
  2364. }
  2365. /*****************************************************************************
  2366. * @doc EXTERNAL WAVE
  2367. *
  2368. * @api MMRESULT | waveInReset | This function stops input on a given waveform
  2369. * input device and resets the current position to 0. All pending
  2370. * buffers are marked as done and returned to the application.
  2371. *
  2372. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
  2373. *
  2374. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2375. * an error number. Possible error returns are:
  2376. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2377. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2378. * thread.
  2379. *
  2380. * @xref waveInStart waveInStop waveInAddBuffer waveInClose
  2381. /****************************************************************************/
  2382. MMRESULT APIENTRY waveInReset(HWAVEIN hWaveIn)
  2383. {
  2384. MMRESULT mmr;
  2385. ClientUpdatePnpInfo();
  2386. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2387. mmr = waveMessage((HWAVE)hWaveIn, WIDM_RESET, 0L, 0L);
  2388. if ((MMSYSERR_NODRIVER == mmr) && (IsHandleDeserted(hWaveIn)))
  2389. {
  2390. mmr = MMSYSERR_NOERROR;
  2391. }
  2392. return (mmr);
  2393. }
  2394. /*****************************************************************************
  2395. * @doc EXTERNAL WAVE
  2396. *
  2397. * @api MMRESULT | waveInGetPosition | This function retrieves the current input
  2398. * position of the specified waveform input device.
  2399. *
  2400. * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
  2401. *
  2402. * @parm LPMMTIME | lpInfo | Specifies a far pointer to an <t MMTIME>
  2403. * structure.
  2404. *
  2405. * @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
  2406. *
  2407. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2408. * an error number. Possible error returns are:
  2409. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  2410. *
  2411. * @comm Before calling <f waveInGetPosition>, set the <e MMTIME.wType> field of the
  2412. * <t MMTIME> structure to indicate the time format that you desire. After
  2413. * calling <f waveInGetPosition>, be sure to check the <e MMTIME.wType> field to
  2414. * determine if the desired time format is supported. If the desired
  2415. * format is not supported, <e MMTIME.wType> will specify an alternative format.
  2416. *
  2417. * The position is set to zero when the device is opened or reset.
  2418. ****************************************************************************/
  2419. MMRESULT APIENTRY waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpInfo,
  2420. UINT wSize)
  2421. {
  2422. V_WPOINTER(lpInfo, wSize, MMSYSERR_INVALPARAM);
  2423. ClientUpdatePnpInfo();
  2424. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2425. return waveMessage((HWAVE)hWaveIn, WIDM_GETPOS, (DWORD_PTR)lpInfo, (DWORD)wSize);
  2426. }
  2427. //--------------------------------------------------------------------------;
  2428. //
  2429. // MMRESULT waveInDesertHandle
  2430. //
  2431. // Description:
  2432. // Cleans up the wave in handle and marks it as deserted.
  2433. //
  2434. // Arguments:
  2435. // HWAVEIN hWaveIn: Wave in handle
  2436. //
  2437. // Return (MMRESULT): Error code.
  2438. //
  2439. // History:
  2440. // 01/25/99 Fwong Adding Pnp Support.
  2441. //
  2442. //--------------------------------------------------------------------------;
  2443. MMRESULT waveInDesertHandle
  2444. (
  2445. HWAVEIN hWaveIn
  2446. )
  2447. {
  2448. MMRESULT mmr;
  2449. PWAVEDEV pDev = (PWAVEDEV)hWaveIn;
  2450. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2451. ENTER_MM_HANDLE((HWAVE)hWaveIn);
  2452. ReleaseHandleListResource();
  2453. if (IsHandleDeserted(hWaveIn))
  2454. {
  2455. LEAVE_MM_HANDLE((HWAVE)hWaveIn);
  2456. return (MMSYSERR_NOERROR);
  2457. }
  2458. if (IsHandleBusy(hWaveIn))
  2459. {
  2460. // Not quite invalid, but marked as closed.
  2461. LEAVE_MM_HANDLE(hWaveIn);
  2462. return (MMSYSERR_HANDLEBUSY);
  2463. }
  2464. // Marking handle as deserted
  2465. SetHandleFlag(hWaveIn, MMHANDLE_DESERTED);
  2466. // Since the handle was invalidated, we have to send the message ourselves...
  2467. (*(pDev->wavedrv->drvMessage))(pDev->wDevice, WIDM_RESET, pDev->dwDrvUser, 0L, 0L);
  2468. (*(pDev->wavedrv->drvMessage))(pDev->wDevice, WIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
  2469. LEAVE_MM_HANDLE((HWAVE)hWaveIn);
  2470. // ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
  2471. // dec on close instead.
  2472. mregDecUsagePtr(pDev->wavedrv);
  2473. return MMSYSERR_NOERROR;
  2474. } // waveInDesertHandle()
  2475. /*****************************************************************************
  2476. * @doc EXTERNAL WAVE
  2477. *
  2478. * @api MMRESULT | waveInGetID | This function gets the device ID for a
  2479. * waveform input device.
  2480. *
  2481. * @parm HWAVEIN | hWaveIn | Specifies the handle to the waveform
  2482. * input device.
  2483. * @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized memory
  2484. * location to be filled with the device ID.
  2485. *
  2486. * @rdesc Returns zero if successful. Otherwise, it returns
  2487. * an error number. Possible error returns are:
  2488. * @flag MMSYSERR_INVALHANDLE | The <p hWaveIn> parameter specifies an
  2489. * invalid handle.
  2490. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
  2491. * thread.
  2492. *
  2493. ****************************************************************************/
  2494. MMRESULT APIENTRY waveInGetID(HWAVEIN hWaveIn, PUINT lpuDeviceID)
  2495. {
  2496. V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
  2497. V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
  2498. *lpuDeviceID = ((PWAVEDEV)hWaveIn)->uDeviceID;
  2499. ReleaseHandleListResource();
  2500. return MMSYSERR_NOERROR;
  2501. }
  2502. /*****************************************************************************
  2503. * @doc EXTERNAL WAVE
  2504. *
  2505. * @api MMRESULT | waveOutGetID | This function gets the device ID for a
  2506. * waveform output device.
  2507. *
  2508. * @parm HWAVEOUT | hWaveOut | Specifies the handle to the waveform
  2509. * output device.
  2510. * @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized memory
  2511. * location to be filled with the device ID.
  2512. *
  2513. * @rdesc Returns zero if successful. Otherwise, it returns
  2514. * an error number. Possible error returns are:
  2515. * @flag MMSYSERR_INVALHANDLE | The <p hWaveIn> parameter specifies an
  2516. * invalid handle.
  2517. * @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
  2518. * thread.
  2519. ****************************************************************************/
  2520. MMRESULT APIENTRY waveOutGetID(HWAVEOUT hWaveOut, PUINT lpuDeviceID)
  2521. {
  2522. V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
  2523. V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
  2524. *lpuDeviceID = ((PWAVEDEV)hWaveOut)->uDeviceID;
  2525. ReleaseHandleListResource();
  2526. return MMSYSERR_NOERROR;
  2527. }