在Vista / 7(C ++)上获取卷更改通知 [英] Getting volume change notifications on Vista/7 (C++)
问题描述
我尝试在Windows Vista / 7上的主音量变化时收到通知。这是我使用的代码:
#include< audiopolicy.h>
#include< audioclient.h>
#include< mmdeviceapi.h>
#include< endpointvolume.h>
#include< windows.h>
#include< shlwapi.h>
#include< iostream>
#include< Tchar.h>
static const GUID AudioSessionVolumeCtx = {0x2715279f,0x4139,0x4ba0,{0x9c,0xb1,0xb3,0x51,0xf1,0xb5,0x8a,0x4a}};
template< class T> void SafeRelease(T ** ppT)
{
if(* ppT)
{
(* ppT) - &
* ppT = NULL;
}
}
class CAudioSessionVolume:public IAudioSessionEvents
{
public:
static HRESULT CreateInstance(UINT uNotificationMessage,HWND hwndNotification,CAudioSessionVolume * * ppAudioSessionVolume)
{
CAudioSessionVolume * pAudioSessionVolume = new(std :: nothrow)
CAudioSessionVolume(uNotificationMessage,hwndNotification);
if(pAudioSessionVolume == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pAudioSessionVolume-> Initialize();
if(SUCCEEDED(hr))
{
* ppAudioSessionVolume = pAudioSessionVolume;
}
else
{
pAudioSessionVolume-> Release();
}
return hr;
}
// IUnknown方法。
STDMETHODIMP QueryInterface(REFIID riid,void ** ppv)
{
static const QITAB qit [] =
{
QITABENT(CAudioSessionVolume,IAudioSessionEvents),
{0},
};
return QISearch(this,qit,riid,ppv);
}
STDMETHODIMP_(ULONG)AddRef()
{
return InterlockedIncrement(& m_cRef);
}
STDMETHODIMP_(ULONG)Release()
{
LONG cRef = InterlockedDecrement(& m_cRef);
if(cRef == 0)
{
delete this;
}
return cRef;
}
STDMETHODIMP OnSimpleVolumeChanged(float NewVolume,BOOL NewMute,LPCGUID EventContext)
{
MessageBox(NULL,_T(vol changed),_T ),MB_OK);
return S_OK;
}
//剩余的音频会话事件不需要任何操作。
STDMETHODIMP OnDisplayNameChanged(LPCWSTR,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnIconPathChanged(LPCWSTR,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnChannelVolumeChanged(DWORD,float [],DWORD,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnGroupingParamChanged(LPCGUID,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnStateChanged(AudioSessionState)
{
return S_OK;
}
STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason)
{
return S_OK;
}
//其他方法
HRESULT启用通知(BOOL bEnable)
{
HRESULT hr = S_OK;
if(bEnable)
{
hr = m_pAudioSession-> RegisterAudioSessionNotification(this);
}
else
{
hr = m_pAudioSession-> UnregisterAudioSessionNotification(this);
}
return hr;
}
HRESULT SetDisplayName(const WCHAR * wszName)
{
if(m_pAudioSession == NULL)
{
return E_FAIL;
}
else
{
return m_pAudioSession-> SetDisplayName(wszName,NULL);
}
}
protected:
CAudioSessionVolume(UINT uNotificationMessage,HWND hwndNotification):
m_cRef(1),m_pAudioSession(NULL),m_pSimpleAudioVolume )
{
}
〜CAudioSessionVolume()
{
EnableNotifications(FALSE);
SafeRelease(& m_pAudioSession);
SafeRelease(& m_pSimpleAudioVolume);
}
HRESULT初始化()
{
HRESULT hr = S_OK;
IMMDeviceEnumerator * pDeviceEnumerator = NULL;
IMMDevice * pDevice = NULL;
IAudioSessionManager * pAudioSessionManager = NULL;
//获取音频端点设备的枚举。
hr = CoCreateInstance(__ uuidof(MMDeviceEnumerator),NULL,
CLSCTX_INPROC_SERVER,IID_PPV_ARGS(& pDeviceEnumerator));
if(FAILED(hr))
{
goto done;
}
//获取SAR将使用的默认音频端点。
hr = pDeviceEnumerator-> GetDefaultAudioEndpoint(eRender,eConsole,
& pDevice);
if(FAILED(hr))
{
goto done;
}
//获取此设备的会话管理器。
hr = pDevice-> Activate(__ uuidof(IAudioSessionManager),
CLSCTX_INPROC_SERVER,NULL,(void **)& pAudioSessionManager);
if(FAILED(hr))
{
goto done;
}
//获取音频会话。
hr = pAudioSessionManager-> GetAudioSessionControl(
& GUID_NULL,//获取默认的音频会话
FALSE,//会话不是跨进程的
& m_pAudioSession);
if(FAILED(hr))
{
goto done;
}
hr = pAudioSessionManager-> GetSimpleAudioVolume(& GUID_NULL,0,
& m_pSimpleAudioVolume);
done:
SafeRelease(& pDeviceEnumerator);
SafeRelease(& pDevice);
SafeRelease(& pAudioSessionManager);
return hr;
}
private:
LONG m_cRef;
IAudioSessionControl * m_pAudioSession;
ISimpleAudioVolume * m_pSimpleAudioVolume;
};
int main()
{
CoInitialize(NULL);
CAudioSessionVolume * asv;
CAudioSessionVolume :: CreateInstance(0,NULL,& asv);
asv-> EnableNotifications(true);
char s;
gets(& s);
}
我希望在系统显示vol changed的消息框
我得到了大部分的代码从 http://msdn.microsoft.com/en-us/library/dd374921(VS.85).aspx
我做错了什么?
EDIT:卷为我的应用程序(感谢@nobugz)。但我想更改主音量通知。 (在Win7的音量调音台对话框中列为设备)
编辑2: Larry Osterman有一系列关于Vista / 7。这一点特别有趣: http://blogs.msdn.com/larryosterman/archive/2007/03/22/fun-with-the-endpoint-volume-interfaces-closing-the-loop.aspx 我会明天试试代码,看看我能得到我想要的。
编辑3:这是Larry的博客文章,包括上面链接的完整代码。它做我需要的,然后一些。我将尝试修剪我不需要的功能。
#include< windows.h>
#include< mmdeviceapi.h>
#include< endpointvolume.h>
#include< Tchar.h>
#include< strsafe.h>
class CVolumeNotification:public IAudioEndpointVolumeCallback
{
LONG m_RefCount;
〜CVolumeNotification(void){};
public:
CVolumeNotification(void):m_RefCount(1)
{
}
STDMETHODIMP_(ULONG)AddRef(){return InterlockedIncrement(& m_RefCount); }
STDMETHODIMP_(ULONG)Release()
{
LONG ref = InterlockedDecrement(& m_RefCount);
if(ref == 0)
delete this;
return ref;
}
STDMETHODIMP QueryInterface(REFIID IID,void ** ReturnValue)
{
if(IID == IID_IUnknown || IID == __uuidof(IAudioEndpointVolumeCallback))
{
* ReturnValue = static_cast< IUnknown *>(this);
Addref();
return S_OK;
}
* ReturnValue = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA NotificationData)
{
wchar_t outputString [256];
DWORD写入;
COORD writeCoord;
StringCbPrintf(outputString,sizeof(outputString),LVolume Changed:%f,NotificationData-> fMasterVolume);
writeCoord.X = 0;
writeCoord.Y = 3,
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),outputString,(DWORD)wcslen(outputString),writeCoord,& written);
return S_OK;
}
};
struct TimerContext
{
IAudioMeterInformation * _Meter;
};
const int TimerPeriodicityMS = 100;
void CALLBACK TimerMeterCallback(PTP_CALLBACK_INSTANCE CallbackInstance,PVOID Context,PTP_TIMER Timer)
{
TimerContext * timerContext =(TimerContext *)Context;
wchar_t outputString [256];
float peakValue;
DWORD写入;
COORD writeCoord;
StringCbCopy(outputString,sizeof(outputString),LMeter:);
timerContext-> _Meter-> GetPeakValue(& peakValue);
for(size_t i = 0; i {
StringCbCat(outputString,sizeof(outputString),L*);
}
for(size_t i =(size_t)(peakValue * 100); i <100; i + = 1)
{
StringCbCat(outputString,sizeof(outputString) ,L。
}
writeCoord.X = 0;
writeCoord.Y = 1;
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),outputString,(DWORD)wcslen(outputString),writeCoord,& written);
}
int _tmain(int argc,_TCHAR * argv [])
{
CoInitialize(NULL)
HRESULT hr;
IMMDeviceEnumerator * deviceEnumerator = NULL ;;
HANDLE句柄;
TP_CALLBACK_ENVIRON callbackEnvironment;
PTP_CLEANUP_GROUP cleanupGroup;
PTP_TIMER timer;
TimerContext上下文;
InitializeThreadpoolEnvironment(& callbackEnvironment);
cleanupGroup = CreateThreadpoolCleanupGroup();
SetThreadpoolCallbackCleanupGroup(& callbackEnvironment,cleanupGroup,NULL);
timer = CreateThreadpoolTimer(TimerMeterCallback,& context,& callbackEnvironment);
//
//清除屏幕。代码被盗:http://support.microsoft.com/kb/319257。
//
handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD writtenChars = 0;
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
COORD首页;
home.X = home.Y = 0;
GetConsoleScreenBufferInfo(handle,& consoleInfo);
FillConsoleOutputCharacter(handle,L'',consoleInfo.dwSize.X * consoleInfo.dwSize.Y,home,& writtenChars);
SetConsoleCursorPosition(handle,home);
//
//将控制台设置为原始模式。
//
DWORD oldMode;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),& oldMode);
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),oldMode&〜(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
//
//实例化端点卷对象。
//
hr = CoCreateInstance(__ uuidof(MMDeviceEnumerator),NULL,CLSCTX_INPROC_SERVER,__uuidof(IMMDeviceEnumerator),(LPVOID *)& deviceEnumerator);
IMMDevice * defaultDevice = NULL;
hr = deviceEnumerator-> GetDefaultAudioEndpoint(eRender,eConsole,& defaultDevice);
deviceEnumerator-> Release();
deviceEnumerator = NULL;
IAudioEndpointVolume * endpointVolume = NULL;
hr = defaultDevice-> Activate(__ uuidof(IAudioEndpointVolume),CLSCTX_INPROC_SERVER,NULL,(LPVOID *)& endpointVolume);
CVolumeNotification * volumeNotification = new CVolumeNotification();
hr = endpointVolume-> RegisterControlChangeNotify(volumeNotification);
hr = defaultDevice-> Activate(__ uuidof(IAudioMeterInformation),CLSCTX_INPROC_SERVER,NULL,(LPVOID *)& context._Meter);
defaultDevice-> Release();
defaultDevice = NULL;
//设置100毫秒定时器。
LARGE_INTEGER timerPeriodicityLI;
FILETIME timerPeriodicity;
timerPeriodicityLI.QuadPart = -1 *(TimerPeriodicityMS * 10000);
timerPeriodicity.dwLowDateTime = timerPeriodicityLI.LowPart;
timerPeriodicity.dwHighDateTime = timerPeriodicityLI.HighPart;
SetThreadpoolTimer(timer,& timerPeriodicity,TimerPeriodicityMS,10);
wchar_t inputChar ='\0';
while(inputChar!='\r')
{
UINT currentStep,stepCount;
DWORD读,写;
COORD writeCoord;
wchar_t outputString [256];
StringCbCopy(outputString,sizeof(outputString),LVolume:);
//
//计算cheesy OSD。
//
endpointVolume-> GetVolumeStepInfo(& currentStep,& stepCount);
for(size_t i = 0; i {
if(i <= currentStep)
{
StringCbCat ,sizeof(outputString),L=);
}
else
{
StringCbCat(outputString,sizeof(outputString),L - );
}
}
writeCoord.X = 0;
writeCoord.Y = 0;
WriteConsoleOutputCharacter(handle,outputString,(DWORD)wcslen(outputString),writeCoord,& written);
ReadConsole(GetStdHandle(STD_INPUT_HANDLE),& inputChar,1,& read,NULL);
if(inputChar =='+')
{
endpointVolume-> VolumeStepUp(NULL);
}
else if(inputChar ==' - ')
{
endpointVolume-> VolumeStepDown(NULL);
}
}
//
//删除我们的通知。
//
endpointVolume-> UnregisterControlChangeNotify(volumeNotification);
endpointVolume-> Release();
volumeNotification-> Release();
SetConsoleMode(getStdHandle(STD_INPUT_HANDLE),oldMode);
CloseThreadpoolCleanupGroupMembers(cleanupGroup,FALSE,NULL);
CloseThreadpoolCleanupGroup(cleanupGroup);
cleanupGroup = NULL;
DestroyThreadpoolEnvironment(& callbackEnvironment);
context._Meter-> Release();
CoUninitialize();
return 0;
}
EDIT 4:
#include< windows.h>
#include< mmdeviceapi.h>
#include< endpointvolume.h>
#include< iostream>
#include< Tchar.h>
class CVolumeNotification:public IAudioEndpointVolumeCallback
{
LONG m_RefCount;
〜CVolumeNotification(void){};
public:
CVolumeNotification(void):m_RefCount(1)
{
}
STDMETHODIMP_(ULONG)AddRef(){return InterlockedIncrement(& m_RefCount); }
STDMETHODIMP_(ULONG)Release()
{
LONG ref = InterlockedDecrement(& m_RefCount);
if(ref == 0)
delete this;
return ref;
}
STDMETHODIMP QueryInterface(REFIID IID,void ** ReturnValue)
{
if(IID == IID_IUnknown || IID == __uuidof(IAudioEndpointVolumeCallback))
{
* ReturnValue = static_cast< IUnknown *>(this);
AddRef();
return S_OK;
}
* ReturnValue = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA NotificationData)
{
std :: cout< NotificationData-> fMasterVolume<< _T();
return S_OK;
}
};
int _tmain(int argc,_TCHAR * argv [])
{
CoInitialize(NULL);
HRESULT hr;
IMMDeviceEnumerator * deviceEnumerator = NULL ;;
//
//实例化端点卷对象。
//
hr = CoCreateInstance(__ uuidof(MMDeviceEnumerator),NULL,CLSCTX_INPROC_SERVER,__uuidof(IMMDeviceEnumerator),(LPVOID *)& deviceEnumerator);
IMMDevice * defaultDevice = NULL;
hr = deviceEnumerator-> GetDefaultAudioEndpoint(eRender,eConsole,& defaultDevice);
deviceEnumerator-> Release();
deviceEnumerator = NULL;
IAudioEndpointVolume * endpointVolume = NULL;
hr = defaultDevice-> Activate(__ uuidof(IAudioEndpointVolume),CLSCTX_INPROC_SERVER,NULL,(LPVOID *)& endpointVolume);
CVolumeNotification * volumeNotification = new CVolumeNotification();
hr = endpointVolume-> RegisterControlChangeNotify(volumeNotification);
defaultDevice-> Release();
defaultDevice = NULL;
wchar_t inputChar ='\0'
while(inputChar!='\r')
{
DWORD read;
ReadConsole(GetStdHandle(STD_INPUT_HANDLE),& inputChar,1,& read,NULL);
}
//
//删除我们的通知。
//
endpointVolume-> UnregisterControlChangeNotify(volumeNotification);
endpointVolume-> Release();
volumeNotification-> Release();
CoUninitialize();
return 0;
}
我还没有看过SDK示例。我现在知道这个东西如何工作,以至于添加我需要我的应用程序。感谢所有人的帮助!
当我尝试它时工作正常。请务必点击音量控制盘图标,点击混音器并修改您的应用的音量。
I'm trying to get notifications whenever the master volume changes on Windows Vista/7. This is the code I'm using:
#include <audiopolicy.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <windows.h>
#include <shlwapi.h>
#include <iostream>
#include <Tchar.h>
static const GUID AudioSessionVolumeCtx = { 0x2715279f, 0x4139, 0x4ba0, { 0x9c, 0xb1, 0xb3, 0x51, 0xf1, 0xb5, 0x8a, 0x4a } };
template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
class CAudioSessionVolume : public IAudioSessionEvents
{
public:
static HRESULT CreateInstance( UINT uNotificationMessage, HWND hwndNotification, CAudioSessionVolume **ppAudioSessionVolume )
{
CAudioSessionVolume *pAudioSessionVolume = new (std::nothrow)
CAudioSessionVolume(uNotificationMessage, hwndNotification);
if (pAudioSessionVolume == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pAudioSessionVolume->Initialize();
if (SUCCEEDED(hr))
{
*ppAudioSessionVolume = pAudioSessionVolume;
}
else
{
pAudioSessionVolume->Release();
}
return hr;
}
// IUnknown methods.
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CAudioSessionVolume, IAudioSessionEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
LONG cRef = InterlockedDecrement( &m_cRef );
if (cRef == 0)
{
delete this;
}
return cRef;
}
STDMETHODIMP OnSimpleVolumeChanged( float NewVolume, BOOL NewMute, LPCGUID EventContext )
{
MessageBox(NULL, _T("vol changed"), _T("test"), MB_OK);
return S_OK;
}
// The remaining audio session events do not require any action.
STDMETHODIMP OnDisplayNameChanged(LPCWSTR,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnIconPathChanged(LPCWSTR,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnChannelVolumeChanged(DWORD,float[],DWORD,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnGroupingParamChanged(LPCGUID,LPCGUID)
{
return S_OK;
}
STDMETHODIMP OnStateChanged(AudioSessionState)
{
return S_OK;
}
STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason)
{
return S_OK;
}
// Other methods
HRESULT EnableNotifications(BOOL bEnable)
{
HRESULT hr = S_OK;
if (bEnable)
{
hr = m_pAudioSession->RegisterAudioSessionNotification(this);
}
else
{
hr = m_pAudioSession->UnregisterAudioSessionNotification(this);
}
return hr;
}
HRESULT SetDisplayName(const WCHAR *wszName)
{
if (m_pAudioSession == NULL)
{
return E_FAIL;
}
else
{
return m_pAudioSession->SetDisplayName(wszName, NULL);
}
}
protected:
CAudioSessionVolume( UINT uNotificationMessage, HWND hwndNotification ) :
m_cRef(1), m_pAudioSession(NULL), m_pSimpleAudioVolume(NULL)
{
}
~CAudioSessionVolume()
{
EnableNotifications(FALSE);
SafeRelease(&m_pAudioSession);
SafeRelease(&m_pSimpleAudioVolume);
}
HRESULT Initialize()
{
HRESULT hr = S_OK;
IMMDeviceEnumerator *pDeviceEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioSessionManager *pAudioSessionManager = NULL;
// Get the enumerator for the audio endpoint devices.
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDeviceEnumerator));
if (FAILED(hr))
{
goto done;
}
// Get the default audio endpoint that the SAR will use.
hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole,
&pDevice);
if (FAILED(hr))
{
goto done;
}
// Get the session manager for this device.
hr = pDevice->Activate(__uuidof(IAudioSessionManager),
CLSCTX_INPROC_SERVER, NULL, (void**) &pAudioSessionManager);
if (FAILED(hr))
{
goto done;
}
// Get the audio session.
hr = pAudioSessionManager->GetAudioSessionControl(
&GUID_NULL, // Get the default audio session.
FALSE, // The session is not cross-process.
&m_pAudioSession);
if (FAILED(hr))
{
goto done;
}
hr = pAudioSessionManager->GetSimpleAudioVolume(&GUID_NULL, 0,
&m_pSimpleAudioVolume);
done:
SafeRelease(&pDeviceEnumerator);
SafeRelease(&pDevice);
SafeRelease(&pAudioSessionManager);
return hr;
}
private:
LONG m_cRef;
IAudioSessionControl *m_pAudioSession;
ISimpleAudioVolume *m_pSimpleAudioVolume;
};
int main()
{
CoInitialize(NULL);
CAudioSessionVolume *asv;
CAudioSessionVolume::CreateInstance(0, NULL, &asv);
asv->EnableNotifications(true);
char s;
gets(&s);
}
I was expecting to get a message box saying "vol changed" when the system volume changes, but I never get a message box.
I got most of the code from http://msdn.microsoft.com/en-us/library/dd374921(VS.85).aspx
What am I doing wrong?
EDIT: I do get notifications when changing the volume for my application (thanks @nobugz). But I want notification when changing the master volume. (Listed as "Device" in Win7's Volume Mixers dialog)
EDIT 2: Larry Osterman has a series of blog posts about the volume in Vista/7. This one in particular is interesting: http://blogs.msdn.com/larryosterman/archive/2007/03/22/fun-with-the-endpoint-volume-interfaces-closing-the-loop.aspx I'll try the code out tomorrow to see if I can get what I want. Now it's time for bed.
EDIT 3: This is the complete code from Larry's blog posts up to and including the link posted above. It does what I need and then some. I'll try to trim the features I don't need.
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <Tchar.h>
#include <strsafe.h>
class CVolumeNotification : public IAudioEndpointVolumeCallback
{
LONG m_RefCount;
~CVolumeNotification(void) {};
public:
CVolumeNotification(void) : m_RefCount(1)
{
}
STDMETHODIMP_(ULONG)AddRef() { return InterlockedIncrement(&m_RefCount); }
STDMETHODIMP_(ULONG)Release()
{
LONG ref = InterlockedDecrement(&m_RefCount);
if (ref == 0)
delete this;
return ref;
}
STDMETHODIMP QueryInterface(REFIID IID, void **ReturnValue)
{
if (IID == IID_IUnknown || IID== __uuidof(IAudioEndpointVolumeCallback))
{
*ReturnValue = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
*ReturnValue = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA NotificationData)
{
wchar_t outputString[256];
DWORD written;
COORD writeCoord;
StringCbPrintf(outputString, sizeof(outputString), L"Volume Changed: %f", NotificationData->fMasterVolume);
writeCoord.X = 0;
writeCoord.Y = 3;
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), outputString, (DWORD)wcslen(outputString), writeCoord, &written);
return S_OK;
}
};
struct TimerContext
{
IAudioMeterInformation *_Meter;
};
const int TimerPeriodicityMS = 100;
void CALLBACK TimerMeterCallback(PTP_CALLBACK_INSTANCE CallbackInstance, PVOID Context, PTP_TIMER Timer)
{
TimerContext *timerContext = (TimerContext *)Context;
wchar_t outputString[256];
float peakValue;
DWORD written;
COORD writeCoord;
StringCbCopy(outputString, sizeof(outputString), L"Meter: ");
timerContext->_Meter->GetPeakValue(&peakValue);
for (size_t i = 0 ; i < peakValue*100; i += 1)
{
StringCbCat(outputString, sizeof(outputString), L"*");
}
for (size_t i = (size_t)(peakValue*100) ; i < 100; i += 1)
{
StringCbCat(outputString, sizeof(outputString), L".");
}
writeCoord.X = 0;
writeCoord.Y = 1;
WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), outputString, (DWORD)wcslen(outputString), writeCoord, &written);
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
HRESULT hr;
IMMDeviceEnumerator *deviceEnumerator = NULL;;
HANDLE handle;
TP_CALLBACK_ENVIRON callbackEnvironment;
PTP_CLEANUP_GROUP cleanupGroup;
PTP_TIMER timer;
TimerContext context;
InitializeThreadpoolEnvironment(&callbackEnvironment);
cleanupGroup = CreateThreadpoolCleanupGroup();
SetThreadpoolCallbackCleanupGroup(&callbackEnvironment, cleanupGroup, NULL);
timer = CreateThreadpoolTimer(TimerMeterCallback, &context, &callbackEnvironment);
//
// Clear the screen. Code stolen from: http://support.microsoft.com/kb/319257.
//
handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD writtenChars = 0;
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
COORD home;
home.X = home.Y = 0;
GetConsoleScreenBufferInfo(handle, &consoleInfo);
FillConsoleOutputCharacter(handle, L' ', consoleInfo.dwSize.X * consoleInfo.dwSize.Y, home, &writtenChars);
SetConsoleCursorPosition(handle, home);
//
// Set the console to raw mode.
//
DWORD oldMode;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &oldMode);
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
//
// Instantiate an endpoint volume object.
//
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;
IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
CVolumeNotification *volumeNotification = new CVolumeNotification();
hr = endpointVolume->RegisterControlChangeNotify(volumeNotification);
hr = defaultDevice->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&context._Meter);
defaultDevice->Release();
defaultDevice = NULL;
// Set a 100 millisecond timer.
LARGE_INTEGER timerPeriodicityLI;
FILETIME timerPeriodicity;
timerPeriodicityLI.QuadPart = -1*(TimerPeriodicityMS* 10000 );
timerPeriodicity.dwLowDateTime = timerPeriodicityLI.LowPart;
timerPeriodicity.dwHighDateTime = timerPeriodicityLI.HighPart;
SetThreadpoolTimer(timer, &timerPeriodicity, TimerPeriodicityMS, 10);
wchar_t inputChar = '\0';
while (inputChar != '\r')
{
UINT currentStep, stepCount;
DWORD read, written;
COORD writeCoord;
wchar_t outputString[256];
StringCbCopy(outputString, sizeof(outputString), L"Volume: ");
//
// Calculate the cheesy OSD.
//
endpointVolume->GetVolumeStepInfo(¤tStep, &stepCount);
for (size_t i = 0 ; i < stepCount ; i += 1)
{
if (i <= currentStep)
{
StringCbCat(outputString, sizeof(outputString), L"=");
}
else
{
StringCbCat(outputString, sizeof(outputString), L"-");
}
}
writeCoord.X = 0;
writeCoord.Y = 0;
WriteConsoleOutputCharacter(handle, outputString, (DWORD)wcslen(outputString), writeCoord, &written);
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &inputChar, 1, &read, NULL);
if (inputChar == '+')
{
endpointVolume->VolumeStepUp(NULL);
}
else if (inputChar == '-')
{
endpointVolume->VolumeStepDown(NULL);
}
}
//
// Remove our notification.
//
endpointVolume->UnregisterControlChangeNotify(volumeNotification);
endpointVolume->Release();
volumeNotification->Release();
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldMode);
CloseThreadpoolCleanupGroupMembers(cleanupGroup, FALSE, NULL);
CloseThreadpoolCleanupGroup(cleanupGroup);
cleanupGroup = NULL;
DestroyThreadpoolEnvironment(&callbackEnvironment);
context._Meter->Release();
CoUninitialize();
return 0;
}
EDIT 4: This is a stripped down version of Larry's code.
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <iostream>
#include <Tchar.h>
class CVolumeNotification : public IAudioEndpointVolumeCallback
{
LONG m_RefCount;
~CVolumeNotification(void) {};
public:
CVolumeNotification(void) : m_RefCount(1)
{
}
STDMETHODIMP_(ULONG)AddRef() { return InterlockedIncrement(&m_RefCount); }
STDMETHODIMP_(ULONG)Release()
{
LONG ref = InterlockedDecrement(&m_RefCount);
if (ref == 0)
delete this;
return ref;
}
STDMETHODIMP QueryInterface(REFIID IID, void **ReturnValue)
{
if (IID == IID_IUnknown || IID== __uuidof(IAudioEndpointVolumeCallback))
{
*ReturnValue = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
*ReturnValue = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA NotificationData)
{
std::cout << NotificationData->fMasterVolume << _T(" ");
return S_OK;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
HRESULT hr;
IMMDeviceEnumerator *deviceEnumerator = NULL;;
//
// Instantiate an endpoint volume object.
//
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
IMMDevice *defaultDevice = NULL;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
deviceEnumerator->Release();
deviceEnumerator = NULL;
IAudioEndpointVolume *endpointVolume = NULL;
hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
CVolumeNotification *volumeNotification = new CVolumeNotification();
hr = endpointVolume->RegisterControlChangeNotify(volumeNotification);
defaultDevice->Release();
defaultDevice = NULL;
wchar_t inputChar = '\0';
while (inputChar != '\r')
{
DWORD read;
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &inputChar, 1, &read, NULL);
}
//
// Remove our notification.
//
endpointVolume->UnregisterControlChangeNotify(volumeNotification);
endpointVolume->Release();
volumeNotification->Release();
CoUninitialize();
return 0;
}
I still haven't looked at the SDK example. I now know how this stuff works well enough to add what I need to my application. Thanks for everyones help!
It works fine when I try it. Be sure to click on the volume control tray icon, click Mixer and modify the volume for your app.
这篇关于在Vista / 7(C ++)上获取卷更改通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!