监控Windows系统音量变化通知

// Header File

#pragma once

#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <corecrt_math.h>

typedef void (CALLBACK* PFN_NOTIFYCALLBACK)(DWORD dwVolume, LPVOID lpContext);

class CVolumeCtrl : public IAudioEndpointVolumeCallback
{
public:
	CVolumeCtrl(PFN_NOTIFYCALLBACK pCallback, LPVOID lpContext);
	~CVolumeCtrl(void);

public:
	inline BOOL VerifyValid(void) { return (NULL != this) ? m_bValid : FALSE; }
	BOOL GetVolume(DWORD* pdwVolume);
	BOOL SetVolume(DWORD dwVolume);
	BOOL GetMute(BOOL* pbMute);
	BOOL SetMute(BOOL bMute);
	BOOL Notify(BOOL bRegister);

public:
	STDMETHODIMP_(ULONG)AddRef() { return InterlockedIncrement(&m_lRefCount); }
	STDMETHODIMP_(ULONG)Release()
	{
		LONG lRet = InterlockedDecrement(&m_lRefCount);
		if (0 == lRet) { delete this; }
		return lRet;
	}

	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 pNotificationData)
	{
		if ((NULL != pNotificationData) && (NULL != m_pCallback))
		{
			DWORD dwVolume = (DWORD)round(pNotificationData->fMasterVolume * 100.0f);
			m_pCallback(dwVolume, m_pContext);
		}

		return S_OK;
	}

private:
	BOOL Initialize(void);
	void Uninitialize(void);

private:
	LONG m_lRefCount;

	IMMDeviceEnumerator* m_pEnumerator;
	IMMDevice* m_pDevice;
	IAudioEndpointVolume* m_pVolume;

	BOOL m_bValid;
	PFN_NOTIFYCALLBACK m_pCallback;
	LPVOID m_pContext;
};


// Implement File
#include "stdafx.h"
#include "VolumeCtrl.h"

CVolumeCtrl::CVolumeCtrl(PFN_NOTIFYCALLBACK pCallback, LPVOID lpContext)
	: m_pCallback(pCallback)
	, m_pContext(lpContext)
	, m_bValid(FALSE)
	, m_lRefCount(1)
	, m_pEnumerator(NULL)
	, m_pDevice(NULL)
	, m_pVolume(NULL)
{
	CoInitialize(NULL);

	do
	{
		if (!Initialize()) { Uninitialize(); break; }

		// Completed
		m_bValid = TRUE;
	} while (0);
	
}

CVolumeCtrl::~CVolumeCtrl()
{
	Uninitialize();

	CoUninitialize();
}

BOOL CVolumeCtrl::GetVolume(DWORD* pdwVolume)
{
	BOOL bRet = FALSE;

	do
	{
		_ASSERT(NULL != pdwVolume);
		_ASSERT(NULL != m_pVolume);
		if (NULL == m_pVolume) { break; }

		HRESULT hr = S_OK;
		
		float fLevel = 0.0f;
		if (FAILED(hr = m_pVolume->GetMasterVolumeLevelScalar(&fLevel))) { break; }

		*pdwVolume = (DWORD)round(fLevel * 100.0f);

		// Completed
		bRet = TRUE;
	} while (0);

	return bRet;
}

BOOL CVolumeCtrl::SetVolume(DWORD dwVolume)
{
	BOOL bRet = FALSE;

	do
	{
		_ASSERT(NULL != m_pVolume);
		if (NULL == m_pVolume) { LOG(ERR, TEXT("Interface Invalid!")); break; }

		HRESULT hr = S_OK;
		
		float fLevel = (float)dwVolume / 100.0f;
		if (FAILED(hr = m_pVolume->SetMasterVolumeLevelScalar(fLevel, &GUID_NULL))) { break; }

		// Completed
		bRet = TRUE;
	} while (0);

	return bRet;
}

BOOL CVolumeCtrl::GetMute(BOOL* pbMute)
{
	BOOL bRet = FALSE;

	do
	{
		_ASSERT(NULL != pbMute);
		_ASSERT(NULL != m_pVolume);
		if (NULL == m_pVolume) { break; }

		HRESULT hr = S_OK;

		if (FAILED(hr = m_pVolume->GetMute(pbMute))) { break; }

		// Completed
		bRet = TRUE;
	} while (0);

	return bRet;
}

BOOL CVolumeCtrl::SetMute(BOOL bMute)
{
	BOOL bRet = FALSE;

	do
	{
		_ASSERT(NULL != m_pVolume);
		if (NULL == m_pVolume) { break; }

		HRESULT hr = S_OK;

		if (FAILED(hr = m_pVolume->SetMute(bMute, &GUID_NULL))) { break; }

		// Completed
		bRet = TRUE;
	} while (0);

	return bRet;
}

BOOL CVolumeCtrl::Notify(BOOL bRegister)
{
	BOOL bRet = FALSE;

	do
	{
		_ASSERT(NULL != m_pVolume);
		if (NULL == m_pVolume) { break; }

		HRESULT hr = S_OK;

		if (bRegister)
		{
			if (FAILED(hr = m_pVolume->RegisterControlChangeNotify(this))) { break; }
		}
		else
		{
			if (FAILED(hr = m_pVolume->UnregisterControlChangeNotify(this))) { break; }
		}

		// Completed
		bRet = TRUE;
	} while (0);

	return bRet;
}

BOOL CVolumeCtrl::Initialize(void)
{
	BOOL bRet = FALSE;

	do
	{
		HRESULT hr = S_OK;
		
		_ASSERT(NULL == m_pEnumerator);
		if (FAILED(hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&m_pEnumerator))) { break; }
		_ASSERT(NULL != m_pEnumerator);

		_ASSERT(NULL == m_pDevice);
		if (FAILED(hr = m_pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice))) { break; }
		_ASSERT(NULL != m_pDevice);

		_ASSERT(NULL == m_pVolume);
		if (FAILED(hr = m_pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&m_pVolume))) { break; }
		_ASSERT(NULL != m_pVolume);

		// Completed
		bRet = TRUE;
	} while (0);

	return bRet;
}

void CVolumeCtrl::Uninitialize(void)
{
	do
	{
		if (NULL != m_pVolume) { Notify(FALSE); m_pVolume->Release(); m_pVolume = NULL; }
		if (NULL != m_pDevice) { m_pDevice->Release(); m_pDevice = NULL; }
		if (NULL != m_pEnumerator) { m_pEnumerator->Release(); m_pEnumerator = NULL; }

		// Completed
	} while (0);
}


// 回调函数,一般定义为类的静态函数或者是全局函数
void CALLBACK NotifyCallback(DWORD dwVolume, LPVOID lpContext)
{
    // dwVolume : 为当前系统音量值。
    // lpContext : 为用户自定义的数据结构,比如为某一个类的指针,窗口类的HWND句柄,或者是NULL
}

// 调用方式
CVolumeCtrl* pVolumeCtrl = new CVolumeCtrl(NotifyCallback, NULL);
ASSERT(NULL != pVolumeCtrl);
if(pVolumeCtrl->VerifyValid())  // 验证有效性
{
  pVolumeCtrl->Noitfy(TRUE);             // 注册音量变化通知
  pVolumeCtrl->SetVolume/GetVolume(...); // 设置/获取当前音量
  pVolumeCtrl->SetMute/GetMute(...);     // 设置/获取当前静音状态
}

 

发布了74 篇原创文章 · 获赞 90 · 访问量 38万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览