windows-nt/Source/XPSP1/NT/multimedia/media/winmm/midi.c
2020-09-26 16:20:57 +08:00

2742 lines
93 KiB
C

/*****************************************************************************
midi.c
Level 1 kitchen sink DLL midi support module
Copyright (c) 1990-2001 Microsoft Corporation
*****************************************************************************/
#include "winmmi.h"
#define DO_DEFAULT_MIDI_MAPPER
/*****************************************************************************
local structures
*****************************************************************************/
/*****************************************************************************
internal prototypes
*****************************************************************************/
/*****************************************************************************
segmentation
*****************************************************************************/
/*****************************************************************************
* @doc INTERNAL MIDI
*
* @api MMRESULT | midiPrepareHeader | This function prepares the header and data
* if the driver returns MMSYSERR_NOTSUPPORTED.
*
* @rdesc Currently always returns MMSYSERR_NOERROR.
****************************************************************************/
STATIC MMRESULT midiPrepareHeader(LPMIDIHDR lpMidiHdr, UINT wSize)
{
if (!HugePageLock(lpMidiHdr, (DWORD)sizeof(MIDIHDR)))
return MMSYSERR_NOMEM;
if (!HugePageLock(lpMidiHdr->lpData, lpMidiHdr->dwBufferLength)) {
HugePageUnlock(lpMidiHdr, (DWORD)sizeof(MIDIHDR));
return MMSYSERR_NOMEM;
}
lpMidiHdr->dwFlags |= MHDR_PREPARED;
return MMSYSERR_NOERROR;
}
/*****************************************************************************
* @doc INTERNAL MIDI
*
* @api MMRESULT | midiUnprepareHeader | This function unprepares the header and
* data if the driver returns MMSYSERR_NOTSUPPORTED.
*
* @rdesc Currently always returns MMSYSERR_NOERROR.
****************************************************************************/
STATIC MMRESULT midiUnprepareHeader(LPMIDIHDR lpMidiHdr, UINT wSize)
{
HugePageUnlock(lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
HugePageUnlock(lpMidiHdr, (DWORD)sizeof(MIDIHDR));
lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
return MMSYSERR_NOERROR;
}
/***************************************************************************
* @doc INTERNAL MIDI
*
* @api MMRESULT | midiReferenceDriverById | This function maps a logical
* id to a device driver table index and physical id.
*
* @parm IN MIDIDRV | pmididrvZ | The list of midi drivers.
*
* @parm IN UINT | id | The logical id to be mapped.
*
* @parm OUT PMIDIDRV* OPTIONAL | ppmididrv | Pointer to MIDIDRV structure
* describing the driver supporting the id.
*
* @parm OUT UINT* OPTIONAL | pport | The driver-relative device number. If
* the caller supplies this buffer then it must also supply ppmididrv.
*
* @comm If the caller specifies ppmididrv then this function increments
* the mididrv's usage before returning. The caller must ensure
* the usage is eventually decremented.
*
* @rdesc The return value is zero if successful, MMSYSERR_BADDEVICEID if
* the id is out of range.
*
* @rdesc The return value contains the dev[] array element in the high UINT and
* the driver physical device number in the low UINT.
*
* @comm Out of range values map to FFFF:FFFF
***************************************************************************/
MMRESULT midiReferenceDriverById(IN PMIDIDRV pmididrvZ, IN UINT id, OUT PMIDIDRV *ppmididrv OPTIONAL, OUT UINT *pport)
{
PMIDIDRV pmididrv;
MMRESULT mmr;
// Should not be called asking for port but not mididrv
WinAssert(!(pport && !ppmididrv));
if (id == MIDI_MAPPER) {
/*
** Make sure we tried to load the mapper
*/
MidiMapperInit();
}
EnterNumDevs("midiReferenceDriverById");
if (MIDI_MAPPER == id)
{
id = 0;
for (pmididrv = pmididrvZ->Next; pmididrv != pmididrvZ; pmididrv = pmididrv->Next)
{
if (pmididrv->fdwDriver & MMDRV_MAPPER) break;
}
} else {
for (pmididrv = pmididrvZ->Next; pmididrv != pmididrvZ; pmididrv = pmididrv->Next)
{
if (pmididrv->fdwDriver & MMDRV_MAPPER) continue;
if (pmididrv->NumDevs > id) break;
id -= pmididrv->NumDevs;
}
}
if (pmididrv != pmididrvZ)
{
if (ppmididrv)
{
mregIncUsagePtr(pmididrv);
*ppmididrv = pmididrv;
if (pport) *pport = id;
}
mmr = MMSYSERR_NOERROR;
} else {
mmr = MMSYSERR_BADDEVICEID;
}
LeaveNumDevs("midiReferenceDriverById");
return mmr;
}
PCWSTR midiReferenceDevInterfaceById(PMIDIDRV pdrvZ, UINT_PTR id)
{
PMIDIDRV pdrv;
PCWSTR DeviceInterface;
if ((pdrvZ == &midioutdrvZ && ValidateHandle((HANDLE)id, TYPE_MIDIOUT)) ||
(pdrvZ == &midiindrvZ && ValidateHandle((HANDLE)id, TYPE_MIDIIN)))
{
DeviceInterface = ((PMIDIDEV)id)->mididrv->cookie;
if (DeviceInterface) wdmDevInterfaceInc(DeviceInterface);
return DeviceInterface;
}
if (!midiReferenceDriverById(pdrvZ, (UINT)id, &pdrv, NULL))
{
DeviceInterface = pdrv->cookie;
if (DeviceInterface) wdmDevInterfaceInc(DeviceInterface);
mregDecUsagePtr(pdrv);
return DeviceInterface;
}
return NULL;
}
/****************************************************************************
* @doc INTERNAL MIDI
*
* @api MMRESULT | midiMessage | This function sends messages to the MIDI device
* drivers.
*
* @parm HMIDI | hMidi | The handle to the MIDI device.
*
* @parm UINT | wMsg | The message to send.
*
* @parm DWORD | dwP1 | Parameter 1.
*
* @parm DWORD | dwP2 | Parameter 2.
*
* @rdesc Returns the value of the message sent.
***************************************************************************/
STATIC MMRESULT midiMessage(HMIDI hMidi, UINT msg, DWORD_PTR dwP1, DWORD_PTR dwP2)
{
MMRESULT mrc;
ENTER_MM_HANDLE(hMidi);
ReleaseHandleListResource();
// Is handle deserted?
if (IsHandleDeserted(hMidi))
{
LEAVE_MM_HANDLE(hMidi);
return (MMSYSERR_NODRIVER);
}
// Are we busy (in the middle of an open/close)?
if (IsHandleBusy(hMidi))
{
LEAVE_MM_HANDLE(hMidi);
return (MMSYSERR_HANDLEBUSY);
}
if (BAD_HANDLE(hMidi, TYPE_MIDIOUT) && BAD_HANDLE(hMidi, TYPE_MIDISTRM) &&
BAD_HANDLE(hMidi, TYPE_MIDIIN) ) {
WinAssert(!"Bad Handle within midiMessage");
mrc = MMSYSERR_INVALHANDLE;
} else {
mrc = (*(((PMIDIDEV)hMidi)->mididrv->drvMessage))
(((PMIDIDEV)hMidi)->wDevice, msg, ((PMIDIDEV)hMidi)->dwDrvUser, dwP1, dwP2);
}
LEAVE_MM_HANDLE(hMidi);
return mrc;
}
/****************************************************************************
* @doc INTERNAL MIDI
*
* @func MMRESULT | midiIDMessage | This function sends a message to the device
* ID specified. It also performs error checking on the ID passed.
*
* @parm PMIDIDRV | mididrv | Pointer to the input or output device list.
*
* @parm UINT | wTotalNumDevs | Total number of devices in device list.
*
* @parm UINT | uDeviceID | Device ID to send message to.
*
* @parm UINT | wMessage | The message to send.
*
* @parm DWORD | dwParam1 | Parameter 1.
*
* @parm DWORD | dwParam2 | Parameter 2.
*
* @rdesc The return value is the low UINT of the returned message.
***************************************************************************/
STATIC MMRESULT midiIDMessage(
PMIDIDRV pmididrvZ,
UINT wTotalNumDevs,
UINT_PTR uDeviceID,
UINT wMessage,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2)
{
PMIDIDRV mididrv;
UINT port;
DWORD mmr;
DWORD dwClass;
if (uDeviceID>=wTotalNumDevs && uDeviceID!=MIDI_MAPPER) {
// this cannot be a device ID.
// it could be a device handle. Try it.
// First we have to verify which type of handle it is (OUT or IN)
// We can work this out as midiIDMessage is only ever called with
// mididrv== midioutdrv or midiindrv
if ((pmididrvZ == &midioutdrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_MIDIOUT))
|| (pmididrvZ == &midiindrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_MIDIIN) )) {
// to preserve as much compatibility with previous code paths
// we do NOT call midiMessage as that calls ENTER_MM_HANDLE
return (MMRESULT)(*(((PMIDIDEV)uDeviceID)->mididrv->drvMessage))
(((PMIDIDEV)uDeviceID)->wDevice,
wMessage,
((PMIDIDEV)uDeviceID)->dwDrvUser, dwParam1, dwParam2);
} else {
return(MMSYSERR_BADDEVICEID);
}
}
// Get Physical Device, and Port
mmr = midiReferenceDriverById(pmididrvZ, (UINT)uDeviceID, &mididrv, &port);
if (mmr)
{
return mmr;
}
if (pmididrvZ == &midiindrvZ)
dwClass = TYPE_MIDIIN;
else if (pmididrvZ == &midioutdrvZ)
dwClass = TYPE_MIDIOUT;
else
dwClass = TYPE_UNKNOWN;
if (!mididrv->drvMessage)
return MMSYSERR_NODRIVER;
// Handle Internal Messages
if (!mregHandleInternalMessages (mididrv, dwClass, port, wMessage, dwParam1, dwParam2, &mmr))
{
// Call Physical Device at Port
mmr = (MMRESULT)((*(mididrv->drvMessage))(port, wMessage, 0L, dwParam1, dwParam2));
}
mregDecUsagePtr(mididrv);
return mmr;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api UINT | midiOutGetNumDevs | This function retrieves the number of MIDI
* output devices present in the system.
*
* @rdesc Returns the number of MIDI output devices present in the system.
*
* @xref midiOutGetDevCaps
****************************************************************************/
UINT APIENTRY midiOutGetNumDevs(void)
{
UINT cDevs;
ClientUpdatePnpInfo();
EnterNumDevs("midiOutGetNumDevs");
cDevs = wTotalMidiOutDevs;
LeaveNumDevs("midiOutGetNumDevs");
return cDevs;
}
/****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutMessage | This function sends messages to the MIDI device
* drivers.
*
* @parm HMIDIOUT | hMidiOut | The handle to the MIDI device.
*
* @parm UINT | msg | The message to send.
*
* @parm DWORD | dw1 | Parameter 1.
*
* @parm DWORD | dw2 | Parameter 2.
*
* @rdesc Returns the value of the message sent.
***************************************************************************/
MMRESULT APIENTRY midiOutMessage(HMIDIOUT hMidiOut, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
{
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return midiIDMessage(&midioutdrvZ, wTotalMidiOutDevs, (UINT_PTR)hMidiOut, msg, dw1, dw2);
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
return midiMessage((HMIDI)hMidiOut, msg, dw1, dw2);
case TYPE_MIDISTRM:
ReleaseHandleListResource();
return midiStreamBroadcast(HtoPT(PMIDISTRM, hMidiOut), msg, dw1, dw2);
}
ReleaseHandleListResource();
Squirt("We should never get here.");
WinAssert(FALSE);
// Getting rid of warning.
return MMSYSERR_INVALHANDLE;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutGetDevCaps | This function queries a specified
* MIDI output device to determine its capabilities.
*
* @parm UINT | uDeviceID | Identifies the MIDI output device.
*
* @parm LPMIDIOUTCAPS | lpCaps | Specifies a far pointer to a <t MIDIOUTCAPS>
* structure. This structure is filled with information about the
* capabilities of the device.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIOUTCAPS> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
* @flag MMSYSERR_NODRIVER | The driver was not installed.
* @flag MMSYSERR_NOMEM | Unable load mapper string description.
*
* @comm Use <f midiOutGetNumDevs> to determine the number of MIDI output
* devices present in the system. The device ID specified by <p uDeviceID>
* varies from zero to one less than the number of devices present.
* The MIDI_MAPPER constant may also be used as a device id. Only
* <p wSize> bytes (or less) of information is copied to the location
* pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied,
* and the function returns zero.
*
* @xref midiOutGetNumDevs
****************************************************************************/
MMRESULT APIENTRY midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, UINT wSize)
{
DWORD_PTR dwParam1, dwParam2;
MDEVICECAPSEX mdCaps;
PMIDIDRV midioutdrv;
PCWSTR DevInterface;
MMRESULT mmr;
if (wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
ClientUpdatePnpInfo();
DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, uDeviceID);
dwParam2 = (DWORD_PTR)DevInterface;
if (0 == dwParam2)
{
dwParam1 = (DWORD_PTR)lpCaps;
dwParam2 = (DWORD)wSize;
}
else
{
mdCaps.cbSize = (DWORD)wSize;
mdCaps.pCaps = lpCaps;
dwParam1 = (DWORD_PTR)&mdCaps;
}
//
// Don't allow non proper drivers in TS environement
//
// ISSUE-2001/01/09-FrankYe Instead of cast to UINT. Should check whether
// this is a handle and get wavedrv from handle if it is.
midioutdrv = NULL;
if ((!midiReferenceDriverById(&midioutdrvZ, (UINT)uDeviceID, &midioutdrv, NULL)) &&
lstrcmpW(midioutdrv->wszSessProtocol, SessionProtocolName))
{
mmr = MMSYSERR_NODRIVER;
}
else
{
AcquireHandleListResourceShared();
if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIOUT))
{
ReleaseHandleListResource();
mmr = midiIDMessage( &midioutdrvZ, wTotalMidiOutDevs, uDeviceID, MODM_GETDEVCAPS, dwParam1, dwParam2 );
}
else
{
mmr = (MMRESULT)midiMessage((HMIDI)uDeviceID, MODM_GETDEVCAPS, dwParam1, dwParam2);
}
}
if (midioutdrv) mregDecUsagePtr(midioutdrv);
if (DevInterface) wdmDevInterfaceDec(DevInterface);
return mmr;
}
MMRESULT APIENTRY midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, UINT wSize)
{
MIDIOUTCAPS2W wDevCaps2;
MIDIOUTCAPS2A aDevCaps2;
DWORD_PTR dwParam1, dwParam2;
MDEVICECAPSEX mdCaps;
MMRESULT mmRes;
PMIDIDRV midioutdrv;
CHAR chTmp[ MAXPNAMELEN * sizeof(WCHAR) ];
PCWSTR DevInterface;
if (wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
ClientUpdatePnpInfo();
DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, uDeviceID);
dwParam2 = (DWORD_PTR)DevInterface;
memset(&wDevCaps2, 0, sizeof(wDevCaps2));
if (0 == dwParam2)
{
dwParam1 = (DWORD_PTR)&wDevCaps2;
dwParam2 = (DWORD)sizeof(wDevCaps2);
}
else
{
mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
mdCaps.pCaps = &wDevCaps2;
dwParam1 = (DWORD_PTR)&mdCaps;
}
//
// Don't allow non proper drivers in TS environement
//
// ISSUE-2001/01/09-FrankYe Bad cast to UINT. Should check whether this
// is a handle and get wavedrv from handle if it is.
midioutdrv = NULL;
if ( uDeviceID < wTotalMidiOutDevs &&
!midiReferenceDriverById(&midioutdrvZ, (UINT)uDeviceID, &midioutdrv, NULL) &&
lstrcmpW(midioutdrv->wszSessProtocol, SessionProtocolName) )
{
mregDecUsagePtr(midioutdrv);
if (DevInterface) wdmDevInterfaceDec(DevInterface);
return MMSYSERR_NODRIVER;
}
AcquireHandleListResourceShared();
if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIOUT))
{
ReleaseHandleListResource();
mmRes = midiIDMessage( &midioutdrvZ, wTotalMidiOutDevs, (UINT)uDeviceID,
MODM_GETDEVCAPS, dwParam1,
dwParam2);
}
else
{
mmRes = midiMessage((HMIDI)uDeviceID, MODM_GETDEVCAPS,
dwParam1, dwParam2);
}
if (midioutdrv) mregDecUsagePtr(midioutdrv);
if (DevInterface) wdmDevInterfaceDec(DevInterface);
//
// Make sure the call worked before proceeding with the thunk.
//
if ( mmRes != MMSYSERR_NOERROR ) {
return mmRes;
}
aDevCaps2.wMid = wDevCaps2.wMid;
aDevCaps2.wPid = wDevCaps2.wPid;
aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
aDevCaps2.wTechnology = wDevCaps2.wTechnology;
aDevCaps2.wVoices = wDevCaps2.wVoices;
aDevCaps2.wNotes = wDevCaps2.wNotes;
aDevCaps2.wChannelMask = wDevCaps2.wChannelMask;
aDevCaps2.dwSupport = wDevCaps2.dwSupport;
aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
aDevCaps2.NameGuid = wDevCaps2.NameGuid;
// copy and convert lpwText to lpText here.
UnicodeStrToAsciiStr( chTmp, chTmp + sizeof( chTmp ), wDevCaps2.szPname );
strcpy( aDevCaps2.szPname, chTmp );
//
// now copy the required amount into the callers buffer.
//
CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
return mmRes;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutGetVolume | This function returns the current volume
* setting of a MIDI output device.
*
* @parm UINT | uDeviceID | Identifies the MIDI output device.
*
* @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location
* to be filled with the current volume setting. The low-order UINT of
* this location contains the left channel volume setting, and the high-order
* UINT contains the right channel setting. A value of 0xFFFF represents
* full volume, and a value of 0x0000 is silence.
*
* If a device does not support both left and right volume
* control, the low-order UINT of the specified location contains
* the mono volume level.
*
* The full 16-bit setting(s)
* set with <f midiOutSetVolume> is returned, regardless of whether
* the device supports the full 16 bits of volume level control.
*
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
* @flag MMSYSERR_NODRIVER | The driver was not installed.
*
* @comm Not all devices support volume control. To determine whether the
* device supports volume control, use the MIDICAPS_VOLUME
* flag to test the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
* structure (filled by <f midiOutGetDevCaps>).
*
* To determine whether the device supports volume control on both the
* left and right channels, use the MIDICAPS_LRVOLUME flag to test
* the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
* structure (filled by <f midiOutGetDevCaps>).
*
* @xref midiOutSetVolume
****************************************************************************/
MMRESULT APIENTRY midiOutGetVolume(HMIDIOUT hmo, LPDWORD lpdwVolume)
{
PCWSTR DevInterface;
MMRESULT mmr;
V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
ClientUpdatePnpInfo();
DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, (UINT_PTR)hmo);
AcquireHandleListResourceShared();
if (BAD_HANDLE(hmo, TYPE_MIDIOUT) && BAD_HANDLE(hmo, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
mmr = midiIDMessage(&midioutdrvZ, wTotalMidiOutDevs, (UINT_PTR)hmo, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
}
else
{
switch(GetHandleType(hmo))
{
case TYPE_MIDIOUT:
mmr = (MMRESULT)midiMessage((HMIDI)hmo, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
break;
case TYPE_MIDISTRM:
ENTER_MM_HANDLE((HMIDI)hmo);
ReleaseHandleListResource();
mmr = (MMRESULT)midiStreamMessage(HtoPT(PMIDISTRM, hmo)->rgIds, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
LEAVE_MM_HANDLE((HMIDI)hmo);
break;
default:
WinAssert(FALSE);
ReleaseHandleListResource();
mmr = MMSYSERR_INVALHANDLE;
break;
}
}
if (DevInterface) wdmDevInterfaceDec(DevInterface);
return mmr;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutSetVolume | This function sets the volume of a
* MIDI output device.
*
* @parm UINT | uDeviceID | Identifies the MIDI output device.
*
* @parm DWORD | dwVolume | Specifies the new volume setting.
* The low-order UINT contains the left channel volume setting, and the
* high-order UINT contains the right channel setting. A value of
* 0xFFFF represents full volume, and a value of 0x0000 is silence.
*
* If a device does not support both left and right volume
* control, the low-order UINT of <p dwVolume> specifies the volume
* level, and the high-order UINT is ignored.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
* @flag MMSYSERR_NODRIVER | The driver was not installed.
*
* @comm Not all devices support volume changes. To determine whether the
* device supports volume control, use the MIDICAPS_VOLUME
* flag to test the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
* structure (filled by <f midiOutGetDevCaps>).
*
* To determine whether the device supports volume control on both the
* left and right channels, use the MIDICAPS_LRVOLUME flag to test
* the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
* structure (filled by <f midiOutGetDevCaps>).
*
* Most devices do not support the full 16 bits of volume level control
* and will use only the high-order bits of the requested volume setting.
* For example, for a device that supports 4 bits of volume control,
* requested volume level values of 0x4000, 0x4fff, and 0x43be will
* all produce the same physical volume setting, 0x4000. The
* <f midiOutGetVolume> function will return the full 16-bit setting set
* with <f midiOutSetVolume>.
*
* Volume settings are interpreted logarithmically. This means the
* perceived increase in volume is the same when increasing the
* volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
*
* @xref midiOutGetVolume
****************************************************************************/
MMRESULT APIENTRY midiOutSetVolume(HMIDIOUT hmo, DWORD dwVolume)
{
PCWSTR DevInterface;
MMRESULT mmr;
ClientUpdatePnpInfo();
DevInterface = midiReferenceDevInterfaceById(&midioutdrvZ, (UINT_PTR)hmo);
AcquireHandleListResourceShared();
if (BAD_HANDLE(hmo, TYPE_MIDIOUT) && BAD_HANDLE(hmo, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
mmr = midiIDMessage(&midioutdrvZ, wTotalMidiOutDevs, (UINT_PTR)hmo, MODM_SETVOLUME, dwVolume, (DWORD_PTR)DevInterface);
}
else
{
switch(GetHandleType(hmo))
{
case TYPE_MIDIOUT:
mmr = (MMRESULT)midiMessage((HMIDI)hmo, MODM_SETVOLUME, (DWORD)dwVolume, (DWORD_PTR)DevInterface);
break;
case TYPE_MIDISTRM:
ReleaseHandleListResource();
mmr = (MMRESULT)midiStreamBroadcast(HtoPT(PMIDISTRM, hmo), MODM_SETVOLUME, (DWORD)dwVolume, (DWORD_PTR)DevInterface);
break;
default:
ReleaseHandleListResource();
WinAssert(FALSE);
mmr = MMSYSERR_INVALHANDLE;
break;
}
}
if (DevInterface) wdmDevInterfaceDec(DevInterface);
return mmr;
}
/*****************************************************************************
* @doc INTERNAL MIDI
*
* @func MMRESULT | midiGetErrorText | This function retrieves a textual
* description of the error identified by the specified error number.
*
* @parm UINT | wError | Specifies the error number.
*
* @parm LPTSTR | lpText | Specifies a far pointer to a buffer which
* is filled with the textual error description.
*
* @parm UINT | wSize | Specifies the length in characters of the buffer
* pointed to by <p lpText>.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
*
* @comm If the textual error description is longer than the specified buffer,
* the description is truncated. The returned error string is always
* null-terminated. If <p wSize> is zero, nothing is copied and MMSYSERR_NOERROR
* is returned. All error descriptions are less than 80 characters long.
****************************************************************************/
STATIC MMRESULT midiGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
{
lpText[0] = 0;
#if MMSYSERR_BASE
if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
#else
if ((wError > MMSYSERR_LASTERROR) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
#endif
return MMSYSERR_BADERRNUM;
if (wSize > 1)
{
if (!LoadStringW(ghInst, wError, lpText, wSize))
return MMSYSERR_BADERRNUM;
}
return MMSYSERR_NOERROR;
}
STATIC MMRESULT midiGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
{
lpText[0] = 0;
#if MMSYSERR_BASE
if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
#else
if ((wError > MMSYSERR_LASTERROR) && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR)))
#endif
return MMSYSERR_BADERRNUM;
if (wSize > 1)
{
if (!LoadStringA(ghInst, wError, lpText, wSize))
return MMSYSERR_BADERRNUM;
}
return MMSYSERR_NOERROR;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutGetErrorText | This function retrieves a textual
* description of the error identified by the specified error number.
*
* @parm UINT | wError | Specifies the error number.
*
* @parm LPTSTR | lpText | Specifies a far pointer to a buffer to be
* filled with the textual error description.
*
* @parm UINT | wSize | Specifies the length in characters of the buffer
* pointed to by <p lpText>.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
*
* @comm If the textual error description is longer than the specified buffer,
* the description is truncated. The returned error string is always
* null-terminated. If <p wSize> is zero, nothing is copied, and the
* function returns MMSYSERR_NOERROR. All error descriptions are
* less than MAXERRORLENGTH characters long.
****************************************************************************/
MMRESULT APIENTRY midiOutGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
{
if(wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
return midiGetErrorTextW(wError, lpText, wSize);
}
MMRESULT APIENTRY midiOutGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
{
if(wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
return midiGetErrorTextA(wError, lpText, wSize);
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutOpen | This function opens a specified MIDI
* output device for playback.
*
* @parm LPHMIDIOUT | lphMidiOut | Specifies a far pointer to an HMIDIOUT
* handle. This location is filled with a handle identifying the opened
* MIDI output device. Use the handle to identify the device when calling
* other MIDI output functions.
*
* @parm UINT | uDeviceID | Identifies the MIDI output device that is
* to be opened.
*
* @parm DWORD | dwCallback | Specifies the address of a fixed callback
* function or
* a handle to a window called during MIDI playback to process
* messages related to the progress of the playback. Specify NULL
* for this parameter if no callback is desired.
*
* @parm DWORD | dwCallbackInstance | Specifies user instance data
* passed to the callback. This parameter is not used with
* window callbacks.
*
* @parm DWORD | dwFlags | Specifies a callback flag for opening the device.
* @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
* assumed to be a window handle.
* @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
* assumed to be a callback procedure address.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are as follows:
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
* @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
* @flag MIDIERR_NOMAP | There is no current MIDI map. This occurs only
* when opening the mapper.
* @flag MIDIERR_NODEVICE | A port in the current MIDI map doesn't exist.
* This occurs only when opening the mapper.
*
* @comm Use <f midiOutGetNumDevs> to determine the number of MIDI output
* devices present in the system. The device ID specified by <p uDeviceID>
* varies from zero to one less than the number of devices present.
* You may also specify MIDI_MAPPER as the device ID to open the MIDI mapper.
*
* If a window is chosen to receive callback information, the following
* messages are sent to the window procedure function to indicate the
* progress of MIDI output: <m MM_MOM_OPEN>, <m MM_MOM_CLOSE>,
* <m MM_MOM_DONE>.
*
* If a function is chosen to receive callback information, the following
* messages are sent to the function to indicate the progress of MIDI
* output: <m MOM_OPEN>, <m MOM_CLOSE>, <m MOM_DONE>. The callback function
* must reside in a DLL. You do not have to use <f MakeProcInstance> to
* get a procedure-instance address for the callback function.
*
* @cb void CALLBACK | MidiOutFunc | <f MidiOutFunc> is a placeholder for
* the application-supplied function name. The actual name must be
* exported by including it in an EXPORTS statement in the DLL's
* module-definition file.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI device
* associated with the callback.
*
* @parm UINT | wMsg | Specifies a MIDI output message.
*
* @parm DWORD | dwInstance | Specifies the instance data
* supplied with <f midiOutOpen>.
*
* @parm DWORD | dwParam1 | Specifies a parameter for the message.
*
* @parm DWORD | dwParam2 | Specifies a parameter for the message.
*
* @comm Because the callback is accessed at interrupt time, it must reside
* in a DLL and its code segment must be specified as FIXED in the
* module-definition file for the DLL. Any data that the callback accesses
* must be in a FIXED data segment as well. The callback may not make any
* system calls except for <f PostMessage>, <f timeGetSystemTime>,
* <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
* <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
*
* @xref midiOutClose
****************************************************************************/
MMRESULT APIENTRY midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
{
MIDIOPENDESC mo;
PMIDIDEV pdev;
PMIDIDRV mididrv;
UINT port;
MMRESULT wRet;
V_WPOINTER(lphMidiOut, sizeof(HMIDIOUT), MMSYSERR_INVALPARAM);
if (uDeviceID == MIDI_MAPPER) {
V_FLAGS(LOWORD(dwFlags), MIDI_O_VALID & ~LOWORD(MIDI_IO_SHARED | MIDI_IO_COOKED), midiOutOpen, MMSYSERR_INVALFLAG);
} else {
V_FLAGS(LOWORD(dwFlags), MIDI_O_VALID & ~LOWORD(MIDI_IO_COOKED), midiOutOpen, MMSYSERR_INVALFLAG);
}
V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
*lphMidiOut = NULL;
ClientUpdatePnpInfo();
wRet = midiReferenceDriverById(&midioutdrvZ, uDeviceID, &mididrv, &port);
if (wRet)
{
return wRet;
}
//
// check if the device is appropriate for the current TS session
//
if (!(mididrv->fdwDriver & MMDRV_MAPPER) &&
lstrcmpW(mididrv->wszSessProtocol, SessionProtocolName))
{
mregDecUsagePtr(mididrv);
return MMSYSERR_NODRIVER;
}
#ifdef DO_DEFAULT_MIDI_MAPPER
/* Default midi mapper :
*
* If a midi mapper is installed as a separate DLL then all midi mapper
* messages are routed to it. If no midi mapper is installed, simply
* loop through the midi devices looking for a match.
*/
if ((uDeviceID == MIDI_MAPPER && !mididrv->drvMessage)) {
UINT wErr = MMSYSERR_NODRIVER;
UINT cMax;
mregDecUsagePtr(mididrv);
cMax = wTotalMidiOutDevs;
for (uDeviceID=0; uDeviceID<cMax; uDeviceID++) {
wErr = midiOutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags);
if (wErr == MMSYSERR_NOERROR)
break;
}
return wErr;
}
#endif // DO_DEFAULT_MIDI_MAPPER
if (!mididrv->drvMessage)
{
mregDecUsagePtr(mididrv);
return MMSYSERR_NODRIVER;
}
pdev = (PMIDIDEV)NewHandle(TYPE_MIDIOUT, mididrv->cookie, sizeof(MIDIDEV));
if( pdev == NULL)
{
mregDecUsagePtr(mididrv);
return MMSYSERR_NOMEM;
}
ENTER_MM_HANDLE(pdev);
SetHandleFlag(pdev, MMHANDLE_BUSY);
ReleaseHandleListResource();
pdev->mididrv = mididrv;
pdev->wDevice = port;
pdev->uDeviceID = uDeviceID;
pdev->fdwHandle = 0;
mo.hMidi = (HMIDI)pdev;
mo.dwInstance = dwInstance;
mo.dwCallback = dwCallback;
mo.dnDevNode = (DWORD_PTR)pdev->mididrv->cookie;
wRet = (MMRESULT)((*(mididrv->drvMessage))
(pdev->wDevice, MODM_OPEN, (DWORD_PTR)&pdev->dwDrvUser, (DWORD_PTR)(LPMIDIOPENDESC)&mo, dwFlags));
// Mark as not busy on successful open...
if (!wRet)
ClearHandleFlag(pdev, MMHANDLE_BUSY);
LEAVE_MM_HANDLE(pdev);
if (wRet)
FreeHandle((HMIDIOUT)pdev);
else {
// Workaround for Bug#330817
mregIncUsagePtr(mididrv);
*lphMidiOut = (HMIDIOUT)pdev;
}
mregDecUsagePtr(mididrv);
return wRet;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutClose | This function closes the specified MIDI
* output device.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output device.
* If the function is successful, the handle is no longer
* valid after this call.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_STILLPLAYING | There are still buffers in the queue.
*
* @comm If there are output buffers that have been sent with
* <f midiOutLongMsg> and haven't been returned to the application,
* the close operation will fail. Call <f midiOutReset> to mark all
* pending buffers as being done.
*
* @xref midiOutOpen midiOutReset
****************************************************************************/
MMRESULT APIENTRY midiOutClose(HMIDIOUT hMidiOut)
{
MMRESULT wRet;
PMIDIDRV pmididrv;
PMIDIDEV pDev = (PMIDIDEV)hMidiOut;
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
ENTER_MM_HANDLE((HMIDI)hMidiOut);
ReleaseHandleListResource();
if (IsHandleDeserted(hMidiOut))
{
// This handle has been deserted. Let's just free it.
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
FreeHandle(hMidiOut);
return MMSYSERR_NOERROR;
}
if (IsHandleBusy(hMidiOut))
{
// Not quite invalid, but marked as closed.
LEAVE_MM_HANDLE(hMidiOut);
return (MMSYSERR_HANDLEBUSY);
}
// Marking handle as 'invalid/closed'.
SetHandleFlag(hMidiOut, MMHANDLE_BUSY);
pmididrv = pDev->mididrv;
wRet = (MMRESULT)(*pmididrv->drvMessage)(pDev->wDevice, MODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
if (MMSYSERR_NOERROR != wRet)
{
// Error closing, set the flag as valid.
ClearHandleFlag(hMidiOut, MMHANDLE_BUSY);
}
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
if (!wRet)
{
FreeHandle(hMidiOut);
mregDecUsagePtr(pmididrv);
return wRet;
}
return wRet;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutPrepareHeader | This function prepares a MIDI
* system-exclusive data block for output.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
* device.
*
* @parm LPMIDIHDR | lpMidiOutHdr | Specifies a far pointer to a <t MIDIHDR>
* structure that identifies the data block to be prepared.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
*
* @comm The <t MIDIHDR> data structure and the data block pointed to by its
* <e MIDIHDR.lpData> field must be allocated with <f GlobalAlloc> using the
* GMEM_MOVEABLE and GMEM_SHARE flags and locked with <f GlobalLock>.
* Preparing a header that has already been prepared has no effect, and
* the function returns zero.
*
* @xref midiOutUnprepareHeader
****************************************************************************/
MMRESULT APIENTRY midiOutPrepareHeader(HMIDIOUT hMidiOut, LPMIDIHDR lpMidiOutHdr, UINT wSize)
{
MMRESULT wRet;
LPMIDIHDR lpmh;
PMIDISTRM pms;
PMIDISTRMID pmsi;
DWORD idx;
#ifdef DEBUG
DWORD cDrvrs;
#endif
DWORD dwSaveFlags;
V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
if (lpMidiOutHdr->dwFlags & MHDR_PREPARED)
return MMSYSERR_NOERROR;
lpMidiOutHdr->dwFlags = 0;
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
dwSaveFlags = lpMidiOutHdr->dwFlags & MHDR_SAVE;
wRet = midiMessage((HMIDI)hMidiOut, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, (DWORD)wSize);
lpMidiOutHdr->dwFlags &= ~MHDR_SAVE;
lpMidiOutHdr->dwFlags |= dwSaveFlags;
if (MMSYSERR_NOTSUPPORTED == wRet)
return midiPrepareHeader(lpMidiOutHdr, wSize);
return wRet;
case TYPE_MIDISTRM:
ENTER_MM_HANDLE((HMIDI)hMidiOut);
ReleaseHandleListResource();
pms = HtoPT(PMIDISTRM, hMidiOut);
if (lpMidiOutHdr->dwBufferLength > 65536L)
{
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
return MMSYSERR_INVALPARAM;
}
lpmh = (LPMIDIHDR)winmmAlloc(sizeof(MIDIHDR) *
pms->cDrvrs);
if (NULL == lpmh)
{
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
return MMSYSERR_NOMEM;
}
lpMidiOutHdr->dwReserved[MH_SHADOW] = (DWORD_PTR)lpmh;
// assert ((HIWORD(lpmh) & 0xFFFE) != (HIWORD(lpMidiOutHdr) & 0xFFFE));
#ifdef DEBUG
cDrvrs = 0;
#endif
wRet = MMSYSERR_ERROR;
for (idx = 0, pmsi = pms->rgIds; idx < pms->cIds; idx++, pmsi++)
if (pmsi->fdwId & MSI_F_FIRST)
{
*lpmh = *lpMidiOutHdr;
lpmh->dwReserved[MH_PARENT] = (DWORD_PTR)lpMidiOutHdr;
lpmh->dwReserved[MH_SHADOW] = 0;
lpmh->dwFlags =
(lpMidiOutHdr->dwFlags & MHDR_MAPPED) | MHDR_SHADOWHDR;
dwSaveFlags = lpmh->dwFlags & MHDR_SAVE;
wRet = (MMRESULT)midiStreamMessage(pmsi, MODM_PREPARE, (DWORD_PTR)lpmh, (DWORD)sizeof(MIDIHDR));
lpmh->dwFlags &= ~MHDR_SAVE;
lpmh->dwFlags |= dwSaveFlags;
if (MMSYSERR_NOTSUPPORTED == wRet)
wRet = midiPrepareHeader(lpmh, sizeof(MIDIHDR));
if (MMSYSERR_NOERROR != wRet)
break;
lpmh++;
#ifdef DEBUG
++cDrvrs;
if (cDrvrs > pms->cDrvrs)
dprintf1(("!Too many drivers in midiOutPrepareHeader()!!!"));
#endif
}
if (MMSYSERR_NOERROR == wRet)
wRet = midiPrepareHeader(lpMidiOutHdr, wSize);
else
{
for (idx = 0, pmsi = pms->rgIds; idx < pms->cIds; idx++, pmsi++)
if (pmsi->fdwId & MSI_F_FIRST)
{
dwSaveFlags = lpmh->dwFlags & MHDR_SAVE;
wRet = (MMRESULT)midiStreamMessage(pmsi, MODM_UNPREPARE, (DWORD_PTR)lpmh, (DWORD)sizeof(MIDIHDR));
lpmh->dwFlags &= ~MHDR_SAVE;
lpmh->dwFlags |= dwSaveFlags;
if (MMSYSERR_NOTSUPPORTED == wRet)
wRet = midiUnprepareHeader(lpmh, sizeof(MIDIHDR));
}
}
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
return wRet;
default:
ReleaseHandleListResource();
break;
}
return MMSYSERR_INVALHANDLE;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutUnprepareHeader | This function cleans up the
* preparation performed by <f midiOutPrepareHeader>. The
* <f midiOutUnprepareHeader> function must be called
* after the device driver fills a data buffer and returns it to the
* application. You must call this function before freeing the data
* buffer.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
* device.
*
* @parm LPMIDIHDR | lpMidiOutHdr | Specifies a pointer to a <t MIDIHDR>
* structure identifying the buffer to be cleaned up.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_STILLPLAYING | <p lpMidiOutHdr> is still in the queue.
*
* @comm This function is the complementary function to
* <f midiOutPrepareHeader>.
* You must call this function before freeing the data buffer with
* <f GlobalFree>.
* After passing a buffer to the device driver with <f midiOutLongMsg>, you
* must wait until the driver is finished with the buffer before calling
* <f midiOutUnprepareHeader>.
*
* Unpreparing a buffer that has not been
* prepared has no effect, and the function returns zero.
*
* @xref midiOutPrepareHeader
****************************************************************************/
MMRESULT APIENTRY midiOutUnprepareHeader(HMIDIOUT hMidiOut, LPMIDIHDR lpMidiOutHdr, UINT wSize)
{
MMRESULT wRet;
MMRESULT mmrc;
PMIDISTRM pms;
PMIDISTRMID pmsi;
DWORD idx;
LPMIDIHDR lpmh;
DWORD dwSaveFlags;
V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED))
return MMSYSERR_NOERROR;
if(lpMidiOutHdr->dwFlags & MHDR_INQUEUE)
{
DebugErr(DBF_WARNING, "midiOutUnprepareHeader: header still in queue\r\n");
return MIDIERR_STILLPLAYING;
}
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
dwSaveFlags = lpMidiOutHdr->dwFlags & MHDR_SAVE;
wRet = midiMessage((HMIDI)hMidiOut, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, (DWORD)wSize);
lpMidiOutHdr->dwFlags &= ~MHDR_SAVE;
lpMidiOutHdr->dwFlags |= dwSaveFlags;
if (wRet == MMSYSERR_NOTSUPPORTED)
return midiUnprepareHeader(lpMidiOutHdr, wSize);
if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiOut)))
{
// if the driver for the handle has been removed, succeed
// the call.
wRet = MMSYSERR_NOERROR;
}
return wRet;
case TYPE_MIDISTRM:
ENTER_MM_HANDLE((HMIDI)hMidiOut);
ReleaseHandleListResource();
pms = HtoPT(PMIDISTRM, hMidiOut);
wRet = MMSYSERR_NOERROR;
lpmh = (LPMIDIHDR)lpMidiOutHdr->dwReserved[MH_SHADOW];
// assert ((HIWORD(lpmh) & 0xFFFE) != (HIWORD(lpMidiOutHdr) & 0xFFFE));
for (idx = 0, pmsi = pms->rgIds; idx < pms->cIds; idx++, pmsi++)
if (pmsi->fdwId & MSI_F_FIRST)
{
dwSaveFlags = lpmh->dwFlags & MHDR_SAVE;
mmrc = (MMRESULT)midiStreamMessage(pmsi, MODM_UNPREPARE, (DWORD_PTR)lpmh, (DWORD)sizeof(MIDIHDR));
lpmh->dwFlags &= ~MHDR_SAVE;
lpmh->dwFlags |= dwSaveFlags;
if (MMSYSERR_NOTSUPPORTED == mmrc)
mmrc = midiUnprepareHeader(lpmh, sizeof(MIDIHDR));
if (MMSYSERR_NOERROR != mmrc)
wRet = mmrc;
lpmh++;
}
// assert (HIWORD(lpmh) == HIWORD(lpMidiOutHdr->dwReserved[MH_SHADOW]));
GlobalFree(GlobalHandle((LPMIDIHDR)lpMidiOutHdr->dwReserved[MH_SHADOW]));
lpMidiOutHdr->dwReserved[MH_SHADOW] = 0;
mmrc = midiUnprepareHeader(lpMidiOutHdr, wSize);
if (MMSYSERR_NOERROR != mmrc)
wRet = mmrc;
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
return wRet;
default:
ReleaseHandleListResource();
break;
}
return MMSYSERR_INVALHANDLE;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutShortMsg | This function sends a short MIDI message to
* the specified MIDI output device. Use this function to send any MIDI
* message except for system-exclusive messages.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
* device.
*
* @parm DWORD | dwMsg | Specifies the MIDI message. The message is packed
* into a DWORD with the first byte of the message in the low-order byte.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_NOTREADY | The hardware is busy with other data.
*
* @comm This function may not return until the message has been sent to the
* output device.
*
* @xref midiOutLongMsg
****************************************************************************/
MMRESULT APIENTRY midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
{
MMRESULT mmr;
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
return (MMRESULT)midiMessage((HMIDI)hMidiOut, MODM_DATA, dwMsg, 0L);
case TYPE_MIDISTRM:
ENTER_MM_HANDLE((HMIDI)hMidiOut);
ReleaseHandleListResource();
mmr = (MMRESULT)midiStreamMessage(HtoPT(PMIDISTRM, hMidiOut)->rgIds, MODM_DATA, dwMsg, 0L);
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
return (mmr);
}
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutLongMsg | This function sends a system-exclusive
* MIDI message to the specified MIDI output device.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
* device.
*
* @parm LPMIDIHDR | lpMidiOutHdr | Specifies a far pointer to a <t MIDIHDR>
* structure that identifies the MIDI data buffer.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_UNPREPARED | <p lpMidiOutHdr> hasn't been prepared.
* @flag MIDIERR_NOTREADY | The hardware is busy with other data.
*
* @comm The data buffer must be prepared with <f midiOutPrepareHeader>
* before it is passed to <f midiOutLongMsg>. The <t MIDIHDR> data
* structure and the data buffer pointed to by its <e MIDIHDR.lpData>
* field must be allocated with <f GlobalAlloc> using the GMEM_MOVEABLE
* and GMEM_SHARE flags, and locked with <f GlobalLock>. The MIDI output
* device driver determines whether the data is sent synchronously or
* asynchronously.
*
* @xref midiOutShortMsg midiOutPrepareHeader
****************************************************************************/
MMRESULT APIENTRY midiOutLongMsg(HMIDIOUT hMidiOut, LPMIDIHDR lpMidiOutHdr, UINT wSize)
{
V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
if (lpMidiOutHdr->dwFlags & ~MHDR_VALID)
return MMSYSERR_INVALFLAG;
if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED))
return MIDIERR_UNPREPARED;
if (lpMidiOutHdr->dwFlags & MHDR_INQUEUE)
return MIDIERR_STILLPLAYING;
if (!lpMidiOutHdr->dwBufferLength)
return MMSYSERR_INVALPARAM;
lpMidiOutHdr->dwFlags &= ~MHDR_ISSTRM;
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
return (MMRESULT)midiMessage((HMIDI)hMidiOut, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, (DWORD)wSize);
case TYPE_MIDISTRM:
ReleaseHandleListResource();
return MMSYSERR_NOTSUPPORTED;
default:
ReleaseHandleListResource();
break;
}
return MMSYSERR_INVALHANDLE;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutReset | This function turns off all notes on all MIDI
* channels for the specified MIDI output device. Any pending
* system-exclusive output buffers are marked as done and
* returned to the application.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
* device.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
*
* @comm To turn off all notes, a note-off message for each note for each
* channel is sent. In addition, the sustain controller is turned off for
* each channel.
*
* @xref midiOutLongMsg midiOutClose
****************************************************************************/
MMRESULT APIENTRY midiOutReset(HMIDIOUT hMidiOut)
{
PMIDISTRM pms;
MMRESULT mmr;
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
mmr = (MMRESULT)midiMessage((HMIDI)hMidiOut, MODM_RESET, 0, 0);
break;
case TYPE_MIDISTRM:
pms = HtoPT(PMIDISTRM, hMidiOut);
ReleaseHandleListResource();
mmr = (MMRESULT)midiStreamBroadcast(pms, MODM_RESET, 0, 0);
break;
default:
ReleaseHandleListResource();
mmr = MMSYSERR_INVALHANDLE;
break;
}
if ((mmr == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiOut)))
{
mmr = MMSYSERR_NOERROR;
}
return mmr;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutCachePatches | This function requests that an internal
* MIDI synthesizer device preload a specified set of patches. Some
* synthesizers are not capable of keeping all patches loaded simultaneously
* and must load data from disk when they receive MIDI program change
* messages. Caching patches ensures specified patches are immediately
* available.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the opened MIDI output
* device. This device must be an internal MIDI synthesizer.
*
* @parm UINT | wBank | Specifies which bank of patches should be used.
* This parameter should be set to zero to cache the default patch bank.
*
* @parm LPWORD | lpPatchArray | Specifies a pointer to a <t PATCHARRAY>
* array indicating the patches to be cached or uncached.
*
* @parm UINT | wFlags | Specifies options for the cache operation. Only one
* of the following flags can be specified:
* @flag MIDI_CACHE_ALL | Cache all of the specified patches. If they
* can't all be cached, cache none, clear the <t PATCHARRAY> array,
* and return MMSYSERR_NOMEM.
* @flag MIDI_CACHE_BESTFIT | Cache all of the specified patches.
* If all patches can't be cached, cache as many patches as
* possible, change the <t PATCHARRAY> array to reflect which
* patches were cached, and return MMSYSERR_NOMEM.
* @flag MIDI_CACHE_QUERY | Change the <t PATCHARRAY> array to indicate
* which patches are currently cached.
* @flag MIDI_UNCACHE | Uncache the specified patches and clear the
* <t PATCHARRAY> array.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* one of the following error codes:
* @flag MMSYSERR_INVALHANDLE | The specified device handle is invalid.
* @flag MMSYSERR_NOTSUPPORTED | The specified device does not support
* patch caching.
* @flag MMSYSERR_NOMEM | The device does not have enough memory to cache
* all of the requested patches.
*
* @comm The <t PATCHARRAY> data type is defined as:
*
* typedef UINT PATCHARRAY[MIDIPATCHSIZE];
*
* Each element of the array represents one of the 128 patches and
* has bits set for
* each of the 16 MIDI channels that use that particular patch. The
* least-significant bit represents physical channel 0; the
* most-significant bit represents physical channel 15 (0x0F). For
* example, if patch 0 is used by physical channels 0 and 8, element 0
* would be set to 0x0101.
*
* This function only applies to internal MIDI synthesizer devices.
* Not all internal synthesizers support patch caching. Use the
* MIDICAPS_CACHE flag to test the <e MIDIOUTCAPS.dwSupport> field of the
* <t MIDIOUTCAPS> structure filled by <f midiOutGetDevCaps> to see if the
* device supports patch caching.
*
* @xref midiOutCacheDrumPatches
****************************************************************************/
MMRESULT APIENTRY midiOutCachePatches(HMIDIOUT hMidiOut, UINT wBank,
LPWORD lpPatchArray, UINT wFlags)
{
V_WPOINTER(lpPatchArray, sizeof(PATCHARRAY), MMSYSERR_INVALPARAM);
V_FLAGS(wFlags, MIDI_CACHE_VALID, midiOutCacheDrumPatches, MMSYSERR_INVALFLAG);
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
return (MMRESULT)midiMessage((HMIDI)hMidiOut,
MODM_CACHEPATCHES,
(DWORD_PTR)lpPatchArray,
MAKELONG(wFlags, wBank));
case TYPE_MIDISTRM:
ReleaseHandleListResource();
return (MMRESULT)midiStreamBroadcast((PMIDISTRM)hMidiOut,
MODM_CACHEPATCHES,
(DWORD_PTR)lpPatchArray,
MAKELONG(wFlags, wBank));
default:
ReleaseHandleListResource();
break;
}
return MMSYSERR_INVALHANDLE;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutCacheDrumPatches | This function requests that an
* internal MIDI synthesizer device preload a specified set of key-based
* percussion patches. Some synthesizers are not capable of keeping all
* percussion patches loaded simultaneously. Caching patches ensures
* specified patches are available.
*
* @parm HMIDIOUT | hMidiOut | Specifies a handle to the opened MIDI output
* device. This device should be an internal MIDI synthesizer.
*
* @parm UINT | wPatch | Specifies which drum patch number should be used.
* This parameter should be set to zero to cache the default drum patch.
*
* @parm LPWORD | lpKeyArray | Specifies a pointer to a <t KEYARRAY>
* array indicating the key numbers of the specified percussion patches
* to be cached or uncached.
*
* @parm UINT | wFlags | Specifies options for the cache operation. Only one
* of the following flags can be specified:
* @flag MIDI_CACHE_ALL | Cache all of the specified patches. If they
* can't all be cached, cache none, clear the <t KEYARRAY> array,
* and return MMSYSERR_NOMEM.
* @flag MIDI_CACHE_BESTFIT | Cache all of the specified patches.
* If all patches can't be cached, cache as many patches as
* possible, change the <t KEYARRAY> array to reflect which
* patches were cached, and return MMSYSERR_NOMEM.
* @flag MIDI_CACHE_QUERY | Change the <t KEYARRAY> array to indicate
* which patches are currently cached.
* @flag MIDI_UNCACHE | Uncache the specified patches and clear the
* <t KEYARRAY> array.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* one of the following error codes:
* @flag MMSYSERR_INVALHANDLE | The specified device handle is invalid.
* @flag MMSYSERR_NOTSUPPORTED | The specified device does not support
* patch caching.
* @flag MMSYSERR_NOMEM | The device does not have enough memory to cache
* all of the requested patches.
*
* @comm The <t KEYARRAY> data type is defined as:
*
* typedef UINT KEYARRAY[MIDIPATCHSIZE];
*
* Each element of the array represents one of the 128 key-based percussion
* patches and has bits set for
* each of the 16 MIDI channels that use that particular patch. The
* least-significant bit represents physical channel 0; the
* most-significant bit represents physical channel 15. For
* example, if the patch on key number 60 is used by physical channels 9
* and 15, element 60 would be set to 0x8200.
*
* This function applies only to internal MIDI synthesizer devices.
* Not all internal synthesizers support patch caching. Use the
* MIDICAPS_CACHE flag to test the <e MIDIOUTCAPS.dwSupport> field of the
* <t MIDIOUTCAPS> structure filled by <f midiOutGetDevCaps> to see if the
* device supports patch caching.
*
* @xref midiOutCachePatches
****************************************************************************/
MMRESULT APIENTRY midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT wPatch,
LPWORD lpKeyArray, UINT wFlags)
{
V_WPOINTER(lpKeyArray, sizeof(KEYARRAY), MMSYSERR_INVALPARAM);
V_FLAGS(wFlags, MIDI_CACHE_VALID, midiOutCacheDrumPatches, MMSYSERR_INVALFLAG);
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiOut, TYPE_MIDIOUT) && BAD_HANDLE(hMidiOut, TYPE_MIDISTRM))
{
ReleaseHandleListResource();
return MMSYSERR_INVALHANDLE;
}
switch(GetHandleType(hMidiOut))
{
case TYPE_MIDIOUT:
return (MMRESULT)midiMessage((HMIDI)hMidiOut,
MODM_CACHEDRUMPATCHES,
(DWORD_PTR)lpKeyArray,
MAKELONG(wFlags, wPatch));
case TYPE_MIDISTRM:
ReleaseHandleListResource();
return (MMRESULT)midiStreamBroadcast((PMIDISTRM)hMidiOut,
MODM_CACHEDRUMPATCHES,
(DWORD_PTR)lpKeyArray,
MAKELONG(wFlags, wPatch));
default:
ReleaseHandleListResource();
break;
}
return MMSYSERR_INVALHANDLE;
}
//--------------------------------------------------------------------------;
//
// MMRESULT midiOutDesertHandle
//
// Description:
// Cleans up the midi out handle and marks it as deserted.
//
// Arguments:
// HMIDIOUT hMidiOut: MIDI out handle.
//
// Return (MMRESULT): Error code.
//
// History:
// 01/25/99 Fwong Adding Pnp Support.
//
//--------------------------------------------------------------------------;
MMRESULT midiOutDesertHandle
(
HMIDIOUT hMidiOut
)
{
MMRESULT mmr;
PMIDIDEV pDev = (PMIDIDEV)hMidiOut;
V_HANDLE_ACQ(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
ENTER_MM_HANDLE((HMIDI)hMidiOut);
ReleaseHandleListResource();
if (IsHandleDeserted(hMidiOut))
{
// Handle has already been deserted...
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
return(MMSYSERR_NOERROR);
}
if (IsHandleBusy(hMidiOut))
{
// Not quite invalid, but marked as closed.
LEAVE_MM_HANDLE(hMidiOut);
return (MMSYSERR_HANDLEBUSY);
}
// Marking handle as deserted
SetHandleFlag(hMidiOut, MMHANDLE_DESERTED);
// Since the handle was invalidated, we have to send the message ourselves...
(*(pDev->mididrv->drvMessage))(pDev->wDevice, MODM_RESET, pDev->dwDrvUser, 0L, 0L);
(*(pDev->mididrv->drvMessage))(pDev->wDevice, MODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
LEAVE_MM_HANDLE((HMIDI)hMidiOut);
// ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
// dec on close instead.
mregDecUsage(PTtoH(HMD, pDev->mididrv));
// Mark handle as deserted, but not freeing.
return MMSYSERR_NOERROR;
} // midiOutDesertHandle()
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api UINT | midiInGetNumDevs | This function retrieves the number of MIDI
* input devices in the system.
*
* @rdesc Returns the number of MIDI input devices present in the system.
*
* @xref midiInGetDevCaps
****************************************************************************/
UINT APIENTRY midiInGetNumDevs(void)
{
UINT cDevs;
ClientUpdatePnpInfo();
EnterNumDevs("midiInGetNumDevs");
cDevs = wTotalMidiInDevs;
LeaveNumDevs("midiInGetNumDevs");
return cDevs;
}
/****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInMessage | This function sends messages to the MIDI device
* drivers.
*
* @parm HMIDIIN | hMidiIn | The handle to the MIDI device.
*
* @parm UINT | msg | The message to send.
*
* @parm DWORD | dw1 | Parameter 1.
*
* @parm DWORD | dw2 | Parameter 2.
*
* @rdesc Returns the value of the message sent.
***************************************************************************/
MMRESULT APIENTRY midiInMessage(HMIDIIN hMidiIn, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
{
ClientUpdatePnpInfo();
AcquireHandleListResourceShared();
if (BAD_HANDLE(hMidiIn, TYPE_MIDIIN))
{
ReleaseHandleListResource();
return midiIDMessage(&midiindrvZ, wTotalMidiInDevs, (UINT_PTR)hMidiIn, msg, dw1, dw2);
}
return midiMessage((HMIDI)hMidiIn, msg, dw1, dw2);
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInGetDevCaps | This function queries a specified MIDI input
* device to determine its capabilities.
*
* @parm UINT | uDeviceID | Identifies the MIDI input device.
*
* @parm LPMIDIINCAPS | lpCaps | Specifies a far pointer to a <t MIDIINCAPS>
* data structure. This structure is filled with information about
* the capabilities of the device.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIINCAPS> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
* @flag MMSYSERR_NODRIVER | The driver was not installed.
*
* @comm Use <f midiInGetNumDevs> to determine the number of MIDI input
* devices present in the system. The device ID specified by <p uDeviceID>
* varies from zero to one less than the number of devices present.
* The MIDI_MAPPER constant may also be used as a device id. Only
* <p wSize> bytes (or less) of information is copied to the location
* pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied,
* and the function returns zero.
*
* @xref midiInGetNumDevs
****************************************************************************/
MMRESULT APIENTRY midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT wSize)
{
DWORD_PTR dwParam1, dwParam2;
MDEVICECAPSEX mdCaps;
PCWSTR DevInterface;
MMRESULT mmr;
if (wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
ClientUpdatePnpInfo();
DevInterface = midiReferenceDevInterfaceById(&midiindrvZ, uDeviceID);
dwParam2 = (DWORD_PTR)DevInterface;
if (0 == dwParam2)
{
dwParam1 = (DWORD_PTR)lpCaps;
dwParam2 = (DWORD)wSize;
}
else
{
mdCaps.cbSize = (DWORD)wSize;
mdCaps.pCaps = lpCaps;
dwParam1 = (DWORD_PTR)&mdCaps;
}
AcquireHandleListResourceShared();
if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIIN))
{
ReleaseHandleListResource();
mmr = midiIDMessage(&midiindrvZ, wTotalMidiInDevs, uDeviceID, MIDM_GETDEVCAPS, dwParam1, dwParam2);
}
else
{
mmr = (MMRESULT)midiMessage((HMIDI)uDeviceID, MIDM_GETDEVCAPS, dwParam1, dwParam2);
}
if (DevInterface) wdmDevInterfaceDec(DevInterface);
return mmr;
}
MMRESULT APIENTRY midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT wSize)
{
MIDIINCAPS2W wDevCaps2;
MIDIINCAPS2A aDevCaps2;
DWORD_PTR dwParam1, dwParam2;
MDEVICECAPSEX mdCaps;
PCWSTR DevInterface;
MMRESULT mmRes;
CHAR chTmp[ MAXPNAMELEN * sizeof(WCHAR) ];
if (wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
ClientUpdatePnpInfo();
DevInterface = midiReferenceDevInterfaceById(&midiindrvZ, uDeviceID);
dwParam2 = (DWORD_PTR)DevInterface;
memset(&wDevCaps2, 0, sizeof(wDevCaps2));
if (0 == dwParam2)
{
dwParam1 = (DWORD_PTR)&wDevCaps2;
dwParam2 = (DWORD)sizeof(wDevCaps2);
}
else
{
mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
mdCaps.pCaps = &wDevCaps2;
dwParam1 = (DWORD_PTR)&mdCaps;
}
AcquireHandleListResourceShared();
if (BAD_HANDLE((HMIDI)uDeviceID, TYPE_MIDIIN))
{
ReleaseHandleListResource();
mmRes = midiIDMessage( &midiindrvZ, wTotalMidiInDevs, uDeviceID,
MIDM_GETDEVCAPS, dwParam1, dwParam2);
}
else
{
mmRes = midiMessage((HMIDI)uDeviceID, MIDM_GETDEVCAPS,
(DWORD)dwParam1, (DWORD)dwParam2);
}
if (DevInterface) wdmDevInterfaceDec(DevInterface);
//
// Make sure the call worked before proceeding with the thunk.
//
if ( mmRes != MMSYSERR_NOERROR ) {
return mmRes;
}
aDevCaps2.wMid = wDevCaps2.wMid;
aDevCaps2.wPid = wDevCaps2.wPid;
aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
aDevCaps2.dwSupport = wDevCaps2.dwSupport;
aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
aDevCaps2.NameGuid = wDevCaps2.NameGuid;
// copy and convert unicode to ascii here.
UnicodeStrToAsciiStr( chTmp, chTmp + sizeof( chTmp ), wDevCaps2.szPname );
strcpy( aDevCaps2.szPname, chTmp );
//
// now copy the required amount into the callers buffer.
//
CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
return mmRes;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInGetErrorText | This function retrieves a textual
* description of the error identified by the specified error number.
*
* @parm UINT | wError | Specifies the error number.
*
* @parm LPTSTR | lpText | Specifies a far pointer to the buffer to be
* filled with the textual error description.
*
* @parm UINT | wSize | Specifies the length in characters of the buffer
* pointed to by <p lpText>.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
*
* @comm If the textual error description is longer than the specified buffer,
* the description is truncated. The returned error string is always
* null-terminated. If <p wSize> is zero, nothing is copied, and
* the function returns zero. All error descriptions are
* less than MAXERRORLENGTH characters long.
****************************************************************************/
MMRESULT APIENTRY midiInGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
{
if(wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
return midiGetErrorTextW(wError, lpText, wSize);
}
MMRESULT APIENTRY midiInGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
{
if(wSize == 0)
return MMSYSERR_NOERROR;
V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
return midiGetErrorTextA(wError, lpText, wSize);
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInOpen | This function opens a specified MIDI input device.
*
* @parm LPHMIDIIN | lphMidiIn | Specifies a far pointer to an HMIDIIN handle.
* This location is filled with a handle identifying the opened MIDI
* input device. Use the handle to identify the device when calling
* other MIDI input functions.
*
* @parm UINT | uDeviceID | Identifies the MIDI input device to be
* opened.
*
* @parm DWORD | dwCallback | Specifies the address of a fixed callback
* function or a handle to a window called with information
* about incoming MIDI messages.
*
* @parm DWORD | dwCallbackInstance | Specifies user instance data
* passed to the callback function. This parameter is not
* used with window callbacks.
*
* @parm DWORD | dwFlags | Specifies a callback flag for opening the device.
* @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
* assumed to be a window handle.
* @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
* assumed to be a callback procedure address.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
* @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
*
* @comm Use <f midiInGetNumDevs> to determine the number of MIDI input
* devices present in the system. The device ID specified by <p uDeviceID>
* varies from zero to one less than the number of devices present.
* The MIDI_MAPPER constant may also be used as a device id.
*
* If a window is chosen to receive callback information, the following
* messages are sent to the window procedure function to indicate the
* progress of MIDI input: <m MM_MIM_OPEN>, <m MM_MIM_CLOSE>,
* <m MM_MIM_DATA>, <m MM_MIM_LONGDATA>, <m MM_MIM_ERROR>,
* <m MM_MIM_LONGERROR>.
*
* If a function is chosen to receive callback information, the following
* messages are sent to the function to indicate the progress of MIDI
* input: <m MIM_OPEN>, <m MIM_CLOSE>, <m MIM_DATA>, <m MIM_LONGDATA>,
* <m MIM_ERROR>, <m MIM_LONGERROR>. The callback function must reside in
* a DLL. You do not have to use <f MakeProcInstance> to get a
* procedure-instance address for the callback function.
*
* @cb void CALLBACK | MidiInFunc | <f MidiInFunc> is a placeholder for
* the application-supplied function name. The actual name must be
* exported by including it in an EXPORTS statement in the DLL's module
* definition file.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
*
* @parm UINT | wMsg | Specifies a MIDI input message.
*
* @parm DWORD | dwInstance | Specifies the instance data supplied
* with <f midiInOpen>.
*
* @parm DWORD | dwParam1 | Specifies a parameter for the message.
*
* @parm DWORD | dwParam2 | Specifies a parameter for the message.
*
* @comm Because the callback is accessed at interrupt time, it must reside
* in a DLL, and its code segment must be specified as FIXED in the
* module-definition file for the DLL. Any data that the callback accesses
* must be in a FIXED data segment as well. The callback may not make any
* system calls except for <f PostMessage>, <f timeGetSystemTime>,
* <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
* <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
*
* @xref midiInClose
****************************************************************************/
MMRESULT APIENTRY midiInOpen(LPHMIDIIN lphMidiIn, UINT uDeviceID,
DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
{
MIDIOPENDESC mo;
PMIDIDEV pdev;
PMIDIDRV mididrv;
UINT port;
MMRESULT wRet;
V_WPOINTER(lphMidiIn, sizeof(HMIDIIN), MMSYSERR_INVALPARAM);
if (uDeviceID == MIDI_MAPPER) {
V_FLAGS(LOWORD(dwFlags), MIDI_I_VALID & ~LOWORD(MIDI_IO_COOKED | MIDI_IO_SHARED), midiInOpen, MMSYSERR_INVALFLAG);
} else {
V_FLAGS(LOWORD(dwFlags), MIDI_I_VALID & ~LOWORD(MIDI_IO_COOKED) , midiInOpen, MMSYSERR_INVALFLAG);
}
V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
*lphMidiIn = NULL;
ClientUpdatePnpInfo();
wRet = midiReferenceDriverById(&midiindrvZ, uDeviceID, &mididrv, &port);
if (wRet)
{
return wRet;
}
if (!mididrv->drvMessage)
{
mregDecUsagePtr(mididrv);
return MMSYSERR_NODRIVER;
}
pdev = (PMIDIDEV)NewHandle(TYPE_MIDIIN, mididrv->cookie, sizeof(MIDIDEV));
if( pdev == NULL)
{
mregDecUsagePtr(mididrv);
return MMSYSERR_NOMEM;
}
ENTER_MM_HANDLE(pdev);
SetHandleFlag(pdev, MMHANDLE_BUSY);
ReleaseHandleListResource();
pdev->mididrv = mididrv;
pdev->wDevice = port;
pdev->uDeviceID = uDeviceID;
pdev->fdwHandle = 0;
mo.hMidi = (HMIDI)pdev;
mo.dwCallback = dwCallback;
mo.dwInstance = dwInstance;
mo.dnDevNode = (DWORD_PTR)pdev->mididrv->cookie;
wRet = (MMRESULT)((*(mididrv->drvMessage))
(pdev->wDevice, MIDM_OPEN, (DWORD_PTR)&pdev->dwDrvUser, (DWORD_PTR)(LPMIDIOPENDESC)&mo, dwFlags));
if (!wRet)
ClearHandleFlag(pdev, MMHANDLE_BUSY);
LEAVE_MM_HANDLE(pdev);
if (wRet)
FreeHandle((HMIDIIN)pdev);
else {
mregIncUsagePtr(mididrv);
*lphMidiIn = (HMIDIIN)pdev;
}
mregDecUsagePtr(mididrv);
return wRet;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInClose | This function closes the specified MIDI input
* device.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
* If the function is successful, the handle is no longer
* valid after this call.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_STILLPLAYING | There are still buffers in the queue.
*
* @comm If there are input buffers that have been sent with
* <f midiInAddBuffer> and haven't been returned to the application,
* the close operation will fail. Call <f midiInReset> to mark all
* pending buffers as being done.
*
* @xref midiInOpen midiInReset
****************************************************************************/
MMRESULT APIENTRY midiInClose(HMIDIIN hMidiIn)
{
MMRESULT wRet;
PMIDIDRV pmididrv;
PMIDIDEV pDev = (PMIDIDEV)hMidiIn;
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
ENTER_MM_HANDLE((HMIDI)hMidiIn);
ReleaseHandleListResource();
if (IsHandleDeserted(hMidiIn))
{
// This handle has been deserted. Let's just free it.
LEAVE_MM_HANDLE((HMIDI)hMidiIn);
FreeHandle(hMidiIn);
return MMSYSERR_NOERROR;
}
if (IsHandleBusy(hMidiIn))
{
// Not quite invalid, but marked as closed.
LEAVE_MM_HANDLE(hMidiIn);
return (MMSYSERR_HANDLEBUSY);
}
// Marking handle as 'invalid/closed'.
SetHandleFlag(hMidiIn, MMHANDLE_BUSY);
pmididrv = pDev->mididrv;
wRet = (MMRESULT)(*(pmididrv->drvMessage))(pDev->wDevice, MIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
if (MMSYSERR_NOERROR != wRet)
{
ClearHandleFlag(hMidiIn, MMHANDLE_BUSY);
}
LEAVE_MM_HANDLE((HWAVE)hMidiIn);
if (!wRet)
{
FreeHandle(hMidiIn);
mregDecUsagePtr(pmididrv);
return wRet;
}
return wRet;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInPrepareHeader | This function prepares a buffer for
* MIDI input.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input
* device.
*
* @parm LPMIDIHDR | lpMidiInHdr | Specifies a pointer to a <t MIDIHDR>
* structure that identifies the buffer to be prepared.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
*
* @comm The <t MIDIHDR> data structure and the data block pointed to by its
* <e MIDIHDR.lpData> field must be allocated with <f GlobalAlloc> using the
* GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
* Preparing a header that has already been prepared has no effect,
* and the function returns zero.
*
* @xref midiInUnprepareHeader
****************************************************************************/
MMRESULT APIENTRY midiInPrepareHeader(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr, UINT wSize)
{
MMRESULT wRet;
V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
if (lpMidiInHdr->dwFlags & MHDR_PREPARED)
return MMSYSERR_NOERROR;
lpMidiInHdr->dwFlags = 0;
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
wRet = midiMessage((HMIDI)hMidiIn, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, (DWORD)wSize);
if (wRet == MMSYSERR_NOTSUPPORTED)
return midiPrepareHeader(lpMidiInHdr, wSize);
return wRet;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInUnprepareHeader | This function cleans up the
* preparation performed by <f midiInPrepareHeader>. The
* <f midiInUnprepareHeader> function must be called
* after the device driver fills a data buffer and returns it to the
* application. You must call this function before freeing the data
* buffer.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input
* device.
*
* @parm LPMIDIHDR | lpMidiInHdr | Specifies a pointer to a <t MIDIHDR>
* structure identifying the data buffer to be cleaned up.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_STILLPLAYING | <p lpMidiInHdr> is still in the queue.
*
* @comm This function is the complementary function to <f midiInPrepareHeader>.
* You must call this function before freeing the data buffer with
* <f GlobalFree>.
* After passing a buffer to the device driver with <f midiInAddBuffer>, you
* must wait until the driver is finished with the buffer before calling
* <f midiInUnprepareHeader>. Unpreparing a buffer that has not been
* prepared has no effect, and the function returns zero.
*
* @xref midiInPrepareHeader
****************************************************************************/
MMRESULT APIENTRY midiInUnprepareHeader(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr, UINT wSize)
{
MMRESULT wRet;
V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED))
return MMSYSERR_NOERROR;
if(lpMidiInHdr->dwFlags & MHDR_INQUEUE)
{
DebugErr(DBF_WARNING, "midiInUnprepareHeader: header still in queue\r\n");
return MIDIERR_STILLPLAYING;
}
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
wRet = midiMessage((HMIDI)hMidiIn, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, (DWORD)wSize);
if (wRet == MMSYSERR_NOTSUPPORTED)
return midiUnprepareHeader(lpMidiInHdr, wSize);
if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiIn)))
{
// if the driver for the handle has been removed, succeed the call.
wRet = MMSYSERR_NOERROR;
}
return wRet;
}
/******************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInAddBuffer | This function sends an input buffer
* to a specified opened MIDI input device. When the buffer is filled,
* it is sent back to the application. Input buffers are
* used only for system-exclusive messages.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
*
* @parm LPMIDIHDR | lpMidiInHdr | Specifies a far pointer to a <t MIDIHDR>
* structure that identifies the buffer.
*
* @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
* @flag MIDIERR_UNPREPARED | <p lpMidiInHdr> hasn't been prepared.
*
* @comm The data buffer must be prepared with <f midiInPrepareHeader> before
* it is passed to <f midiInAddBuffer>. The <t MIDIHDR> data structure
* and the data buffer pointed to by its <e MIDIHDR.lpData> field must be allocated
* with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
* locked with <f GlobalLock>.
*
* @xref midiInPrepareHeader
*****************************************************************************/
MMRESULT APIENTRY midiInAddBuffer(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr, UINT wSize)
{
V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED))
{
DebugErr(DBF_WARNING, "midiInAddBuffer: buffer not prepared\r\n");
return MIDIERR_UNPREPARED;
}
if (lpMidiInHdr->dwFlags & MHDR_INQUEUE)
{
DebugErr(DBF_WARNING, "midiInAddBuffer: buffer already in queue\r\n");
return MIDIERR_STILLPLAYING;
}
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
return midiMessage((HMIDI)hMidiIn, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, (DWORD)wSize);
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInStart | This function starts MIDI input on the
* specified MIDI input device.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
*
* @comm This function resets the timestamps to zero; timestamp values for
* subsequently received messages are relative to the time this
* function was called.
*
* All messages other than system-exclusive messages are sent
* directly to the client when received. System-exclusive
* messages are placed in the buffers supplied by <f midiInAddBuffer>;
* if there are no buffers in the queue,
* the data is thrown away without notification to the client, and input
* continues.
*
* Buffers are returned to the client when full, when a
* complete system-exclusive message has been received,
* or when <f midiInReset> is
* called. The <e MIDIHDR.dwBytesRecorded> field in the header will contain the
* actual length of data received.
*
* Calling this function when input is already started has no effect, and
* the function returns zero.
*
* @xref midiInStop midiInReset
****************************************************************************/
MMRESULT APIENTRY midiInStart(HMIDIIN hMidiIn)
{
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
return midiMessage((HMIDI)hMidiIn, MIDM_START, 0L, 0L);
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInStop | This function terminates MIDI input on the
* specified MIDI input device.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
*
* @comm Current status (running status, parsing state, etc.) is maintained
* across calls to <f midiInStop> and <f midiInStart>.
* If there are any system-exclusive message buffers in the queue,
* the current buffer
* is marked as done (the <e MIDIHDR.dwBytesRecorded> field in the header will
* contain the actual length of data), but any empty buffers in the queue
* remain there. Calling this function when input is not started has no
* no effect, and the function returns zero.
*
* @xref midiInStart midiInReset
****************************************************************************/
MMRESULT APIENTRY midiInStop(HMIDIIN hMidiIn)
{
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
return midiMessage((HMIDI)hMidiIn, MIDM_STOP, 0L, 0L);
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInReset | This function stops input on a given MIDI
* input device and marks all pending input buffers as done.
*
* @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
*
* @rdesc Returns zero if the function was successful. Otherwise, it returns
* an error number. Possible error returns are:
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
*
* @xref midiInStart midiInStop midiInAddBuffer midiInClose
****************************************************************************/
MMRESULT APIENTRY midiInReset(HMIDIIN hMidiIn)
{
MMRESULT mmr;
ClientUpdatePnpInfo();
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
mmr = midiMessage((HMIDI)hMidiIn, MIDM_RESET, 0L, 0L);
if ((mmr == MMSYSERR_NODRIVER) && (IsHandleDeserted(hMidiIn)))
{
mmr = MMSYSERR_NOERROR;
}
return mmr;
}
//--------------------------------------------------------------------------;
//
// MMRESULT midiInDesertHandle
//
// Description:
// Cleans up the midi in handle and marks it as deserted.
//
// Arguments:
// HMIDIIN hMidiIn: MIDI in handle.
//
// Return (MMRESULT): Error code.
//
// History:
// 01/25/99 Fwong Adding Pnp Support.
//
//--------------------------------------------------------------------------;
MMRESULT midiInDesertHandle
(
HMIDIIN hMidiIn
)
{
MMRESULT mmr;
PMIDIDEV pDev = (PMIDIDEV)hMidiIn;
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
ENTER_MM_HANDLE((HMIDI)hMidiIn);
ReleaseHandleListResource();
if (IsHandleDeserted(hMidiIn))
{
LEAVE_MM_HANDLE((HMIDI)hMidiIn);
return (MMSYSERR_NOERROR);
}
if (IsHandleBusy(hMidiIn))
{
// Not quite invalid, but marked as closed.
LEAVE_MM_HANDLE(hMidiIn);
return (MMSYSERR_HANDLEBUSY);
}
// Marking handle as deserted
SetHandleFlag(hMidiIn, MMHANDLE_DESERTED);
// Since the handle was invalidated, we have to send the message ourselves...
(*(pDev->mididrv->drvMessage))(pDev->wDevice, MIDM_RESET, pDev->dwDrvUser, 0L, 0L);
(*(pDev->mididrv->drvMessage))(pDev->wDevice, MIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
LEAVE_MM_HANDLE((HWAVE)hMidiIn);
// ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
// dec on close instead.
mregDecUsage(PTtoH(HMD, pDev->mididrv));
return MMSYSERR_NOERROR;
} // midiInDesertHandle()
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiInGetID | This function gets the device ID for a
* MIDI input device.
*
* @parm HMIDIIN | hMidiIn | Specifies the handle to the MIDI input
* device.
* @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized
* memory location to be filled with the device ID.
*
* @rdesc Returns zero if successful. Otherwise, returns
* an error number. Possible error returns are:
*
* @flag MMSYSERR_INVALHANDLE | The <p hMidiIn> parameter specifies an
* invalid handle.
*
****************************************************************************/
MMRESULT APIENTRY midiInGetID(HMIDIIN hMidiIn, PUINT lpuDeviceID)
{
V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
V_HANDLE_ACQ(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
*lpuDeviceID = ((PMIDIDEV)hMidiIn)->uDeviceID;
ReleaseHandleListResource();
return MMSYSERR_NOERROR;
}
/*****************************************************************************
* @doc EXTERNAL MIDI
*
* @api MMRESULT | midiOutGetID | This function gets the device ID for a
* MIDI output device.
*
* @parm HMIDIOUT | hMidiOut | Specifies the handle to the MIDI output
* device.
* @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized
* memory location to be filled with the device ID.
*
* @rdesc Returns MMSYSERR_NOERROR if successful. Otherwise, returns
* an error number. Possible error returns are:
*
* @flag MMSYSERR_INVALHANDLE | The <p hMidiOut> parameter specifies an
* invalid handle.
*
****************************************************************************/
MMRESULT APIENTRY midiOutGetID(HMIDIOUT hMidiOut, PUINT lpuDeviceID)
{
V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
V_HANDLE_ACQ(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
*lpuDeviceID = ((PMIDIDEV)hMidiOut)->uDeviceID;
ReleaseHandleListResource();
return MMSYSERR_NOERROR;
}