有没有办法从Win32应用程序中检测Windows 10中的Focus Assist(以前称为Quiet Hours)的更改

问题描述 投票:3回答:1

我想在启用“对焦辅助”时自动将应用程序中的状态更改为DND。

基本上有两个问题:

  • 是否可以通过例如检查焦点辅助状态来检查Windows 10 SDK? 在Windows 8中有一个类似的安静时间问题:Get windows Quiet hours from Win32 or C# API,虽然目前尚不清楚它是否仍然适用于“焦点辅助”,因为它不再是真或假价值。安静时间只有ON / OFF状态,而Focus Assist可以是OFF / PRIORITY / ALARMS。
  • 然而,更有趣的问题,在上面提到的帖子中没有回答:是否有我可以注册的事件,以获得状态变化的通知? 目标是在焦点辅助状态发生变化时立即得到通知,以便不必定期查询注册表。
winapi notifications windows-10 integration
1个回答
3
投票

据我所知,没有正式记录的获得Focus辅助状态的方法。

它仍然可以通过查询该功能的WNF State来访问,尽管这完全没有记录,也没有得到官方支持。

WNF数据的各种状态都是reverse engineered,所以焦点助手的状态是WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED

下面的C ++示例显示了如何获得Focus Assist功能的状态(主要是offpriority_onlyalarm_only)。

再一次,要小心微软没有正式支持:

#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;
}
© www.soinside.com 2019 - 2024. All rights reserved.