Qt 使用Win32 API进行wifi通讯

Qt :使用Win32 API进行wifi通讯


目录

1:WlanOpenHandle

2:WlanEnumInterfaces 

3:WlanGetAvailableNetworkList

4:WlanSetProfile

5:WlanConnect

6:清空和关闭WIFI


wlanapi.h header使用说明:https://docs.microsoft.com/zh-cn/windows/win32/api/wlanapi/

wlanapi.h 论坛中文说明:https://blog.csdn.net/softwave/article/details/41389907

参考内容:

QT---Native Wifi functions 应用(WiFi有密码连接)https://www.cnblogs.com/findumars/p/6294156.html

Native wifi API使用(有涉及XML配置文件,非常详细):https://blog.csdn.net/hgy413/article/details/20784277

Native Wifi functions 应用(WiFi有密码连接)(有涉及XML配置文件):https://blog.csdn.net/xiapang009/article/details/73649383

Windows Native WIFI 编程:https://blog.csdn.net/mafujunfang/article/details/77747444

VC++玩转Native Wifi API:https://blog.csdn.net/lincyang/article/details/34430939

界面设计部分参考,左下角的电池和wifi资源来自于下文

Qt Windows 7(Win7)下获取并显示电池电量和WIFI信号强度:https://blog.csdn.net/caoshangpa/article/details/51062351

非常感谢以上优秀的博文 


WIFI相关文章:

wifi网络结构(上):https://blog.csdn.net/peixiuhui/article/details/45674859

wifi网络结构(下):https://blog.csdn.net/peixiuhui/article/details/45674867

 

wifi驱动的理解(1)——驱动架构:https://blog.csdn.net/peixiuhui/article/details/45674931

wifi驱动的理解(2)——usb接口在wifi模块中的角色:https://blog.csdn.net/peixiuhui/article/details/45674955

wifi驱动的理解(3)——usb接口在wifi模块中的角色:https://blog.csdn.net/peixiuhui/article/details/45674971

 

wifi网络接入原理(上)——扫描Scanning:https://blog.csdn.net/peixiuhui/article/details/45674881

wifi网络接入原理(中)——认证Authentication:https://blog.csdn.net/peixiuhui/article/details/45674893

wifi网络接入原理(下)——关联Association:https://blog.csdn.net/peixiuhui/article/details/45674917


主要使用的函数如下:(后面链接为MSDN说明) 

WlanOpenHandle:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanopenhandle

WlanEnumInterfaces:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanenuminterfaces

WlanGetAvailableNeiworkList:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist

WlanSetProfile:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlansetprofile

WlanConnect:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanconnect

WlanFreeMemory:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanfreememory

WlanClosehandle:https://docs.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanclosehandle


主要是对上述文章内容进行了整理和优化,具体的细节文字说明还请以Win 32 API介绍为主


配置文件定义:


static const QString STR_PROFILE_DEMO =
"<?xml version=\"1.0\"?> \
<WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\">\
    <name>Home</name>\
    <SSIDConfig>\
        <SSID>\
            <name>Home</name>\
        </SSID>\
    </SSIDConfig>\
    <connectionType>ESS</connectionType>\
    <connectionMode>auto</connectionMode>\
    <MSM>\
        <security>\
            <authEncryption>\
                <authentication>WPA2PSK</authentication>\
                <encryption>AES</encryption>\
                <useOneX>false</useOneX>\
            </authEncryption>\
            <sharedKey>\
                <keyType>passPhrase</keyType>\
                <protected>false</protected>\
                <keyMaterial>AAAAAA</keyMaterial>\
            </sharedKey>\
        </security>\
    </MSM>\
</WLANProfile>";

以上配置文件,STR_PROFILE_DEMO,可以使用函数WlanGetProfile进行打印,或者访问

配置文件样本,进行设置https://docs.microsoft.com/zh-cn/windows/win32/nativewifi/wireless-profile-samples

在具体的认证与关联过程中,需要XML配置文件

整体思路如下:粉红色为调用的参数

连接WIFI需要按照目录的函数的顺序进行调用,下面将对以下函数进行解释:

1:WlanOpenHandle

DWORD WlanOpenHandle(
  DWORD   dwClientVersion,
  PVOID   pReserved,
  PDWORD  pdwNegotiatedVersion,
  PHANDLE phClientHandle
);

关于函数功能的具体要求,可以访问MSDN,使用WlanOpenHandle函数主要是为了得到hClientHandle,往后的其他函数会需要这个句柄

函数需要四个参数:

①1或者2

含义

1

适用于Windows XP的Windows XP客户端版本和适用于Windows XP SP2的无线LAN API。

2

适用于Windows Vista和Windows Server 2008的客户端版本

②第二个参数保留供将来使用,为nullptr

③DWORD类型

④HANDLE类型

    //HANDLE hClientHandle;//万能指针  
    DWORD dwError = ERROR_SUCCESS;//原来我DWORD MFC的数据类型,相当于unsigned long
    //DWORD dwNegotiatedVersion;
    //WlanOpenHandle以下函数功能:打开wifi连接
//    qDebug()<<"dwError1:"<<dwError;
    dwError = WlanOpenHandle(1, nullptr, &dwNegotiatedVersion, &hClientHandle);
    //打开成功,返回ERROR_SUCCESS,不成功,返回其他,详情见win32 的api介绍
    //ERROR_SUCCESS打印出来是0
//    qDebug()<<"dwError2:"<<dwError;
    //连接不成功
    if (dwError != ERROR_SUCCESS)
    {
        qDebug()<<"未打开成功!";
        WlanCloseHandle(hClientHandle,nullptr);
        return;
    }

函数会更改 HANDLE hClientHandle的值,这个值在后面的函数中将会被反复调用

  2:WlanEnumInterfaces 

DWORD WlanEnumInterfaces(
  HANDLE                    hClientHandle,
  PVOID                     pReserved,
  PWLAN_INTERFACE_INFO_LIST *ppInterfaceList
);

函数需要三个参数

hClientHandle,通过先前调用WlanOpenHandle函数获得。

②第二个参数保留供将来使用,为nullptr

③类成员:PWLAN_INTERFACE_INFO_LIST  pInterfaceList;

    dwError = WlanEnumInterfaces(hClientHandle, nullptr,&pInterfaceList);
    //返回值还是DWRD类型的,成功的话是ERROR_SUCCESS
    if ( dwError != ERROR_SUCCESS )
    {
        qDebug()<<"未发现wifi相关列表!";
        WlanFreeMemory(pInterfaceList);//释放列表
        //释放内存,从Native Wifi函数返回的任何内存必须释放
        WlanCloseHandle(hClientHandle,nullptr);//关闭wlan
        return;
    }

 函数调用成功后,会更改pInterfaceList的指向,后面函数会用到这个指针

3:WlanGetAvailableNetworkList

DWORD WlanGetAvailableNetworkList(
  HANDLE                       hClientHandle,
  const GUID                   *pInterfaceGuid,
  DWORD                        dwFlags,
  PVOID                        pReserved,
  PWLAN_AVAILABLE_NETWORK_LIST *ppAvailableNetworkList
);

函数需要五个参数

hClientHandle,通过先前调用WlanOpenHandle函数获得。

②全局唯一标识符(globally unique identifier)

指向要查询的无线LAN接口的GUID的指针。

可以使用WlanEnumInterfaces函数确定在本地计算机上启用的每个无线LAN接口的GUID 。

第二个参数从pInterfaceList中获得,而pInterfaceList需要调用WlanEnumInterfaces得到。

GUID &guid = pInterfaceList->InterfaceInfo[0].InterfaceGuid;

③2

④参数保留供将来使用,为nullptr

指向存储的指针,用于接收WLAN_AVAILABLE_NETWORK_LIST结构中返回的可见网络列表。

    //GUID全局唯一标识符
    GUID &guid = pInterfaceList->InterfaceInfo[0].InterfaceGuid;
    //检测可用的网络
    PWLAN_AVAILABLE_NETWORK_LIST pWLAN_AVAILABLE_NETWORK_LIST = nullptr;
    //获取无线LAN接口上的可用网络列表
//    hClientHandle客户端的会话句柄,通过先前调用WlanOpenHandle函数获得。
//    pInterfaceGuid指向要查询的无线LAN接口的GUID的指针。
//    可以使用WlanEnumInterfaces函数确定在本地计算机上启用的每个无线LAN接口的GUID 。
//    dwFlags 一组控制列表中返回的网络类型的标志。此参数可以是这些可能值的组合。2
//    ppAvailableNetworkList指向存储的指针,用于接收WLAN_AVAILABLE_NETWORK_LIST结构中返回的可见网络列表。
    dwError = WlanGetAvailableNetworkList(hClientHandle, &guid,2,nullptr, &pWLAN_AVAILABLE_NETWORK_LIST);
    if (dwError != ERROR_SUCCESS)
    {
        qDebug()<<"未发现可用的网络!";

        WlanFreeMemory(pInterfaceList);
        WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
        WlanCloseHandle(hClientHandle,nullptr);
        QPixmap pixmapWireless(":/icons/WirelessIcon4.png");
        labelForWIFI->setPixmap(pixmapWireless);
        qTextBrowerNumberAvailWIFI->setText("0");
        return;
    }

具体的wifi列表打印部分

    WLAN_AVAILABLE_NETWORK wlanAN;
    //结构包含可用的无线网络信息
    bool isConnected=false;
    //访问的是_WLAN_AUTH_CIPHER_PAIR_LIST结构体中的成员,表示可用网络的数量
    DWORD numberOfItems = pWLAN_AVAILABLE_NETWORK_LIST->dwNumberOfItems;
    //储存可用网络的个数
    qDebug()<<"numberOf——AVAILABLE_NETWORK——Items:"<<numberOfItems;
    QString NumberAvailWIFI = QString::number(numberOfItems,10);
    qTextBrowerNumberAvailWIFI->setText(NumberAvailWIFI);

    if (numberOfItems > 0)//遍历所有的
    {
        for(DWORD i = 0; i <numberOfItems; i++)
        {
            //访问的是_WLAN_AUTH_CIPHER_PAIR_LIST结构体中的成员,表示可用网络的数目,每个ip都会存在Network数组里面
            wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[i];

            char *p;
            QString str1;

            //下面这段才是最精髓的
            if (wlanAN.dot11Ssid.uSSIDLength != 0)
            {
               p = (char*) wlanAN.dot11Ssid.ucSSID;//
               str1.append(p);
//               qDebug()<<"str1:"<<str1;
            }
            QListWidgetItem * ListitemJustForNOW= new QListWidgetItem(listWidgetAvailWIFI);
            ListitemJustForNOW->setText(str1);                     //设置列表项的文本
            listWidgetAvailWIFI->addItem(ListitemJustForNOW);          //加载列表项到列表框
            //下面这段才是最精髓的
            if(wlanAN.dwFlags & 1)
            {
                isConnected=true;

                int wifiQuality=(int)wlanAN.wlanSignalQuality;//返回信号的强度

                if(wifiQuality>75)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }
                else if(wifiQuality>50&&wifiQuality<=75)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon1.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }
                else if(wifiQuality>25&&wifiQuality<=50)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon2.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }
                else if(wifiQuality>0&&wifiQuality<=25)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon3.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }

            }
        }
    }

4:WlanSetProfile

以下代码是修改配置文件的内容,将WIFI的名称与密码进行配置,

之后调用WlanSetProfile函数,需要八个参数:

hClientHandle,通过先前调用WlanOpenHandle函数获得。

②全局唯一标识符(globally unique identifier)

指向要查询的无线LAN接口的GUID的指针。

可以使用WlanEnumInterfaces函数确定在本地计算机上启用的每个无线LAN接口的GUID 。

第二个参数从pInterfaceList中获得,而pInterfaceList需要调用WlanEnumInterfaces得到。

GUID &guid = pInterfaceList->InterfaceInfo[0].InterfaceGuid;

要在配置文件上设置的标志。

带有SP3的Windows XP和用于Windows XP SP2的无线LAN API:   dwFlags必须为0.不支持每用户配置文件。

含义

0

该配置文件是一个全用户配置文件。

WLAN_PROFILE_GROUP_POLICY

00000001

配置文件是组策略配置文件。

WLAN_PROFILE_USER

0x00000002

该配置文件是每用户配置文件。

本程序中为0

④配置文件

调用静态变量

static const QString STR_PROFILE_DEMO =
"<?xml version=\"1.0\"?> \
<WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\">\
    <name>Home</name>\
    <SSIDConfig>\
        <SSID>\
            <name>Home</name>\
        </SSID>\
    </SSIDConfig>\
    <connectionType>ESS</connectionType>\
    <connectionMode>auto</connectionMode>\
    <MSM>\
        <security>\
            <authEncryption>\
                <authentication>WPA2PSK</authentication>\
                <encryption>AES</encryption>\
                <useOneX>false</useOneX>\
            </authEncryption>\
            <sharedKey>\
                <keyType>passPhrase</keyType>\
                <protected>false</protected>\
                <keyMaterial>AAAAAA</keyMaterial>\
            </sharedKey>\
        </security>\
    </MSM>\
</WLANProfile>";

以上配置文件可以使用函数WlanGetProfile进行打印,或者访问

配置文件样本,进行设置https://docs.microsoft.com/zh-cn/windows/win32/nativewifi/wireless-profile-samples

⑤如果为新的所有用户配置文件将此参数设置为NULL

⑥指定此配置文件是否覆盖现有配置文件。如果此参数为FALSE且配置文件已存在,则不会覆盖现有配置文件,并将返回错误。

⑦参数保留供将来使用,为nullptr

⑧一个WLAN_REASON_CODE

 

    // 先决条件
    if (NameForWIFI.isEmpty())
    {
        return;
    }

    wchar_t profile[1024] = {};

    // 生成profile这个是关键,有了这个,全部都能解决
    QString strProfile = STR_PROFILE_DEMO;
    QRegExp regName("<name>.*</name>");
    regName.setMinimal(true);
    strProfile.replace(regName, QString("<name>%1</name>").arg(NameForWIFI));
    QRegExp regPassword("<keyMaterial>.*</keyMaterial>");
    regPassword.setMinimal(true);
    strProfile.replace(regPassword, QString("<keyMaterial>%1</keyMaterial>").arg(PassNumber));

    strProfile.toWCharArray(profile);
    qDebug()<<"strProfile:"<<strProfile;
    DWORD dwReasonCode = 0;
    DWORD dwResult  = WlanSetProfile(
        hClientHandle,
        &pInterfaceList->InterfaceInfo[0].InterfaceGuid,
        0,
        profile,
        nullptr,
        TRUE,
        nullptr,
        &dwReasonCode
        );

    // 密码错误返回 ERROR_BAD_PROFILE
    if (dwResult == ERROR_SUCCESS)
    {
        qDebug()<<"设置成功";
    }
    else if(dwResult == ERROR_BAD_PROFILE)
    {
        qDebug()<<"设置失败";
    }

5:WlanConnect

这是WIFI连接的关键一步,需要四个参数:

hClientHandle,通过先前调用WlanOpenHandle函数获得。

②全局唯一标识符(globally unique identifier)

指向要查询的无线LAN接口的GUID的指针。

可以使用WlanEnumInterfaces函数确定在本地计算机上启用的每个无线LAN接口的GUID 。

第二个参数从pInterfaceList中获得,而pInterfaceList需要调用WlanEnumInterfaces得到。

GUID &guid = pInterfaceList->InterfaceInfo[0].InterfaceGuid;

③&wlanConnPara ,WLAN_CONNECTION_PARAMETERS结构体,需要对内容进行赋值

④NULL第四个参数为保留内容,直接设置成NULL即可

    //密码连接
    //具体参数的配置
    wchar_t wifi[MAX_PATH] = {};
    NameForWIFI.toWCharArray(wifi);
    qDebug()<<"ConnectWIFI_wifi:"<<wifi;
    WLAN_CONNECTION_PARAMETERS wlanConnPara;
    wlanConnPara.wlanConnectionMode =wlan_connection_mode_profile ; //YES,WE CONNECT AP VIA THE PROFILE
//    wlan_connection_mode_profile	将使用配置文件进行连接。
//    wlan_connection_mode_temporary_profile	将使用临时配置文件进行连接。
//    wlan_connection_mode_discovery_secure	安全发现将用于建立连接。
//    wlan_connection_mode_discovery_unsecure	将使用不安全的发现来建立连接。
//    wlan_connection_mode_auto	无线服务使用持久性配置文件自动启动连接。
//    wlan_connection_mode_invalid	不曾用过。
    wlanConnPara.strProfile =wifi;							// set the profile name,wifi名
    wlanConnPara.pDot11Ssid = nullptr;									// SET SSID NULL,设置为NULL时,会去配置有的ssid
    wlanConnPara.dot11BssType = dot11_BSS_type_infrastructure;		//dot11_BSS_type_any,I do not need it this time.
    wlanConnPara.pDesiredBssidList = nullptr;							// the desired BSSID list is empty
    wlanConnPara.dwFlags = WLAN_CONNECTION_HIDDEN_NETWORK;			//it works on my WIN7\8

//    dwFlags这个参数有很多的模式可以选择
    //配置完成后的连接情况
/*WlanOpenHandle的最后一个参数是hClient,
 * 第二个参数是需要连接的网络的Guid,WlanEnumInterfaces枚举会返回一个指针
 * 第三个参数,一个指向结构体的指针,上面内容即为具体参数的配置,
 * 第四个参数保留
*/
    DWORD dwResult = 0;

    dwResult=WlanConnect(hClientHandle,&pInterfaceList->InterfaceInfo[0].InterfaceGuid,&wlanConnPara ,NULL);
    if (dwResult==ERROR_SUCCESS)
    {
        qDebug()<<"连接成功!";

    }
    else
    {
        qDebug()<<"连接失败:错误信息为:"<<dwResult;
        if(dwResult==ERROR_INVALID_PARAMETER)
        {
            qDebug()<<"连接失败:错误信息为:ERROR_INVALID_PARAMETER";
        }
        else if(dwResult==ERROR_INVALID_HANDLE)
        {
            qDebug()<<"连接失败:错误信息为:ERROR_INVALID_HANDLE";
        }
        else if(dwResult==ERROR_ACCESS_DENIED)
        {
            qDebug()<<"连接失败:错误信息为:ERROR_ACCESS_DENIED";
        }
        else
        {
            qDebug()<<"连接失败:错误信息为:多种"<<dwResult;
        }

    }

6:清空和关闭WIFI

void Widget::closeEvent(QCloseEvent *event)
{
    int ret = QMessageBox::question(this,"close","Are you sure?",QMessageBox::Yes,QMessageBox::No);
    if(ret == QMessageBox::Yes)
    {
        WlanFreeMemory(pInterfaceList);
//        WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
        WlanCloseHandle(hClientHandle,nullptr);
        event->accept();//接受
    }
    else if(ret == QMessageBox::No)
    {
        qDebug()<<"继续";
        event->ignore();//忽视
    }
}

 

部分代码:

#include "widget.h"
#include "ui_widget.h"



Widget::Widget(QWidget *parent) :
    QWidget(parent)
//    ui(new Ui::Widget)
{
//    ui->setupUi(this);
    labelForWIFI = new QLabel(this);//wifi显示
    labelForBattery = new QLabel(this);//battery显示
    labelForNumberAvailWIFI = new QLabel("可用WIFI数量:",this);
    FreshPushButton  = new QPushButton("刷新",this);//刷新界面


    qTextBrowerNumberAvailWIFI = new QTextBrowser(this);//显示可以连接的wifi数量

    listWidgetAvailWIFI = new QListWidget(this);
    Listitem = new QListWidgetItem(listWidgetAvailWIFI);//注意父对象
    Pass = new PassNumberDialog(this);//输入密码的窗口
    connect(listWidgetAvailWIFI,&QListWidget::itemDoubleClicked,this,&Widget::OpenThePassDialog);
    connect(Pass,&PassNumberDialog::GiveWidgetPassWord,this,&Widget::GetPassWord);
    connect(FreshPushButton,&QPushButton::clicked,this,&Widget::slotTimeout);
    hClientHandle = nullptr;//万能指针
    pInterfaceList = nullptr;

    UisetForWifi();
//    timer=new QTimer(this);
//    connect(timer,SIGNAL(timeout()),this,SLOT(slotTimeout()));
//    timer->start(3000);
    showBattery();
    showWIFI();

}
Widget::~Widget()
{
//    delete ui;
}
void Widget::UisetForWifi()
{
    this->setFixedSize(400,600);
    labelForWIFI->setGeometry(280,520,100,100);
    labelForBattery->setGeometry(320,520,100,100);
    FreshPushButton->setGeometry(40,500,80,30);

    QFont FontForQTextBrower;
    FontForQTextBrower.setFamily("Segoe UI");
    FontForQTextBrower.setBold(true);
    FontForQTextBrower.setPixelSize(14);

    labelForNumberAvailWIFI->setGeometry(40,30,100,30);
    labelForNumberAvailWIFI->setFont(FontForQTextBrower);

    qTextBrowerNumberAvailWIFI->setGeometry(140,30,100,30);
    qTextBrowerNumberAvailWIFI->setFont(FontForQTextBrower);

    listWidgetAvailWIFI->setGeometry(40,80,200,400);

}
void Widget::slotTimeout()
{
    listWidgetAvailWIFI->clear();
    showBattery();
    showWIFI();
}

void Widget::showBattery()
{
    SYSTEM_POWER_STATUS systemPowerSatus;
    GetSystemPowerStatus(&systemPowerSatus);
    int remaindPower=(int)systemPowerSatus.BatteryLifePercent;
    if(remaindPower>75)
    {
        QPixmap pixmapBattery("://icons/BatteryIcon.png");
        labelForBattery->setPixmap(pixmapBattery);
    }
    else if(remaindPower>50&&remaindPower<=75)
    {
        QPixmap pixmapBattery("://icons/BatteryIcon1.png");
        labelForBattery->setPixmap(pixmapBattery);
    }
    else if(remaindPower>25&&remaindPower<=50)
    {
        QPixmap pixmapBattery("://icons/BatteryIcon2.png");
        labelForBattery->setPixmap(pixmapBattery);
    }
    else if(remaindPower>0&&remaindPower<=25)
    {
        QPixmap pixmapBattery("://icons/BatteryIcon3.png");
        labelForBattery->setPixmap(pixmapBattery);
    }
    else
    {
        QPixmap pixmapBattery("://icons/BatteryIcon4.png");
        labelForBattery->setPixmap(pixmapBattery);
    }
}
//一下内容均使用了win 32api,所以有大量的句柄是MFC的
//还是保留其中的MFC句柄,这样在window官网上查找相关的句柄,函数返回值也知道该怎么做
void Widget::showWIFI()
{
    DWORD dwError = ERROR_SUCCESS;//原来我DWORD MFC的数据类型,相当于unsigned long
    DWORD dwNegotiatedVersion;
    //WlanOpenHandle以下函数功能:打开wifi连接
//    qDebug()<<"dwError1:"<<dwError;
    dwError = WlanOpenHandle(1, nullptr, &dwNegotiatedVersion, &hClientHandle);
    //打开成功,返回ERROR_SUCCESS,不成功,返回其他,详情见win32 的api介绍
    //ERROR_SUCCESS打印出来是0
//    qDebug()<<"dwError2:"<<dwError;
    //连接不成功
    if (dwError != ERROR_SUCCESS)
    {
        qDebug()<<"未打开成功!";
        WlanCloseHandle(hClientHandle,nullptr);
        return;
    }

    //structure contains an array of NIC interface information.包含有相关信息
    //hClientHandle是从WlanOpenHandle中获得的,第二个参数保留,变成nullptr即可,ppInterfaceList保存的是可以wifi的列表
    dwError = WlanEnumInterfaces(hClientHandle, nullptr,&pInterfaceList);
    //返回值还是DWRD类型的,成功的话是ERROR_SUCCESS
    if ( dwError != ERROR_SUCCESS )
    {
        qDebug()<<"未发现wifi相关列表!";
        WlanFreeMemory(pInterfaceList);//释放列表
        //释放内存,从Native Wifi函数返回的任何内存必须释放
        WlanCloseHandle(hClientHandle,nullptr);//关闭wlan
        return;
    }

    //GUID全局唯一标识符
    GUID &guid = pInterfaceList->InterfaceInfo[0].InterfaceGuid;
    //检测可用的网络
    PWLAN_AVAILABLE_NETWORK_LIST pWLAN_AVAILABLE_NETWORK_LIST = nullptr;
    //获取无线LAN接口上的可用网络列表
//    hClientHandle客户端的会话句柄,通过先前调用WlanOpenHandle函数获得。
//    pInterfaceGuid指向要查询的无线LAN接口的GUID的指针。
//    可以使用WlanEnumInterfaces函数确定在本地计算机上启用的每个无线LAN接口的GUID 。
//    dwFlags 一组控制列表中返回的网络类型的标志。此参数可以是这些可能值的组合。2
//    ppAvailableNetworkList指向存储的指针,用于接收WLAN_AVAILABLE_NETWORK_LIST结构中返回的可见网络列表。
    dwError = WlanGetAvailableNetworkList(hClientHandle, &guid,2,nullptr, &pWLAN_AVAILABLE_NETWORK_LIST);
    if (dwError != ERROR_SUCCESS)
    {
        qDebug()<<"未发现可用的网络!";

        WlanFreeMemory(pInterfaceList);
        WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
        WlanCloseHandle(hClientHandle,nullptr);
        QPixmap pixmapWireless(":/icons/WirelessIcon4.png");
        labelForWIFI->setPixmap(pixmapWireless);
        qTextBrowerNumberAvailWIFI->setText("0");
        return;
    }

    WLAN_AVAILABLE_NETWORK wlanAN;
    //结构包含可用的无线网络信息
    bool isConnected=false;
    //访问的是_WLAN_AUTH_CIPHER_PAIR_LIST结构体中的成员,表示可用网络的数量
    DWORD numberOfItems = pWLAN_AVAILABLE_NETWORK_LIST->dwNumberOfItems;
    //储存可用网络的个数
    qDebug()<<"numberOf——AVAILABLE_NETWORK——Items:"<<numberOfItems;
    QString NumberAvailWIFI = QString::number(numberOfItems,10);
    qTextBrowerNumberAvailWIFI->setText(NumberAvailWIFI);

    if (numberOfItems > 0)//遍历所有的
    {
        for(DWORD i = 0; i <numberOfItems; i++)
        {
            //访问的是_WLAN_AUTH_CIPHER_PAIR_LIST结构体中的成员,表示可用网络的数目,每个ip都会存在Network数组里面
            wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[i];

            char *p;
            QString str1;

            //下面这段才是最精髓的
            if (wlanAN.dot11Ssid.uSSIDLength != 0)
            {
               p = (char*) wlanAN.dot11Ssid.ucSSID;//
               str1.append(p);
//               qDebug()<<"str1:"<<str1;
            }
            QListWidgetItem * ListitemJustForNOW= new QListWidgetItem(listWidgetAvailWIFI);
            ListitemJustForNOW->setText(str1);                     //设置列表项的文本
            listWidgetAvailWIFI->addItem(ListitemJustForNOW);          //加载列表项到列表框
            //下面这段才是最精髓的
            if(wlanAN.dwFlags & 1)
            {
                isConnected=true;

                int wifiQuality=(int)wlanAN.wlanSignalQuality;//返回信号的强度

                if(wifiQuality>75)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }
                else if(wifiQuality>50&&wifiQuality<=75)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon1.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }
                else if(wifiQuality>25&&wifiQuality<=50)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon2.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }
                else if(wifiQuality>0&&wifiQuality<=25)
                {
                    QPixmap pixmapWireless("://icons/WirelessIcon3.png");
                    labelForWIFI->setPixmap(pixmapWireless);
                }

            }
        }
    }
    //释放工作
//    WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);


}
void Widget::OpenThePassDialog(QListWidgetItem *item)
{
    NameForWIFI = item->text();
    qDebug()<<"选择WIFI为:"<<item->text();
    Pass->exec();//打开输入密码的窗口

}
void Widget::wlanSetProfile()
{
    // 先决条件
    if (NameForWIFI.isEmpty())
    {
        return;
    }

    wchar_t profile[1024] = {};

    // 生成profile这个是关键,有了这个,全部都能解决
    QString strProfile = STR_PROFILE_DEMO;
    QRegExp regName("<name>.*</name>");
    regName.setMinimal(true);
    strProfile.replace(regName, QString("<name>%1</name>").arg(NameForWIFI));
    QRegExp regPassword("<keyMaterial>.*</keyMaterial>");
    regPassword.setMinimal(true);
    strProfile.replace(regPassword, QString("<keyMaterial>%1</keyMaterial>").arg(PassNumber));

    strProfile.toWCharArray(profile);
    qDebug()<<"strProfile:"<<strProfile;
    DWORD dwReasonCode = 0;
    DWORD dwResult  = WlanSetProfile(
        hClientHandle,
        &pInterfaceList->InterfaceInfo[0].InterfaceGuid,
        0,
        profile,
        NULL,
        TRUE,
        NULL,
        &dwReasonCode
        );

    // 密码错误返回 ERROR_BAD_PROFILE
    if (dwResult == ERROR_SUCCESS)
    {
        qDebug()<<"设置成功";
    }
    else if(dwResult == ERROR_BAD_PROFILE)
    {
        qDebug()<<"设置失败";
    }

}

void Widget::ConnectWIFI()
{

    //密码连接
    //具体参数的配置
    wchar_t wifi[MAX_PATH] = {};
    NameForWIFI.toWCharArray(wifi);
    qDebug()<<"ConnectWIFI_wifi:"<<wifi;
    WLAN_CONNECTION_PARAMETERS wlanConnPara;
    wlanConnPara.wlanConnectionMode =wlan_connection_mode_profile ; //YES,WE CONNECT AP VIA THE PROFILE
//    wlan_connection_mode_profile	将使用配置文件进行连接。
//    wlan_connection_mode_temporary_profile	将使用临时配置文件进行连接。
//    wlan_connection_mode_discovery_secure	安全发现将用于建立连接。
//    wlan_connection_mode_discovery_unsecure	将使用不安全的发现来建立连接。
//    wlan_connection_mode_auto	无线服务使用持久性配置文件自动启动连接。
//    wlan_connection_mode_invalid	不曾用过。
    wlanConnPara.strProfile =wifi;							// set the profile name,wifi名
    wlanConnPara.pDot11Ssid = NULL;									// SET SSID NULL,设置为NULL时,会去配置有的ssid
    wlanConnPara.dot11BssType = dot11_BSS_type_infrastructure;		//dot11_BSS_type_any,I do not need it this time.
    wlanConnPara.pDesiredBssidList = NULL;							// the desired BSSID list is empty
    wlanConnPara.dwFlags = WLAN_CONNECTION_HIDDEN_NETWORK;			//it works on my WIN7\8

//    dwFlags这个参数有很多的模式可以选择
    //配置完成后的连接情况
/*WlanOpenHandle的最后一个参数是hClient,
 * 第二个参数是需要连接的网络的Guid,WlanEnumInterfaces枚举会返回一个指针
 * 第三个参数,一个指向结构体的指针,上面内容即为具体参数的配置,
 * 第四个参数保留
*/
    DWORD dwResult = 0;

    dwResult=WlanConnect(hClientHandle,&pInterfaceList->InterfaceInfo[0].InterfaceGuid,&wlanConnPara ,NULL);
    if (dwResult==ERROR_SUCCESS)
    {
        qDebug()<<"连接成功!";

    }
    else
    {
        qDebug()<<"连接失败:错误信息为:"<<dwResult;
        if(dwResult==ERROR_INVALID_PARAMETER)
        {
            qDebug()<<"连接失败:错误信息为:ERROR_INVALID_PARAMETER";
        }
        else if(dwResult==ERROR_INVALID_HANDLE)
        {
            qDebug()<<"连接失败:错误信息为:ERROR_INVALID_HANDLE";
        }
        else if(dwResult==ERROR_ACCESS_DENIED)
        {
            qDebug()<<"连接失败:错误信息为:ERROR_ACCESS_DENIED";
        }
        else
        {
            qDebug()<<"连接失败:错误信息为:多种"<<dwResult;
        }

    }
}
void Widget::GetPassWord(const QString number)
{
    PassNumber = number;
    qDebug()<<"密码为:"<<PassNumber;
    wlanSetProfile();
    ConnectWIFI();
}
void Widget::closeEvent(QCloseEvent *event)
{
    int ret = QMessageBox::question(this,"close","Are you sure?",QMessageBox::Yes,QMessageBox::No);
    if(ret == QMessageBox::Yes)
    {
        WlanFreeMemory(pInterfaceList);
//        WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
        WlanCloseHandle(hClientHandle,nullptr);
        event->accept();//接受
    }
    else if(ret == QMessageBox::No)
    {
        qDebug()<<"继续";
        event->ignore();//忽视
    }
}

界面展示:

源文件下载地址:https://download.csdn.net/download/qq_41605114/11716245

  • 2
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值