You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2741 lines
95 KiB
2741 lines
95 KiB
/*****************************************************************************
|
|
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;
|
|
}
|