有个项目是c#做的, 有个需求是程序启动自动连接指定wifi,想到windows有个系统库支持,就用c++调的系统库,然后c#再调c++封装好的接口,比较简单,先上代码
c++动态库部分
静态调用的时候好像有问题,没细琢磨,就直接改用动态加载了
.h
#pragma once
#include <wlanapi.h>
#pragma comment(lib,"wlanapi.lib")
#pragma comment(lib,"ole32.lib")
typedef int WINBOOL;
typedef DWORD(WINAPI* pfnWlanGetAvailableNetworkList)(
HANDLE hClientHandle,
const GUID* pInterfaceGuid,
DWORD dwFlags,
PVOID pReserved,
PWLAN_AVAILABLE_NETWORK_LIST* ppAvailableNetworkList
);
typedef DWORD(WINAPI* pfnWlanOpenHandle)(
DWORD dwClientVersion,
PVOID pReserved,
PDWORD pdwNegotiatedVersion,
PHANDLE phClientHandle
);
typedef DWORD(WINAPI* pfnWlanEnumInterfaces)(
HANDLE hClientHandle,
PVOID pReserved,
PWLAN_INTERFACE_INFO_LIST* ppInterfaceList
);
typedef DWORD(WINAPI* pfnWlanQueryInterface)(
HANDLE hClientHandle,
const GUID* pInterfaceGuid,
WLAN_INTF_OPCODE OpCode,
PVOID pReserved,
PDWORD pdwDataSize,
PVOID* ppData,
PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType
);
typedef DWORD(WINAPI* pfnWlanSetProfile)(
HANDLE hClientHandle,
const GUID* pInterfaceGuid,
DWORD dwFlags,
LPCWSTR strProfileXml,
LPCWSTR strAllUserProfileSecurity,
WINBOOL bOverwrite,
PVOID pReserved,
DWORD* pdwReasonCode
);
typedef DWORD(WINAPI* pfnWlanSetInterface)(
HANDLE hClientHandle,
const GUID* pInterfaceGuid,
WLAN_INTF_OPCODE OpCode,
DWORD dwDataSize,
const PVOID pData,
PVOID pReserved
);
typedef DWORD (WINAPI* pfnWlanConnect)(
HANDLE hClientHandle,
const GUID* pInterfaceGuid,
const PWLAN_CONNECTION_PARAMETERS pConnectionParameters,
PVOID pReserved
);
typedef DWORD (WINAPI* pfnWlanDisconnect)(
_In_ HANDLE hClientHandle,
_In_ CONST GUID* pInterfaceGuid,
_Reserved_ PVOID pReserved
);
typedef DWORD (WINAPI* pfnWlanCloseHandle)(
_In_ HANDLE hClientHandle,
_Reserved_ PVOID pReserved
);
typedef VOID (WINAPI* pfnWlanFreeMemory)(
_In_ PVOID pMemory
);
class exportDLl
{
public:
static exportDLl* m_pInstance;
static exportDLl* getInstance();
public:
bool pLoadLibrary();
void pReleaseLibrary();
int pFindWifi(const char* sWifiName);
int connect(const char* sXmlName);
private:
bool wifiInit();
int isConnect(const char* sWifiName);
private:
pfnWlanGetAvailableNetworkList fnWlanGetAvailableNetworkList = nullptr;
pfnWlanOpenHandle fnWlanOpenHandle = nullptr;
pfnWlanEnumInterfaces fnWlanEnumInterfaces = nullptr;
pfnWlanQueryInterface fnWlanQueryInterface = nullptr;
pfnWlanSetProfile fnWlanSetProfile = nullptr;
pfnWlanSetInterface fnWlanSetInterface = nullptr;
pfnWlanConnect fnWlanConnect = nullptr;
pfnWlanDisconnect fnWlanDisconnect = nullptr;
pfnWlanCloseHandle fnWlanCloseHandle = nullptr;
pfnWlanFreeMemory fnWlanFreeMemory = nullptr;
HMODULE hDll = nullptr;
HANDLE hClient = NULL;
DWORD dwMaxClient = 2;
DWORD dwCurVersion = 0;
DWORD dwResult = 0;
PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
PWLAN_INTERFACE_INFO pIfInfo = NULL;
PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
bool m_bisLoad = false;
};
extern "C"
{
__declspec(dllexport) bool pLoadLibrary();
__declspec(dllexport) int pFindWifi(const char* path);
__declspec(dllexport) int connect(const char* filename);
}
.cpp
#include "pch.h"
#include "exportDLl.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
static string string_to_hex(const string& str)
{
string result = "";
string tmp;
std::stringstream ss;
for (int i = 0; i < str.size(); i++)
{
ss << hex << int(str[i]) << endl;
ss >> tmp;
result += tmp;
}
return result;
}
static LPCWSTR StringToLPCWSTR(std::string orig)
{
size_t origsize = orig.length() + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t* wcstring = (wchar_t*)malloc(sizeof(wchar_t) * (orig.length() - 1));
mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE);
return wcstring;
}
static void LPCWSTRToString(std::string& szDst, wchar_t* wchar)
{
wchar_t* wText = wchar;
DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, NULL, 0, NULL, FALSE);// WideCharToMultiByte的运用
char* psText; // psText为char*的临时数组,作为赋值给std::string的中间变量
psText = new char[dwNum];
WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, psText, dwNum, NULL, FALSE);// WideCharToMultiByte的再次运用
szDst = psText;// std::string赋值
delete[]psText;// psText的清除
}
exportDLl* exportDLl::m_pInstance = nullptr;
exportDLl* exportDLl::getInstance()
{
if (!m_pInstance)
{
m_pInstance = new exportDLl;
}
return m_pInstance;
}
bool pLoadLibrary()
{
return exportDLl::getInstance()->pLoadLibrary();
}
int pFindWifi(const char* sWifiName)
{
return exportDLl::getInstance()->pFindWifi(sWifiName);
}
int connect(const char* filename)
{
return exportDLl::getInstance()->connect(filename);
}
//加载wlanapi.dll系统动态库
bool exportDLl::pLoadLibrary()
{
if (m_bisLoad)
{
return true;
}
if (hDll == nullptr)
{
hDll = LoadLibraryA("wlanapi.dll");
}
else
{
return true;
}
if (hDll == nullptr)
{
m_bisLoad = false;
return false;
}
fnWlanGetAvailableNetworkList = (pfnWlanGetAvailableNetworkList)GetProcAddress(hDll, "WlanGetAvailableNetworkList");
fnWlanOpenHandle = (pfnWlanOpenHandle)GetProcAddress(hDll, "WlanOpenHandle");
fnWlanEnumInterfaces = (pfnWlanEnumInterfaces)GetProcAddress(hDll, "WlanEnumInterfaces");
fnWlanQueryInterface = (pfnWlanQueryInterface)GetProcAddress(hDll, "WlanQueryInterface");
fnWlanSetProfile = (pfnWlanSetProfile)GetProcAddress(hDll, "WlanSetProfile");
fnWlanSetInterface = (pfnWlanSetInterface)GetProcAddress(hDll, "WlanSetInterface");
fnWlanConnect = (pfnWlanConnect)GetProcAddress(hDll, "WlanConnect");
fnWlanDisconnect = (pfnWlanDisconnect)GetProcAddress(hDll, "WlanDisconnect");
fnWlanCloseHandle = (pfnWlanCloseHandle)GetProcAddress(hDll, "WlanCloseHandle");
fnWlanFreeMemory = (pfnWlanFreeMemory)GetProcAddress(hDll, "WlanFreeMemory");
if (!fnWlanGetAvailableNetworkList || !fnWlanOpenHandle || !fnWlanEnumInterfaces || !fnWlanQueryInterface
|| !fnWlanSetProfile || !fnWlanSetInterface || !fnWlanConnect || !fnWlanDisconnect || !fnWlanCloseHandle || !fnWlanFreeMemory)
{
FreeLibrary(hDll);
hDll = nullptr;
m_bisLoad = false;
return false;
}
m_bisLoad = true;
return true;
}
void exportDLl::pReleaseLibrary()
{
fnWlanGetAvailableNetworkList = nullptr;
fnWlanOpenHandle = nullptr;
fnWlanEnumInterfaces = nullptr;
fnWlanQueryInterface = nullptr;
fnWlanSetProfile = nullptr;
fnWlanSetInterface = nullptr;
fnWlanConnect = nullptr;
fnWlanDisconnect = nullptr;
fnWlanCloseHandle = nullptr;
fnWlanFreeMemory = nullptr;
}
int exportDLl::pFindWifi(const char* sWifiName)
{
if (!m_bisLoad)
{
return -3;
}
if (!wifiInit())
{
return -4;
}
if (isConnect(sWifiName) == 0)
{
//等于0 则需要查找的wifi正在连接 后续不用再操作
//关闭句柄
fnWlanCloseHandle(hClient, NULL);
if (pIfList != NULL) {
WlanFreeMemory(pIfList);
pIfList = NULL;
}
pReleaseLibrary();
return 0;
}
//有正在连接的wifi 断开连接
fnWlanDisconnect(hClient, &pIfInfo->InterfaceGuid, 0);
PWLAN_AVAILABLE_NETWORK_LIST pBssList = NULL;
PWLAN_AVAILABLE_NETWORK pBssEntry = NULL;
fnWlanGetAvailableNetworkList(hClient, &pIfInfo->InterfaceGuid, 0, NULL, &pBssList);
if (pBssList == NULL)
{
return -1;
}
cout << pBssList->dwNumberOfItems << endl;
for (int j = 0; j < (int)pBssList->dwNumberOfItems; ++j)
{
pBssEntry = (WLAN_AVAILABLE_NETWORK*)&pBssList->Network[j];
std::string temp = std::string(reinterpret_cast<char*>(pBssEntry->dot11Ssid.ucSSID));
if (temp.empty())
{
cout << "null wifiname\n";
continue;
}
cout << temp.c_str() << " <-> "<<sWifiName << endl;
if(strcmp(temp.c_str(),sWifiName) == 0)
{
return (int)pBssList->dwNumberOfItems;
}
}
return -2;
}
int exportDLl::connect(const char* sXmlPath)
{
if (!m_bisLoad)
{
return -2;
}
ifstream infile;
infile.open(sXmlPath);
if (!infile.is_open())
{
return 1;
}
char c;
string s;
infile >> noskipws;
while (infile >> c) //读xml文件
{
s += c;
}
infile.close();
cout << s << endl;
WLAN_REASON_CODE Wlanreason;
//此处第四个参数是profile文件的内容,就是c#调用里组的xml
int ret = fnWlanSetProfile(hClient, &pIfInfo->InterfaceGuid, 0, StringToLPCWSTR(s), NULL, TRUE, NULL, &Wlanreason);
if (ret != 0)
{
return -1;
}
string sXMLName = sXmlPath;
int index = sXMLName.find_last_of("\\") + 1;
if (string::npos == index)
{
//未查找到 \ 符号 说明文件在当前目录下 不用截取
}
else
{
sXMLName = sXMLName.substr(index);
}
DOT11_SSID stSsid;
WLAN_CONNECTION_PARAMETERS stConnectionParameters;
memset(&stSsid, 0, sizeof(stSsid));
memset(&stConnectionParameters, 0, sizeof(WLAN_CONNECTION_PARAMETERS));
memcpy(stSsid.ucSSID, sXMLName.c_str(), sizeof(stSsid.ucSSID));
stSsid.uSSIDLength = strlen(sXMLName.c_str()) + 1;
stConnectionParameters.pDot11Ssid = &stSsid;
stConnectionParameters.wlanConnectionMode = wlan_connection_mode_discovery_unsecure;
stConnectionParameters.strProfile = StringToLPCWSTR(sXMLName);
stConnectionParameters.dot11BssType = dot11_BSS_type_independent; // msdn说可以dot11_BSS_type_any,实测不行
stConnectionParameters.pDesiredBssidList = NULL;
stConnectionParameters.dwFlags = 0; // WLAN_CONNECTION_ADHOC_JOIN_ONLY
//此处第三个参数很关键,也很复杂,稍微传错一点就会失败,暂时还没弄得很清楚
ret = fnWlanConnect(hClient, &pIfInfo->InterfaceGuid, &stConnectionParameters, NULL);//pIfList
if (ret == ERROR_SUCCESS)
{
cout << "连接成功\n";
fnWlanCloseHandle(hClient, NULL); //关闭句柄
if (pIfList != NULL) {
WlanFreeMemory(pIfList);
pIfList = NULL;
}
pReleaseLibrary();
}
return ret;
}
bool exportDLl::wifiInit()
{
if (!m_bisLoad)
{
return false;
}
dwResult = fnWlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
if (ERROR_SUCCESS != dwResult)
{
cout << "WlanOpenHandle failed with error:" << dwResult;
return false;
}
dwResult = fnWlanEnumInterfaces(hClient, NULL, &pIfList);
if (ERROR_SUCCESS != dwResult)
{
cout << "WlanEnumInterfaces failed with error " << dwResult;
return false;
}
int iScan = 1;
PVOID pData = &iScan;
dwResult = fnWlanSetInterface(hClient, &pIfInfo->InterfaceGuid, wlan_intf_opcode_background_scan_enabled, sizeof(int), pData, NULL);
return true;
}
int exportDLl::isConnect(const char* sWifiName)
{
if (!m_bisLoad)
{
return -3;
}
pIfInfo = (WLAN_INTERFACE_INFO*)&pIfList->InterfaceInfo[0];
string CurConnectedWlanProfileName;
if (pIfInfo->isState == wlan_interface_state_connected)
{
dwResult = fnWlanQueryInterface(hClient,
&pIfInfo->InterfaceGuid,
wlan_intf_opcode_current_connection,
NULL,
&connectInfoSize,
(PVOID*)&pConnectInfo,
&opCode);
if (dwResult != ERROR_SUCCESS)
{
//
}
else
{
switch (pConnectInfo->isState)
{
case wlan_interface_state_connected:
{
string s;
LPCWSTRToString(s,pConnectInfo->strProfileName);
cout << s << " is connected\n";
if (strcmp(s.c_str(), sWifiName) == 0)
{
//如果要查找的wifi已经连接 则不再操作
return 0;
}
return -1;
}
default:
{
break;
}
}
}
}
else
{
return -1;
//未连接
}
return -1;
}
c#调用部分
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace csharpWlan
{
class Program
{
[DllImport("wlandll.dll")]
public extern static bool pLoadLibrary();
[DllImport("wlandll.dll")]
public extern static int pFindWifi(String wifiName);
[DllImport("wlandll.dll")]
public extern static int connect(String xmlPath);
public static void CreateNode(XmlDocument xmlDoc, XmlNode parentNode, string name, string value)
{
XmlNode node = xmlDoc.CreateNode(XmlNodeType.Element, name, null);
node.InnerText = value;
parentNode.AppendChild(node);
}
public delegate int MethodWlanConn();
public static String CreateXML(String path = "")
{
if (path == "")
{
path = String.Format(@"{0}\{1}", System.Environment.CurrentDirectory, sXMLName);
}
if (File.Exists(sXMLName))
{
return path;
}
XmlDocument xmlDoc = new XmlDocument();
XmlDeclaration Declaration = xmlDoc.CreateXmlDeclaration("1.0", "", null);
xmlDoc.AppendChild(Declaration);
XmlNode rootNode = xmlDoc.CreateElement("WLANProfile");
XmlAttribute rootNodeattribute = xmlDoc.CreateAttribute("xmlns");
rootNodeattribute.Value = "http://www.microsoft.com/networking/WLAN/profile/v1";
rootNode.Attributes.Append(rootNodeattribute);
xmlDoc.AppendChild(rootNode);
XmlNode Node1 = xmlDoc.CreateElement("name");
Node1.InnerText = sWifiName;
rootNode.AppendChild(Node1);
XmlNode Node2 = xmlDoc.CreateElement("SSIDConfig");
XmlNode Node3_1 = xmlDoc.CreateElement("SSID");
XmlNode Node4_1 = xmlDoc.CreateElement("hex");
Node4_1.InnerText = BitConverter.ToString(ASCIIEncoding.Default.GetBytes(sWifiName)).Replace("-", ""); //wifi名转十六进制
XmlNode Node4_2 = xmlDoc.CreateElement("name");
Node4_2.InnerText = sWifiName;
Node3_1.AppendChild(Node4_1);
Node3_1.AppendChild(Node4_2);
Node2.AppendChild(Node3_1);
rootNode.AppendChild(Node2);
XmlNode Node2_1 = xmlDoc.CreateElement("connectionType");
XmlNode Node2_2 = xmlDoc.CreateElement("connectionMode");
Node2_1.InnerText = "ESS";
Node2_2.InnerText = "auto";
rootNode.AppendChild(Node2_1);
rootNode.AppendChild(Node2_2);
XmlNode Node2_3 = xmlDoc.CreateElement("MSM");
XmlNode Node3_3 = xmlDoc.CreateElement("security");
XmlNode Node4_3 = xmlDoc.CreateElement("authEncryption");
XmlNode Node5_1 = xmlDoc.CreateElement("authentication");
Node5_1.InnerText = "WPA2PSK";
XmlNode Node5_2 = xmlDoc.CreateElement("encryption");
Node5_2.InnerText = "AES";
XmlNode Node5_3 = xmlDoc.CreateElement("useOneX");
Node5_3.InnerText = "false";
XmlNode Node4_4 = xmlDoc.CreateElement("sharedKey");
XmlNode Node5_4 = xmlDoc.CreateElement("keyType");
Node5_4.InnerText = "passPhrase";
XmlNode Node5_5 = xmlDoc.CreateElement("protected");
Node5_5.InnerText = "false";
XmlNode Node5_6 = xmlDoc.CreateElement("keyMaterial");
Node5_6.InnerText = sWifipwd; //密码
Node4_4.AppendChild(Node5_4);
Node4_4.AppendChild(Node5_5);
Node4_4.AppendChild(Node5_6);
Node4_3.AppendChild(Node5_1);
Node4_3.AppendChild(Node5_2);
Node4_3.AppendChild(Node5_3);
Node3_3.AppendChild(Node4_3);
Node3_3.AppendChild(Node4_4);
Node2_3.AppendChild(Node3_3);
rootNode.AppendChild(Node2_3);
XmlNode Node2_4 = xmlDoc.CreateElement("MacRandomization");
XmlAttribute Node2_4attribute = xmlDoc.CreateAttribute("xmlns");
Node2_4attribute.Value = "http://www.microsoft.com/networking/WLAN/profile/v3";
Node2_4.Attributes.Append(Node2_4attribute);
XmlNode Node3_4 = xmlDoc.CreateElement("enableRandomization");
Node3_4.InnerText = "false";
Node2_4.AppendChild(Node3_4);
rootNode.AppendChild(Node2_4);
try
{
xmlDoc.Save(path);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine(path);
return path;
}
public static bool loadLibrary()
{
return pLoadLibrary();
}
public static int findWifi(String wifiName = "")
{
if (wifiName == "")
{
wifiName = sWifiName;
}
return pFindWifi(wifiName);
}
public static int connWifi()
{
if (!loadLibrary())
{
Console.WriteLine("loadLibrary() == false\n");
return -1;
}
Console.WriteLine("loadLibrary ok\n");
int find = findWifi();
if (find < 0)
{
Console.WriteLine("findWifi() <= 0\n");
return -1;
}
else if(find == 0)
{
Console.WriteLine("connect is already ok\n");
return 0;
}
Console.WriteLine("findWifi ok\n");
int conn = connect(CreateXML());
if (conn != 0)
{
Console.WriteLine(conn+" connect error\n");
return -1;
}
Console.WriteLine(conn + " connect ok\n");
return 0;
}
static void Main(string[] args)
{
connWifi();
}
static String sXMLName = "XXXXXX.xml";//profile文件名
static String sWifiName = "wifiname"; //wifi名
static String sWifipwd = "12345678"; //密码
static String sDLLName = "wlandll.dll";
}
}
补充一点:
netsh wlan show profile //可以查看所有连接过的wifi
netsh wlan export profile key=clear //导出所有连接过的wifi信息
做完了之后,发现有三个问题
1.调用完fnWlanSetProfile之后,有的wifi就已经能连接成功了,后面的fnWlanConnect无论返回什么都不影响。
2.有的wifi虽然fnWlanSetProfile和fnWlanConnect都返回成功,但是wifi实际却没有连接成功。
3.不是百分百每次都能连接成功,偶尔会失败
如果哪位大神知道是啥情况,请指教指教
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)