//==========================================================================; // // mixer.c // // Copyright (c) 1992-2001 Microsoft Corporation // // Description: // // // History: // 6/27/93 cjp [curtisp] // //==========================================================================; #define UNICODE #include "winmmi.h" #include "mixer.h" // This file drags in a ton of stuff to support the mixers PMIXERDEV gpMixerDevHeader = NULL; /* A LL of open devices */ UINT guTotalMixerDevs; // total mixer 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 mixerdrvZ; char gszMxdMessage[] = "mxdMessage"; TCHAR gszMixer[] = TEXT("mixer"); #ifdef MIXER_MAPPER TCHAR gszMixerMapper[] = TEXT("mixermapper"); #endif #ifdef MIXER_MAPPER #define MMDRVI_MAPPER 0x8000 // install this driver as the mapper #endif //#define MMDRVI_MIXER 0x0006 #define MMDRVI_HDRV 0x4000 // hdrvr is an installable driver #define MMDRVI_REMOVE 0x2000 // remove the driver //--------------------------------------------------------------------------; // // BOOL MixerCallbackFunc // // Description: // // NOTE! we document that a mixer must NEVER call this function at // interrupt time! we don't want to fix our code or data segments. // // Arguments: // HMIXER hmx: // // UINT uMsg: // // DWORD dwInstance: // // DWORD dwParam1: // // DWORD dwParam2: // // Return (BOOL): // // History: // 07/21/93 cjp [curtisp] // //--------------------------------------------------------------------------; BOOL CALLBACK MixerCallbackFunc( HMIXER hmx, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) { PMIXERDEV pmxdev; // // step through all open handles and do callbacks to the appropriate // clients... // // // Serialize access to hande list - only necessary for Win32 // MIXMGR_ENTER; for (pmxdev = gpMixerDevHeader; pmxdev; pmxdev = pmxdev->pmxdevNext) { // // same device? (could also use hmx->uDeviceID) // if (pmxdev->uDeviceID != dwInstance) continue; DriverCallback(pmxdev->dwCallback, (HIWORD(pmxdev->fdwOpen) | DCB_NOSWITCH), GetWOWHandle((HANDLE)pmxdev) ? (HANDLE)(UINT_PTR)GetWOWHandle((HANDLE)pmxdev) : (HANDLE)pmxdev, uMsg, pmxdev->dwInstance, dwParam1, dwParam2); } MIXMGR_LEAVE; return (TRUE); } // MixerCallbackFunc() //--------------------------------------------------------------------------; // // MMRESULT mixerReferenceDriveryById // // Description: // This function maps a logical id to a device driver and physical id. // // Arguments: // IN UINT uId: The logical id to be mapped. // // OUT PMIXERDRV* OPTIONAL ppmixerdrv: Pointer to the MIXERDRV structure // describing describing the driver supporing the id. // // OUT UINT* OPTIONAL pport: The driverj-relative device number. If the // caller supplies this buffer then it must also supply ppmixerdrv. // // Return (MMRESULT): // The return value is zero if successful, MMSYSERR_BADDEVICEID if the id // is out of range. // // Comments: // If the caller specifies ppmixerdrv then this function increments the // mixerdrv's usage before returning. The caller must ensure the usage // is eventually decremented. // // History: // 03/17/93 cjp [curtisp] // //--------------------------------------------------------------------------; MMRESULT mixerReferenceDriverById( IN UINT id, OUT PMIXERDRV *ppdrv OPTIONAL, OUT UINT *pport OPTIONAL ) { PMIXERDRV pdrv; MMRESULT mmr; // Should not be called asking for port but not mixerdrv WinAssert(!(pport && !ppdrv)); EnterNumDevs("mixerReferenceDriverById"); #ifdef MIXER_MAPPER if (MIXER_MAPPER == id) { id = 0; for (pdrv = mixerdrvZ.Next; pdrv != &mixerdrvZ; pdrv = pdrv->Next) { if (pdrv->fdwDriver & MMDRV_MAPPER) break; } } else #endif { for (pdrv = mixerdrvZ.Next; pdrv != &mixerdrvZ; pdrv = pdrv->Next) { if (pdrv->fdwDriver & MMDRV_MAPPER) continue; if (pdrv->NumDevs > id) break; id -= pdrv->NumDevs; } } if (pdrv != &mixerdrvZ) { if (ppdrv) { mregIncUsagePtr(pdrv); *ppdrv = pdrv; if (pport) *pport = id; } mmr = MMSYSERR_NOERROR; } else { mmr = MMSYSERR_BADDEVICEID; } LeaveNumDevs("mixerReferenceDriverById"); return mmr; ; } // IMixerMapId() PCWSTR mixerReferenceDevInterfaceById(UINT_PTR id) { PMIXERDRV pdrv; PCWSTR DevInterface; if (ValidateHandle((HANDLE)id, TYPE_MIXER)) { DevInterface = ((PMIXERDEV)id)->pmxdrv->cookie; if (DevInterface) wdmDevInterfaceInc(DevInterface); return DevInterface; } if (!mixerReferenceDriverById((UINT)id, &pdrv, NULL)) { DevInterface = pdrv->cookie; if (DevInterface) wdmDevInterfaceInc(DevInterface); mregDecUsagePtr(pdrv); return DevInterface; } return NULL; } //--------------------------------------------------------------------------; // // 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_PTR dwP1, DWORD_PTR dwP2 ) { PMIXERDEV pmxd; DWORD dwRc; pmxd = (PMIXERDEV)hmx; ENTER_MM_HANDLE(hmx); ReleaseHandleListResource(); // Is handle deserted? if (IsHandleDeserted(hmx)) { LEAVE_MM_HANDLE(hmx); return (MMSYSERR_NODRIVER); } if (IsHandleBusy(hmx)) { LEAVE_MM_HANDLE(hmx); return (MMSYSERR_HANDLEBUSY); } EnterCriticalSection(&pmxd->pmxdrv->MixerCritSec); if (BAD_HANDLE(hmx, TYPE_MIXER)) { // Do we still need to check for this? WinAssert(!"Bad Handle within IMixerMessageHandle"); dwRc = MMSYSERR_INVALHANDLE; } else { dwRc = ((*(pmxd->pmxdrv->drvMessage)) (pmxd->wDevice, uMsg, pmxd->dwDrvUser, dwP1, dwP2)); } LeaveCriticalSection(&pmxd->pmxdrv->MixerCritSec); LEAVE_MM_HANDLE(hmx); 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] // //--------------------------------------------------------------------------; extern void lstrncpyW (LPWSTR pszTarget, LPCWSTR pszSource, size_t cch); DWORD NEAR PASCAL IMixerMessageId( UINT uDeviceID, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) { PMIXERDRV pmxdrv; UINT port; DWORD dwRc; HMIXER hmx; PMIXERDEV pmxdev; MMRESULT mmr; mmr = mixerReferenceDriverById(uDeviceID, &pmxdrv, &port); if (mmr) { return mmr; } if (mregHandleInternalMessages(pmxdrv, TYPE_MIXER, port, uMsg, dwParam1, dwParam2, &mmr)) { mregDecUsagePtr(pmxdrv); return mmr; } dwRc = mixerOpen(&hmx, uDeviceID, 0L, 0L, MIXER_OBJECTF_MIXER); // Should we go through IMixerMessageHandle??? if (MMSYSERR_NOERROR == dwRc) { pmxdev = (PMIXERDEV)hmx; pmxdrv = pmxdev->pmxdrv; if (!pmxdrv->drvMessage) { dwRc = MMSYSERR_NODRIVER; } else { EnterCriticalSection( &pmxdrv->MixerCritSec); dwRc = ((*(pmxdrv->drvMessage)) (port, uMsg, pmxdev->dwDrvUser, dwParam1, dwParam2)); LeaveCriticalSection( &pmxdrv->MixerCritSec); } mixerClose(hmx); } mregDecUsagePtr(pmxdrv); return dwRc; } // IMixerMessageId() //==========================================================================; // // // // //==========================================================================; /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api UINT | mixerGetNumDevs | The function retrieves * the number of audio mixer devices present in the system. * * @rdesc Returns the number of audio mixer devices present in the system. * If no audio mixer devices are available, zero is returned. * * @xref , * **/ UINT APIENTRY mixerGetNumDevs( void ) { UINT cDevs; ClientUpdatePnpInfo(); EnterNumDevs("mixerGetNumDevs"); cDevs = guTotalMixerDevs; LeaveNumDevs("mixerGetNumDevs"); return cDevs; } // mixerGetNumDevs() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCAPS | The structure describes the capabilities * of a mixer device. * * @field WORD | wMid | Specifies a manufacturer identifier for the mixer * device driver. Manufacturer identifiers are defined in Appendix B, * Manufacturer ID and Product ID Lists. * * @field WORD | wPid | Specifies a product identifier for the mixer device * driver. Product identifiers are defined in Appendix B, * Manufacturer ID and Product ID Lists. * * @field MMVERSION | vDriverVersion | Specifies the version number of the * mixer device driver. The high-order byte is the major version * number, and the low-order byte is the minor version number. * * @field char | szPname[MAXPNAMELEN] | Specifies the name of the product. * If the mixer device driver supports multiple cards, this string must * uniquely and easily identify (potentially to a user) this specific * card. For example, szPname = Sound Card Mixer, I/O address 200 * would uniquely identify (to the user) this particular card as a * Sound Card Mixer for the physical card based at I/O address 200. If * only one device is installed, it is recommended that only the base * name be returned. For example, szPname should be Sound Card Mixer * if only one device is present. * * @field DWORD | fdwSupport | Specifies various support information for * the mixer device driver. No extended support bits are currently * defined. * * @field DWORD | cDestinations | The number of audio mixer line destinations * available through the mixer. All mixer devices must support at least * one destination line, so this member can never be zero. Destination * indexes used in the member of the * structure range from zero to the value specified in the * member minus one. * * @tagname tMIXERCAPS * * @othertype MIXERCAPS FAR * | LPMIXERCAPS | A pointer to a * structure. * * @othertype MIXERCAPS * | PMIXERCAPS | A pointer to a * structure. * * @xref , , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerGetDevCaps | The function * queries a specified audio mixer device to determine its capabilities. * * @parm UINT | uMxId | Identifies the audio mixer device with either * an audio mixer device identifier or a handle to an opened audio mixer * device. * * @parm LPMIXERCAPS | pmxcaps | Pointer to a structure that * receives information about the capabilities of the device. * * @parm UINT | cbmxcaps | Specifies the size, in bytes, of the * structure. * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The specified device identifier is * out of range. * * @flag | The audio mixer device handle passed * is invalid. * * @flag | One or more arguments passed is * invalid. * * @comm Use the function to determine the number of * audio mixer devices present in the system. The device identifier * specified by

varies from zero to one less than the number * of mixer devices present. * * Only

bytes (or less) of information is copied to the * location pointed to by

. If

is zero, nothing * is copied, and the function returns success. * * This function also accepts an audio mixer device handle returned by * the function as the

argument. The calling * application should cast the handle to a UINT. * * @xref , , * **/ MMRESULT APIENTRY mixerGetDevCapsA( UINT_PTR uMxId, LPMIXERCAPSA pmxcapsA, UINT cbmxcaps ) { MIXERCAPS2W mxcaps2W; MIXERCAPS2A mxcaps2A; MMRESULT mmr; if (0 == cbmxcaps) return (MMSYSERR_NOERROR); V_WPOINTER(pmxcapsA, cbmxcaps, MMSYSERR_INVALPARAM); memset(&mxcaps2W, 0, sizeof(mxcaps2W)); mmr = mixerGetDevCaps(uMxId, (LPMIXERCAPSW)&mxcaps2W, sizeof(mxcaps2W)); if (mmr != MMSYSERR_NOERROR) { return mmr; } // // Copy the structure back as cleanly as possible. This would // Be a little easier if all the strings were at the end of structures. // Things would be a LOT more sensible if they could ONLY ask for the // whole structure (then we could copy the result direct to the // caller's memory). // // Because of all this it's easiest to get the whole UNICODE structure, // massage it into an ASCII stucture then (for the 0.001% of such apps) // copy back the part they actually asked for. The definition of the // API means that, far from these apps going faster, everyone goes slow. // Iwcstombs(mxcaps2A.szPname, mxcaps2W.szPname, MAXPNAMELEN); mxcaps2A.wMid = mxcaps2W.wMid; mxcaps2A.wPid = mxcaps2W.wPid; mxcaps2A.vDriverVersion = mxcaps2W.vDriverVersion; mxcaps2A.fdwSupport = mxcaps2W.fdwSupport; mxcaps2A.cDestinations = mxcaps2W.cDestinations; mxcaps2A.ManufacturerGuid = mxcaps2W.ManufacturerGuid; mxcaps2A.ProductGuid = mxcaps2W.ProductGuid; mxcaps2A.NameGuid = mxcaps2W.NameGuid; CopyMemory((PVOID)pmxcapsA, &mxcaps2A, min(sizeof(mxcaps2A), cbmxcaps)); return mmr; } // mixerGetDevCapsA() MMRESULT APIENTRY mixerGetDevCaps( UINT_PTR uMxId, LPMIXERCAPS pmxcaps, UINT cbmxcaps ) { DWORD_PTR dwParam1, dwParam2; MDEVICECAPSEX mdCaps; PCWSTR DevInterface; MMRESULT mmr; if (0 == cbmxcaps) return (MMSYSERR_NOERROR); V_WPOINTER(pmxcaps, cbmxcaps, MMSYSERR_INVALPARAM); ClientUpdatePnpInfo(); DevInterface = mixerReferenceDevInterfaceById(uMxId); dwParam2 = (DWORD_PTR)DevInterface; if (0 == dwParam2) { dwParam1 = (DWORD_PTR)pmxcaps; dwParam2 = (DWORD)cbmxcaps; } else { mdCaps.cbSize = (DWORD)cbmxcaps; mdCaps.pCaps = pmxcaps; dwParam1 = (DWORD_PTR)&mdCaps; } AcquireHandleListResourceShared(); if ((uMxId >= guTotalMixerDevs) && !BAD_HANDLE((HMIXER)uMxId, TYPE_MIXER)) { mmr = (MMRESULT)IMixerMessageHandle((HMIXER)uMxId, MXDM_GETDEVCAPS, dwParam1, dwParam2); } else { ReleaseHandleListResource(); mmr = (MMRESULT)IMixerMessageId((UINT)uMxId, MXDM_GETDEVCAPS, (DWORD_PTR)dwParam1, (DWORD_PTR)dwParam2); } if (DevInterface) wdmDevInterfaceDec(DevInterface); return (mmr); } // mixerGetDevCaps() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerGetID | The function gets the device * identifier for an audio mixer device that corresponds to audio mixer * object handle

. * * @parm | hmxobj | Identifies the audio mixer object handle * to map to an audio mixer device identifier. * * @parm UINT FAR * | puMxId | Points to a UINT-sized variable that will * receive the audio mixer device identifier. If no mixer device is * available for the

object, then '-1' is placed in this * location (an error code of is also returned). * * @parm DWORD | fdwId | Specifies flags for how to map the audio mixer * object

. * * @flag | Specifies that

is an audio * mixer device identifier in the range of zero to one less than the * number of devices returned by . This flag is * optional. * * @flag | Specifies that

is a mixer * device handle returned by . This flag is optional. * * @flag | Specifies that

is a * waveform output device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform output handle returned by . * * @flag | Specifies that

is a * waveform input device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform input handle returned by . * * @flag | Specifies that

is a MIDI * output device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a * MIDI output handle returned by . * * @flag | Specifies that

is a MIDI * input device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a MIDI * input handle returned by . * * @flag | Specifies that

is an * auxiliary device identifier in the range of zero to one less than the * number of devices returned by . * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The

argument specifies an * invalid device identifier. * * @flag | The

argument specifies an * invalid handle. * * @flag | One or more flags are invalid. * * @flag | One or more arguments passed is * invalid. * * @flag | No audio mixer device is available for * the object specified by

. Note that the location referenced * by

will also contain the value '-1'. * * @comm Use the function to determine what audio mixer * device (if any) is responsible for performing mixing functions on a * media device. For example, an application can use to * get the mixer device identifier responsible for setting the volume * on a waveform output handle. Or the application may want to display * a peak meter for waveform input device. * * @xref , , * **/ MMRESULT APIENTRY mixerGetID( HMIXEROBJ hmxobj, UINT FAR *puMxId, DWORD fdwId ) { ClientUpdatePnpInfo(); return IMixerGetID( hmxobj, (PUINT)puMxId, NULL, fdwId ); } // mixerGetID() //--------------------------------------------------------------------------; // // MMRESULT IMixerGetID // // Description: // // // Arguments: // HMIXEROBJ hmxobj: // // UINT FAR *puMxId: // // DWORD fdwId: // // Return (MMRESULT): // // History: // 06/27/93 cjp [curtisp] // //--------------------------------------------------------------------------; MMRESULT IMixerGetID( HMIXEROBJ hmxobj, PUINT 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: { mmr = (fdwId & MIXER_OBJECTF_HANDLE) ? MMSYSERR_INVALHANDLE : MMSYSERR_BADDEVICEID; if ((UINT_PTR)hmxobj >= guTotalMixerDevs) { V_HANDLE_ACQ(hmxobj, TYPE_MIXER, mmr); *puMxId = ((PMIXERDEV)hmxobj)->uDeviceID; ReleaseHandleListResource(); } else { *puMxId = PtrToUint(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_PTR)(LPVOID)&dwId); if (MMSYSERR_NOERROR == mmr) { uId = (UINT)dwId; } } hmxobj = (HMIXEROBJ)(UINT_PTR)uId; } case MIXER_OBJECTF_WAVEOUT: { WAVEOUTCAPS woc; mmr = waveOutGetDevCaps((UINT_PTR)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 = PtrToUlong(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_PTR)(LPVOID)&dwId); if (MMSYSERR_NOERROR == mmr) { uId = (UINT)dwId; } } hmxobj = (HMIXEROBJ)(UINT_PTR)uId; } case MIXER_OBJECTF_WAVEIN: { WAVEINCAPS wic; mmr = waveInGetDevCaps((UINT_PTR)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 = PtrToUlong(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_PTR)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 = PtrToUlong(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_PTR)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 = PtrToUlong(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_PTR)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 = PtrToUlong(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(u, MXDM_GETLINEINFO, (DWORD_PTR)(LPVOID)&mxl, MIXER_GETLINEINFOF_TARGETTYPE); if (MMSYSERR_NOERROR == mmr) { *puMxId = u; if (NULL != pmxl) { DWORD cbStruct; cbStruct = pmxl->cbStruct; CopyMemory(pmxl, &mxl, (UINT)cbStruct); pmxl->cbStruct = cbStruct; } return (mmr); } } return (MMSYSERR_NODRIVER); } // IMixerGetID() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerOpen | The function opens a specified * audio mixer device for use. An application must open a mixer device * if it wishes to receive notifications of mixer line and control * changes. This function also ensures that the device will not be * removed until the application closes the handle. * * @parm LPHMIXER | phmx | Points to a variable that will receive a handle * that identifies the opened audio mixer device. Use this handle to * identify the device when calling other audio mixer functions. This * argument may not be NULL. If an application wishes to query for * audio mixer support on a media device, the function * may be used. * * @parm UINT | uMxId | Identifies the audio mixer device to open. Use a * valid device identifier or any (see for * a description of mixer object handles). Note that there is currently * no 'mapper' for audio mixer devices, so a mixer device identifier of * '-1' is not valid. * * @parm DWORD | dwCallback | Specifies a handle to a window called when the * state of an audio mixer line and/or control associated with the * device being opened is changed. Specify zero for this argument * if no callback mechanism is to be used. * * @parm DWORD | dwInstance | This parameter is currently not used and * should be set to zero. * * @parm DWORD | fdwOpen | Specifies flags for opening the device. * * @flag CALLBACK_WINDOW | If this flag is specified,

is * assumed to be a window handle. * * @flag | Specifies that

is an audio * mixer device identifier in the range of zero to one less than the * number of devices returned by . This flag is * optional. * * @flag | Specifies that

is a mixer * device handle returned by . This flag is optional. * * @flag | Specifies that

is a * waveform output device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform output handle returned by . * * @flag | Specifies that

is a * waveform input device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform input handle returned by . * * @flag | Specifies that

is a MIDI * output device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a * MIDI output handle returned by . * * @flag | Specifies that

is a MIDI * input device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a MIDI * input handle returned by . * * @flag | Specifies that

is an * auxiliary device identifier in the range of zero to one less than the * number of devices returned by . * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The

argument specifies an * invalid device identifier. * * @flag | The

argument specifies an * invalid handle. * * @flag | One or more flags are invalid. * * @flag | One or more arguments passed is * invalid. * * @flag | No audio mixer device is available for * the object specified by

. Note that the location referenced * by

will also contain the value '-1'. * * @flag | The specified resource is already * allocated by the maximum number of clients possible. * * @flag | Unable to allocate resources. * * @comm Use the function to determine the number of * audio mixer devices present in the system. The device identifier * specified by

varies from zero to one less than the number * of devices present. * * If a window is chosen to receive callback information, the following * messages are sent to the window procedure function to indicate when * a line or control state changes: , * .

is the handle to the mixer * device.

is the line identifier for * or the control identifier for that * changed state. * * @xref , , , * * **/ MMRESULT APIENTRY mixerOpen( LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen ) { MMRESULT mmr; PMIXERDRV pmxdrv; UINT port; PMIXERDEV pmxdev; PMIXERDEV pmxdevRunList; MIXEROPENDESC mxod; DWORD_PTR dwDrvUser; // // // V_WPOINTER(phmx, sizeof(HMIXER), MMSYSERR_INVALPARAM); ClientUpdatePnpInfo(); *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)(UINT_PTR)uMxId, &uMxId, NULL, (MIXER_OBJECTF_TYPEMASK & fdwOpen)); if (MMSYSERR_NOERROR != mmr) return (mmr); // // // // mmr = mixerReferenceDriverById(uMxId, &pmxdrv, &port); if (mmr) { return mmr; } #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; } mregDecUsagePtr(pmxdrv); return (mmr); } #endif // // Get some memory for the dev structure // pmxdev = (PMIXERDEV)NewHandle(TYPE_MIXER, pmxdrv->cookie, sizeof(MIXERDEV)); if (NULL == pmxdev) { mregDecUsagePtr(pmxdrv); return (MMSYSERR_NOMEM); } ENTER_MM_HANDLE(pmxdev); SetHandleFlag(pmxdev, MMHANDLE_BUSY); ReleaseHandleListResource(); // // initialize our open instance struct for the client // pmxdev->uHandleType = TYPE_MIXER; pmxdev->pmxdrv = pmxdrv; pmxdev->wDevice = port; pmxdev->uDeviceID = uMxId; pmxdev->fdwHandle = 0; // // save the client's callback info // pmxdev->dwCallback = dwCallback; pmxdev->dwInstance = dwInstance; pmxdev->fdwOpen = fdwOpen; MIXMGR_ENTER; // // Check to see if we already have this device open // for (pmxdevRunList = gpMixerDevHeader; pmxdevRunList; pmxdevRunList = pmxdevRunList->pmxdevNext) { if (pmxdevRunList->pmxdrv != pmxdrv) continue; if (pmxdevRunList->wDevice != port) continue; break; } // // Have we found a match? // if (NULL != pmxdevRunList) { // // Set the driver's dwUser to the value we got before. // pmxdev->dwDrvUser = pmxdevRunList->dwDrvUser; // // We have a match, add the caller to the devlist chain (next in // line AFTER the one we just found). // pmxdev->pmxdevNext = pmxdevRunList->pmxdevNext; pmxdevRunList->pmxdevNext = pmxdev; ClearHandleFlag(pmxdev, MMHANDLE_BUSY); MIXMGR_LEAVE; LEAVE_MM_HANDLE(pmxdev); // // Tell the caller the good news // *phmx = (HMIXER)pmxdev; // // All done. Note we don't dec usage on pmxdrv. // return (MMSYSERR_NOERROR); } // // 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)NULL; mxod.dwCallback = (DWORD_PTR)MixerCallbackFunc; mxod.dwInstance = (DWORD_PTR)uMxId; mxod.dnDevNode = (DWORD_PTR)pmxdev->pmxdrv->cookie; EnterCriticalSection(&pmxdrv->MixerCritSec); mmr = (MMRESULT)((*(pmxdrv->drvMessage))(port, MXDM_OPEN, (DWORD_PTR)(LPDWORD)&dwDrvUser, (DWORD_PTR)(LPVOID)&mxod, CALLBACK_FUNCTION)); LeaveCriticalSection(&pmxdrv->MixerCritSec); if (MMSYSERR_NOERROR != mmr) { // Should we do this after the MIXMGR_LEAVE??? LEAVE_MM_HANDLE(pmxdev); MIXMGR_LEAVE; FreeHandle((HMIXER)pmxdev); } else { MIXERCAPS mxcaps; DWORD_PTR dwParam1, dwParam2; MDEVICECAPSEX mdCaps; mregIncUsagePtr(pmxdrv); dwParam2 = (DWORD_PTR)pmxdev->pmxdrv->cookie; if (0 == dwParam2) { dwParam1 = (DWORD_PTR)&mxcaps; dwParam2 = (DWORD)sizeof(mxcaps); } else { mdCaps.cbSize = (DWORD)sizeof(mxcaps); mdCaps.pCaps = &mxcaps; dwParam1 = (DWORD_PTR)&mdCaps; } // Calling manually since we don't have the HandleList resource... EnterCriticalSection(&pmxdrv->MixerCritSec); (*(pmxdrv->drvMessage))(port, MXDM_GETDEVCAPS, dwDrvUser, dwParam1, dwParam2); LeaveCriticalSection(&pmxdrv->MixerCritSec); // // cache some stuff for parameter validation // pmxdev->fdwSupport = mxcaps.fdwSupport; pmxdev->cDestinations = mxcaps.cDestinations; pmxdev->dwDrvUser = dwDrvUser; *phmx = (HMIXER)pmxdev; // // Put this new device into the devlist chain. // pmxdev->pmxdevNext = gpMixerDevHeader; gpMixerDevHeader = pmxdev; ClearHandleFlag(pmxdev, MMHANDLE_BUSY); LEAVE_MM_HANDLE(pmxdev); MIXMGR_LEAVE; } mregDecUsagePtr(pmxdrv); return (mmr); } // mixerOpen() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerClose | The function closes the * specified audio mixer device. An application must close all mixer * handles before exiting (or when the application is finished using * the device). * * @parm | hmx | Specifies a handle to the audio mixer device. * This handle must have been returned successfully by . If * is successful,

is no longer valid. * * @rdesc Returns zero if the function was successful. Otherwise, it returns * a non-zero error number. Possible error returns are: * * @flag | Specified device handle is invalid. * * @xref * **/ MMRESULT APIENTRY mixerClose( HMIXER hmx ) { MMRESULT mmr; PMIXERDEV pmxdev; PMIXERDRV pmxdrv; BOOL closemixerdriver; ClientUpdatePnpInfo(); V_HANDLE_ACQ(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE); ENTER_MM_HANDLE(hmx); ReleaseHandleListResource(); if (IsHandleDeserted(hmx)) { // This handle has been deserted. Let's just free it. LEAVE_MM_HANDLE(hmx); FreeHandle(hmx); return MMSYSERR_NOERROR; } // // remove the mixer handle from the linked list // // BUGBUG: We're removing the driver from the list BEFORE we know if // the close is successful (for the last handle). // MIXMGR_ENTER; pmxdev = (PMIXERDEV)hmx; pmxdrv = pmxdev->pmxdrv; if (pmxdev == gpMixerDevHeader) { gpMixerDevHeader = pmxdev->pmxdevNext; } else { PMIXERDEV pmxdevT; for (pmxdevT = gpMixerDevHeader; pmxdevT && (pmxdevT->pmxdevNext != pmxdev); pmxdevT = pmxdevT->pmxdevNext) ; if (NULL == pmxdevT) { DebugErr1(DBF_ERROR, "mixerClose: invalid mixer handle (%.04Xh).", hmx); MIXMGR_LEAVE; LEAVE_MM_HANDLE(hmx); return (MMSYSERR_INVALHANDLE); } pmxdevT->pmxdevNext = pmxdev->pmxdevNext; } // // see if this is the last handle on this open instance // closemixerdriver = TRUE; if (gpMixerDevHeader) { PMIXERDEV pmxdevT; for (pmxdevT = gpMixerDevHeader; pmxdevT; pmxdevT = pmxdevT->pmxdevNext) { if (pmxdevT->pmxdrv != pmxdev->pmxdrv) continue; if (pmxdevT->wDevice != pmxdev->wDevice) continue; closemixerdriver = FALSE; break; } } MIXMGR_LEAVE; // handle should be marked as "busy" even if we don't send the driver // message. SetHandleFlag(hmx, MMHANDLE_BUSY); // // if last open instance, then close it // mmr = MMSYSERR_NOERROR; if (closemixerdriver) { EnterCriticalSection(&pmxdrv->MixerCritSec); mmr = (MMRESULT)(*(pmxdrv->drvMessage))(pmxdev->wDevice, MXDM_CLOSE, pmxdev->dwDrvUser, 0L, 0L); LeaveCriticalSection(&pmxdrv->MixerCritSec); if (MMSYSERR_NOERROR != mmr) { // Should we put the handle back in the list??? ClearHandleFlag(hmx, MMHANDLE_BUSY); } } LEAVE_MM_HANDLE(hmx); mregDecUsagePtr(pmxdev->pmxdrv); if (MMSYSERR_NOERROR == mmr) { // // we're done with the memory block. now free the memory and return. // FreeHandle(hmx); } return (mmr); } // mixerClose() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api DWORD | mixerMessage | The function sends a user * defined audio mixer driver message directly to a mixer driver. * * @parm | hmx | Specifies a handle to an open instance of a * mixer device. This handle is returned by . * * @parm UINT | uMsg | Specifies the user defined mixer driver message to * send to the mixer driver. This message must be above or equal to * the message. * * @parm DWORD | dwParam1 | Contains the first argument associated with the * message being sent. * * @parm DWORD | dwParam2 | Contains the second argument associated with the * message being sent. * * @rdesc The return value is specific to the user defined mixer driver * message

sent. However, the following return values are * possible: * * @flag | Specified device handle is invalid. * * @flag |

is not in the * range. * * @flag | The mixer device did not process * the message. * * @comm The function is provided to allow audio mixer * driver specific messages to be sent to a mixer device. The messages * that may be sent through this function must be above or equal to the * message. * * User defined messages must only be sent to a mixer driver that * specifically supports the messages. The caller should verify that * the mixer driver is in fact the correct driver by getting the * mixer capabilities and checking the , * , and * members of the structure. * * It is important for an application to verify all members specified * above due to many driver writers releasing drivers with improper * or unregistered manufacturer and product identifiers. * * Never send user defined messages to an unknown audio mixer driver. * * @xref , * **/ DWORD APIENTRY mixerMessage( HMIXER hmx, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) { DWORD dw; ClientUpdatePnpInfo(); AcquireHandleListResourceShared(); if (BAD_HANDLE(hmx, TYPE_MIXER)) { ReleaseHandleListResource(); return IMixerMessageId (PtrToUint(hmx), uMsg, dwParam1, dwParam2); } // // 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); ReleaseHandleListResource(); return (MMSYSERR_INVALPARAM); } dw = IMixerMessageHandle(hmx, uMsg, dwParam1, dwParam2); return (dw); } // mixerMessage() //--------------------------------------------------------------------------; // // BOOL IMixerIsValidComponentType // // Description: // // // Arguments: // DWORD dwComponentType: // // UINT uSrcDst: // // Return (BOOL): // // History: // 10/06/93 cjp [curtisp] // //--------------------------------------------------------------------------; BOOL IMixerIsValidComponentType ( DWORD dwComponentType, DWORD fdwLine ) { if (0 == (MIXERLINE_LINEF_SOURCE & fdwLine)) { if (dwComponentType > MIXERLINE_COMPONENTTYPE_DST_LAST) return (FALSE); return (TRUE); } else { if (dwComponentType < MIXERLINE_COMPONENTTYPE_SRC_FIRST) return (FALSE); if (dwComponentType > MIXERLINE_COMPONENTTYPE_SRC_LAST) return (FALSE); return (TRUE); } } // IMixerIsValidComponentType() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERLINE | The structure describes the state * and metrics of an audio mixer device line. * * @syntaxex * typedef struct tMIXERLINE * { * DWORD cbStruct; * DWORD dwDestination; * DWORD dwSource; * DWORD dwLineID; * DWORD fdwLine; * DWORD dwUser; * DWORD dwComponentType; * DWORD cChannels; * DWORD cConnections; * DWORD cControls; * char szShortName[MIXER_SHORT_NAME_CHARS]; * char szName[MIXER_LONG_NAME_CHARS]; * struct * { * DWORD dwType; * DWORD dwDeviceID; * WORD wMid; * WORD wPid; * MMVERSION vDriverVersion; * char szPname[MAXPNAMELEN]; * } Target; * } MIXERLINE; * * @field DWORD | cbStruct | Specifies the size, in bytes, of the * structure. This member must be initialized before * calling the function. The size specified in this * member must be large enough to contain the base * structure. When the function returns, this * member contains the actual size of the information returned. The * returned information will never exceed the requested size. * * @field DWORD | dwDestination | Specifies the destination line index. * This member ranges from zero to one less than the value specified * in the member of the * structure retrieved by the function. When the * function is called with the * flag specified, the details for * the destination line are returned. Note that the * member must be set to zero in this case. When * called with the flag specified, the * details for the source given by the member * associated with the member are returned. * * @field DWORD | dwSource | Specifies the source line index for the source * line associated with the member. That * is, this member specifies the nth source line associated with the * specified destination line. This member is not used for destination * lines and must be set to zero when * is specified for . When the * flag is specified, this member ranges * from zero to one less than the value specified in the * of the structure for the * destination line given in the member. * * @field DWORD | dwLineID | Specifies an audio mixer defined identifier * that uniquely refers to the line described by the * structure. This identifier is unique only to a single mixer device * and may be of any format that the mixer device wishes. An application * should only use this identifier as an abstract handle. No two * lines for a single mixer device will have the same line identifier * under any circumstances. * * @field DWORD | fdwLine | Specifies status and support flags for the * audio mixer line. This member is always returned to the application * and requires no initialization. * * @flag | Specifies that this audio mixer * line is a source line associated with a single destination line. If * this flag is not set, then this line is a destination line associated * with zero or more source lines. * * @flag | Specifies that this audio * mixer line is disconnected. A disconnected line's associated controls * can still be modified but the changes will have no effect until the * line becomes connected. An application may want to modify its * behavior if a mixer line is disconnected. * * @flag | Specifies that this audio mixer * line is active. An active line specifies that a signal is (probably) * passing through the line. For example, if a waveform output device * is not in use by an application, then the line associated with that * device would not be active (the flag would * not be set). If the waveform output device is opened, then the * the line is considered active and the flag * will be set. Note that a 'paused' or 'starved' waveform output device * is still considered active. In other words, if the waveform output * device is opened by an application regardless of whether data is * being played, the associated line is considered active. If a line * cannot be strictly defined as 'active' verses 'inactive', then the * audio mixer device will always set the * flag. An example of where this information can be used by an * application is displaying a 'peak meter.' Peak meters are polled * meters. An application may want to disable its polling timer while * the line is inactive to improve system performance. Note that the * flag is also affected by the status of * the mixer line's mute control. Muted mixer lines are never active. * * @field DWORD | dwUser | Specifies 32-bits of audio mixer device defined * instance data for the line. This member is intended for custom * audio mixer applications designed specifically for the mixer device * returning this information. An application that is not specifically * tailored to understand this member should simply ignore this data. * * @field DWORD | dwComponentType | Specifies the component type for this * line. An application may use this information to display tailored * graphics or search for a particular component. If an application * does not know about a component type, then this member should be * ignored. Currently, this member may be one of the following values: * * @flag | Specifies that the * line is a destination that cannot be defined by one of the standard * component types. An audio mixer device is required to use this * component type for line component types that have not been defined * by Microsoft. * * @flag | Specifies that the * line is a digital destination (for example, digital input to a DAT * or CD Audio Disc). * * @flag | Specifies that the line * is a line level destination (for example, line level input from * a CD Audio Disc) that will be the final recording source for the * ADC. Most audio cards for the PC provide some sort of gain for the * recording source line, so the mixer device will use the * type. * * @flag | Specifies that the * line is a destination used for a monitor. * * @flag | Specifies that the * line is an adjustable (gain and/or attenuation) destination intended * to drive speakers. This is the normal component type for the audio * output of most audio cards for the PC. * * @flag | Specifies that the * line is an adjustable (gain and/or attenuation) destination intended * to driver headphones. Most audio cards use the same destination * line for speakers and headphones--in which case the mixer device * will simply use the type. * * @flag | Specifies that the * line is a destination that will be routed to the telephone line. * * @flag | Specifies that the * line is a destination that will be the final recording source for the * waveform input (ADC). This line will normally provide some sort of * gain or attenuation. This is the normal component type for the * recording line of most audio cards for the PC. * * @flag | Specifies that the * line is a destination that will be the final recording source for * voice input. This component type is exactly like * but is intended specifically * for settings used during voice recording/recognition. This line * is entirely optional for a mixer device to support--many mixer * devices may only provide . * * * @flag | Specifies that the * line is a source that cannot be defined by one of the standard * component types. An audio mixer device is required to use this * component type for line component types that have not been defined * by Microsoft. * * @flag | Specifies that the * line is a digital source (for example, digital output from a DAT or * CD Audio Disc). * * @flag | Specifies that the line * is a line level source (for example, line level input from * an external stereo) that will be used as a, perhaps, optional source * for recording. Most audio cards for the PC provide some sort of gain * for the recording source line, so the mixer device will use the * type. * * @flag | Specifies that the * line is a microphone recording source. Most audio cards for the * PC provide at least two types of recording sources: an auxiliary * line and microphone input. A microphone line normally provides * some sort of gain. Audio cards that use a single input for use * with a microphone or auxiliary line should use the * component type. * * @flag | Specifies that * the line is a source originating from the output of an internal * synthesizer. Most audio cards for the PC provide some sort of * MIDI synthesizer (for example, an Ad Lib compatible or OPL/3 FM * synthesizer). * * @flag | Specifies that * the line is a source originating from the output of an internal audio * compact disc. This component type is provided for those audio cards * that provide a source line solely intended to be connected to an * audio compact disc (or CD-ROM playing a Redbook Audio CD). * * @flag | Specifies that the * line is a source originating from an incoming telephone line. * * @flag | Specifies that the * line is a source originating from the PC speaker. Several audio cards * for the PC provide the ability to mix what would normally be played * on the internal speaker with the output of an audio card. The * ability to use this output as a source for recording has also been * exploited by some audio cards. * * @flag | Specifies that the * line is a source originating from the waveform output (DAC). Most * cards for the PC provide this component type as a source to the * destination. Some cards will * also allow this source to be routed to the * destination. * * @flag | Specifies that the * line is a source originating from the auxiliary line. This line type * is intended as a source with gain or attenuation that can be routed * to the destination and/or * recorded from through the * destination. * * @flag | Specifies that the * line is a source originating from one or more lines. This line type * is intended for audio mixers that can mix multiple lines into a * single source for that can be routed to the * destination and/or * recorded from through the * destination. * * @field DWORD | cChannels | Specifies the maximum number of separate * channels that can be manipulated independantly for the line. Most * of the modern audio cards for the PC are stereo devices, so this * member will be two. Channel one is assumed to be the left channel; * channel two is assumed to be the right channel. Note that a * multi-channel line may have one or more uniform controls (controls * that affect all channels of a line uniformly) associated with it. * An example of a uniform control is a Mute that mutes all channels * of a line simultaneously. A line must have at least one channel-- * this member will never be zero. * * @field DWORD | cConnections | Specifies the number of connections that * are associated with the line. Currently, this member is used only * for destination lines and specifies the number of source lines * that are associated with it. This number may be zero. For source * lines, this member is always zero. * * @field DWORD | cControls | Specifies the number of controls associated * with the line. This value may be zero. If no controls are associated * with the line, then the line is probably (but not always) just a * source that may be selected in a MUX or Mixer but allows no * manipulation of the signal. For example, a digital source may have * this attribute. * * @field char | szShortName[] | Specifies a short * string that describes the audio mixer line. * This description is appropriate for using as a displayable label for * the line that can fit in small spaces. * * @field char | szName[] | Specifies a string * that describes the audio mixer line. This * description is appropriate for using as a displayable description * for the line that is not limited by screen space. * * @field struct | Target | Contains the target media information. * * @field2 DWORD | dwType | Specifies the target media device type * associated with the audio mixer line described in the * structure. An application must ignore target information for media * device types that it does not understand. Currently, this member may * be one of the following: * * @flag | Specifies that the line * described by this structure is not strictly bound * to a defined media type. All remaining structure * members of the structure should be ignored. Note that * an application may not use the * target type when calling the function with the * flag. * * @flag | Specifies that the line * described by this structure is strictly bound to * the waveform output device detailed in the remaining members of * the structure member of the * structure. * * @flag | Specifies that the line * described by this structure is strictly bound to * the waveform input device detailed in the remaining members of * the structure member of the * structure. * * @flag | Specifies that the line * described by this structure is strictly bound to * the MIDI output device detailed in the remaining members of * the structure member of the * structure. * * @flag | Specifies that the line * described by this structure is strictly bound to * the MIDI input device detailed in the remaining members of * the structure member of the * structure. * * @flag | Specifies that the line * described by this structure is strictly bound to * the auxiliary device detailed in the remaining members of * the structure member of the * structure. * * @field2 DWORD | dwDeviceID | In the case of the * member being a target type other than * , this member is the current device * identifier of the target media device. This identifier is identical * to the current media device index of the associated media device. * Note that when calling the function with * the flag, this member is ignored on * input and will be returned to the caller by the audio mixer manager. * * @field2 WORD | wMid | In the case of the * member being a target type other than , * this member is the manufacturer identifier of the target media device. * This identifier is identical to the wMid member of the associated * media device capabilities structure. * * @field WORD | wPid | In the case of the * member being a target type other than , * this member is the product identifier of the target media device. * This identifier is identical to the wPid member of the associated * media device capabilities structure. * * @field2 MMVERSION | vDriverVersion | In the case of the * member being a target type other than * , this member is the driver version * of the target media device. This version is identical to the * vDriverVersion member of the associated media device capabilities * structure. * * @field char | szPname[MAXPNAMELEN] | In the case of the * member being a target type other than * , this member is the product * name of the target media device. This name is identical to the * szPname member of the associated media device capabilities structure. * * @tagname tMIXERLINE * * @othertype MIXERLINE FAR * | LPMIXERLINE | A pointer to a * structure. * * @othertype MIXERLINE * | PMIXERLINE | A pointer to a * structure. * * @xref , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerGetLineInfo | The function * retrieves information about a specified audio mixer devices 'line'. * * @parm | hmxobj | Specifies a handle to the audio mixer * device object to get line information from. * * @parm LPMIXERLINE | pmxl | Points to a structure. This * structure is filled with information about the mixer line for the * audio mixer device. See the comments for each query flag passed * through

for details on what members of the * structure must be initialized before calling . * Note that in all cases, must be initialized * to be the size, in bytes, of the structure. * * @parm DWORD | fdwInfo | Specifies flags for getting information on a * mixer line. * * @flag | If this flag is specified, *

is to receive information on the destination line * specified by the member of the * structure. This index ranges from zero to one less * than of the structure. * All remaining structure members except require * no further initialization. * * @flag | If this flag is specified, *

is to receive information on the source line specified by * the and members * of the structure. The index specified by * ranges from zero to one less than * of the structure. The * index specified by for ranges from * zero to one less than the member of the * structure returned for the * line. All remaining structure members except * require no further initialization. * * @flag | If this flag is specified, *

is to receive information on the line specified by the * member of the structure. This * is usually used to retrieve updated information on a line's state. * All remaining structure members except require * no further initialization. * * @flag | If this flag is * specified,

is to receive information on the first line of * the type specified in the member of the * structure. This is used to retrieve information * on a line that is of a specific component type (for example, an * application could specify * to retrieve information on the first Microphone input associated * with the specified

). All remaining structure members * except require no further initialization. * * @flag | If this flag is specified, *

is to receive information on the line that is for the * of the structure. This is * used to retrieve information on a line that handles the target * type ( for example). An application * must initialize , , * , and * of the structure before * calling . All of these values can be retrieved * from the device capabilities structures for all media devices. All * remaining structure members except require * no further initialization. * * @flag | Specifies that

is an audio * mixer device identifier in the range of zero to one less than the * number of devices returned by . This flag is * optional. * * @flag | Specifies that

is a mixer * device handle returned by . This flag is optional. * * @flag | Specifies that

is a * waveform output device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform output handle returned by . * * @flag | Specifies that

is a * waveform input device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform input handle returned by . * * @flag | Specifies that

is a MIDI * output device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a * MIDI output handle returned by . * * @flag | Specifies that

is a MIDI * input device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a MIDI * input handle returned by . * * @flag | Specifies that

is an * auxiliary device identifier in the range of zero to one less than the * number of devices returned by . * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The

argument specifies an * invalid device identifier. * * @flag | The

argument specifies an * invalid handle. * * @flag | One or more flags are invalid. * * @flag | One or more arguments passed is * invalid. * * @flag | No audio mixer device is available for * the object specified by

. * * @flag | The audio mixer device line reference is * invalid. * * @xref , , , , * * **/ MMRESULT APIENTRY mixerGetLineInfoA( HMIXEROBJ hmxobj, LPMIXERLINEA pmxlA, DWORD fdwInfo ) { MIXERLINEW mxlW; MMRESULT mmr; // // Validate the mixer line info pointer // V_WPOINTER(pmxlA, sizeof(DWORD), MMSYSERR_INVALPARAM); if (pmxlA->cbStruct < sizeof(MIXERLINEA)) { return MMSYSERR_INVALPARAM; } V_WPOINTER(pmxlA, pmxlA->cbStruct, MMSYSERR_INVALPARAM); // // Call the UNICODE version to get the full set of data // CopyMemory((PVOID)&mxlW, (PVOID)pmxlA, FIELD_OFFSET(MIXERLINE, cChannels)); mxlW.cbStruct = sizeof(mxlW); // // If target stuff wanted we must set the target data // if ((fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) == MIXER_GETLINEINFOF_TARGETTYPE) { CopyMemory((PVOID)&mxlW.Target.dwType, (PVOID)&pmxlA->Target.dwType, FIELD_OFFSET(MIXERLINE, Target.szPname[0]) - FIELD_OFFSET(MIXERLINE, Target.dwType)); Imbstowcs(mxlW.Target.szPname, pmxlA->Target.szPname, MAXPNAMELEN); } // // Set the relevant values // mmr = mixerGetLineInfo(hmxobj, &mxlW, fdwInfo); if (mmr != MMSYSERR_NOERROR) { return mmr; } // // Massage the return data to ASCII // ConvertMIXERLINEWToMIXERLINEA(pmxlA, &mxlW); return mmr; } // mixerGetLineInfoA() MMRESULT APIENTRY mixerGetLineInfo( HMIXEROBJ hmxobj, LPMIXERLINE pmxl, DWORD fdwInfo ) { DWORD fdwMxObjType; MMRESULT mmr; PMIXERDEV pmxdev; // UINT cb; UINT uMxId; BOOL fSourceLine, fResource; V_DFLAGS(fdwInfo, MIXER_GETLINEINFOF_VALID, mixerGetLineInfo, MMSYSERR_INVALFLAG); V_WPOINTER(pmxl, sizeof(DWORD), MMSYSERR_INVALPARAM); if (sizeof(MIXERLINE) > 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); ClientUpdatePnpInfo(); // // // fSourceLine = FALSE; switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { case MIXER_GETLINEINFOF_DESTINATION: pmxl->dwSource = (DWORD)-1L; pmxl->dwLineID = (DWORD)-1L; pmxl->dwComponentType = (DWORD)-1L; break; case MIXER_GETLINEINFOF_SOURCE: fSourceLine = TRUE; pmxl->dwLineID = (DWORD)-1L; pmxl->dwComponentType = (DWORD)-1L; break; case MIXER_GETLINEINFOF_LINEID: pmxl->dwSource = (DWORD)-1L; pmxl->dwDestination = (DWORD)-1L; pmxl->dwComponentType = (DWORD)-1L; break; case MIXER_GETLINEINFOF_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 MIXER_GETLINEINFOF_TARGETTYPE: pmxl->dwSource = (DWORD)-1L; pmxl->dwDestination = (DWORD)-1L; pmxl->dwLineID = (DWORD)-1L; pmxl->dwComponentType = (DWORD)-1L; if (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 & MIXER_GETLINEINFOF_QUERYMASK); return (MMSYSERR_INVALFLAG); } // // // fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwInfo); fResource = FALSE; AcquireHandleListResourceShared(); // Checking for the type of mixer object. If it is a non-mixer type // calling IMixerMesssageID (called by IMixerGetID) with the shared // resource will deadlock. if ((MIXER_OBJECTF_MIXER == fdwMxObjType) || (MIXER_OBJECTF_HMIXER == fdwMxObjType)) { if (BAD_HANDLE(hmxobj, TYPE_MIXER)) { ReleaseHandleListResource(); } else { fResource = TRUE; } } else { ReleaseHandleListResource(); } mmr = IMixerGetID(hmxobj, &uMxId, pmxl, fdwMxObjType); if (MMSYSERR_NOERROR != mmr) { dprintf(( "!IMixerGetLineInfo: IMixerGetID() failed!" )); if (fResource) ReleaseHandleListResource(); 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_PTR)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) { ReleaseHandleListResource(); DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid destination index (%lu).", pmxl->dwDestination); return (MMSYSERR_INVALPARAM); } #endif mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj, MXDM_GETLINEINFO, (DWORD_PTR)(LPVOID)pmxl, fdwInfo); } else { #pragma message("----IMixerGetLineInfo: dwDestination not validated for ID's!!") mmr = (MMRESULT)IMixerMessageId(uMxId, MXDM_GETLINEINFO, (DWORD_PTR)(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) != 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 (0 == (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 (0 == pmxl->cChannels) { DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned zero channels?!?"); pmxl->cChannels = 1; } if (fSourceLine) { if (0 != 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 (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); } // mixerGetLineInfo() // // Abstract converting the complex mixerline structure // void ConvertMIXERLINEWToMIXERLINEA( PMIXERLINEA pmxlA, PMIXERLINEW pmxlW ) { // // Don't copy cbStruct // CopyMemory((PVOID)((PBYTE)pmxlA + sizeof(DWORD)), (PVOID)((PBYTE)pmxlW + sizeof(DWORD)), FIELD_OFFSET(MIXERLINEA, szShortName[0]) - sizeof(DWORD)); Iwcstombs(pmxlA->szShortName, pmxlW->szShortName, sizeof(pmxlA->szShortName)); Iwcstombs(pmxlA->szName, pmxlW->szName, sizeof(pmxlA->szName)); CopyMemory((PVOID)&pmxlA->Target, (PVOID)&pmxlW->Target, FIELD_OFFSET(MIXERLINEA, Target.szPname[0]) - FIELD_OFFSET(MIXERLINEA, Target.dwType)); Iwcstombs(pmxlA->Target.szPname, pmxlW->Target.szPname, sizeof(pmxlA->Target.szPname)); } /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCONTROL | The structure describes the state * and metrics of a single control for an audio mixer line. * * @syntaxex * typedef struct tMIXERCONTROL * { * DWORD cbStruct; * DWORD dwControlID; * DWORD dwControlType; * DWORD fdwControl; * DWORD cMultipleItems; * char szShortName[MIXER_SHORT_NAME_CHARS]; * char szName[MIXER_LONG_NAME_CHARS]; * union * { * struct * { * LONG lMinimum; * LONG lMaximum; * }; * struct * { * DWORD dwMinimum; * DWORD dwMaximum; * }; * DWORD dwReserved[6]; * } Bounds; * union * { * DWORD cSteps; * DWORD cbCustomData; * DWORD dwReserved[6]; * } Metrics; * } MIXERCONTROL; * * @field DWORD | cbStruct | Specifies the size, in bytes, of the * structure. Since the structure * is only passed as a receiving buffer referenced and described by * the structure passed to the * function, it is not necessary for the * calling application to initialize this member (or any other members * of this structure). When the function * returns, this member contains the actual size of the information * returned by the mixer device. The returned information will never * exceed the requested size and will never be smaller than the * base structure. * * @field DWORD | dwControlID | Specifies an audio mixer defined identifier * that uniquely refers to the control described by the * structure. This identifier is unique only to a single mixer device * and may be of any format that the mixer device wishes. An application * should only use this identifier as an abstract handle. No two * controls for a single mixer device will have the same control * identifier under any circumstances. * * @field DWORD | dwControlType | Specifies the control type for this * control. An application must use this information to display the * appropriate control for input from the user. An application may * also wish to display tailored graphics based on the control type or * search for a particular control type on a specific line. If an * application does not know about a control type, then this control * must be ignored. There are currently seven different control type * classifications. * * The control type class consists of * the following standard control types. * * * * The control type class consists of * the following standard control types. * * * * * * * The control type class consists of * the following standard control types. * * * * * * * * * * * The control type class consists of * the following standard control types. * * * * * * * The control type class consists of * the following standard control types. * * * * * * The control type class consists of * the following standard control types. * * * * * * * * The control type class consists of * the following standard control types. * * * * * The control type class consists of * the following standard control types. * * * * * * * @field DWORD | fdwControl | Specifies status and support flags for the * audio mixer line control. * * @flag | Specifies that the control * acts on all channels of a multi-channel line in a uniform fashion. * For example, a Mute control that mutes both channels of a stereo * line would set this flag. Most MUX and Mixer controls will also * specify the flag. * * @flag | Specifies that the control * has two or more settings per channel. An example of a control * that requires the multiple flag is an equalizer--each frequency * band can be set to different values. Note that an equalizer that * affects both channels of a stereo line in a uniform fashion will * also set the flag. * * @flag | Specifies that the control * is disabled (perhaps due to other settings for the mixer hardware) * and cannot be used. An application can read current settings from * a disabled control, but cannot apply settings. * * @field DWORD | cMultipleItems | Specifies the number of items per * channel that a control contains. * This number will always be two or greater for multiple item * controls. If the control is not a multiple item control, this * member will be zero and should be ignored. * * @field char | szShortName[] | Specifies a short * string that describes the audio mixer * line control. This description is appropriate for using as a * displayable label for the control that can fit in small spaces. * * @field char | szName[] | Specifies a string * that describes the audio mixer line * control. This description is appropriate for using as a displayable * description for the control that is not limited by screen space. * * @field union | Bounds | Contains the union of boundary types. * * @field2 DWORD | dwMinimum | Specifies the minimum unsigned value * for a control that has an unsigned boundary nature. Refer to the * description for each control type to determine if this member is * appropriate for the control. This member overlaps with the * member and cannot be used in * conjunction with that member. * * @field2 DWORD | dwMaximum | Specifies the maximum unsigned value * for a control that has an unsigned boundary nature. Refer to the * description for each control type to determine if this member is * appropriate for the control. This member overlaps with the * member and cannot be used in * conjunction with that member. * * @field2 DWORD | lMinimum | Specifies the minimum signed value * for a control that has a signed boundary nature. Refer to the * description for each control type to determine if this member is * appropriate for the control. This member overlaps with the * member and cannot be used in * conjunction with that member. * * @field2 DWORD | lMaximum | Specifies the maximum signed value * for a control that has a signed boundary nature. Refer to the * description for each control type to determine if this member is * appropriate for the control. This member overlaps with the * member and cannot be used in * conjunction with that member. * * @field union | Metrics | Contains the union of boundary metrics. * * @field2 DWORD | cSteps | Specifies the number of discrete * ranges within the specified for a control. * Refer to the description for each control type to determine if this * member is appropriate for the control. This member overlaps with the * other members of the structure member and * cannot be used in conjunction with those members. * * @field2 DWORD | cbCustomData | Specifies the size, in bytes, * required to hold the state of a custom control type. This member * is only appropriate for the * control type. See the description for custom control types for more * information on the use of this member. * * @tagname tMIXERCONTROL * * @othertype MIXERCONTROL FAR * | LPMIXERCONTROL | A pointer to a * structure. * * @othertype MIXERCONTROL * | PMIXERCONTROL | A pointer to a * structure. * * @xref , , , * , , * * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERLINECONTROLS | The structure references * what controls to retrieve information on from an audio mixer line. * * @field DWORD | cbStruct | Specifies the size, in bytes, of the * structure. This member must be initialized * before calling the function. The size * specified in this member must be large enough to contain the base * structure. When the * function returns, this member contains the actual size of the * information returned. The returned information will never exceed * the requested size and will never be smaller than the base * structure. * * @field DWORD | dwLineID | Specifies the line identifier to retrieve * one or all controls for. This member is not used if the * flag is specified for the * function--but the mixer device will return * this member in this case. The * and members are not used when * is specified. * * @field DWORD | dwControlID | Specifies the control identifier of the * control desired. This member is used with the * flag for * to retrieve the control information of the specified control. * Note that the member of the * structure will be returned by the mixer device * and is not required as an input parameter. This member overlaps with * the member and cannot be used in * conjunction with the query type. * * @field DWORD | dwControlType | Specifies the control type of the * control desired. This member is used with the * flag for * to retrieve the first control of the specified type on the line * specified by the member of the * structure. This member overlaps with the * member and cannot be used in * conjunction with the query type. * * @field DWORD | cControls | Specifies the number of * structure elements to retrieve. This member must be initialized by * the application before calling the function. * This member may only be one (if or * is specified) or the value * returned in the member of the * structure returned for a line. This member cannot be zero. If a * line specifies that it has no controls, then * should not be called. * * @field DWORD | cbmxctrl | Specifies the size, in bytes, of a single * structure. This must be at least large enough * to hold the base structure. The total size, in * bytes, required for the buffer pointed to by * member is the product of the and * members of the * structure. * * @field LPMIXERCONTROL | pamxctrl | Points to one or more * structures to receive the details on the requested audio mixer line * controls. This member may never be NULL and must be initialized before * calling the function. Each element of the * array of controls must be at least large enough to hold a base * structure. The member * must specify the size, in bytes, of each element in this array. No * initialization of the buffer pointed to by this member needs to be * initialized by the application. All members will be filled in by * the mixer device (including the member * of each structure) upon returning successfully to * the application. * * @tagname tMIXERLINECONTROLS * * @othertype MIXERLINECONTROLS FAR * | LPMIXERLINECONTROLS | A pointer to a * structure. * * @othertype MIXERLINECONTROLS * | PMIXERLINECONTROLS | A pointer to a * structure. * * @xref , , , * , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerGetLineControls | The * function is used to retrieve one or more controls associated with * an audio mixer device line. * * @parm | hmxobj | Specifies a handle to the audio mixer * device object to get line control information from. * * @parm LPMIXERLINECONTROLS | pmxlc | Points to a * structure. This structure is used to reference one or more * structures to be filled with information about the * controls associated with a mixer line. * See the comments for each query flag passed through

* for details on what members of the structure * that must be initialized. Note that in all cases, the * member of the * structure must be initialized to be the size, in bytes, of the * structure. * * @parm DWORD | fdwControls | Specifies flags for getting information on * one or more control associated with a mixer line. * * @flag | If this flag is specified, *

references a list of structures that * will receive information on all controls associated with the * line identified by the member of * the structure. * must be initialized to the number of controls associated with the * line. This number is retrieved from the * member of the structure returned by the * function. must * be initialized to the size, in bytes, of a single * structure. must point to * the first structure to be filled in. Both the * and * members are ignored for this query. * * @flag | If this flag is specified, *

references a single structure that * will receive information on the control identified by the * member of the * structure. must be initialized to one. * must be initialized to the size, in * bytes, of a single structure. * must point to a * structure to be filled in. Both the * and members are ignored for this * query. This query is usually used to refresh a control after * receiving a control change notification * message by the user-specified callback (see ). * * @flag | If this flag is specified, *

references a single structure that * will receive information on the fist control associated with the * line identified by of the type * specified in the member of the * structure. * must be * initialized to one. must be initialized * to the size, in bytes, of a single structure. * must point to a * structure to be filled in. The * member is ignored for this query. This query can be used by an * application to get information on single control associated with * a line. For example, an application may only want to use a peak * meter from a waveform output line. * * @flag | Specifies that

is an audio * mixer device identifier in the range of zero to one less than the * number of devices returned by . This flag is * optional. * * @flag | Specifies that

is a mixer * device handle returned by . This flag is optional. * * @flag | Specifies that

is a * waveform output device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform output handle returned by . * * @flag | Specifies that

is a * waveform input device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform input handle returned by . * * @flag | Specifies that

is a MIDI * output device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a * MIDI output handle returned by . * * @flag | Specifies that

is a MIDI * input device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a MIDI * input handle returned by . * * @flag | Specifies that

is an * auxiliary device identifier in the range of zero to one less than the * number of devices returned by . * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The

argument specifies an * invalid device identifier. * * @flag | The

argument specifies an * invalid handle. * * @flag | One or more flags are invalid. * * @flag | One or more arguments passed is * invalid. * * @flag | No audio mixer device is available for * the object specified by

. * * @flag | The audio mixer device line reference is * invalid. * * @flag | The control reference is invalid. * * @xref , , , * , , * **/ MMRESULT APIENTRY mixerGetLineControlsA( HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlcA, DWORD fdwControls ) { MIXERLINECONTROLSW mxlcW; MMRESULT mmr; DWORD cControls; V_WPOINTER(pmxlcA, sizeof(DWORD), MMSYSERR_INVALPARAM); V_WPOINTER(pmxlcA, (UINT)pmxlcA->cbStruct, MMSYSERR_INVALPARAM); if (sizeof(MIXERLINECONTROLSA) > pmxlcA->cbStruct) { DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbStruct not initialized (%lu).", pmxlcA->cbStruct); return (MMSYSERR_INVALPARAM); } // // Set up a MIXERCONTROLW structure and allocate space for the // returned data // CopyMemory((PVOID)&mxlcW, (PVOID)pmxlcA, FIELD_OFFSET(MIXERLINECONTROLSA, pamxctrl)); mxlcW.cbmxctrl = mxlcW.cbmxctrl + sizeof(MIXERCONTROLW) - sizeof(MIXERCONTROLA); // // Work out how many controls (what a mess - why isn't the count // ALWAYS required)! // switch (MIXER_GETLINECONTROLSF_QUERYMASK & fdwControls) { case MIXER_GETLINECONTROLSF_ONEBYID: case MIXER_GETLINECONTROLSF_ONEBYTYPE: cControls = 1; break; default: cControls = mxlcW.cControls; break; } if (cControls != 0) { mxlcW.pamxctrl = (LPMIXERCONTROLW) LocalAlloc(LPTR, cControls * mxlcW.cbmxctrl); if (mxlcW.pamxctrl == NULL) { return MMSYSERR_NOMEM; } } else { mxlcW.pamxctrl = NULL; } // // Call the real function // mmr = mixerGetLineControls(hmxobj, &mxlcW, fdwControls); if (mmr != MMSYSERR_NOERROR) { if (mxlcW.pamxctrl != NULL) { LocalFree((HLOCAL)mxlcW.pamxctrl); } return mmr; } // // The INPUT line id can be changed !! // pmxlcA->dwLineID = mxlcW.dwLineID; // // The control id can be changed !! // pmxlcA->dwControlID = mxlcW.dwControlID; // // Copy and massage the data back for the application // { UINT i; LPMIXERCONTROLA pamxctrlA; LPMIXERCONTROLW pamxctrlW; for (i = 0, pamxctrlA = pmxlcA->pamxctrl, pamxctrlW = mxlcW.pamxctrl; i < cControls; i++, *(LPBYTE *)&pamxctrlA += pmxlcA->cbmxctrl, *(LPBYTE *)&pamxctrlW += mxlcW.cbmxctrl ) { CopyMemory((PVOID)pamxctrlA, (PVOID)pamxctrlW, FIELD_OFFSET(MIXERCONTROLA, szShortName[0])); /* ** Set the size */ pamxctrlA->cbStruct = sizeof(MIXERCONTROLA); Iwcstombs(pamxctrlA->szShortName, pamxctrlW->szShortName, sizeof(pamxctrlA->szShortName)); Iwcstombs(pamxctrlA->szName, pamxctrlW->szName, sizeof(pamxctrlA->szName)); CopyMemory((PVOID)((PBYTE)pamxctrlA + FIELD_OFFSET(MIXERCONTROLA, Bounds.lMinimum)), (PVOID)((PBYTE)pamxctrlW + FIELD_OFFSET(MIXERCONTROLW, Bounds.lMinimum)), sizeof(MIXERCONTROLW) - FIELD_OFFSET(MIXERCONTROLW, Bounds.lMinimum)); } } if (mxlcW.pamxctrl != NULL) { LocalFree((HLOCAL)mxlcW.pamxctrl); } return mmr; } // mixerGetLineControlsA() MMRESULT APIENTRY mixerGetLineControls( HMIXEROBJ hmxobj, LPMIXERLINECONTROLS pmxlc, DWORD fdwControls ) { DWORD fdwMxObjType; UINT uMxId; BOOL fResource; MMRESULT mmr; V_DFLAGS(fdwControls, MIXER_GETLINECONTROLSF_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) > 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) > pmxlc->cbmxctrl) { DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbmxctrl not initialized (%lu).", pmxlc->cbmxctrl); return (MMSYSERR_INVALPARAM); } ClientUpdatePnpInfo(); // // // switch (MIXER_GETLINECONTROLSF_QUERYMASK & fdwControls) { case MIXER_GETLINECONTROLSF_ALL: if (0 == pmxlc->cControls) { DebugErr(DBF_ERROR, "mixerGetLineControls: cControls cannot be zero."); return (MMSYSERR_INVALPARAM); } pmxlc->dwControlID = (DWORD)-1L; break; case MIXER_GETLINECONTROLSF_ONEBYID: pmxlc->dwLineID = (DWORD)-1L; // -- fall through -- case MIXER_GETLINECONTROLSF_ONEBYTYPE: pmxlc->cControls = (DWORD)1; break; default: DebugErr1(DBF_ERROR, "mixerGetLineControls: invalid query flags (%.08lXh).", MIXER_GETLINECONTROLSF_QUERYMASK & fdwControls); return (MMSYSERR_INVALFLAG); } V_WPOINTER(pmxlc->pamxctrl, pmxlc->cControls * pmxlc->cbmxctrl, MMSYSERR_INVALPARAM); // // // fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwControls); fResource = FALSE; AcquireHandleListResourceShared(); // Checking for the type of mixer object. If it is a non-mixer type // calling IMixerMesssageID (called by IMixerGetID) with the shared // resource will deadlock. if ((MIXER_OBJECTF_MIXER == fdwMxObjType) || (MIXER_OBJECTF_HMIXER == fdwMxObjType)) { if (BAD_HANDLE(hmxobj, TYPE_MIXER)) { ReleaseHandleListResource(); } else { fResource = TRUE; } } else { ReleaseHandleListResource(); } mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType); if (MMSYSERR_NOERROR != mmr) { if (fResource) ReleaseHandleListResource(); 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_PTR)hmxobj == uMxId) hmxobj = NULL; } else { hmxobj = NULL; } // // // // if (NULL != hmxobj) { mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj, MXDM_GETLINECONTROLS, (DWORD_PTR)pmxlc, fdwControls); } else { mmr = (MMRESULT)IMixerMessageId(uMxId, MXDM_GETLINECONTROLS, (DWORD_PTR)pmxlc, fdwControls); } return (mmr); } // mixerGetLineControls() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCONTROLDETAILS_LISTTEXT | The * structure is used to get list text, label text, and/or band range * information for multiple item controls. This structure is only used * in conjunction with the flag * on the function. * * @field DWORD | dwParam1 | Specifies the first 32 bit control type * specific value. Refer to the description of the multiple item control * type for information on what this value represents for the given * control. * * @field DWORD | dwParam1 | Specifies the second 32 bit control type * specific value. Refer to the description of the multiple item control * type for information on what this value represents for the given * control. * * @field char | szName[] | Specifies a name that * describes a single item in a multiple item control. This text can * be used as a label or item text depending on the specific control * type. * * @comm The following standard control types use the * structure for getting the item text * descriptions on multiple item controls: * * * * * * * * * @tagname tMIXERCONTROLDETAILS_LISTTEXT * * @othertype MIXERCONTROLDETAILS_LISTTEXT FAR * | LPMIXERCONTROLDETAILS_LISTTEXT | * A pointer to a structure. * * @othertype MIXERCONTROLDETAILS_LISTTEXT * | PMIXERCONTROLDETAILS_LISTTEXT | * A pointer to a structure. * * @xref , , * , , * , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCONTROLDETAILS_BOOLEAN | The * structure is used to get and set Boolean type control details for * an audio mixer control. Refer to the control type description for * the desired control to determine what details structure to use. * * @field LONG | fValue | Specifies the Boolean value for a single item * or channel. This value is assumed to zero for a 'FALSE' state (for * example, off or disabled). This value is assumed to be non-zero * for a 'TRUE' state (for example, on or enabled). * * @comm The following standard control types use the * structure for getting and setting * details: * * * * * * * * * * * * * * * * * * @tagname tMIXERCONTROLDETAILS_BOOLEAN * * @othertype MIXERCONTROLDETAILS_BOOLEAN FAR * | LPMIXERCONTROLDETAILS_BOOLEAN | * A pointer to a structure. * * @othertype MIXERCONTROLDETAILS_BOOLEAN * | PMIXERCONTROLDETAILS_BOOLEAN | * A pointer to a structure. * * @xref , , * , , * , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCONTROLDETAILS_SIGNED | The * structure is used to get and set signed type control details for * an audio mixer control. Refer to the control type description for * the desired control to determine what details structure to use. * * @field LONG | lValue | Specifies a signed integer value for a single * item or channel. This value must be inclusively within the bounds * given in the structure member of the * structure for signed integer controls. * * @comm The following standard control types use the * structure for getting and setting * details: * * * * * * * * * * * * @tagname tMIXERCONTROLDETAILS_SIGNED * * @othertype MIXERCONTROLDETAILS_SIGNED FAR * | LPMIXERCONTROLDETAILS_SIGNED | * A pointer to a structure. * * @othertype MIXERCONTROLDETAILS_SIGNED * | PMIXERCONTROLDETAILS_SIGNED | * A pointer to a structure. * * @xref , , * , , * , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCONTROLDETAILS_UNSIGNED | The * structure is used to get and set unsigned type control details for * an audio mixer control. Refer to the control type description for * the desired control to determine what details structure to use. * * @field DWORD | dwValue | Specifies an unsigned integer value for a single * item or channel. This value must be inclusively within the bounds * given in the structure member of the * structure for unsigned integer controls. * * @comm The following standard control types use the * structure for getting and setting * details: * * * * * * * * * * * * * * * * @tagname tMIXERCONTROLDETAILS_UNSIGNED * * @othertype MIXERCONTROLDETAILS_UNSIGNED FAR * | LPMIXERCONTROLDETAILS_UNSIGNED | * A pointer to a structure. * * @othertype MIXERCONTROLDETAILS_UNSIGNED * | PMIXERCONTROLDETAILS_UNSIGNED | * A pointer to a structure. * * @xref , , * , , * , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK STRUCTURE * * @types MIXERCONTROLDETAILS | The structure * references control detail structures to retrieve or set state * information of an audio mixer control. All members of this structure * must be initialized before calling the * and functions. * * @field DWORD | cbStruct | Specifies the size, in bytes, of the * structure. This member must be initialized * before calling the and * functions. The size specified in this * member must be large enough to contain the base * structure. When the * function returns, this member contains the actual size of the * information returned. The returned information will never exceed * the requested size and will never be smaller than the base * structure. * * @field DWORD | dwControlID | Specifies the control identifier to get or * set details on. This member must always be initialized before calling * the and * functions. * * @field DWORD | cChannels | Specifies the number of channels to get or * set details for. This member can be one of the following values for a * control. * * 1. If the details for the control are expected on all channels for * a line, then this member must be equal the * member of the structure. * * 2. If the control is a control, then * this member must be set to one. * * 3. If the control is not uniform, but the application wishes to * get and set all channels as if they were uniform, then this member * should be set to one. * * 4. If the control is a control, * then this member must be zero. * * An application is not allowed to specify any value that comes * between one and the number of channels for the line. For example, * specifying two or three for a four channel line is not valid. * This member can never be zero for non-custom control types. * * @field DWORD | cMultipleItems | Specifies the number of multiple items * per channel to get or set details for. This member can be one of * the following values for a control. * * 1. If the control is not a control, * then this member must be zero. * * 2. If the control is a control, * then this member must be equal to the * member of the structure. * * 3. If the control is a control, * then this member must be zero unless the * flag is specified for the * function. In this case, the * member overlaps with the * member and is therefore the value * of the window handle. * * An application is not allowed to specify any value other than the * value specified in the member of * the structure for a * control. * * @field DWORD | cbDetails | Specifies the size, in bytes, of a single * details structure. This size must be the exact size of the correct * details structure. There are currently four different details * structures: * * @flag | Defines an unsigned * value for a mixer line control. * * @flag | Defines an signed * value for a mixer line control. * * @flag | Defines a Boolean * value for a mixer line control. * * @flag | Defines a list text * buffer for a mixer line control. * * Refer to the description of the control type for information on what * details structure is appropriate for a specific control. * * If the control is a control, * then this member must be equal to the * member of the structure. * * @field LPVOID | paDetails | Points to an array of one or more details * structures to get or set details for the specified control in. The * required size for this buffer is computed as follows: * * 1. For controls that are not types, * the size of this buffer is the product of the * and * members of the structure. * * 2. For controls that are types, * the size of this buffer is the product of the * , * and members of the * structure. * * The layout of the details elements in this array are as follows: * * 1. For controls that are not types, * each element index is equivalent to the zero based channel that it * affects. That is, [0] is for the * left channel, [1] is for the * right channel. * * 2. For controls that are types, * the array can be thought of as a two dimensional array that is * 'channel major'. That is, all multiple items for the left channel * are given, then all multiple items for the right channel, etc. * * If the control is a control, * then this member must point to a buffer that is at least large * enough to hold the size, in bytes, specified by the * member of the * structure. * * @tagname tMIXERCONTROLDETAILS * * @othertype MIXERCONTROLDETAILS FAR * | LPMIXERCONTROLDETAILS | A pointer * to a structure. * * @othertype MIXERCONTROLDETAILS * | PMIXERCONTROLDETAILS | A pointer * to a structure. * * @ex So the following example shows how to address a single item in a * multiple item control for using the * details structure. | * { * MIXERCONTROLDETAILS mxcd; * PMIXERCONTROLDETAILS_SIGNED pamxcd_s; * PMIXERCONTROLDETAILS_SIGNED pmxcd_s; * * // * // 'mxcd' is assumed to be a valid MIXERCONTROLDETAILS * // structure. * // * // 'channel' is assumed to be a valid channel ranging from zero * // to one less than the number of channels available for the * // signed control. * // * // 'item' is assumed to be a valid item index ranging from zero * // to one less than the number of 'multiple items' stored in * // the variable called 'cMultipleItems'. * // * pamxcd_s = (PMIXERCONTROLDETAILS_SIGNED)mxcd.paDetails; * pmxcd_s = &pamxcd_s[(channel * cMultipleItems) + item]; * } * * @xref , , * , * **/ /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerGetControlDetails | The * function is used to retrieve details on a single control associated * with an audio mixer device line. * * @parm | hmxobj | Specifies a handle to the audio mixer * device object to get control details for. * * @parm LPMIXERCONTROLDETAILS | pmxcd | Points to a * structure. This structure is used to reference control detail * structures to be filled with state information about the control. * See the comments for each query flag passed through

* for details on what members of the structure * must be initialized before calling the * function. Note that in all cases, the * member of the structure must be initialized * to be the size, in bytes, of the structure. * * @parm DWORD | fdwDetails | Specifies flags for getting details on * a control. * * @flag | If this flag is specified, * the application is interested in getting the current value(s) for a * control. The member of the * points to one or more details structures of * the correct type for the control type. Refer to the description of the * structure for information on what each member * of this structure must be initialized before calling the * function. * * @flag | If this flag is specified, * the member of the * structure points to one or more * structures to receive text labels for multiple item controls. Note * that an application must get all list text items for a multiple item * control at once. Refer to the description of the * structure for information on what each member of this structure must * be initialized before calling the function. * This flag cannot be used with * controls. * * @flag | Specifies that

is an audio * mixer device identifier in the range of zero to one less than the * number of devices returned by . This flag is * optional. * * @flag | Specifies that

is a mixer * device handle returned by . This flag is optional. * * @flag | Specifies that

is a * waveform output device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform output handle returned by . * * @flag | Specifies that

is a * waveform input device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform input handle returned by . * * @flag | Specifies that

is a MIDI * output device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a * MIDI output handle returned by . * * @flag | Specifies that

is a MIDI * input device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a MIDI * input handle returned by . * * @flag | Specifies that

is an * auxiliary device identifier in the range of zero to one less than the * number of devices returned by . * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The

argument specifies an * invalid device identifier. * * @flag | The

argument specifies an * invalid handle. * * @flag | One or more flags are invalid. * * @flag | One or more arguments passed is * invalid. * * @flag | No audio mixer device is available for * the object specified by

. * * @flag | The control reference is invalid. * * @xref , , , * , * **/ MMRESULT APIENTRY mixerGetControlDetailsA( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails ) { MIXERCONTROLDETAILS mxcd; MMRESULT mmr; int cDetails; // // Everything is OK unless it's MIXER_GETCONTROLDETAILSF_LISTTEXT // if ((MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails) != MIXER_GETCONTROLDETAILSF_LISTTEXT) { return mixerGetControlDetails(hmxobj, pmxcd, fdwDetails); } V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM); // // the structure header for MIXERCONTROLDETAILS must be at least the // minimum size // if (sizeof(MIXERCONTROLDETAILS) > 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); if (sizeof(MIXERCONTROLDETAILS_LISTTEXTA) < pmxcd->cbDetails) { DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized for _LISTTEXT (%lu).", pmxcd->cbDetails); return (MMSYSERR_INVALPARAM); } // // Allocate space for the return structure. // mxcd = *pmxcd; cDetails = pmxcd->cChannels * pmxcd->cMultipleItems; mxcd.paDetails = (PVOID)LocalAlloc(LPTR, cDetails * sizeof(MIXERCONTROLDETAILS_LISTTEXTW)); mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); if (mxcd.paDetails == NULL) { return MMSYSERR_NOMEM; } // // Call the UNICODE version // mmr = mixerGetControlDetails(hmxobj, &mxcd, fdwDetails); if (mmr != MMSYSERR_NOERROR) { LocalFree((HLOCAL)(mxcd.paDetails)); return mmr; } // // Copy the return data back // { int i; PMIXERCONTROLDETAILS_LISTTEXTW pDetailsW; PMIXERCONTROLDETAILS_LISTTEXTA pDetailsA; for (i = 0, pDetailsW = (PMIXERCONTROLDETAILS_LISTTEXTW)mxcd.paDetails, pDetailsA = (PMIXERCONTROLDETAILS_LISTTEXTA)pmxcd->paDetails; i < cDetails; i++, pDetailsW++, *(LPBYTE *)&pDetailsA += pmxcd->cbDetails) { pDetailsA->dwParam1 = pDetailsW->dwParam1; pDetailsA->dwParam2 = pDetailsW->dwParam2; Iwcstombs(pDetailsA->szName, pDetailsW->szName, sizeof(pDetailsA->szName)); } } LocalFree((HLOCAL)mxcd.paDetails); return mmr; } // mixerGetControlDetailsA() MMRESULT APIENTRY mixerGetControlDetails( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails ) { DWORD fdwMxObjType; MMRESULT mmr; UINT uMxId; UINT cDetails; BOOL fResource; V_DFLAGS(fdwDetails, MIXER_GETCONTROLDETAILSF_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) > 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 (MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails) { case MIXER_GETCONTROLDETAILSF_VALUE: // // if both cChannels and cMultipleItems are zero, it is a // custom control // if ((0 == pmxcd->cChannels) && (0 == pmxcd->cMultipleItems)) { if (0 == pmxcd->cbDetails) { DebugErr(DBF_ERROR, "mixerGetControlDetails: cbDetails cannot be zero."); return (MMSYSERR_INVALPARAM); } V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM); } else { if (0 == 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 (0 != pmxcd->cMultipleItems) { cDetails *= (UINT)pmxcd->cMultipleItems; } V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM); } break; case MIXER_GETCONTROLDETAILSF_LISTTEXT: if (0 == pmxcd->cChannels) { DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _LISTTEXT cannot be zero."); return (MMSYSERR_INVALPARAM); } if (2 > 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).", MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails); return (MMSYSERR_INVALFLAG); } ClientUpdatePnpInfo(); // // // fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails); fResource = FALSE; AcquireHandleListResourceShared(); // Checking for the type of mixer object. If it is a non-mixer type // calling IMixerMesssageID (called by IMixerGetID) with the shared // resource will deadlock. if ((MIXER_OBJECTF_MIXER == fdwMxObjType) || (MIXER_OBJECTF_HMIXER == fdwMxObjType)) { if (BAD_HANDLE(hmxobj, TYPE_MIXER)) { ReleaseHandleListResource(); } else { fResource = TRUE; } } else { ReleaseHandleListResource(); } mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType); if (MMSYSERR_NOERROR != mmr) { if (fResource) ReleaseHandleListResource(); 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_PTR)hmxobj == uMxId) hmxobj = NULL; } else { hmxobj = NULL; } // // // // if (NULL != hmxobj) { mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj, MXDM_GETCONTROLDETAILS, (DWORD_PTR)pmxcd, fdwDetails); } else { mmr = (MMRESULT)IMixerMessageId(uMxId, MXDM_GETCONTROLDETAILS, (DWORD_PTR)pmxcd, fdwDetails); } return (mmr); } // mixerGetControlDetails() /*--------------------------------------------------------------------------; * * @doc EXTERNAL MIXER SDK API * * @api MMRESULT | mixerSetControlDetails | The * function is used to set details on a single control associated * with an audio mixer device line. * * @parm | hmxobj | Specifies a handle to the audio mixer * device object to set control details for. * * @parm LPMIXERCONTROLDETAILS | pmxcd | Points to a * structure. This structure is used to reference control detail * structures to that contain the desired state for the control. * See the description for the structure * to determine what members of this structure must be initialized * before calling the function. Note that * in all cases, the member of the * structure must be initialized * to be the size, in bytes, of the structure. * * @parm DWORD | fdwDetails | Specifies flags for setting details for * a control. * * @flag | If this flag is specified, * the application is interested in setting the current value(s) for a * control. The member of the * points to one or more details structures of * the correct type for the control type. Refer to the description of the * structure for information on what each member * of this structure must be initialized before calling the * function. * * @flag | If this flag is specified, * the application is asking the mixer device to display a custom * dialog for the specified custom mixer control. The handle for the * owning window is specified in the * member (this handle may, validly, be NULL). The mixer device will * gather the required information from the user and return the data * in the specified buffer. This data may then be saved by the * application and later set back to the same state using the * flag. If an application only * needs to get the current state of a custom mixer control without * displaying a dialog, then the function * can be used with the flag. * * @flag | Specifies that

is an audio * mixer device identifier in the range of zero to one less than the * number of devices returned by . This flag is * optional. * * @flag | Specifies that

is a mixer * device handle returned by . This flag is optional. * * @flag | Specifies that

is a * waveform output device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform output handle returned by . * * @flag | Specifies that

is a * waveform input device identifier in the range of zero to one less * than the number of devices returned by . * * @flag | Specifies that

is a * waveform input handle returned by . * * @flag | Specifies that

is a MIDI * output device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a * MIDI output handle returned by . * * @flag | Specifies that

is a MIDI * input device identifier in the range of zero to one less than the * number of devices returned by . * * @flag | Specifies that

is a MIDI * input handle returned by . * * @flag | Specifies that

is an * auxiliary device identifier in the range of zero to one less than the * number of devices returned by . * * @rdesc The return value is zero if the function is successful. Otherwise, * it returns a non-zero error number. Possible error returns include * the following: * * @flag | The

argument specifies an * invalid device identifier. * * @flag | The

argument specifies an * invalid handle. * * @flag | One or more flags are invalid. * * @flag | One or more arguments passed is * invalid. * * @flag | No audio mixer device is available for * the object specified by

. * * @flag | The control reference is invalid. * * @xref , , , * , * **/ MMRESULT APIENTRY mixerSetControlDetails( HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails ) { DWORD fdwMxObjType; MMRESULT mmr; UINT uMxId; UINT cDetails; BOOL fResource; V_DFLAGS(fdwDetails, MIXER_SETCONTROLDETAILSF_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) > 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 (MIXER_SETCONTROLDETAILSF_QUERYMASK & fdwDetails) { case MIXER_SETCONTROLDETAILSF_VALUE: // // cChannels is zero for custom controls // if (0 == pmxcd->cChannels) { if (0 == pmxcd->cbDetails) { DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero."); return (MMSYSERR_INVALPARAM); } V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM); // // // if (0 != 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 (0 != pmxcd->cMultipleItems) { cDetails *= (UINT)(pmxcd->cMultipleItems); } V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM); } break; case MIXER_SETCONTROLDETAILSF_CUSTOM: if (0 == pmxcd->cbDetails) { DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero for custom controls."); return (MMSYSERR_INVALPARAM); } if (0 != 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).", MIXER_SETCONTROLDETAILSF_QUERYMASK & fdwDetails); return (MMSYSERR_INVALFLAG); } ClientUpdatePnpInfo(); // // // fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails); fResource = FALSE; AcquireHandleListResourceShared(); // Checking for the type of mixer object. If it is a non-mixer type // calling IMixerMesssageID (called by IMixerGetID) with the shared // resource will deadlock. if ((MIXER_OBJECTF_MIXER == fdwMxObjType) || (MIXER_OBJECTF_HMIXER == fdwMxObjType)) { if (BAD_HANDLE(hmxobj, TYPE_MIXER)) { ReleaseHandleListResource(); } else { fResource = TRUE; } } else { ReleaseHandleListResource(); } mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType); if (MMSYSERR_NOERROR != mmr) { if (fResource) ReleaseHandleListResource(); 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_PTR)hmxobj == uMxId) hmxobj = NULL; } else { hmxobj = NULL; } // // // // if (NULL != hmxobj) { mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj, MXDM_SETCONTROLDETAILS, (DWORD_PTR)pmxcd, fdwDetails); } else { mmr = (MMRESULT)IMixerMessageId(uMxId, MXDM_SETCONTROLDETAILS, (DWORD_PTR)pmxcd, fdwDetails); } return (mmr); } // mixerSetControlDetails() //--------------------------------------------------------------------------; // // MMRESULT mixerDesertHandle // // Description: // Cleans up the mixer handle and marks it as deserted. // // Arguments: // HMIXER hmx: Mixer handle. // // Return (MMRESULT): Error code. // // History: // 01/25/99 Fwong Adding Pnp Support. // //--------------------------------------------------------------------------; MMRESULT mixerDesertHandle ( HMIXER hmx ) { MMRESULT mmr; PMIXERDEV pmxdev; PMIXERDEV pmxdevT; PMIXERDRV pmxdrv; BOOL fClose; V_HANDLE_ACQ(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE); ENTER_MM_HANDLE(hmx); ReleaseHandleListResource(); if (IsHandleDeserted(hmx)) { // Handle has already been deserted... LEAVE_MM_HANDLE(hmx); return (MMSYSERR_NOERROR); } // Marking handle as deserted SetHandleFlag(hmx, MMHANDLE_DESERTED); // // remove the mixer handle from the linked list // MIXMGR_ENTER; pmxdev = (PMIXERDEV)hmx; pmxdrv = pmxdev->pmxdrv; if (pmxdev == gpMixerDevHeader) { gpMixerDevHeader = pmxdev->pmxdevNext; } else { for (pmxdevT = gpMixerDevHeader; pmxdevT && (pmxdevT->pmxdevNext != pmxdev); pmxdevT = pmxdevT->pmxdevNext) ; if (NULL == pmxdevT) { DebugErr1(DBF_ERROR, "mixerDesertHandle: invalid mixer handle (%.04Xh).", hmx); MIXMGR_LEAVE; LEAVE_MM_HANDLE(hmx); return (MMSYSERR_INVALHANDLE); } pmxdevT->pmxdevNext = pmxdev->pmxdevNext; } // // see if this is the last handle on this open instance // fClose = TRUE; if (gpMixerDevHeader) { PMIXERDEV pmxdevT2; for (pmxdevT2 = gpMixerDevHeader; pmxdevT2; pmxdevT2 = pmxdevT2->pmxdevNext) { if (pmxdevT2->pmxdrv != pmxdev->pmxdrv) continue; if (pmxdevT2->wDevice != pmxdev->wDevice) continue; fClose = FALSE; break; } } MIXMGR_LEAVE; if (fClose) { EnterCriticalSection(&pmxdev->pmxdrv->MixerCritSec); mmr = (*(pmxdrv->drvMessage))(pmxdev->wDevice, MXDM_CLOSE, pmxdev->dwDrvUser, 0L, 0L); LeaveCriticalSection(&pmxdev->pmxdrv->MixerCritSec); if (MMSYSERR_NOERROR != mmr) { // Close message failed. // Should we put the handle back in the list??? LEAVE_MM_HANDLE(hmx); return mmr; } } LEAVE_MM_HANDLE(hmx); mregDecUsage(PTtoH(HMD, pmxdev->pmxdrv)); return MMSYSERR_NOERROR; } // mixerDesertHandle()