作者:faaronzheng 转载请注明出处!
最近宿舍wifi不知道为什么不稳定,经常电脑会断开连接,需要手动重连。而我又会整夜开着电脑下东西,十分蛋疼。所以我就小小的学以致用一下,写了一个简单地wifi断网自动重连工具,并且可以设置在断网超过一定时间后会自动关机。开发环境为win8+vs2012,亲测win8下可以连接路由器和connectify。连接时请注意正确选择认证方式和加密方式。但是即使配置正确也有一定可能因为路由器问题无法连接。
这个程序的实现其实很简单,下面是主要代码的实现。
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或有好的改进请告诉我,大家共同学习。