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

C++/WinRT BLE扫描器调用Start()报非法状态变更错误如何解决

问题解决方案

1. 修复对象生命周期问题

你当前把BluetoothLEAdvertisementWatcher定义为bleConnect函数的局部变量,函数执行完成后对象会立刻被析构,而Start()是异步启动扫描的方法,对象提前销毁会直接触发非法状态异常。
你需要把watcher对象提升为窗口类的成员变量或者全局变量,保证扫描期间对象始终存活:

// 示例:在窗口类头文件中添加成员声明
class CYourDlg : public CDialogEx
{
    // ... 其他原有类成员
private:
    winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcher m_bleWatcher;
};

2. 必须先调用权限请求接口再启动扫描

所有Windows蓝牙BLE API调用前,都需要先主动请求访问权限,没有权限的情况下直接调用Start()会固定抛出非法状态异常,修改启动逻辑如下:

winrt::IAsyncAction bleConnect(HWND hWnd)
{
    // 先请求蓝牙访问权限
    auto accessStatus = co_await winrt::Windows::Devices::Bluetooth::BluetoothAdapter::RequestAccessAsync();
    if (accessStatus != winrt::Windows::Devices::Enumeration::DeviceAccessStatus::Allowed)
    {
        wprintf(L"蓝牙权限被拒绝\n");
        co_return;
    }

    // 使用类成员的m_bleWatcher,禁止使用局部变量
    m_bleWatcher.ScanningMode(winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEScanningMode::Active);

    // 建议至少注册Stopped事件方便排查错误
    m_bleWatcher.Stopped([](auto&&, auto&& args) {
        wprintf(L"扫描停止,错误码: 0x%X\n", args.Error().value);
    });
    // Received事件根据业务需要添加即可,不强制注册

    if (m_bleWatcher.Status() == winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisementWatcherStatus::Created)
    {
        m_bleWatcher.Start();
        wprintf(L"扫描启动成功\n");
    }
}

3. 确认C++/WinRT运行时已正确初始化

MFC/Win32程序使用C++/WinRT前,需要在程序入口处初始化WinRT公寓,建议用多线程公寓适配蓝牙异步API,在项目的InitInstance方法开头添加初始化代码:

BOOL CYourApp::InitInstance()
{
    // 最先执行WinRT初始化
    winrt::init_apartment(winrt::apartment_type::multi_threaded);
    
    // ... 保留原有MFC初始化逻辑
}

4. 修复manifest配置问题

Win32程序调用UWP蓝牙API需要在manifest里添加必要的声明,调试阶段无需打包也能生效:

  • 首先在自定义manifest.xml中添加Windows 10/11兼容性标识,让系统识别程序支持调用WinRT API:
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
        <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
</compatibility>
  • 再添加蓝牙权限声明:
<Capabilities>
    <DeviceCapability Name="bluetooth"/>
</Capabilities>
  • 调试阶段加载manifest的方法:打开VS项目属性 -> 配置属性 -> 链接器 -> 清单文件 -> 附加清单文件,填入你的自定义manifest.xml路径,重新编译后调试会自动加载配置。

额外排查点

如果修改后仍报错,首先检查系统蓝牙开关是否处于开启状态,蓝牙适配器未启用时调用Start()也会抛出相同异常;另外可以打印accessStatus的返回值,确认权限是否真的获取成功。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 07:54:02