问题描述
- windows系统音量控制,API函数调用出错
-
最近在开发一个项目过程中遇到一些问题,问题具体如下:
项目中我需要控制系统音量,也就是麦克风以及扬声器音量,于是我找到了一个CVolume类,代码如下://Volume.h
include "MMSystem.h"
define HMIXER_NUM_MAX 10
class CVolume
{
public:
CVolume(void);
public:
~CVolume(void);public:
HMIXER m_hMixer[HMIXER_NUM_MAX];
BOOL m_barrOpened[HMIXER_NUM_MAX];
HMIXER m_hMixerMic;
HMIXER m_hMixerSpk;
int m_iMixerNums;
MIXERLINE m_MixerLineMicrophone;BOOL MixerOpen();
void MixerClose();
BOOL m_bIsOpen;
BOOL GetMicrophoneID();
BOOL GetMicrophoneLevel(DWORD* dwLevel, DWORD* dwLevelMax);
BOOL SetMicrophoneLevel(DWORD dwLevel);
BOOL GetSpeakerLevel(DWORD* dwLevel, DWORD* dwLevelMax);
BOOL SetSpeakerLevel(DWORD dwLevel);};
//Volume.cpp
include "stdafx.h"
include "Volume.h"
CVolume::CVolume(void)
{
m_bIsOpen = FALSE;
m_iMixerNums = 0;
m_hMixerMic = 0;
m_hMixerSpk = 0;
for (int i = 0; i < HMIXER_NUM_MAX; i ++)
m_barrOpened[i] = FALSE;
}CVolume::~CVolume(void)
{
MixerClose();
}BOOL CVolume::MixerOpen()
{
m_iMixerNums = mixerGetNumDevs();
if (mixerGetNumDevs() < 1)
return FALSE;
m_iMixerNums = min(m_iMixerNums, HMIXER_NUM_MAX);
m_bIsOpen = FALSE;
for (int i = 0; i < m_iMixerNums; i ++)
{
MMRESULT mmresult = mixerOpen(&m_hMixer[i], (UINT)i, 0, 0, MIXER_OBJECTF_MIXER);if (mmresult == MMSYSERR_NOERROR)
{
m_barrOpened[i] = TRUE;
m_bIsOpen = TRUE;
}
}
return m_bIsOpen;
}void CVolume::MixerClose()
{
if (m_bIsOpen)
{
for (int i = 0; i < m_iMixerNums; i ++)
{
if (m_barrOpened[i])
{
mixerClose(m_hMixer[i]);
m_barrOpened[i] = FALSE;
}
}
m_bIsOpen = FALSE;
}
}BOOL CVolume::GetMicrophoneID()
{
MMRESULT mmresult;
if (!m_bIsOpen)
return FALSE;
m_MixerLineMicrophone.cbStruct = sizeof(m_MixerLineMicrophone);
m_MixerLineMicrophone.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
for (int i = 0; i < m_iMixerNums; i ++)
{
mmresult = mixerGetLineInfo((HMIXEROBJ)m_hMixer[i], &m_MixerLineMicrophone,
MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);
if (mmresult == MMSYSERR_NOERROR)
{
m_hMixerMic = m_hMixer[i];
break;
}
}
if (m_hMixerMic == 0)
return FALSE;
DWORD dwConnections = m_MixerLineMicrophone.cConnections;
DWORD dwLineID = 0;
for (DWORD i = 0; i < dwConnections; i++){
m_MixerLineMicrophone.dwSource = i;
MMRESULT mr = mixerGetLineInfo((HMIXEROBJ)m_hMixerMic, &m_MixerLineMicrophone,
MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_SOURCE);
if (mr != MMSYSERR_NOERROR)
{
break;
}
if (m_MixerLineMicrophone.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
{
dwLineID = m_MixerLineMicrophone.dwLineID;
break;
}
}
if (dwLineID == 0)
{
return FALSE;
}
return TRUE;
}BOOL CVolume::GetMicrophoneLevel(DWORD* dwLevel, DWORD* dwLevelMax)
{
MMRESULT mmresult;
MIXERCONTROL mxc;MIXERLINECONTROLS mxlc;
if (!m_bIsOpen)
return FALSE;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);mxlc.dwLineID = m_MixerLineMicrophone.dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
mmresult = mixerGetLineControls(
reinterpret_cast(m_hMixerMic),
&mxlc,
MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmresult != MMSYSERR_NOERROR)
return FALSE;
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdVolume;
mmresult = mixerGetControlDetails(
reinterpret_cast(m_hMixerMic),
&mxcd,
MIXER_GETCONTROLDETAILSF_VALUE);
if (mmresult != MMSYSERR_NOERROR)
return FALSE;
*dwLevel = mxcdVolume.dwValue;
*dwLevelMax = mxc.Bounds.dwMaximum;
return TRUE;
}BOOL CVolume::SetMicrophoneLevel(DWORD dwLevel)
{
MMRESULT mmresult;
MIXERCONTROL mxc;MIXERLINECONTROLS mxlc;
if (!m_bIsOpen)
return FALSE;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);mxlc.dwLineID = m_MixerLineMicrophone.dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
mmresult = mixerGetLineControls(
reinterpret_cast(m_hMixerMic),
&mxlc,
MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmresult != MMSYSERR_NOERROR)
return FALSE;
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume_Set ={
dwLevel
};
MIXERCONTROLDETAILS mxcd_Set;
mxcd_Set.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd_Set.dwControlID = mxc.dwControlID;
mxcd_Set.cChannels = 1;
mxcd_Set.cMultipleItems = 0;
mxcd_Set.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd_Set.paDetails = &mxcdVolume_Set;
mmresult = mixerSetControlDetails(reinterpret_cast(m_hMixerMic),
&mxcd_Set,
MIXER_OBJECTF_HMIXER |
MIXER_SETCONTROLDETAILSF_VALUE);
return (mmresult == MMSYSERR_NOERROR);
}BOOL CVolume::GetSpeakerLevel(DWORD* dwLevel, DWORD* dwLevelMax)
{
MMRESULT mmr;
MIXERLINE mxl;
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
if (!m_bIsOpen)
return FALSE;
for (int i = 0; i < m_iMixerNums; i ++)
{
mxl.cbStruct = sizeof(mxl);
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
mmr = mixerGetLineInfo((HMIXEROBJ)m_hMixer[i], &mxl, MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);
if ( mmr == MMSYSERR_NOERROR)
{
m_hMixerSpk = m_hMixer[i];
break;
}
}
if (m_hMixerSpk == 0)
return FALSE;
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = mxl.dwLineID;
mxlc.cControls = mxl.cControls;
mxlc.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls((HMIXEROBJ)m_hMixerSpk, &mxlc, MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(mxcdVolume);
mxcd.paDetails = &mxcdVolume;
mmr = mixerGetControlDetails((HMIXEROBJ)m_hMixerSpk, &mxcd,
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);if (mmr != MMSYSERR_NOERROR)
return FALSE;
*dwLevel = mxcdVolume.dwValue;
*dwLevelMax = mxc.Bounds.dwMaximum;
return TRUE;
}BOOL CVolume::SetSpeakerLevel(DWORD dwLevelPercent)
{
MMRESULT mmr;
MIXERLINE mxl;
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
if (!m_bIsOpen)
return FALSE;
mxl.cbStruct = sizeof(mxl);
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
mmr = mixerGetLineInfo((HMIXEROBJ)m_hMixerSpk, &mxl, MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = mxl.dwLineID;
mxlc.cControls = mxl.cControls;
mxlc.dwControlID = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls((HMIXEROBJ)m_hMixerSpk, &mxlc, MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume_Set ={
dwLevelPercent
};
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(mxcdVolume);
mxcd.paDetails = &mxcdVolume_Set;
mmr = mixerSetControlDetails((HMIXEROBJ)m_hMixerSpk, &mxcd,
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);return (mmr == MMSYSERR_NOERROR);
}
可以看到这个类结构还是非常简单明了的,但是却出现了意想不到的错误,我在基于对话框项目程序中调用volumeControl.MixerOpen()函数时,volumeControl是我添加的CVolume类,编译连接都没有出现问题,在运行程序时出现:Unhandled exception at 0x0002bfc0 in CSHowlingSupress.exe: 0xC0000005: Access violation.
我知道问题肯定是出现在MixerOpen函数中,于是我在MixerOpen入口处设置断点,这时我发现mixerGetNumDevs函数 CXX0017: Error: symbol "mixerGetNumDevs" not found。 也就是说这个函数根明就没有申明,调用了空指针。但是我实在搞不明白,mixerGetNumDevs不是WIN API 函数吗,需要用的库函数Winmm.lib我也加在项目属性中添加了,怎么还会出现这种问题呢,我无语了。我电脑安装了有两块声卡,Realtek High Definition Audio和RME Fireface UC。哪位大神能帮我看看啊,感激不尽!