zoukankan      html  css  js  c++  java
  • Visual C++ 编程实现Soft AP (HostedNetwork / 承载网络) 功能

    从Windows 7开始,微软在操作系统中加入的Soft AP功能,使用户能够通过无线网卡,开启虚拟AP,从而实现网络共享。Soft AP又称HostedNetwork(承载网络),在Windows SDK中,提供了相应的API,以WlanHostedNetwork***开头的一系列函数。

    要编码实现Soft AP,首先需要添加相应的头文件及lib库

    1 #include <wlanapi.h>
    2 #include <iphlpapi.h>
    3 #include <winsock2.h>
    4 #pragma comment(lib, "ws2_32.lib")
    5 #pragma comment(lib, "Wlanapi.lib")
    6 #pragma comment(lib, "IPHLPAPI.lib"

    其中,wlanapi.h是无线网络API的声明文件,函数名一般以Wlan开头。iphlpapi.h用于调用GetAdapterInfo函数,获取网络虚拟接口信息。

    和winsock套接字编程类似,Wlan库使用前需获得句柄,并进行版本协商,只不过都在WlanOpenHandle实现了。使用完句柄后,调用WlanCloseHandle关闭以释放资源。

    WlanOpenHandle原形如下:

    1 DWORD WINAPI WlanOpenHandle(
    2   _In_        DWORD dwClientVersion,
    3   _Reserved_  PVOID pReserved,
    4   _Out_       PDWORD pdwNegotiatedVersion,
    5   _Out_       PHANDLE phClientHandle
    6 );

    dwClientVersion指定程序期望使用的Wlan版本,使用宏WLAN_API_VERSION代替。从vista开始,版本号为2,xp系统为1。协商后的版本通过参数pdwNegotiatedVersion返回,通过检查主版本号来验证(如下代码所示)。句柄通过phClient返回。

     1     DWORD dwError = 0;
     2     DWORD dwServiceVersion = 0;
     3     HANDLE hClient = NULL;
     4 
     5     if (ERROR_SUCCESS != (dwError = WlanOpenHandle(
     6         WLAN_API_VERSION,   
     7         NULL,               // reserved
     8         &dwServiceVersion,
     9         &hClient
    10         )))
    11     {
    12         return -1;
    13     }
    14 
    15     // check service version
    16     if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0))
    17     {
    18         WlanCloseHandle(hClient, NULL);
    19     }

      

     启动承载网络前,需要将模式配置为allow状态,并设置SSID和密码。可以调用WlanHostedNetworkSetProperty进行设置,WlanHostedNetworkSetProperty原型如下:

    1 DWORD WINAPI WlanHostedNetworkSetProperty(
    2   _In_        HANDLE hClientHandle,
    3   _In_        WLAN_HOSTED_NETWORK_OPCODE OpCode,
    4   _In_        DWORD dwDataSize,
    5   _In_        PVOID pvData,
    6   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
    7   _Reserved_  PVOID pvReserved
    8 );

    其中hClientHandle是我们之前调用WlanOpenHnadle获得的句柄;dwDataSize指定了pvData缓冲区的大小,而pvData指向的变量类型取决与OpCode的取值。OpCode为WLAN_HOSTED_NETWORK_OPCODE枚举,如果指定为wlan_hosted_network_opcode_enable,那么pvData传入一个BOOL型的变量指针,用于指示承载网络模式为允许还是禁止(allow/disallow);如果OpCode为wlan_hosted_network_opcode_connection_settings,那么pvData指向WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS结构体,指定承载网络的SSID和最大连接数目(peer count).

    示例代码:

     1     // 设置承载网络模式为允许
     2     BOOL bIsAllow = TRUE;
     3     WLAN_HOSTED_NETWORK_REASON dwFailedReason;
     4     DWORD dwReturnValue = WlanHostedNetworkSetProperty(hWlanClient, 
     5         wlan_hosted_network_opcode_enable, 
     6         sizeof(BOOL), 
     7         &bIsAllow, 
     8         &dwFailedReason, 
     9         NULL);
    10 
    11     if(ERROR_SUCCESS != dwReturnValue)
    12     {
    13         return -1;
    14     }
    15 
    16 
    17 
    18 
    19     // 设置承载网络的SSID和最大连接数
    20     WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS wlanConnectionSetting;
    21     memset(&wlanConnectionSetting, 0, sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS));
    22 
    23     // WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS中的SSID字段必须为ANSI类型,因此如果程序使用的是Unicode,则需要做转换。
    24 #ifdef _UNICODE
    25     WideCharToMultiByte(CP_ACP,
    26         0,
    27         strSSID.GetBuffer(0),   // 保存SSID的CString类型
    28         strSSID.GetLength(),    // SSID字符串的长度
    29         (LPSTR)wlanConnectionSetting.hostedNetworkSSID.ucSSID,
    30         32,
    31         NULL,
    32         NULL);
    33 #else
    34     memcpy(wlanConnectionSetting.hostedNetworkSSID.ucSSID, strSSID.GetBuffer(0), strlen(strSSID.GetBuffer(0)));
    35 #endif   
    36 
    37     wlanConnectionSetting.hostedNetworkSSID.uSSIDLength = strlen((const char*)wlanConnectionSetting.hostedNetworkSSID.ucSSID);
    38     wlanConnectionSetting.dwMaxNumberOfPeers = 100;    
    39 
    40     dwReturnValue = WlanHostedNetworkSetProperty(m_hWlanClient, 
    41         wlan_hosted_network_opcode_connection_settings, 
    42         sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS), 
    43         &wlanConnectionSetting,
    44         &dwFailedReason,
    45         NULL);
    46     if(ERROR_SUCCESS != dwReturnValue)
    47     {
    48         return -1;
    49     }

    调用WlanHostedNetworkSetSecondaryKey函数,设置承载网络的连接密码,函数原型如下:

    1 DWORD WINAPI WlanHostedNetworkSetSecondaryKey(
    2   _In_        HANDLE hClientHandle,
    3   _In_        DWORD dwKeyLength,
    4   _In_        PUCHAR pucKeyData,
    5   _In_        BOOL bIsPassPhrase,
    6   _In_        BOOL bPersistent,
    7   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
    8   _Reserved_  PVOID pvReserved
    9 );

    hClientHandle是我们之前调用WlanOpenHnadle获得的句柄;

    bIsPassPhrase表明传入pucKeyData的密码是否为口令格式,如果是口令格式,则是8-63位的ASCII字符串,该参数设置为TRUE;如果为16进制的binary,参数设置为FALSE;

    dwKeyLength是密码缓冲区的长度,密码为口令格式时,必须包括结尾的'\0'

    pucKeyData如果字符串,则必须为ANSI类型,因此如果IDE环境将字符串配置为UNICODE,需要做转换,可使用WideCharToMultiByte,或者T2A,W2A宏。

    bPersistent用来指示密码是否是持久的。如果不是,那么该密码只在本次启动有效;否则下次启动Soft AP依然使用本次设置的密码。

    示例代码:

     1     UCHAR keyBuf[100] = {0};
     2 #ifdef _UNICODE
     3     WideCharToMultiByte(CP_ACP,
     4         0,
     5         strSecondaryKey.GetBuffer(0),
     6         strSecondaryKey.GetLength(),
     7         (LPSTR)keyBuf,
     8         100,
     9         NULL,
    10         NULL);
    11 #else
    12     memcpy(keyBuf, strSecondaryKey.GetBuffer(0), strlen(strSecondaryKey.GetBuffer(0)));
    13 #endif
    14     dwReturnValue = WlanHostedNetworkSetSecondaryKey(m_hWlanClient,
    15         strlen((const char*)keyBuf) + 1,
    16         keyBuf,
    17         TRUE,
    18         FALSE,
    19         &dwFailedReason,
    20         NULL);
    21     if(ERROR_SUCCESS != dwReturnValue)
    22     {
    23         return -1;
    24     }

    启动或者停止Soft AP,需要用到如下四个函数:

     1 DWORD WINAPI WlanHostedNetworkStartUsing(
     2   _In_        HANDLE hClientHandle,
     3   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
     4   _Reserved_  PVOID pvReserved
     5 );
     6 
     7 
     8 DWORD WINAPI WlanHostedNetworkStopUsing(
     9   _In_        HANDLE hClientHandle,
    10   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
    11   _Reserved_  PVOID pvReserved
    12 );
    13 
    14 DWORD WINAPI WlanHostedNetworkForceStart(
    15   _In_        HANDLE hClientHandle,
    16   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
    17   _Reserved_  PVOID pvReserved
    18 );
    19 
    20 DWORD WINAPI WlanHostedNetworkForceStop(
    21   _In_        HANDLE hClientHandle,
    22   _Out_opt_   PWLAN_HOSTED_NETWORK_REASON pFailReason,
    23   _Reserved_  PVOID pvReserved
    24 );

    参数的含义很直观,这里不再做更多地解释。值得注意的是,如果用StartUsing或者StopUsing版本的函数时,如果有客户端连接到了AP,调用WlanHostedNetworkStopUsing并不能立即停止Soft AP,而要等到客户端主动断开连接后,Soft AP才会停止。如果调用带Force的函数版本,则会强制停止Soft AP,不管是否有客户端正在连接到该AP上。当然,调用带Force的函数版本需要程序以管理员方式启动。

    示例代码:

     1     dwReturnValue = WlanHostedNetworkStartUsing(m_hWlanClient, &dwFailedReason, NULL);    
     2     if(ERROR_SUCCESS != dwReturnValue)
     3     {
     4         if (wlan_hosted_network_reason_interface_unavailable == dwFailedReason)
     5         {
     6             return 0;
     7         }
     8         return -1;
     9     }
    10 
    11     dwReturnValue = WlanHostedNetworkStopUsing(m_hWlanClient, &dwFailedReason, NULL);
    12     if (ERROR_SUCCESS != dwReturnValue)
    13     {
    14         return -1;
    15     }

    启动Soft AP后,绑定Ip需要一定的时间,一般为2-3秒。Ip地址一般为192.168.173.1(也有可能是192.168.137.1). 

    调试程序时,可使用命令行方式使用Soft AP(管理员方式打开cmd):

    查看当前承载网络状态 - netsh wlan show hostednetwork 

    配置承载网络属性,如SSID,密码等 - netsh wlan set hostednetwork ssid=***** key=***** mode=allow|disallow  (星号部分为ascii字符,key必须在8-63个字符之间)

    启动承载网络 - netsh wlan start hostednetwork

    关闭承载网络 - netsh wlan stop hostednetwork

    如果本文对你有帮助,可以考虑捐赠以支持作者。

    比特币地址:   1NPXhyv9W1tcqQc8iiSgx4YyPYbfoLSVzf

    莱特币地址:   LSXEAZt67sdpBjZ7yhvTpPUjy6hZKivYph

  • 相关阅读:
    noip模拟赛(一)宠物之战
    noip模拟赛(一)魔法树
    luogu1097统计数字[noip2007提高组Day1T1]
    luogu1207双重回文数[usaco1.2]Dual Palindromes
    【2018.9.20】JOI 2017 Final T3「JOIOI 王国 / The Kingdom of JOIOI」
    【2018.9.20】JOI 2017 Final T2「準急電車 / Semiexpress」
    Codeforces Round #510
    【2018.9.15】陈老师模拟赛1
    【loj6191】「美团 CodeM 复赛」配对游戏
    【loj6029】「雅礼集训 2017 Day1」市场
  • 原文地址:https://www.cnblogs.com/radiolover/p/3321561.html
Copyright © 2011-2022 走看看