如何让C++ WinRT控制台应用监听到Windows设置触发的无线电状态变更事件
问题解决方案
核心原因
你遇到的问题是两个常见的C++/WinRT桌面控制台应用开发陷阱:
- 你在循环中创建的
Radio对象是局部变量,循环结束后对象被析构,自动解绑了已注册的StateChanged事件。你通过代码修改状态时能收到回调,是因为修改动作和事件派发都发生在对象被释放前的当前线程上下文中。 - 控制台应用默认没有Windows消息循环,系统设置修改无线电属于跨进程事件通知,需要依赖消息循环才能投递到你的应用线程。
修复步骤
1. 延长Radio对象生命周期
将需要监听的Radio对象存储到全局变量、静态变量或者类成员中,避免对象提前析构导致事件解绑。
2. 添加消息循环
主线程初始化完成后启动Win32消息循环,用来接收系统派发的跨进程事件。
3. 声明无线电访问权限
如果是打包的MSIX/APPX应用,需要在应用清单中添加无线电设备权限:
<Capabilities> <DeviceCapability Name="radios" /> </Capabilities>
未打包的桌面应用首次运行时会弹出权限请求,点击允许即可。
修复后完整代码示例
#include <winrt/Windows.Devices.Radios.h> #include <winrt/Windows.Foundation.h> #include <Windows.h> #include <cstdio> using namespace winrt; using namespace Windows::Devices::Radios; // 全局存储需要监听的Radio对象,维持生命周期 std::vector<Radio> g_monitoredRadios; void Radio_StateChanged(Radio const& sender, Windows::Foundation::IInspectable const& /* args */) { printf("\t 收到状态变更通知: 无线电名称%ls,当前状态: %d\n", sender.Name().c_str(), static_cast<int>(sender.State())); } void Initialize() { auto radios = Radio::GetRadiosAsync().get(); for (auto const& r : radios) { if (r.Kind() == RadioKind::MobileBroadband) { g_monitoredRadios.push_back(r); // 注册状态变更事件 r.StateChanged(Radio_StateChanged); printf("\t 成功注册移动宽带无线电监听: %ls\n", r.Name().c_str()); // 原有状态切换逻辑保留 if (r.State() == RadioState::Off) { printf("\t 正在打开无线电\n"); // 等待异步操作完成避免提前退出 r.SetStateAsync(RadioState::On).get(); } else { printf("\t 正在关闭无线电\n"); r.SetStateAsync(RadioState::Off).get(); } } } } int main() { // 初始化单线程COM公寓,C++/WinRT必须步骤 winrt::init_apartment(winrt::apartment_type::single_threaded); Initialize(); // 启动消息循环接收系统事件 MSG msg; while (GetMessageW(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } return 0; }
额外注意事项
- 请确保项目配置的目标Windows版本最低为Windows 10 1709,这是
RadioAPI的最低支持版本 - 64位编译和32位编译逻辑无差异,只要上述步骤正确都可以正常收到系统设置触发的变更通知
内容的提问来源于stack exchange,提问作者Priyanka
相关产品推荐
相关产品推荐

