宿舍用手機連 wifi 總是要用瀏覽器登錄聯通的 wlan 登陸頁面,無奈手機太挫內存只有 512M,開個網頁再幹其他的事情就卡的要死,所以果斷下載了個 wifi 共享精靈。用了一次就果斷卸載了,爲啥呢?竟然有廣告,受不了啊。正好在學 VC++ 算了自己做一個吧。
關於無線承載網絡
無線承載網絡 (Wireless Hosted Network) 是指安裝有無線局域網服務的 Windows 7 和 Windows Server 2008 R2 所提供的一種 WLAN 功能,具備兩項主要功能:
第一、把一個物理無線網卡虛擬化成一個或多個虛擬無線網卡,稱爲虛擬的 WiFi。
第二、藉助無線網卡把當前接網絡虛擬成爲一個基於軟件的無線接入點,稱爲虛擬 AP 或軟 AP。
========================= 萬惡的分割線 ===========================
項目需要包含 wlanapi.h 頭文件和 wlanapi.lib 庫
備註:測試環境 win7_64, 建議關閉一些安全軟件,(比如我測試的時候忘了關 comodo 導致防火牆總是拒絕其他設備的連接)。
=============================================================
功能不復雜,用到的主要函數有下面幾個
1. 調用 WlanOpenHandled 得到一個連接 hClientHandle,下面的操作都要用到這個連接。當然程序退出的時候記得調用 WlanCloseHandle 關閉這個連接。
DWORD WINAPI WlanOpenHandle(
_In_ DWORD dwClientVersion,
_Reserved_ PVOID pReserved,
_Out_ PDWORD pdwNegotiatedVersion,
_Out_ PHANDLE phClientHandle
);
DWORD WINAPI WlanCloseHandle(
_In_ HANDLE hClientHandle,
_Reserved_ PVOID pReserved
);
2. 下面的函數用來設置承載網絡的一些屬性。
DWORD WINAPI WlanHostedNetworkSetProperty(
_In_ HANDLE hClientHandle,
_In_ WLAN_HOSTED_NETWORK_OPCODE OpCode,
_In_ DWORD dwDataSize,
_In_ PVOID pvData,
_Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason,
_Reserved_ PVOID pvReserved
);typedef enum _WLAN_HOSTED_NETWORK_OPCODE {
wlan_hosted_network_opcode_connection_settings, //設置一些連接屬性
wlan_hosted_network_opcode_security_settings, //設置安全屬性
wlan_hosted_network_opcode_station_profile, //query the wireless Hosted Network station profile
wlan_hosted_network_opcode_enable //query or set the wireless Hosted Network enabled flag
} WLAN_HOSTED_NETWORK_OPCODE, *PWLAN_HOSTED_NETWORK_OPCODE;
3. 啓用和禁用無線承載網絡。
打開網絡和共享中心 單擊更改適配器設置,如果啓用了無線承載網絡 面板裏面就會有描述爲 Microsoft Virtual WiFi Miniport Adapter 的一個虛擬網卡。禁用之後這個虛擬網卡就會消失了。
當然只有啓用了無線承載網絡才能分享 wifi 啦
DWORD WINAPI WlanHostedNetworkForceStart(
_In_ HANDLE hClientHandle,
_Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason,
_Reserved_ PVOID pvReserved
);
DWORD WINAPI WlanHostedNetworkForceStop(
_In_ HANDLE hClientHandle,
_Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason,
_Reserved_ PVOID pvReserved
);
4. 連接和斷開網絡
DWORD WINAPI WlanHostedNetworkStartUsing(
_In_ HANDLE hClientHandle,
_Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason,
_Reserved_ PVOID pvReserved
);
DWORD WINAPI WlanHostedNetworkStopUsing(
_In_ HANDLE hClientHandle,
_Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason,
_Reserved_ PVOID pvReserved
);
5. 用來查詢承載網絡的網絡狀況。
DWORD WINAPI WlanHostedNetworkQueryStatus(
_In_ HANDLE hClientHandle,
_Out_ PWLAN_HOSTED_NETWORK_STATUS *ppWlanHostedNetworkStatus,
_Reserved_ PVOID pvReserved
);
typedef struct _WLAN_HOSTED_NETWORK_STATUS {
WLAN_HOSTED_NETWORK_STATE HostedNetworkState;
GUID IPDeviceID;
DOT11_MAC_ADDRESS wlanHostedNetworkBSSID;
DOT11_PHY_TYPE dot11PhyType;
ULONG ulChannelFrequency;
DWORD dwNumberOfPeers; //已連接的節點數目
WLAN_HOSTED_NETWORK_PEER_STATE PeerList[1]; //存放節點信息的數組
} WLAN_HOSTED_NETWORK_STATUS, *PWLAN_HOSTED_NETWORK_STATUS;
typedef struct _WLAN_HOSTED_NETWORK_PEER_STATE {
DOT11_MAC_ADDRESS PeerMacAddress; //節點設備的MAC地址
WLAN_HOSTED_NETWORK_PEER_AUTH_STATE PeerAuthState; //節點的認證狀態
} WLAN_HOSTED_NETWORK_PEER_STATE, *PWLAN_HOSTED_NETWORK_PEER_STATE;
調用 WlanHostedNetworkQueryStatus 將得到一個 WLAN_HOSTED_NETWORK_STATUS 結構體,就可以查詢一些網絡基本信息了,比如 dwNumberOfPeers 連接到這個網絡的節點數,PeerList 數組存放着對應節點的詳細信息,包括 MAC 地址和認證狀態。
6. 用來設置密碼
注意密碼長度必須 大於 8 小於 63 否則會調用失敗
DWORD WINAPI WlanHostedNetworkSetSecondaryKey(
_In_ HANDLE hClientHandle,
_In_ DWORD dwKeyLength,
_In_ PUCHAR pucKeyData,
_In_ BOOL bIsPassPhrase,
_In_ BOOL bPersistent,
_Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason,
_Reserved_ PVOID pvReserved
);
====================== 貼代碼 ==========================
//WIFIMAIN.h 實現文件
#pragma once
#include <wlanapi.h>
#pragma comment(lib,"wlanapi.lib")
// WIFIMAIN
class WIFIMAIN : public CWnd
{
DECLARE_DYNAMIC(WIFIMAIN)
public:
WIFIMAIN();
virtual ~WIFIMAIN();
protected:
DECLARE_MESSAGE_MAP()
private:
bool allow;
bool start;
HANDLE hClient;
public:
int Init(void);
int AllowHostedNetWork(void);
int DisallowHostedNetWork(void);
int StartHostedNetWork(void);
int StopHostedNetWork(void);
bool isStart(void);
bool isAllow(void);
int Resume(void);
int getpeernumber(void);
int SetKEY(CString key);
int SetSSID(CString ssidname);
};
// WIFIMAIN.cpp : 實現文件
//
#include "stdafx.h"
#include "wifi共享1028.h"
#include "WIFIMAIN.h"
// WIFIMAIN
IMPLEMENT_DYNAMIC(WIFIMAIN, CWnd)
WIFIMAIN::WIFIMAIN()
: allow(false)
, start(false)
{
Init();
}
WIFIMAIN::~WIFIMAIN()
{
StopHostedNetWork();
WlanCloseHandle(hClient, NULL);
}
BEGIN_MESSAGE_MAP(WIFIMAIN, CWnd)
END_MESSAGE_MAP()
// WIFIMAIN 消息處理程序
int WIFIMAIN::Init(void)
{
DWORD dwCurVersion = 0;
DWORD dwResult = 0;
dwResult = WlanOpenHandle(WLAN_API_VERSION, NULL, &dwCurVersion, &hClient);
if( ERROR_SUCCESS != dwResult )
{
return -1;
}
BOOL bIsAllow = true;
WLAN_HOSTED_NETWORK_REASON dwFailedReason;
dwResult = WlanHostedNetworkSetProperty(hClient,
wlan_hosted_network_opcode_enable,
sizeof(BOOL),
&bIsAllow,
&dwFailedReason,
NULL);
if( ERROR_SUCCESS != dwResult )
{
return -2;
}
return 0;
}
int WIFIMAIN::AllowHostedNetWork(void)
{
PWLAN_HOSTED_NETWORK_REASON pFailReason = NULL;
DWORD dwResult= 0;
dwResult=WlanHostedNetworkForceStart(hClient,pFailReason,NULL);
if( dwResult != ERROR_SUCCESS )
{
return -1;
}
allow=true;
return 0;
}
int WIFIMAIN::DisallowHostedNetWork(void)
{
PWLAN_HOSTED_NETWORK_REASON pFailReason = NULL;
DWORD dwResult= 0;
dwResult=WlanHostedNetworkForceStop(hClient,pFailReason,NULL);
if( dwResult != ERROR_SUCCESS )
{
return -1;
}
allow=false;
return 0;
}
int WIFIMAIN::StartHostedNetWork(void)
{
PWLAN_HOSTED_NETWORK_REASON pFailReason = NULL;
DWORD dwResult= 0;
dwResult=WlanHostedNetworkStartUsing(hClient,pFailReason,NULL);
if( dwResult != ERROR_SUCCESS )
{
return -1;
}
start=true;
return 0;
}
int WIFIMAIN::StopHostedNetWork(void)
{
PWLAN_HOSTED_NETWORK_REASON pFailReason = NULL;
DWORD dwResult= 0;
dwResult=WlanHostedNetworkStopUsing(hClient,pFailReason,NULL);
if( dwResult != ERROR_SUCCESS )
{
return -1;
}
start=false;
return 0;
}
bool WIFIMAIN::isStart(void)
{
return start;
}
bool WIFIMAIN::isAllow(void)
{
return allow;
}
int WIFIMAIN::Resume(void)
{
DWORD dwResult = 0;
BOOL bIsAllow = false;
WLAN_HOSTED_NETWORK_REASON dwFailedReason;
dwResult = WlanHostedNetworkSetProperty(hClient,
wlan_hosted_network_opcode_enable,
sizeof(BOOL),
&bIsAllow,
&dwFailedReason,
NULL);
if( ERROR_SUCCESS != dwResult )
{
return -2;
}
return 0;
}
int WIFIMAIN::getpeernumber(void)
{
PWLAN_HOSTED_NETWORK_STATUS ppWlanHostedNetworkStatus=NULL;
int retval = WlanHostedNetworkQueryStatus(hClient,&ppWlanHostedNetworkStatus,NULL);
if( retval != ERROR_SUCCESS ){
return -1;
}
return ppWlanHostedNetworkStatus->dwNumberOfPeers;
}
int WIFIMAIN::SetKEY(CString key)
{
char chkey[64];
int index;
for(index=0; index<key.GetLength(); index++ )
{
chkey[index] = key[index];
}
chkey[index]='\0';
WLAN_HOSTED_NETWORK_REASON dwFailedReason;
DWORD dwResult= 0;
dwResult = WlanHostedNetworkSetSecondaryKey(hClient,
strlen((const char*)chkey) + 1,
(PUCHAR)chkey,
TRUE,
FALSE,
&dwFailedReason,
NULL);
if(ERROR_SUCCESS != dwResult)
{
return -1;
}
return 0;
}
int WIFIMAIN::SetSSID(CString ssidname)
{
char chname[64];
int index;
for(index=0; index<ssidname.GetLength(); index++ )
{
chname[index] = ssidname[index];
}
chname[index]='\0';
DWORD dwResult= 0;
WLAN_HOSTED_NETWORK_REASON dwFailedReason;
WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS cfg;
memset(&cfg, 0, sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS));
memcpy( cfg.hostedNetworkSSID.ucSSID, chname, strlen(chname) ) ;
cfg.hostedNetworkSSID.uSSIDLength = strlen((const char*)cfg.hostedNetworkSSID.ucSSID);
cfg.dwMaxNumberOfPeers = 20; //最大連接數
dwResult = WlanHostedNetworkSetProperty(hClient,
wlan_hosted_network_opcode_connection_settings,
sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS),
&cfg,
&dwFailedReason,
NULL);
if(ERROR_SUCCESS != dwResult )
{
return -1;
}
return 0;
}
==========================================
這裏只貼出了比較重要的代碼,其他的略去了,需要的可以去我的網盤下載完整項目代碼。
代碼和程序下載:http://pan.baidu.com/s/1GI0kG
程序只完成了基本功能,還有待完善,但是學習的過程還是很有意思的。
下面是幾篇關於無線承載網絡比較不錯的文章,當時對我幫助很大。
關於無線承載網絡 http://blog.wbpluto.com/2010/08/about-wireless-hosted-network/
==========================================
2014-3-14 修改:
實在抱歉,以前寫的時候有些東西沒有補充完整,導致讓好多網友走了彎路,今天把大家問的幾個較多的問題回覆補充一下,以免給大家在帶來困擾。
1. 我寫程序的時候環境是 win7 64 位,vs2010. 需要用到的某些 api 可能在 xp 下無法編譯。
2. 這個版本的程序還沒有加入 自動設置網絡連接共享的功能,需要手動設置在網卡(接入 internet 的網卡)屬性中設置網絡連接共享,相關 api 參考 http://msdn.microsoft.com/en-us/library/bb525393%28v=vs.85%29.aspx
3. 面板上的開機自動啓動代碼沒有加入,發佈的時候都忘記取消這個控件了,哎 犯罪了。
4.win8 下會提示某些運行庫找不到,這個屬於兼容性問題,屬性中設置以 win7 兼容模式運行即可。部分電腦需要以管理員權限運行。(估計是啓用虛擬網卡的 api 需要較高權限吧)
本來準備過年就寫個新版本的,但是開學太忙就一直拖着沒開始。等時間多了我會針對大家反映的問題推出一個新的版本。