在 Windows CE 下自带有无线网卡的配置和连接程序,这篇文章就来谈一下如何用那么可以利用微软自带的WZC函数来重新编写一个独立于系统的WIFI连接程序.
下面是一整套通过WZC函数连接无线网的程序,我自己测试后保证在系统下是可以运行.大家可以参考一下。
一、非常重要的库文件。
#include <eaputil.h>
#include <pm.h>
#include <wzcsapi.h>
#include <iphlpapi.h>
#pragma comment(lib,"Iphlpapi.lib")
#pragma comment(lib,"Wzcsapi.lib")
#pragma comment(lib,"cclib.lib")
二、枚举系统中可用的无线网络设备
- BOOL GetFirstWirelessCard(PTCHAR pCard)
- {
- if (!pCard)
- {
- return FALSE;
- }
- INTFS_KEY_TABLE IntfsTable;
- IntfsTable.dwNumIntfs = 0;
- IntfsTable.pIntfs = NULL;
- _tcscpy(pCard, TEXT(""));
- // 枚举系统中可用的无线网卡
- DWORD dwStatus = WZCEnumInterfaces(NULL, &IntfsTable);
- if (dwStatus != ERROR_SUCCESS)
- {
- RETAILMSG(DBG_MSG, (TEXT("WZCEnumInterfaces() error 0x%08X\n"),dwStatus));
- return FALSE;
- }
- // 判断无线网卡的数量,可以根据无线网卡数量来枚举出所有可用的无线网卡
- if (!IntfsTable.dwNumIntfs)
- {
- RETAILMSG(DBG_MSG, (TEXT("System has no wireless card.\n")));
- return FALSE;
- }
- _tcscpy(pCard, IntfsTable.pIntfs[0].wszGuid);
- LocalFree(IntfsTable.pIntfs);
- return TRUE;
- }
三、获取无线网络信息
获取到了系统可用的无线网卡后,我们就可以利用它的 GUID 号来进行进一步的操作了,首先要做的事情就是得到该无线网卡的信息以及该无线网卡扫描到的 WIFI 网关信息。
以下函数可以获取到该无线网卡及扫描的到的无线 AP 信息
- //
- // pCard: 无线网卡 GUID
- // pIntf: 无线网卡配置信息结果体
- // pOutFlags: 网卡配置信息掩码标志
- //
- BOOL GetWirelessCardInfo(PTCHAR pCard, PINTF_ENTRY_EX pIntf, PDWORD pOutFlags)
- {
- TCHAR *szWiFiCard = NULL;
- // 参数校验
- if (!pCard || !pIntf || !pOutFlags)
- {
- RETAILMSG(DBG_MSG, (TEXT("Param Error.\n")));
- return FALSE;
- }
- szWiFiCard = pCard;
- *pOutFlags = 0;
- // 初始化无线网卡信息
- ZeroMemory(pIntf, sizeof(INTF_ENTRY_EX));
- // 设置 GUID 号
- pIntf->wszGuid = szWiFiCard;
- // 查询无线网卡信息
- DWORD dwStatus = WZCQueryInterfaceEx(NULL, INTF_ALL, pIntf, pOutFlags);
- if (dwStatus != ERROR_SUCCESS)
- {
- RETAILMSG(DBG_MSG, (TEXT("WZCQueryInterfaceEx() error 0x%08X\n"), dwStatus));
- return FALSE;
- }
- return TRUE;
- }
四、判断连接状态
我们可以通过无线网卡的状态来判断当前无线网卡是否已经和无线AP建立了连接
- BOOL IsAssociated(const INTF_ENTRY_EX Intf, const DWORD dwOutFlags)
- {
- if (dwOutFlags & INTF_BSSID)
- {
- PRAW_DATA prdMAC = (PRAW_DATA)(&Intf.rdBSSID);
- // 判断 BSSID 的 MAC 地址是否有效来判断是否和无线AP建立了连接
- if (prdMAC == NULL || prdMAC->dwDataLen == 0 ||
- (!prdMAC->pData[0] && !prdMAC->pData[1] && !prdMAC->pData[2] &
- !prdMAC->pData[3] && !prdMAC->pData[4] && !prdMAC->pData[5]))
- {
- RETAILMSG(DBG_MSG, (TEXT("(This wifi card is not associated to any)\n")));
- return FALSE;
- }
- else
- {
- RETAILMSG(DBG_MSG, (TEXT("(This wifi card is associated state)\n")));
- return TRUE;
- }
- }
- else
- {
- return FALSE;
- }
- }
五、获取无线AP信息
获取了无线网卡的信息后,可以通过无线网卡枚举出当前所有可用的无线AP的SSID名称以及加密模式等等所有可用信息,一下函数可以实现该功能
- void GetWirelseeListSSID(const PRAW_DATA prdBSSIDList, HWND hListCtlWnd)
- {
- if (prdBSSIDList == NULL || prdBSSIDList->dwDataLen == 0)
- {
- RETAILMSG(DBG_MSG, (TEXT("<null> entry.\n")));
- }
- else
- {
- PWZC_802_11_CONFIG_LIST pConfigList = (PWZC_802_11_CONFIG_LIST)prdBSSIDList->pData;
- //RETAILMSG(DBG_MSG, (TEXT("[%d] entries.\n"), pConfigList->NumberOfItems));
- uint i;
- // 枚举所有无线AP
- for (i = 0; i < pConfigList->NumberOfItems; i++)
- {
- PWZC_WLAN_CONFIG pConfig = &(pConfigList->Config[i]);
- RAW_DATA rdBuffer;
- rdBuffer.dwDataLen = pConfig->Ssid.SsidLength;
- rdBuffer.pData = pConfig->Ssid.Ssid;
- TCHAR tSsid[MAX_PATH];
- // 将 SSID 的 ASCII 码转化成字符串
- PrintSSID(&rdBuffer, tSsid);
- if (hListCtlWnd)
- {
- if (ListBox_FindString(hListCtlWnd, 0, tSsid) == LB_ERR)
- {
- ListBox_AddString(hListCtlWnd, tSsid);
- }
- }
- //RETAILMSG(DBG_MSG, (TEXT("\n")));
- }
- }
- }
六、连接到指定的无线AP
- //
- // pCard: 无线网卡 GUID
- // pSSID: 无线AP SSID号
- // bAdhoc: 是否点对点的 WIFI 连接
- // ulPrivacy: 加密模式(WEP/WPA....)
- // ndisMode: 认证模式(Open/Share)
- // iKeyIndex: 密钥索引(1-4)
- // pKey: 密码
- // iEapType: 802.11 认证模式
- //
- BOOL WirelessConnect(PTCHAR pCard, PTCHAR pSSID, BOOL bAdhoc, ULONG ulPrivacy, NDIS_802_11_AUTHENTICATION_MODE ndisMode, int iKeyIndex, PTCHAR pKey, int iEapType)
- {
- BOOL bRet = FALSE;
- if (!pSSID)
- {
- RETAILMSG(DBG_MSG, (TEXT("Param Error.\n")));
- return FALSE;
- }
- else
- {
- WZC_WLAN_CONFIG wzcConfig;
- ZeroMemory(&wzcConfig, sizeof(WZC_WLAN_CONFIG));
- wzcConfig.Length = sizeof(WZC_WLAN_CONFIG);
- wzcConfig.dwCtlFlags = 0;
- wzcConfig.Ssid.SsidLength = _tcslen(pSSID);
- for (UINT i = 0; i < wzcConfig.Ssid.SsidLength; i++)
- {
- wzcConfig.Ssid.Ssid[i] = (CHAR)pSSID[i];
- }
- if (bAdhoc)
- {
- wzcConfig.InfrastructureMode = Ndis802_11IBSS;
- }
- else
- {
- wzcConfig.InfrastructureMode = Ndis802_11Infrastructure;
- }
- wzcConfig.AuthenticationMode = ndisMode;
- wzcConfig.Privacy = ulPrivacy;
- if (pKey == NULL || _tcslen(pKey) == 0)
- {
- // 对密钥进行转换
- bRet = InterpretEncryptionKeyValue(wzcConfig, 0, NULL, TRUE);
- wzcConfig.EapolParams.dwEapType = iEapType;
- wzcConfig.EapolParams.dwEapFlags = EAPOL_ENABLED;
- wzcConfig.EapolParams.bEnable8021x = TRUE;
- wzcConfig.EapolParams.dwAuthDataLen = 0;
- wzcConfig.EapolParams.pbAuthData = 0;
- }
- else
- {
- RETAILMSG(DBG_MSG, (TEXT("WirelessConnect iKeyIndex = %d.\n"), iKeyIndex));
- bRet = InterpretEncryptionKeyValue(wzcConfig, iKeyIndex, pKey, FALSE);
- }
- // 连接到指定的无线AP,并将该AP添加到首先无线AP中
- AddToPreferredNetworkList(pCard, wzcConfig, pSSID);
- }
- return bRet;
- }
七、密钥转换
输入的密钥需要通过加密方式进行一定的转化,以下函数可以完成改功能
- static void EncryptWepKMaterial(IN OUT WZC_WLAN_CONFIG* pwzcConfig)
- {
- BYTE chFakeKeyMaterial[] = { 0x56, 0x09, 0x08, 0x98, 0x4D, 0x08, 0x11, 0x66, 0x42, 0x03, 0x01, 0x67, 0x66 };
- for (int i = 0; i < WZCCTL_MAX_WEPK_MATERIAL; i++)
- pwzcConfig->KeyMaterial[i] ^= chFakeKeyMaterial[(7*i)%13];
- }
- BOOL InterpretEncryptionKeyValue(IN OUT WZC_WLAN_CONFIG& wzcConfig, IN int iKeyIndex, IN PTCHAR pKey, IN BOOL bNeed8021X)
- {
- if(wzcConfig.Privacy == Ndis802_11WEPEnabled)
- {
- if(!bNeed8021X && pKey)
- {
- wzcConfig.KeyIndex = iKeyIndex;
- wzcConfig.KeyLength = _tcslen(pKey);
- if((wzcConfig.KeyLength == 5) || (wzcConfig.KeyLength == 13))
- {
- for(UINT i=0; i<wzcConfig.KeyLength; i++)
- wzcConfig.KeyMaterial[i] = (UCHAR)pKey[i];
- }
- else
- {
- if((pKey[0] != TEXT('0')) || (pKey[1] != TEXT('x')))
- {
- RETAILMSG(DBG_MSG, (TEXT("Invalid key value.\n")));
- return FALSE;
- }
- pKey += 2;
- wzcConfig.KeyLength = wcslen(pKey);
- if((wzcConfig.KeyLength != 10) && (wzcConfig.KeyLength != 26))
- {
- RETAILMSG(DBG_MSG, (TEXT("Invalid key value.\n")));
- return FALSE;
- }
- wzcConfig.KeyLength >>= 1;
- for(UINT i=0; i<wzcConfig.KeyLength; i++)
- {
- wzcConfig.KeyMaterial[i] = (HEX(pKey[2 * i]) << 4) | HEX(pKey[2 * i + 1]);
- }
- }
- EncryptWepKMaterial(&wzcConfig);
- wzcConfig.dwCtlFlags |= WZCCTL_WEPK_PRESENT;
- }
- }
- else if(wzcConfig.Privacy == Ndis802_11Encryption2Enabled
- || wzcConfig.Privacy == Ndis802_11Encryption3Enabled)
- {
- if(!bNeed8021X)
- {
- wzcConfig.KeyLength = wcslen(pKey);
- if((wzcConfig.KeyLength < 8) || (wzcConfig.KeyLength > 63))
- {
- RETAILMSG(DBG_MSG, (TEXT("WPA-PSK/TKIP key should be 8-63 char long string.\n")));
- return FALSE;
- }
- char szEncryptionKeyValue8[64]; // longest key is 63
- memset(szEncryptionKeyValue8, 0, sizeof(szEncryptionKeyValue8));
- WideCharToMultiByte(CP_ACP,
- 0,
- pKey,
- wzcConfig.KeyLength + 1,
- szEncryptionKeyValue8,
- wzcConfig.KeyLength + 1,
- NULL,
- NULL);
- WZCPassword2Key(&wzcConfig, szEncryptionKeyValue8);
- EncryptWepKMaterial(&wzcConfig);
- wzcConfig.dwCtlFlags |= WZCCTL_WEPK_XFORMAT
- | WZCCTL_WEPK_PRESENT
- | WZCCTL_ONEX_ENABLED;
- }
- wzcConfig.EapolParams.dwEapFlags = EAPOL_ENABLED;
- wzcConfig.EapolParams.dwEapType = DEFAULT_EAP_TYPE;
- wzcConfig.EapolParams.bEnable8021x = TRUE;
- wzcConfig.WPAMCastCipher = Ndis802_11Encryption2Enabled;
- }
- return TRUE;
- }
通过以上操作,完全可以连接到可用的无线AP了。