You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3桌面C++程序:如何获取飞行模式切换事件(非注册表线程方式)

监听Windows飞行模式切换事件(无需持续线程等待的方案)

针对WinUI3桌面C++应用,无需线程持续等待的飞行模式事件监听方案主要有以下几种:

1. 使用WinRT RadioManager API(推荐)

WinUI3基于Windows Runtime(WinRT),直接使用Windows.Devices.Radios命名空间下的API是最适配的方案——它采用事件驱动模式,系统会在飞行模式切换时自动触发回调,无需手动维护等待线程。

代码示例

#include <winrt/Windows.Devices.Radios.h>
#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Devices::Radios;
using namespace Windows::Foundation;

// 注册飞行模式监听函数
void SetupFlightModeListener()
{
    RadioManager radioManager = RadioManager::GetDefault();
    
    // 订阅无线电状态变更事件
    auto eventToken = radioManager.RadioStateChanged([](const IInspectable&, const RadioStateChangedEventArgs& args)
    {
        // 获取当前系统飞行模式状态
        bool isFlightModeEnabled = RadioManager::GetDefault().IsFlightModeEnabled();
        
        if (isFlightModeEnabled)
        {
            // 处理飞行模式开启逻辑
        }
        else
        {
            // 处理飞行模式关闭逻辑
        }
    });

    // 保存eventToken,后续需要取消监听时调用radioManager.RadioStateChanged(eventToken)
}

优势

  • 与WinUI3开发原生适配,代码简洁
  • 事件驱动机制,无需手动管理线程或等待句柄
  • 直接获取飞行模式状态,无需解析注册表或其他系统数据

2. 监听Win32 WM_SETTINGCHANGE广播消息

WinUI3桌面应用本质基于Win32窗口,可通过窗口消息循环监听系统设置变更的广播消息WM_SETTINGCHANGE,当飞行模式切换时,系统会发送该消息并附带SystemRadioState标识。

代码示例

在WinUI3桌面应用的窗口过程中添加消息处理:

LRESULT CALLBACK AppWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SETTINGCHANGE:
            // 判断是否为无线电状态变更(飞行模式属于此类)
            if (lParam != nullptr && wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"SystemRadioState") == 0)
            {
                // 读取当前飞行模式状态
                RadioManager radioManager = RadioManager::GetDefault();
                bool isFlightModeOn = radioManager.IsFlightModeEnabled();
                
                // 处理飞行模式切换逻辑
            }
            break;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

优势

  • 依托Win32原生消息机制,无需额外依赖
  • 无需启动额外线程,消息由系统直接投递到窗口过程

3. WMI异步事件订阅

通过Windows Management Instrumentation(WMI)异步订阅系统无线电管理事件,WMI会在事件触发时自动调用回调函数,无需持续等待。

代码示例(简化版)

#include <wbemidl.h>
#include <comdef.h>

#pragma comment(lib, "wbemuuid.lib")

// 自定义WMI事件接收器
class CFlightModeEventSink : public IWbemObjectSink
{
    ULONG m_refCount = 0;
public:
    HRESULT STDMETHODCALLTYPE Indicate(long lObjCount, IWbemClassObject** ppObjArray) override
    {
        if (lObjCount <= 0 || ppObjArray == nullptr)
            return WBEM_S_NO_ERROR;

        VARIANT flightModeVar;
        HRESULT hr = ppObjArray[0]->Get(L"FlightModeEnabled", 0, &flightModeVar, nullptr, nullptr);
        if (SUCCEEDED(hr) && flightModeVar.vt == VT_BOOL)
        {
            bool isFlightModeOn = (flightModeVar.boolVal == VARIANT_TRUE);
            // 处理飞行模式切换逻辑
        }
        VariantClear(&flightModeVar);
        return WBEM_S_NO_ERROR;
    }

    // 实现IWbemObjectSink其他纯虚函数
    HRESULT STDMETHODCALLTYPE SetStatus(LONG, HRESULT, BSTR, IWbemClassObject*) override { return WBEM_S_NO_ERROR; }
    ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&m_refCount); }
    ULONG STDMETHODCALLTYPE Release() override 
    { 
        ULONG count = InterlockedDecrement(&m_refCount);
        if (count == 0) delete this;
        return count;
    }
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) override
    {
        if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
        {
            *ppv = static_cast<IWbemObjectSink*>(this);
            AddRef();
            return WBEM_S_NO_ERROR;
        }
        return E_NOINTERFACE;
    }
};

// 注册WMI监听
HRESULT RegisterWmiFlightModeListener()
{
    HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    if (FAILED(hr)) return hr;

    IWbemLocator* pLoc = nullptr;
    hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<void**>(&pLoc));
    if (FAILED(hr)) { CoUninitialize(); return hr; }

    IWbemServices* pSvc = nullptr;
    hr = pLoc->ConnectServer(_bstr_t(L"ROOT\\cimv2"), nullptr, nullptr, 0, NULL, 0, 0, &pSvc);
    if (FAILED(hr)) { pLoc->Release(); CoUninitialize(); return hr; }

    // 设置安全级别
    hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
    if (FAILED(hr)) { pSvc->Release(); pLoc->Release(); CoUninitialize(); return hr; }

    IUnsecuredApartment* pUnsecApp = nullptr;
    hr = CoCreateInstance(CLSID_UnsecuredApartment, nullptr, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, reinterpret_cast<void**>(&pUnsecApp));
    if (FAILED(hr)) { pSvc->Release(); pLoc->Release(); CoUninitialize(); return hr; }

    CFlightModeEventSink* pSink = new CFlightModeEventSink();
    IWbemObjectSink* pStubSink = nullptr;
    hr = pUnsecApp->CreateObjectStub(pSink, reinterpret_cast<IUnknown**>(&pStubSink));
    if (FAILED(hr)) { pSink->Release(); pUnsecApp->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); return hr; }

    // 订阅Win32_RadioManagementEvent事件
    hr = pSvc->ExecNotificationQueryAsync(
        _bstr_t("WQL"),
        _bstr_t("SELECT * FROM Win32_RadioManagementEvent"),
        WBEM_FLAG_SEND_STATUS,
        nullptr,
        pStubSink
    );

    // 释放临时资源(注意pStubSink和pSink由WMI持有,无需手动释放)
    pUnsecApp->Release();
    pSvc->Release();
    pLoc->Release();

    return hr;
}

优势

  • 可监听多种系统级事件,灵活性高
  • 异步回调模式,无需持续等待线程

内容的提问来源于stack exchange,提问作者Harshith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:30:35