Windowsシステムの音量変化を監視する通知

5662 ワード

// Header File

#pragma once

#include 
#include 
#include 

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(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(...);     //   /        
}