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.
1950 lines
54 KiB
1950 lines
54 KiB
//==========================================================================;
|
|
//
|
|
// mixapi.c
|
|
//
|
|
// Copyright (C) 1992-1993 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// History:
|
|
// 6/27/93 cjp [curtisp]
|
|
//
|
|
//==========================================================================;
|
|
#define _WINDLL
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <string.h>
|
|
|
|
#include <mmsystem.h>
|
|
#include <mmddk.h>
|
|
|
|
#include "mmreg.h"
|
|
#include "mmsysi.h"
|
|
|
|
//
|
|
// fix a conflict will a bad define in MMREG.H that shipped with NT
|
|
// the define is bad for some Media Vision things...
|
|
//
|
|
// why not just build MSMIXMGR with a NEW mmreg.h??
|
|
//
|
|
#ifdef MIXERR_BASE
|
|
#undef MIXERR_BASE
|
|
#endif // MIXERR_BASE
|
|
|
|
|
|
#define _INC_MMDDK
|
|
#include "msmixmgr.y"
|
|
|
|
|
|
#define WODM_MAPPER_STATUS (0x2000)
|
|
#define WAVEOUT_MAPPER_STATUS_DEVICE 0
|
|
#define WIDM_MAPPER_STATUS (0x2000)
|
|
#define WAVEIN_MAPPER_STATUS_DEVICE 0
|
|
|
|
#include "idrv.h"
|
|
#include "mixmgri.h"
|
|
#include "debug.h"
|
|
|
|
UINT FAR PASCAL
|
|
mmCallProc32(
|
|
DWORD uId,
|
|
DWORD uMsg,
|
|
DWORD dwInst,
|
|
DWORD dwP1,
|
|
DWORD dwP2,
|
|
DRIVERMSGPROC fp,
|
|
DWORD dwDirChange );
|
|
|
|
/* -------------------------------------------------------------------------
|
|
** thunking global variables
|
|
** -------------------------------------------------------------------------
|
|
*/
|
|
DWORD mix32Lib;
|
|
|
|
BOOL FAR PASCAL
|
|
InitMixerThunks(
|
|
void
|
|
);
|
|
|
|
DWORD CALLBACK
|
|
mxdMessage(
|
|
UINT uId,
|
|
UINT uMsg,
|
|
DWORD dwInstance,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2
|
|
);
|
|
|
|
#define CHECK_AND_INIT_THUNKS( _x_ ) \
|
|
if ( (_x_) == 0L ) { \
|
|
if ( InitMixerThunks() == FALSE ) { \
|
|
return MMSYSERR_NODRIVER; \
|
|
} \
|
|
}
|
|
|
|
UINT guTotalMixerDevs; // total mixer devices
|
|
DRIVERMSGPROC mix32Message;
|
|
typedef MMDRV MIXERDRV, *PMIXERDRV;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
typedef struct tMIXERDEV {
|
|
UINT uHandleType; // for parameter validation
|
|
|
|
struct tMIXERDEV *pmxdevNext; /* How quaint, a linked list... */
|
|
PMIXERDRV pmxdrv;
|
|
UINT wDevice;
|
|
DWORD dwDrvUser;
|
|
UINT uDeviceID;
|
|
|
|
DWORD fdwSupport; // from the driver's mixercaps
|
|
DWORD cDestinations; // from the driver's mixercaps
|
|
|
|
DWORD dwCallback; // client's callback and inst data
|
|
DWORD dwInstance;
|
|
|
|
DWORD fdwOpen; /* The open flags the caller used */
|
|
} MIXERDEV, *PMIXERDEV;
|
|
|
|
PMIXERDEV gpMixerDevHeader = NULL; /* A LL of open devices */
|
|
|
|
//
|
|
// mixer device driver list--add one to accomodate the MIXER_MAPPER. note
|
|
// that even if we are not compiling with mapper support we need to add
|
|
// one because other code relies on it (for other device mappers).
|
|
//
|
|
MIXERDRV mixerdrv[1];
|
|
|
|
|
|
|
|
|
|
//==========================================================================;
|
|
//
|
|
// Mixer API's
|
|
//
|
|
//
|
|
//==========================================================================;
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD IMixerMapId
|
|
//
|
|
// Description:
|
|
// This function maps a logical id to a device driver table index and
|
|
// physical id.
|
|
//
|
|
// Arguments:
|
|
// PMIXERDRV pmxdrv: The array of mixer drivers.
|
|
//
|
|
// UINT uTotalNumDevs: The total number of mixer devices.
|
|
//
|
|
// UINT uId: The logical id to be mapped.
|
|
//
|
|
// Return (DWORD):
|
|
// The return value contains the dev[] array element id in the high word
|
|
// and the driver physical device number in the low word.
|
|
//
|
|
// Out of range values map to FFFF:FFFF
|
|
//
|
|
// History:
|
|
// 03/17/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD NEAR PASCAL IMixerMapId(
|
|
PMIXERDRV pmxdrv,
|
|
UINT uTotalNumDevs,
|
|
UINT uId
|
|
)
|
|
{
|
|
UINT u;
|
|
|
|
#ifdef MIXER_MAPPER
|
|
//
|
|
// the mapper is always the last element of the MIXERDEV array.
|
|
//
|
|
if (uId == MIXER_MAPPER)
|
|
return (MAKELONG(0, MAXMIXERDRIVERS));
|
|
#endif
|
|
|
|
if (uId >= uTotalNumDevs)
|
|
return ((DWORD)-1);
|
|
|
|
#ifdef DEBUG_RETAIL
|
|
if (fIdReverse)
|
|
uId = uTotalNumDevs - 1 - uId;
|
|
#endif
|
|
|
|
for (u = 0; u < MAXMIXERDRIVERS; u++)
|
|
{
|
|
if (pmxdrv[u].bNumDevs > (BYTE)uId)
|
|
return (MAKELONG(uId, u));
|
|
|
|
uId -= pmxdrv[u].bNumDevs;
|
|
}
|
|
|
|
return ((DWORD)-1);
|
|
} // IMixerMapId()
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD IMixerMessageHandle
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// HMIXER hmx:
|
|
//
|
|
// UINT uMsg:
|
|
//
|
|
// DWORD dwP1:
|
|
//
|
|
// DWORD dwP2:
|
|
//
|
|
// Return (DWORD):
|
|
//
|
|
// History:
|
|
// 03/17/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD NEAR PASCAL IMixerMessageHandle(
|
|
HMIXER hmx,
|
|
UINT uMsg,
|
|
DWORD dwP1,
|
|
DWORD dwP2
|
|
)
|
|
{
|
|
PMIXERDEV pmxd;
|
|
DWORD dwRc;
|
|
|
|
pmxd = (PMIXERDEV)hmx;
|
|
|
|
dwRc = ((*(pmxd->pmxdrv->drvMessage))
|
|
(pmxd->wDevice, uMsg, pmxd->dwDrvUser, dwP1, dwP2));
|
|
|
|
return dwRc;
|
|
} // IMixerMessageHandle()
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD IMixerMessageId
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// PMIXERDRV pmxdrv:
|
|
//
|
|
// UINT uTotalNumDevs:
|
|
//
|
|
// UINT uDeviceID:
|
|
//
|
|
// UINT uMsg:
|
|
//
|
|
// DWORD dwParam1:
|
|
//
|
|
// DWORD dwParam2:
|
|
//
|
|
// Return (DWORD):
|
|
//
|
|
// History:
|
|
// 03/17/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD NEAR PASCAL IMixerMessageId(
|
|
PMIXERDRV pmxdrv,
|
|
UINT uTotalNumDevs,
|
|
UINT uDeviceID,
|
|
UINT uMsg,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2
|
|
)
|
|
{
|
|
DWORD dwMap;
|
|
DWORD dwRc;
|
|
|
|
dwMap = IMixerMapId(pmxdrv, uTotalNumDevs, uDeviceID);
|
|
|
|
if (dwMap == (DWORD)-1)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
pmxdrv = (PMIXERDRV)&pmxdrv[HIWORD(dwMap)];
|
|
if (!pmxdrv->drvMessage)
|
|
return (MMSYSERR_NODRIVER);
|
|
|
|
dwRc = ((*(pmxdrv->drvMessage))
|
|
((UINT)dwMap, uMsg, 0L, dwParam1, dwParam2));
|
|
|
|
return dwRc;
|
|
|
|
} // IMixerMessageId()
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerGetNumDevs
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
UINT MIXAPI mixerGetNumDevs(
|
|
void
|
|
)
|
|
{
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
|
|
return guTotalMixerDevs;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerGetDevCaps
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerGetDevCaps(
|
|
UINT uMxId,
|
|
LPMIXERCAPS pmxcaps,
|
|
UINT cbmxcaps
|
|
)
|
|
{
|
|
|
|
MMRESULT mmr;
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
|
|
if (0 == cbmxcaps)
|
|
return (MMSYSERR_NOERROR);
|
|
|
|
V_WPOINTER(pmxcaps, cbmxcaps, MMSYSERR_INVALPARAM);
|
|
|
|
if (uMxId >= MAXMIXERDRIVERS)
|
|
{
|
|
V_HANDLE((HMIXER)uMxId, TYPE_MIXER, MMSYSERR_INVALHANDLE);
|
|
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)uMxId,
|
|
MXDM_GETDEVCAPS,
|
|
(DWORD)pmxcaps,
|
|
(DWORD)cbmxcaps);
|
|
}
|
|
else
|
|
{
|
|
if (uMxId >= guTotalMixerDevs)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetDevCaps: mixer device id is out of range (%u).", uMxId);
|
|
return (MMSYSERR_BADDEVICEID);
|
|
}
|
|
|
|
mmr = (MMRESULT)IMixerMessageId(mixerdrv,
|
|
guTotalMixerDevs,
|
|
uMxId,
|
|
MXDM_GETDEVCAPS,
|
|
(DWORD)pmxcaps,
|
|
(DWORD)cbmxcaps);
|
|
}
|
|
return mmr;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerGetID
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerGetID(
|
|
HMIXEROBJ hmxobj,
|
|
UINT FAR *puMxId,
|
|
DWORD fdwId
|
|
)
|
|
{
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
return IMixerGetID( hmxobj, puMxId, NULL, fdwId );
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* IMixerGetID
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT FNGLOBAL IMixerGetID(
|
|
HMIXEROBJ hmxobj,
|
|
UINT FAR *puMxId,
|
|
LPMIXERLINE pmxl,
|
|
DWORD fdwId
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
MIXERLINE mxl;
|
|
UINT u;
|
|
|
|
V_DFLAGS(fdwId, MIXER_GETIDF_VALID, IMixerGetID, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(puMxId, sizeof(UINT), MMSYSERR_INVALPARAM);
|
|
|
|
|
|
//
|
|
// set to '-1' which would be the mixer mapper (if there was one)
|
|
// this way we will definitely fail any calls made on this id if
|
|
// this function fails and the caller doesn't check his return value.
|
|
//
|
|
*puMxId = (UINT)-1;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
switch (MIXER_OBJECTF_TYPEMASK & fdwId)
|
|
{
|
|
case MIXER_OBJECTF_MIXER:
|
|
case MIXER_OBJECTF_HMIXER:
|
|
if ((UINT)hmxobj > MAXMIXERDRIVERS)
|
|
{
|
|
V_HANDLE(hmxobj, TYPE_MIXER, MMSYSERR_INVALHANDLE);
|
|
|
|
*puMxId = ((PMIXERDEV)hmxobj)->uDeviceID;
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
if ((UINT)hmxobj >= guTotalMixerDevs)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetID: mixer device id is out of range (%u).", hmxobj);
|
|
return (MMSYSERR_BADDEVICEID);
|
|
}
|
|
|
|
*puMxId = (UINT)hmxobj;
|
|
return (MMSYSERR_NOERROR);
|
|
|
|
|
|
case MIXER_OBJECTF_HWAVEOUT:
|
|
{
|
|
UINT uId;
|
|
DWORD dwId;
|
|
|
|
mmr = waveOutGetID((HWAVEOUT)hmxobj, &uId);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
if (WAVE_MAPPER == uId)
|
|
{
|
|
mmr = (MMRESULT)waveOutMessage((HWAVEOUT)hmxobj,
|
|
WODM_MAPPER_STATUS,
|
|
WAVEOUT_MAPPER_STATUS_DEVICE,
|
|
(DWORD)(LPVOID)&dwId);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
uId = (UINT)dwId;
|
|
}
|
|
}
|
|
|
|
hmxobj = (HMIXEROBJ)uId;
|
|
}
|
|
|
|
case MIXER_OBJECTF_WAVEOUT:
|
|
{
|
|
WAVEOUTCAPS woc;
|
|
|
|
mmr = waveOutGetDevCaps((UINT)hmxobj, &woc, sizeof(woc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
|
|
mxl.Target.dwDeviceID = (UINT)hmxobj;
|
|
mxl.Target.wMid = woc.wMid;
|
|
mxl.Target.wPid = woc.wPid;
|
|
mxl.Target.vDriverVersion = woc.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, woc.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_HWAVEIN:
|
|
{
|
|
UINT uId;
|
|
DWORD dwId;
|
|
|
|
mmr = waveInGetID((HWAVEIN)hmxobj, &uId);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
if (WAVE_MAPPER == uId)
|
|
{
|
|
mmr = (MMRESULT)waveInMessage((HWAVEIN)hmxobj,
|
|
WIDM_MAPPER_STATUS,
|
|
WAVEIN_MAPPER_STATUS_DEVICE,
|
|
(DWORD)(LPVOID)&dwId);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
uId = (UINT)dwId;
|
|
}
|
|
}
|
|
|
|
hmxobj = (HMIXEROBJ)uId;
|
|
}
|
|
|
|
case MIXER_OBJECTF_WAVEIN:
|
|
{
|
|
WAVEINCAPS wic;
|
|
|
|
mmr = waveInGetDevCaps((UINT)hmxobj, &wic, sizeof(wic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
|
|
mxl.Target.dwDeviceID = (UINT)hmxobj;
|
|
mxl.Target.wMid = wic.wMid;
|
|
mxl.Target.wPid = wic.wPid;
|
|
mxl.Target.vDriverVersion = wic.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, wic.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_HMIDIOUT:
|
|
mmr = midiOutGetID((HMIDIOUT)hmxobj, (UINT FAR *)&hmxobj);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_INVALHANDLE);
|
|
|
|
case MIXER_OBJECTF_MIDIOUT:
|
|
{
|
|
MIDIOUTCAPS moc;
|
|
|
|
mmr = midiOutGetDevCaps((UINT)hmxobj, &moc, sizeof(moc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
moc.szPname[SIZEOF(moc.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT;
|
|
mxl.Target.dwDeviceID = (UINT)hmxobj;
|
|
mxl.Target.wMid = moc.wMid;
|
|
mxl.Target.wPid = moc.wPid;
|
|
mxl.Target.vDriverVersion = moc.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, moc.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_HMIDIIN:
|
|
mmr = midiInGetID((HMIDIIN)hmxobj, (UINT FAR *)&hmxobj);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_INVALHANDLE);
|
|
|
|
case MIXER_OBJECTF_MIDIIN:
|
|
{
|
|
MIDIINCAPS mic;
|
|
|
|
mmr = midiInGetDevCaps((UINT)hmxobj, &mic, sizeof(mic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
mic.szPname[SIZEOF(mic.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_MIDIIN;
|
|
mxl.Target.dwDeviceID = (UINT)hmxobj;
|
|
mxl.Target.wMid = mic.wMid;
|
|
mxl.Target.wPid = mic.wPid;
|
|
mxl.Target.vDriverVersion = mic.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, mic.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_AUX:
|
|
{
|
|
AUXCAPS ac;
|
|
|
|
mmr = auxGetDevCaps((UINT)hmxobj, &ac, sizeof(ac));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
ac.szPname[SIZEOF(ac.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_AUX;
|
|
mxl.Target.dwDeviceID = (UINT)hmxobj;
|
|
mxl.Target.wMid = ac.wMid;
|
|
mxl.Target.wPid = ac.wPid;
|
|
mxl.Target.vDriverVersion = ac.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, ac.szPname);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetID: unknown mixer object flag (%.08lXh).",
|
|
MIXER_OBJECTF_TYPEMASK & fdwId);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
mxl.cbStruct = sizeof(mxl);
|
|
mxl.dwDestination = (DWORD)-1L;
|
|
mxl.dwSource = (DWORD)-1L;
|
|
mxl.dwLineID = (DWORD)-1L;
|
|
mxl.fdwLine = 0;
|
|
mxl.dwUser = 0;
|
|
mxl.dwComponentType = (DWORD)-1L;
|
|
mxl.cChannels = 0;
|
|
mxl.cConnections = 0;
|
|
mxl.cControls = 0;
|
|
mxl.szShortName[0] = '\0';
|
|
mxl.szName[0] = '\0';
|
|
|
|
|
|
for (u = 0; u < guTotalMixerDevs; u++)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(mixerdrv,
|
|
guTotalMixerDevs,
|
|
u,
|
|
MXDM_GETLINEINFO,
|
|
(DWORD)(LPVOID)&mxl,
|
|
M_GLINFOF_TARGETTYPE);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
*puMxId = u;
|
|
|
|
if (NULL != pmxl)
|
|
{
|
|
DWORD cbStruct;
|
|
|
|
cbStruct = pmxl->cbStruct;
|
|
|
|
_fmemcpy(pmxl, &mxl, (UINT)cbStruct);
|
|
|
|
pmxl->cbStruct = cbStruct;
|
|
}
|
|
|
|
return (mmr);
|
|
}
|
|
}
|
|
|
|
return (MMSYSERR_NODRIVER);
|
|
} // IMixerGetID()
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerOpen
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerOpen(
|
|
LPHMIXER phmx,
|
|
UINT uMxId,
|
|
DWORD dwCallback,
|
|
DWORD dwInstance,
|
|
DWORD fdwOpen
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
DWORD dwMap;
|
|
PMIXERDRV pmxdrv;
|
|
PMIXERDEV pmxdev;
|
|
MIXEROPENDESC mxod;
|
|
DWORD dwDrvUser;
|
|
MIXERCAPS mxcaps;
|
|
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
|
|
//
|
|
//
|
|
//
|
|
V_WPOINTER(phmx, sizeof(HMIXER), MMSYSERR_INVALPARAM);
|
|
|
|
*phmx = NULL;
|
|
|
|
//
|
|
// Don't allow callback functions - they're not useful and they
|
|
// cause headaches. Specifically for Windows NT the only way
|
|
// to cause an asynchronous callback to 16-bit land from a 32-bit DLL
|
|
// is to cause an interrupt but we don't want to require mixer stuff
|
|
// to be locked down to allow for this.
|
|
//
|
|
|
|
if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerOpen: CALLBACK_FUNCTION is not supported");
|
|
return MMSYSERR_INVALFLAG;
|
|
}
|
|
|
|
V_DCALLBACK(dwCallback, HIWORD(fdwOpen & CALLBACK_TYPEMASK), MMSYSERR_INVALPARAM);
|
|
V_DFLAGS(fdwOpen, MIXER_OPENF_VALID, mixerOpen, MMSYSERR_INVALFLAG);
|
|
|
|
mmr = IMixerGetID((HMIXEROBJ)uMxId, &uMxId, NULL, (MIXER_OBJECTF_TYPEMASK & fdwOpen));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
dwMap = IMixerMapId(mixerdrv, guTotalMixerDevs, uMxId);
|
|
if ((DWORD)-1 == dwMap)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
pmxdrv = &mixerdrv[HIWORD(dwMap)];
|
|
|
|
#ifdef MIXER_MAPPER
|
|
//
|
|
// Default Mixer Mapper:
|
|
//
|
|
// If a mixer mapper is installed as a separate DLL then all mixer
|
|
// mapper messages are routed to it. If no mixer mapper is installed,
|
|
// simply loop through the mixer devices looking for a match.
|
|
//
|
|
if ((MIXER_MAPPER == uMxId) && (NULL == pmxdrv->drvMessage))
|
|
{
|
|
for (uMxId = 0; uMxId < guTotalMixerDevs; uMxId++)
|
|
{
|
|
// try to open it
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
break;
|
|
|
|
}
|
|
|
|
return (mmr);
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Get some memory for the dev structure
|
|
//
|
|
pmxdev = (PMIXERDEV)NewHandle(TYPE_MIXER, sizeof(MIXERDEV));
|
|
if (NULL == pmxdev)
|
|
{
|
|
return (MMSYSERR_NOMEM);
|
|
}
|
|
|
|
//
|
|
// initialize our open instance struct for the client
|
|
//
|
|
pmxdev->uHandleType = TYPE_MIXER;
|
|
pmxdev->pmxdrv = pmxdrv;
|
|
pmxdev->wDevice = LOWORD(dwMap);
|
|
pmxdev->uDeviceID = uMxId;
|
|
|
|
//
|
|
// save the client's callback info
|
|
//
|
|
pmxdev->dwCallback = dwCallback;
|
|
pmxdev->dwInstance = dwInstance;
|
|
pmxdev->fdwOpen = fdwOpen;
|
|
|
|
|
|
//
|
|
// this should probably be done when the driver is booted.. can change
|
|
// this later..
|
|
//
|
|
mmr = mixerGetDevCaps(uMxId, &mxcaps, sizeof(mxcaps));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
DPF((0, "!mixerOpen() failing because mixerGetDevCaps() failed!"));
|
|
|
|
FreeHandle((HMIXER)pmxdev);
|
|
return (mmr);
|
|
}
|
|
|
|
//
|
|
// cache some stuff for parameter validation
|
|
//
|
|
pmxdev->fdwSupport = mxcaps.fdwSupport;
|
|
pmxdev->cDestinations = mxcaps.cDestinations;
|
|
|
|
|
|
//
|
|
// If we get here, no one has the device currently open. Let's
|
|
// go open it, then.
|
|
//
|
|
|
|
//
|
|
// Load up our local MIXEROPENDESC struct
|
|
//
|
|
|
|
mxod.hmx = (HMIXER)pmxdev;
|
|
mxod.pReserved0 = (LPVOID)(fdwOpen & ~MIXER_OBJECTF_TYPEMASK);
|
|
mxod.dwCallback = dwCallback;
|
|
mxod.dwInstance = dwInstance;
|
|
mmr = (MMRESULT)((*(pmxdrv->drvMessage))(LOWORD(dwMap),
|
|
MXDM_OPEN,
|
|
(DWORD)(LPDWORD)&dwDrvUser,
|
|
(DWORD)(LPVOID)&mxod,
|
|
(DWORD)uMxId ));
|
|
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
FreeHandle((HMIXER)pmxdev);
|
|
}
|
|
else
|
|
{
|
|
pmxdrv->bUsage++;
|
|
pmxdev->dwDrvUser = dwDrvUser;
|
|
*phmx = (HMIXER)pmxdev;
|
|
|
|
//
|
|
// Put this new device into the devlist chain.
|
|
//
|
|
|
|
MIXMGR_ENTER;
|
|
|
|
pmxdev->pmxdevNext = gpMixerDevHeader;
|
|
gpMixerDevHeader = pmxdev;
|
|
|
|
MIXMGR_LEAVE;
|
|
}
|
|
return mmr;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerClose
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerClose(
|
|
HMIXER hmx
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
PMIXERDEV pmxdev;
|
|
PMIXERDEV pmxdevT;
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
V_HANDLE(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE);
|
|
|
|
|
|
//
|
|
// if last open instance, then close it
|
|
//
|
|
mmr = (MMRESULT)IMixerMessageHandle(hmx, MXDM_CLOSE, 0L, 0L);
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
|
|
//
|
|
// remove the mixer handle from the linked list
|
|
//
|
|
|
|
MIXMGR_ENTER;
|
|
|
|
pmxdev = (PMIXERDEV)hmx;
|
|
if (pmxdev == gpMixerDevHeader)
|
|
{
|
|
gpMixerDevHeader = pmxdev->pmxdevNext;
|
|
}
|
|
else
|
|
{
|
|
for (pmxdevT = gpMixerDevHeader;
|
|
pmxdevT && (pmxdevT->pmxdevNext != pmxdev);
|
|
pmxdevT = pmxdevT->pmxdevNext)
|
|
;
|
|
|
|
if (NULL == pmxdevT)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerClose: invalid mixer handle (%.04Xh).", hmx);
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
pmxdevT->pmxdevNext = pmxdev->pmxdevNext;
|
|
}
|
|
|
|
MIXMGR_LEAVE;
|
|
|
|
//
|
|
// dec usage count
|
|
//
|
|
pmxdev->pmxdrv->bUsage--;
|
|
|
|
|
|
//
|
|
// we're done with the memory block. now free the memory and return.
|
|
//
|
|
FreeHandle(hmx);
|
|
return mmr;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerMessage
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
DWORD MIXAPI mixerMessage(
|
|
HMIXER hmx,
|
|
UINT uMsg,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2
|
|
)
|
|
{
|
|
DWORD dw;
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
V_HANDLE(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE);
|
|
|
|
//
|
|
// don't allow any non-user range messages through this API
|
|
//
|
|
if (MXDM_USER > uMsg)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerMessage: message must be in MXDM_USER range--what's this (%u)?", uMsg);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
dw = IMixerMessageHandle(hmx, uMsg, dwParam1, dwParam2);
|
|
return dw;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// BOOL IMixerIsValidComponentType
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// DWORD dwComponentType:
|
|
//
|
|
// UINT uSrcDst:
|
|
//
|
|
// Return (BOOL):
|
|
//
|
|
// History:
|
|
// 10/06/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
BOOL FNLOCAL IMixerIsValidComponentType(
|
|
DWORD dwComponentType,
|
|
DWORD fdwLine
|
|
)
|
|
{
|
|
|
|
if (0L == (MIXERLINE_LINEF_SOURCE & fdwLine))
|
|
{
|
|
if (dwComponentType > MLCT_DST_LAST)
|
|
return (FALSE);
|
|
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (dwComponentType < MLCT_SRC_FIRST)
|
|
return (FALSE);
|
|
|
|
if (dwComponentType > MLCT_SRC_LAST)
|
|
return (FALSE);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
return (FALSE);
|
|
} // IMixerIsValidComponentType()
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerGetLineInfo
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerGetLineInfo(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERLINE pmxl,
|
|
DWORD fdwInfo
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
MMRESULT mmr;
|
|
PMIXERDEV pmxdev;
|
|
UINT uMxId;
|
|
BOOL fSourceLine;
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
|
|
V_DFLAGS(fdwInfo, M_GLINFOF_VALID, mixerGetLineInfo, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxl, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
if (sizeof(MIXERLINE) > (UINT)pmxl->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: structure size too small or cbStruct not initialized (%lu).", pmxl->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxl, pmxl->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fSourceLine = FALSE;
|
|
switch (fdwInfo & M_GLINFOF_QUERYMASK)
|
|
{
|
|
case M_GLINFOF_DESTINATION:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
break;
|
|
|
|
case M_GLINFOF_SOURCE:
|
|
fSourceLine = TRUE;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
break;
|
|
|
|
case M_GLINFOF_LINEID:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwDestination = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
break;
|
|
|
|
case M_GLINFOF_COMPONENTTYPE:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwDestination = (DWORD)-1L;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
|
|
if (!IMixerIsValidComponentType(pmxl->dwComponentType, 0) &&
|
|
!IMixerIsValidComponentType(pmxl->dwComponentType, MIXERLINE_LINEF_SOURCE))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid dwComponentType (%lu).", pmxl->dwComponentType);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
case M_GLINFOF_TARGETTYPE:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwDestination = (DWORD)-1L;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
|
|
if ((DWORD)MIXERLINE_TARGETTYPE_AUX < pmxl->Target.dwType)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid Target.dwType (%lu).", pmxl->Target.dwType);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid query flag (%.08lXh).",
|
|
fdwInfo & M_GLINFOF_QUERYMASK);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwInfo);
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, pmxl, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
DPF((0, "!IMixerGetLineInfo: IMixerGetID() failed!"));
|
|
return (mmr);
|
|
}
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
|
|
//
|
|
// clear all fields before calling driver
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
//
|
|
//
|
|
//
|
|
pmxdev = (PMIXERDEV)hmxobj;
|
|
#if 0
|
|
if (pmxdev->cDestinations <= pmxl->dwDestination)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid destination index (%lu).", pmxl->dwDestination);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
#endif
|
|
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_GETLINEINFO,
|
|
(DWORD)(LPVOID)pmxl,
|
|
fdwInfo);
|
|
}
|
|
else
|
|
{
|
|
#pragma message("----IMixerGetLineInfo: dwDestination not validated for ID's!!")
|
|
mmr = (MMRESULT)IMixerMessageId(mixerdrv,
|
|
guTotalMixerDevs,
|
|
uMxId,
|
|
MXDM_GETLINEINFO,
|
|
(DWORD)(LPVOID)pmxl,
|
|
fdwInfo);
|
|
}
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
#pragma message("----IMixerGetLineInfo: should validate mixer driver didn't hose us!")
|
|
|
|
|
|
//
|
|
// validate the driver's returned stuff...
|
|
//
|
|
//
|
|
if (sizeof(MIXERLINE) != (UINT)pmxl->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver returned invalid cbStruct (%lu).", pmxl->cbStruct);
|
|
pmxl->cbStruct = sizeof(MIXERLINE);
|
|
}
|
|
|
|
if ((DWORD)-1L == pmxl->dwDestination)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwDestination member.");
|
|
}
|
|
if (fSourceLine)
|
|
{
|
|
if (0L == (MIXERLINE_LINEF_SOURCE & pmxl->fdwLine))
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to set MIXERLINE_LINEF_SOURCE.");
|
|
pmxl->fdwLine |= MIXERLINE_LINEF_SOURCE;
|
|
}
|
|
|
|
if ((DWORD)-1L == pmxl->dwSource)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwSource member.");
|
|
}
|
|
}
|
|
if ((DWORD)-1L == pmxl->dwLineID)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwLineID member.");
|
|
}
|
|
if (pmxl->fdwLine & ~0x80008001L)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver set reserved line flags (%.08lXh)!", pmxl->fdwLine);
|
|
pmxl->fdwLine &= 0x80008001L;
|
|
}
|
|
if (!IMixerIsValidComponentType(pmxl->dwComponentType, pmxl->fdwLine))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver returned invalid dwComponentType (%.08lXh).", pmxl->dwComponentType);
|
|
pmxl->dwComponentType = MIXERLINE_TARGETTYPE_UNDEFINED;
|
|
}
|
|
if (0L == pmxl->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned zero channels?!?");
|
|
pmxl->cChannels = 1;
|
|
}
|
|
if (fSourceLine)
|
|
{
|
|
if (0L != pmxl->cConnections)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned non-zero connections on source?!?");
|
|
pmxl->cConnections = 0;
|
|
}
|
|
}
|
|
|
|
pmxl->szShortName[SIZEOF(pmxl->szShortName) - 1] = '\0';
|
|
pmxl->szName[SIZEOF(pmxl->szName) - 1] = '\0';
|
|
|
|
|
|
//
|
|
// Does this really need to be done if TARGETTYPE was requested?
|
|
//
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
if ((DWORD)MIXERLINE_TARGETTYPE_UNDEFINED != pmxl->Target.dwType)
|
|
{
|
|
UINT u;
|
|
|
|
pmxl->Target.dwDeviceID = (DWORD)-1L;
|
|
|
|
|
|
//
|
|
// we have a wMid, wPid and szPname (supposedly) of type dwType
|
|
// so let's go find it...
|
|
//
|
|
switch (pmxl->Target.dwType)
|
|
{
|
|
case MIXERLINE_TARGETTYPE_WAVEOUT:
|
|
u = waveOutGetNumDevs();
|
|
while (u--)
|
|
{
|
|
WAVEOUTCAPS woc;
|
|
|
|
mmr = waveOutGetDevCaps(u, &woc, sizeof(woc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
|
|
|
|
if (woc.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (woc.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (woc.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(woc.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_WAVEIN:
|
|
u = waveInGetNumDevs();
|
|
while (u--)
|
|
{
|
|
WAVEINCAPS wic;
|
|
|
|
mmr = waveInGetDevCaps(u, &wic, sizeof(wic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
|
|
|
|
if (wic.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (wic.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (wic.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(wic.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_MIDIOUT:
|
|
u = midiOutGetNumDevs();
|
|
while (u--)
|
|
{
|
|
MIDIOUTCAPS moc;
|
|
|
|
mmr = midiOutGetDevCaps(u, &moc, sizeof(moc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
moc.szPname[SIZEOF(moc.szPname) - 1] = '\0';
|
|
|
|
if (moc.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (moc.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (moc.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(moc.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_MIDIIN:
|
|
u = midiInGetNumDevs();
|
|
while (u--)
|
|
{
|
|
MIDIINCAPS mic;
|
|
|
|
mmr = midiInGetDevCaps(u, &mic, sizeof(mic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
mic.szPname[SIZEOF(mic.szPname) - 1] = '\0';
|
|
|
|
if (mic.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (mic.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (mic.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(mic.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_AUX:
|
|
u = auxGetNumDevs();
|
|
while (u--)
|
|
{
|
|
AUXCAPS ac;
|
|
|
|
mmr = auxGetDevCaps(u, &ac, sizeof(ac));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
ac.szPname[SIZEOF(ac.szPname) - 1] = '\0';
|
|
|
|
if (ac.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (ac.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (ac.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(ac.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pmxl->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return mmr;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerGetLineControls
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerGetLineControls(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERLINECONTROLS pmxlc,
|
|
DWORD fdwControls
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
UINT uMxId;
|
|
MMRESULT mmr;
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
V_DFLAGS(fdwControls, M_GLCONTROLSF_VALID, mixerGetLineControls, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxlc, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERLINECONTROLS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERLINECONTROLS) > (UINT)pmxlc->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbStruct not initialized (%lu).", pmxlc->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxlc, pmxlc->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
if (sizeof(MIXERCONTROL) > (UINT)pmxlc->cbmxctrl)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbmxctrl not initialized (%lu).", pmxlc->cbmxctrl);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
switch (M_GLCONTROLSF_QUERYMASK & fdwControls)
|
|
{
|
|
case M_GLCONTROLSF_ALL:
|
|
if (0L == pmxlc->cControls)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineControls: cControls cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
pmxlc->dwControlID = (DWORD)-1L;
|
|
break;
|
|
|
|
case M_GLCONTROLSF_ONEBYID:
|
|
pmxlc->dwLineID = (DWORD)-1L;
|
|
|
|
// -- fall through --
|
|
|
|
case M_GLCONTROLSF_ONEBYTYPE:
|
|
pmxlc->cControls = (DWORD)1;
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: invalid query flags (%.08lXh).",
|
|
M_GLCONTROLSF_QUERYMASK & fdwControls);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
V_WPOINTER(pmxlc->pamxctrl, pmxlc->cControls * pmxlc->cbmxctrl, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwControls);
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
hmxobj = NULL;
|
|
fdwControls &= ~MIXER_OBJECTF_TYPEMASK;
|
|
fdwControls |= MIXER_OBJECTF_MIXER;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_GETLINECONTROLS,
|
|
(DWORD)pmxlc,
|
|
fdwControls);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(mixerdrv,
|
|
guTotalMixerDevs,
|
|
uMxId,
|
|
MXDM_GETLINECONTROLS,
|
|
(DWORD)pmxlc,
|
|
fdwControls);
|
|
}
|
|
|
|
return mmr;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerGetControlDetails
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerGetControlDetails(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERCONTROLDETAILS pmxcd,
|
|
DWORD fdwDetails
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
MMRESULT mmr;
|
|
UINT uMxId;
|
|
UINT cDetails;
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
V_DFLAGS(fdwDetails, M_GCDSF_VALID, mixerGetControlDetails, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERCONTROLDETAILS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERCONTROLDETAILS) > (UINT)pmxcd->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
switch (M_GCDSF_QUERYMASK & fdwDetails)
|
|
{
|
|
case M_GCDSF_VALUE:
|
|
//
|
|
// if both cChannels and cMultipleItems are zero, it is a
|
|
// custom control
|
|
//
|
|
if ((0L == pmxcd->cChannels) && (0L == pmxcd->cMultipleItems))
|
|
{
|
|
if (0L == pmxcd->cbDetails)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cbDetails cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
|
|
}
|
|
else
|
|
{
|
|
if (0L == pmxcd->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _VALUE cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_SIGNED))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
cDetails = (UINT)pmxcd->cChannels;
|
|
if (0L != pmxcd->cMultipleItems)
|
|
{
|
|
cDetails *= (UINT)pmxcd->cMultipleItems;
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
case M_GCDSF_LISTTEXT:
|
|
if (0L == pmxcd->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _LISTTEXT cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
if (2L > pmxcd->cMultipleItems)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cMultipleItems for _LISTTEXT must be 2 or greater.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_LISTTEXT))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
cDetails = (UINT)pmxcd->cChannels * (UINT)pmxcd->cMultipleItems;
|
|
V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: invalid query flags (%.08lXh).",
|
|
M_GCDSF_QUERYMASK & fdwDetails);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails);
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
hmxobj = NULL;
|
|
fdwDetails &= ~MIXER_OBJECTF_TYPEMASK;
|
|
fdwDetails |= MIXER_OBJECTF_MIXER;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_GETCONTROLDETAILS,
|
|
(DWORD)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(mixerdrv,
|
|
guTotalMixerDevs,
|
|
uMxId,
|
|
MXDM_GETCONTROLDETAILS,
|
|
(DWORD)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
|
|
return mmr;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* mixerSetControlDetails
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
MMRESULT MIXAPI mixerSetControlDetails(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERCONTROLDETAILS pmxcd,
|
|
DWORD fdwDetails
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
MMRESULT mmr;
|
|
UINT uMxId;
|
|
UINT cDetails;
|
|
|
|
CHECK_AND_INIT_THUNKS(mix32Lib);
|
|
V_DFLAGS(fdwDetails, M_SCDF_VALID, mixerSetControlDetails, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERCONTROLDETAILS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERCONTROLDETAILS) > (UINT)pmxcd->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
|
|
switch (M_SCDF_QUERYMASK & fdwDetails)
|
|
{
|
|
case M_SCDF_VALUE:
|
|
//
|
|
// cChannels is zero for custom controls
|
|
//
|
|
if (0L == pmxcd->cChannels)
|
|
{
|
|
if (0L == pmxcd->cbDetails)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
//
|
|
//
|
|
if (0L != pmxcd->cMultipleItems)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cMultipleItems must be zero for custom controls.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_SIGNED))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
cDetails = (UINT)pmxcd->cChannels;
|
|
|
|
//
|
|
//
|
|
//
|
|
if (0L != pmxcd->cMultipleItems)
|
|
{
|
|
cDetails *= (UINT)(pmxcd->cMultipleItems);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
case M_SCDF_CUSTOM:
|
|
if (0L == pmxcd->cbDetails)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero for custom controls.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
if (0L != pmxcd->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cChannels must be zero for custom controls.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
//
|
|
//
|
|
if ((NULL != pmxcd->hwndOwner) && !IsWindow(pmxcd->hwndOwner))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: hwndOwner must be a valid window handle (%.04Xh).", pmxcd->hwndOwner);
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: invalid query flags (%.08lXh).",
|
|
M_SCDF_QUERYMASK & fdwDetails);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails);
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
fdwDetails &= ~MIXER_OBJECTF_TYPEMASK;
|
|
fdwDetails |= MIXER_OBJECTF_MIXER;
|
|
hmxobj = NULL;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_SETCONTROLDETAILS,
|
|
(DWORD)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(mixerdrv,
|
|
guTotalMixerDevs,
|
|
uMxId,
|
|
MXDM_SETCONTROLDETAILS,
|
|
(DWORD)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
|
|
return mmr;
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* InitMixerThunks
|
|
*
|
|
* Initializes the thunking system.
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
BOOL FAR PASCAL
|
|
InitMixerThunks(
|
|
void
|
|
)
|
|
{
|
|
|
|
/*
|
|
** For WOW we have a fake device driver (that actually lives inside
|
|
** this library). When an applications makes an api call to this
|
|
** library we check to see is the WOW thunks are loaded. If they are
|
|
** not loaded "InitWOWThunks" is called. This function loads the 32
|
|
** bit library and determines the total number of mixer devices
|
|
** present in the system. It then sets mixerdrv[0].bUsage
|
|
** and guTotalMixerDevs to this value. This appears to the 16 bit code
|
|
** that we have one 16 bit device driver that supports all the
|
|
** 32 bit devices !!. The entry point to this fake driver is
|
|
** mxdMessage, which just passes the message through to the 32 bit
|
|
** side.
|
|
*/
|
|
|
|
mixerdrv[0].hDriver = NULL;
|
|
mixerdrv[0].bNumDevs = (BYTE)0;
|
|
mixerdrv[0].bUsage = 0;
|
|
mixerdrv[0].drvMessage = mxdMessage;
|
|
guTotalMixerDevs = 0;
|
|
|
|
|
|
/*
|
|
** First try winmm.dll
|
|
*/
|
|
mix32Lib = LoadLibraryEx32W( "winmm.dll", NULL, 0L );
|
|
if ( mix32Lib ) {
|
|
mix32Message = (DRIVERMSGPROC)GetProcAddress32W( mix32Lib,
|
|
"mxd32Message" );
|
|
if ( mix32Message ) {
|
|
|
|
mxdMessage( 0, MXDM_INIT, 0L, 0L, 0L );
|
|
guTotalMixerDevs = (UINT)mxdMessage( 0, MXDM_GETNUMDEVS,
|
|
0L, 0L, 0L );
|
|
|
|
mixerdrv[0].bNumDevs = (BYTE)guTotalMixerDevs;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Then try msmix32.dll
|
|
*/
|
|
mix32Lib = LoadLibraryEx32W( "msmix32.dll", NULL, 0L );
|
|
if ( mix32Lib ) {
|
|
|
|
mix32Message = (DRIVERMSGPROC)GetProcAddress32W( mix32Lib,
|
|
"mxd32Message" );
|
|
if ( mix32Message ) {
|
|
|
|
mxdMessage( 0, MXDM_INIT, 0L, 0L, 0L );
|
|
guTotalMixerDevs = (UINT)mxdMessage( 0, MXDM_GETNUMDEVS,
|
|
0L, 0L, 0L );
|
|
|
|
mixerdrv[0].bNumDevs = (BYTE)guTotalMixerDevs;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Give up !!
|
|
*/
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* mxdMessage
|
|
*
|
|
* Entry point for the fake WOW device driver.
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
DWORD CALLBACK
|
|
mxdMessage(
|
|
UINT uId,
|
|
UINT uMsg,
|
|
DWORD dwInstance,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2
|
|
)
|
|
{
|
|
return mmCallProc32( (DWORD)uId, (DWORD)uMsg, dwInstance,
|
|
dwParam1, dwParam2, mix32Message, 0L );
|
|
}
|