- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
每当 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)->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);
}
我希望在系统音量更改时收到一个消息框说“vol changed”,但我从来没有收到消息框。
我从 http://msdn.microsoft.com/en-us/library/dd374921(VS.85).aspx 得到了大部分代码
我做错了什么?
编辑: 在更改我的应用程序的音量时,我确实会收到通知(感谢@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明天我会尝试代码,看看我是否能得到我想要的。现在该 sleep 了。
编辑 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 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;
}
编辑 4:这是 Larry 代码的精简版。
#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;
}
我还没有看过 SDK 示例。我现在知道这些东西如何工作得足够好,可以将我需要的东西添加到我的应用程序中。感谢大家的帮助!
最佳答案
当我尝试时它工作正常。请务必点击音量控制托盘图标,点击混音器并修改您的应用的音量。
关于c++ - 在 Vista/7 (C++) 上获取音量变化通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2232125/
如何以编程方式获取 Vista Edition,即 Home Basic、Home Premium、Business 或 Ultimate? 最佳答案 MSDN 给出了广泛的答案: Getting t
似乎在 Vista/Windows Server 2008 中大量使用临界区会导致操作系统无法完全恢复内存。 我们在 Delphi 应用程序中发现了这个问题,这显然是因为使用了 CS API。 (见此
我在这篇文章中读到: http://technet.microsoft.com/en-us/library/cc709628.aspx Windows 通过文件名检测安装程序,遵循这个提示,在安装程序
我创建了一个示例小工具(当然使用 google :D)。它显示“Hello World!”。 我已经创建了一个 .gadget 文件来安装这个小工具。 我编写了一个应用程序,它执行 ShellExec
当系统虚拟内存不足时,Vista 会显示对话框“关闭程序以防止信息丢失”。 在此对话框中,它命名您应该关闭的程序。人们向我报告说,它有时会命名我开发的程序。 Vista 如何决定应该关闭哪些程序?我想
我只是想知道是否有人知道 vista 在哪里存储每个用户帐户的个人资料图像。我知道在 XP 中它存储在 C:\Documents and Settings\All Users\Application
我正在将我的开发工作站从 32 位 Vista 迁移到 64 位 Vista。 生产平台为 32 位 Windows Server 和 SQL Server 2008。 有谁知道迁移代码库有任何问题?
有没有办法以编程方式禁用设备? (最好在 .net、win32 或批处理中)。 谷歌上的大多数点击都建议使用 devcon,但它似乎不适用于 Windows Vista/7 64 位。 How do
我们正在开发的产品允许用户轻松地将其设置为在计算机启动时自动运行。这很有帮助,因为该产品是我们大多数用户基本工作环境的一部分。 这个功能是在不久前实现的,有一段时间一切都很好,但是当我们开始在 Vis
存储对每个用户都相同但必须对程序可写的程序数据文件的正确位置是什么? MS Windows XP 上的等效位置是什么?我已经读到 C:\ProgramData 在普通用户安装后不可写。真的吗?如何使用
我有一个普通用户需要能够运行的应用程序,但需要管理员权限才能实际运行。 我试图让我的用户使用“以管理员身份运行”运行它的快捷方式,但这只会在他们尝试运行应用程序时导致 UAC 提示。 有没有办法以编程
我正在尝试安装 OpenCV 超过 windows vista 64x 但它显示了一个致命的错误。 我尽我所能,但它是无用的。 openCV 可以在 vista 64 上运行吗? 我该如何摆脱这个问题
我希望能够使用 mklink 在我的 Windows Vista 家庭版计算机上创建符号链接(symbolic link)。 但是,我必须先授予 SeCreateSymbolicLink,然后 mkl
Windows Vista 中 %allusersprofile% 文件夹的确切路径是什么?在某些系统上,我看到该文件夹为“c:\Users\All Users”,在某些系统上它被映射到“C:\P
我有一个 directx9 应用程序需要在禁用 Aero 的机器上运行。该应用程序以窗口模式运行。首次创建窗口时,它在单个屏幕中看起来很好。当我以跨越连接到同一图形适配器(和 GPU)的两个屏幕的方式
从桌面应用程序开发人员的角度来看,为 Windows XP 开发和为 Windows Vista 开发之间有什么区别吗? 最佳答案 用户界面 看着Windows Vista User Experien
我可以使用哪个内置(如果有)工具来确定某个 NTFS 分区的分配单元大小? 最佳答案 打开管理员命令提示符,然后执行以下命令: fsutil fsinfo ntfsinfo [your drive]
我们有一个服务可以启动一个与登录用户交互的应用程序。我们启动的应用程序始终以我们拥有凭据的特定用户身份运行。我们执行必要的操作(获取事件 session ID、logonUser、调整 token )
如果不关闭 UAC,我的 msi 安装程序无法安装在 Vista 机器上。由于我的应用程序将分发给我的客户,大约 20 台机器,并且他们不想关闭 UAC,有没有一种方法可以设置一些属性,使我的安装程序
我在网上搜索了很多关于这个问题的答案:他们说这是真的,SBCL 在 Vista 下不工作。但我真的需要在我的家用 Vista 笔记本电脑上使用 lisp,而 VM 真的没有帮助......而CL因为速
我是一名优秀的程序员,十分优秀!