作者:faaronzheng 转载请注明出处!
最近宿舍wifi不知道为什么不稳定,经常电脑会断开连接,需要手动重连。而我又会整夜开着电脑下东西,十分蛋疼。所以我就小小的学以致用一下,写了一个简单地wifi断网自动重连工具,并且可以设置在断网超过一定时间后会自动关机。开发环境为win8+vs2012,亲测win8下可以连接路由器和connectify。连接时请注意正确选择认证方式和加密方式。但是即使配置正确也有一定可能因为路由器问题无法连接。
这个程序的实现其实很简单,下面是主要代码的实现。
主要用到了wininet.dll、managedwifi.dll、c#操作cmd、c#操作xml文件和多线程的知识。
wininet.dll主要是获得当前网络的连接状态。使用方法如下先导入wininet.dll
//检测网络状态
[DllImport("wininet.dll", EntryPoint = "InternetGetConnectedState")]
public extern static bool InternetGetConnectedState(out int conState, int reder); //使用时直接调用InternetGetConnectedState(out int conState, int reder)函数。
我的使用是先定义int Desc = 0;
然后判断 if (InternetGetConnectedState(out Desc, 0)) //如果有网络连接会返回true
managedwifi.dll主要是用来获取所有无线wifi和对特定wifi进行连接。
#region 枚举所有无线设备接收到的SSID
public List<WIFISSID> ScanSSID() //获取所有可用wifi
{
List<WIFISSID> wifiName = new List<WIFISSID>(); //用来保存wifi信息
WlanClient client = new WlanClient();
foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
Wlan.WlanAvailableNetwork[] networks = wlanIface.GetAvailableNetworkList(0);
foreach (Wlan.WlanAvailableNetwork network in networks)
{
WIFISSID targetSSID = new WIFISSID();
targetSSID.wlanInterface = wlanIface;
targetSSID.wlanSignalQuality = (int)network.wlanSignalQuality;
targetSSID.SSID = GetStringForSSID(network.dot11Ssid);
targetSSID.dot11DefaultAuthAlgorithm = network.dot11DefaultAuthAlgorithm.ToString();
targetSSID.dot11DefaultCipherAlgorithm = network.dot11DefaultCipherAlgorithm.ToString();
wifiName.Add(targetSSID);
}
}
return wifiName;
}
#endregion
#region 连接到指定的SSID
public void ConnectToSSID(WIFISSID ssid,Boolean isSave) //连接指定wifi
{
string profileXml = string.Format("<?xml version=\"1.0\" encoding=\"US-ASCII\"?> <WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\"><name>{0}</name><SSIDConfig><SSID><name>{0}</name></SSID></SSIDConfig> <connectionType>ESS</connectionType><connectionMode>auto</connectionMode><autoSwitch>false</autoSwitch><MSM><security><authEncryption><authentication>{1}</authentication><encryption>{2}</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>passPhrase</keyType><protected>false</protected><keyMaterial>{3}</keyMaterial></sharedKey></security></MSM></WLANProfile>",name,authen,encry, pswd);
ssid.wlanInterface.SetProfile(Wlan.WlanProfileFlags.AllUser, profileXml, true);
ssid.wlanInterface.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any,name);
if (isSave) //是否需要保存
{
//xml文件操作
XmlDocument doc = new XmlDocument();
doc.Load("setting.xml");
XmlNodeList nodeList = doc.SelectSingleNode("setting").ChildNodes;
foreach (XmlNode xn in nodeList)
{
XmlElement xe = (XmlElement)xn;
if (xe.GetAttribute("ssid").Equals(name))
{
isAdded = true;
}
}
if (!isAdded) //是否已经存在
{
XmlOP xml = new XmlOP();
xml.addXml(name, pswd); //将wifi名和密码写入xml文件
}
}
}
#endregion
上面这段代码中最重要的是profileXml,不同的网络格式也会不尽相同,具体请参考
http://msdn.microsoft.com/en-us/library/windows/desktop/aa369853%28v=vs.85%29.aspx
c#操作cmd代码,这部分主要是实现关机和取消关机
#region 调用Cmd
public void useCmd(string str)
{
System.Diagnostics.Process process = new Process();
//StartInfo获取或设置要传递给Process的Start方法的属性.为ProcessStartInfo类型
process.StartInfo.FileName = "cmd.exe";
//设置UseShellExecute以指定是否使用操作系统外壳程序启动进程
process.StartInfo.UseShellExecute = false;
//使进程从文件或其他设备获取输入
process.StartInfo.RedirectStandardInput = true;
//向文件或其他设备返回输出
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
//给命令行传入关机命令
process.StandardInput.WriteLine(str);
process.StandardInput.WriteLine("exit");
process.Close();
}
#endregion
c#操作xml文件,xml文件主要是用来保存配置信息、wifi名和wifi密码。主要是因为我没用过xml所以就尝试一下。我觉得xml文件像一个树的结构。具体使用可以自行查找资料,还是十分简单的。
以下是我的实现代码.
#region 创建xml文件
public void creXml()
{
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "gb2312", "yes");
doc.AppendChild(dec);
XmlElement elem1 = doc.CreateElement("", "setting", "");
doc.AppendChild(elem1);
XmlNode root = doc.SelectSingleNode("setting");
XmlElement basic = doc.CreateElement("basic");
basic.SetAttribute("timeout", "10");
basic.SetAttribute("authen", "WPAPSK");
basic.SetAttribute("encry", "AES");
root.AppendChild(basic);
doc.Save("setting.xml");
}
#endregion
#region 添加结点到xml
public void addXml(string SSID,string pswd)
{
XmlDocument doc = new XmlDocument();
doc.Load("setting.xml");
XmlNode root = doc.SelectSingleNode("setting");
XmlElement elem = doc.CreateElement(SSID);
elem.SetAttribute("ssid", SSID);
elem.SetAttribute("pswd", pswd);
root.AppendChild(elem);
doc.Save("setting.xml");
}
#endregion
这个程序也用到了多线程知识。除了主线程外还有重连线程、断网关机线程。
具体实现代码如下
#region 重连线程
public void AutoConThread(Boolean isSave)
{
int Desc = 0;
while (true)
{
if (InternetGetConnectedState(out Desc, 0)) //有网络连接
{
sw.Reset(); //重置时间
continue;
}
else
{
AutoConFlag = true;
sw.Start(); //开始计时
Thread.Sleep(1000);
}
if (AutoConFlag)
{
wifi.ConnectToSSID(targetSSID, isSave); //连接wifi
AutoConFlag = false;
Thread.Sleep(60000);
}
Thread.Sleep(10000);
}
}
#endregion
#region 断网关机线程
public void watchThread()
{
while (true)
{
if (Convert.ToInt32(sw.ElapsedMilliseconds) > time)
{
timeout = true;
}
if (timeout)
{
useCmd("shutdown -s -t 600");
timeout = false;
}
Thread.Sleep(10000);
}
}
#endregion
这些线程都是死循环一直运行的,这样的话启动后即使你关掉程序,但是线程还在继续工作,进程里还能看到程序在跑。一个很好地解决办法就是把这些线程设置为后台线程,这样的话关闭应用程序后线程也会结束。
autoConnect = new Thread(()=>state.AutoConThread(isSave));
autoConnect.IsBackground = true; //设置线程为后台进程
//System.Environment.Exit(0); 也可以起到退出后程序完全关闭的效果
autoConnect.Start();
源代码下载:
http://download.csdn.net/detail/faaronzheng/7250515
发现bug或有好的改进请告诉我,大家共同学习。