有没有一种方法可以从 Win32 应用程序检测 Windows 10 中 Focus Assist(以前称为 Quiet Hours)的变化
Is there a way to detect changes in Focus Assist (formerly Quiet Hours) in Windows 10 from a Win32 App
我想在 Focus Assist 打开时自动将 App 中的在线状态更改为免打扰。
所以基本上有两个问题:
是否可以通过例如Windows10个SDK?
在 Windows 8 中也有类似的 Quiet Hours 问题:Get windows Quiet hours from Win32 or C# API,但不清楚它是否仍然适用于“Focus Assist”,因为这不再是真实的或错误的价值。
安静时间只有 ON/OFF 状态,而 Focus Assist 可以是 OFF/PRIORITY/ALARMS.
上面提到的 post 中没有回答的更有趣的问题是:有没有我可以注册的事件,以获得有关状态更改的通知?
目标是在 Focus Assist 状态发生变化时立即收到通知,而不必定期查询注册表。
据我所知,没有正式记录的获取 Focus 辅助状态的方法。
它仍然可以通过查询该功能的 WNF State 来访问,尽管这完全没有记录并且不受官方支持。
WNF 数据的各种状态已经 reverse engineered,因此 Focus Assist 的状态是 WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED
。
下面的 C++ 示例显示了如何获取焦点辅助功能的状态(主要是 off
、priority_only
和 alarm_only
)。
再次提醒,这 未被 Microsoft 官方支持:
#include <Windows.h>
#include <iostream>
#include <string>
#include <map>
// from ntdef.h
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
// from ntdef.h
typedef struct _WNF_STATE_NAME
{
ULONG Data[2];
} WNF_STATE_NAME;
typedef struct _WNF_STATE_NAME* PWNF_STATE_NAME;
typedef const struct _WNF_STATE_NAME* PCWNF_STATE_NAME;
typedef struct _WNF_TYPE_ID
{
GUID TypeId;
} WNF_TYPE_ID, *PWNF_TYPE_ID;
typedef const WNF_TYPE_ID* PCWNF_TYPE_ID;
typedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP;
enum FocusAssistResult
{
not_supported = -2,
failed = -1,
off = 0,
priority_only = 1,
alarms_only = 2
};
std::map<int, std::string> result_map = {
{-2, "Not Supported"},
{-1, "Failed"},
{0, "Off"},
{1, "Priority Only"},
{2, "Alarm Only"}
};
typedef NTSTATUS (NTAPI *PNTQUERYWNFSTATEDATA)(
_In_ PWNF_STATE_NAME StateName,
_In_opt_ PWNF_TYPE_ID TypeId,
_In_opt_ const VOID* ExplicitScope,
_Out_ PWNF_CHANGE_STAMP ChangeStamp,
_Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer,
_Inout_ PULONG BufferSize);
int main(int argc, CHAR** argv)
{
// note: ntdll is guaranteed to be in the process address space.
const auto h_ntdll = GetModuleHandle(_T("ntdll"));
// get pointer to function
const auto pNtQueryWnfStateData = PNTQUERYWNFSTATEDATA(GetProcAddress(h_ntdll, "NtQueryWnfStateData"));
if (!pNtQueryWnfStateData)
{
std::cerr << "[-] Error: couldn't get pointer to NtQueryWnfStateData() function." << std::endl;
return -1;
}
// state name for active hours (Focus Assist)
WNF_STATE_NAME WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED{0xA3BF1C75, 0xD83063E};
// note: we won't use it but it's required
WNF_CHANGE_STAMP change_stamp = {0};
// on output buffer will tell us the status of Focus Assist
DWORD buffer = 0;
ULONG buffer_size = sizeof(buffer);
if (NT_SUCCESS(pNtQueryWnfStateData(&WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED, nullptr, nullptr, &change_stamp,
&buffer, &buffer_size)))
{
// check if the result is one of FocusAssistResult
if (result_map.count(buffer) == 0)
{
std::cout << "Focus Assist result is unknown." << std::endl;
}
else
{
std::cout << "Focus assist state: " << result_map[buffer] << std::endl;
}
}
else
{
std::cerr << "[-] Error while calling NtQueryWnfStateData." << std::endl;
return -1;
}
return 0;
}
我想在 Focus Assist 打开时自动将 App 中的在线状态更改为免打扰。
所以基本上有两个问题:
是否可以通过例如Windows10个SDK?
在 Windows 8 中也有类似的 Quiet Hours 问题:Get windows Quiet hours from Win32 or C# API,但不清楚它是否仍然适用于“Focus Assist”,因为这不再是真实的或错误的价值。 安静时间只有 ON/OFF 状态,而 Focus Assist 可以是 OFF/PRIORITY/ALARMS.
上面提到的 post 中没有回答的更有趣的问题是:有没有我可以注册的事件,以获得有关状态更改的通知?
目标是在 Focus Assist 状态发生变化时立即收到通知,而不必定期查询注册表。
据我所知,没有正式记录的获取 Focus 辅助状态的方法。
它仍然可以通过查询该功能的 WNF State 来访问,尽管这完全没有记录并且不受官方支持。
WNF 数据的各种状态已经 reverse engineered,因此 Focus Assist 的状态是 WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED
。
下面的 C++ 示例显示了如何获取焦点辅助功能的状态(主要是 off
、priority_only
和 alarm_only
)。
再次提醒,这 未被 Microsoft 官方支持:
#include <Windows.h>
#include <iostream>
#include <string>
#include <map>
// from ntdef.h
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
// from ntdef.h
typedef struct _WNF_STATE_NAME
{
ULONG Data[2];
} WNF_STATE_NAME;
typedef struct _WNF_STATE_NAME* PWNF_STATE_NAME;
typedef const struct _WNF_STATE_NAME* PCWNF_STATE_NAME;
typedef struct _WNF_TYPE_ID
{
GUID TypeId;
} WNF_TYPE_ID, *PWNF_TYPE_ID;
typedef const WNF_TYPE_ID* PCWNF_TYPE_ID;
typedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP;
enum FocusAssistResult
{
not_supported = -2,
failed = -1,
off = 0,
priority_only = 1,
alarms_only = 2
};
std::map<int, std::string> result_map = {
{-2, "Not Supported"},
{-1, "Failed"},
{0, "Off"},
{1, "Priority Only"},
{2, "Alarm Only"}
};
typedef NTSTATUS (NTAPI *PNTQUERYWNFSTATEDATA)(
_In_ PWNF_STATE_NAME StateName,
_In_opt_ PWNF_TYPE_ID TypeId,
_In_opt_ const VOID* ExplicitScope,
_Out_ PWNF_CHANGE_STAMP ChangeStamp,
_Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer,
_Inout_ PULONG BufferSize);
int main(int argc, CHAR** argv)
{
// note: ntdll is guaranteed to be in the process address space.
const auto h_ntdll = GetModuleHandle(_T("ntdll"));
// get pointer to function
const auto pNtQueryWnfStateData = PNTQUERYWNFSTATEDATA(GetProcAddress(h_ntdll, "NtQueryWnfStateData"));
if (!pNtQueryWnfStateData)
{
std::cerr << "[-] Error: couldn't get pointer to NtQueryWnfStateData() function." << std::endl;
return -1;
}
// state name for active hours (Focus Assist)
WNF_STATE_NAME WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED{0xA3BF1C75, 0xD83063E};
// note: we won't use it but it's required
WNF_CHANGE_STAMP change_stamp = {0};
// on output buffer will tell us the status of Focus Assist
DWORD buffer = 0;
ULONG buffer_size = sizeof(buffer);
if (NT_SUCCESS(pNtQueryWnfStateData(&WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED, nullptr, nullptr, &change_stamp,
&buffer, &buffer_size)))
{
// check if the result is one of FocusAssistResult
if (result_map.count(buffer) == 0)
{
std::cout << "Focus Assist result is unknown." << std::endl;
}
else
{
std::cout << "Focus assist state: " << result_map[buffer] << std::endl;
}
}
else
{
std::cerr << "[-] Error while calling NtQueryWnfStateData." << std::endl;
return -1;
}
return 0;
}