如何在Windows C++应用中监听WiFi网络状态变更通知
解决Windows C++ WiFi网络变更通知问题
看起来你在使用wlanapi.h实现WiFi网络变更通知时遇到了回调触发异常的问题,我帮你梳理下代码里的核心问题,并给出修正后的完整实现方案。
问题分析
你的代码里有几个关键错误,直接导致了回调不触发或乱触发:
- 回调函数签名不符合要求:Windows的WLAN通知回调必须严格遵循
DWORD WINAPI的调用约定且返回DWORD类型,你的回调是void返回且没有WINAPI修饰,系统根本无法正确调用它——这是回调不触发的主要原因。 - 通知源范围太广:你用了
WLAN_NOTIFICATION_SOURCE_ALL,会收到大量无关的WLAN通知(比如驱动状态变更、扫描结果更新等),这就是为什么无操作时回调也会被多次调用的原因。我们只需要关注WLAN_NOTIFICATION_SOURCE_ACM(自动配置模块)的通知,这才对应网络连接、切换的核心场景。 - 未过滤目标事件类型:即使注册了正确的通知源,也需要在回调里筛选你关心的具体事件,避免处理无关通知。
修正后的完整代码
#include <windows.h> #include <Wlanapi.h> #include <iostream> #include <string> // 链接wlanapi库 #pragma comment(lib, "wlanapi.lib") // 正确的回调函数签名:WINAPI调用约定,返回DWORD DWORD WINAPI WlanNotificationCallback(PWLAN_NOTIFICATION_DATA pNotificationData, PVOID pContext); void EventLoop(); int main() { HANDLE hClient; DWORD dwNegotiatedVersion = 0; DWORD dwResult = WlanOpenHandle( 2, // 请求的WLAN API版本 NULL, // 保留参数,必须为NULL &dwNegotiatedVersion, &hClient ); if (dwResult != ERROR_SUCCESS) { std::cout << "WlanOpenHandle失败,错误码: " << dwResult << std::endl; return 1; } // 仅注册ACM(自动配置模块)的通知,聚焦网络连接变更事件 dwResult = WlanRegisterNotification( hClient, WLAN_NOTIFICATION_SOURCE_ACM, TRUE, // 开启所有ACM通知(包括连接/断开) WlanNotificationCallback, NULL, // 自定义上下文参数,这里不需要可以传NULL NULL, // 保留参数 NULL // 保留参数 ); if (dwResult != ERROR_SUCCESS) { std::cout << "WlanRegisterNotification失败,错误码: " << dwResult << std::endl; WlanCloseHandle(hClient, NULL); return 1; } std::cout << "正在监听WiFi网络变更... (按Ctrl+C退出)" << std::endl; EventLoop(); // 清理资源 WlanCloseHandle(hClient, NULL); return 0; } void EventLoop() { // 标准Windows消息循环,保证线程能接收异步通知 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } DWORD WINAPI WlanNotificationCallback(PWLAN_NOTIFICATION_DATA pNotificationData, PVOID pContext) { // 只处理ACM源的通知 if (pNotificationData->NotificationSource != WLAN_NOTIFICATION_SOURCE_ACM) { return ERROR_SUCCESS; } switch (pNotificationData->NotificationCode) { case wlan_notification_acm_connection_complete: { // 连接新网络完成(对应场景1:连接新网络;场景3:切换到网络B) PWLAN_CONNECTION_NOTIFICATION_DATA pConnData = reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>(pNotificationData->pData); std::cout << "\n[事件] 已连接到网络: " << pConnData->strProfileName << std::endl; break; } case wlan_notification_acm_disconnect: { // 断开网络连接(对应场景2:断开网络;场景3:从网络A断开) PWLAN_DISCONNECT_NOTIFICATION_DATA pDisconnData = reinterpret_cast<PWLAN_DISCONNECT_NOTIFICATION_DATA>(pNotificationData->pData); std::cout << "\n[事件] 已断开网络连接. 原因: " << pDisconnData->dwReason << std::endl; break; } // 其他ACM通知类型可根据需求添加,比如连接开始、漫游等 default: // 忽略无关通知 break; } return ERROR_SUCCESS; }
关键说明
- 回调签名修正:必须使用
DWORD WINAPI,这是Windows API回调的强制要求,确保系统能正确调用你的函数。 - 精准通知源:
WLAN_NOTIFICATION_SOURCE_ACM专门负责WiFi的连接、断开、切换等事件,避免了无关通知的干扰。 - 事件匹配:回调里的两个核心事件完全覆盖你关注的场景:
- 连接新网络/切换到新网络:触发
wlan_notification_acm_connection_complete - 断开网络:触发
wlan_notification_acm_disconnect(切换网络时会先触发断开原网络,再触发新网络连接)
- 连接新网络/切换到新网络:触发
- 消息循环:用
GetMessage实现的消息循环是Windows程序接收异步通知的标准方式,比简单的死循环更规范,也能兼容其他潜在的消息处理。
测试提示
- 普通用户权限即可运行,不需要管理员权限
- 切换网络时会先后收到断开和连接的通知,属于正常流程
- 如果需要获取SSID、信号强度等更详细的网络信息,可以在
connection_complete事件中调用WlanGetCurrentConnection或WlanGetAvailableNetworkList接口获取
内容的提问来源于stack exchange,提问作者NightFuryLxD
相关产品推荐
相关产品推荐

