WiFiAssistant 无线承载网络设置助手的开发历程

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

今年6月中旬,我曾经基于MFC写过一个WiFiHelper的小程序,开启和关闭虚拟WiFi,并且能够支持定时关机,当然,真正使用虚拟WiFi还需要手动设置共享。并且,由于我的是台式机,所以并没有去升级WiFiHelper。

估计是即将毕业的缘故,总想做出一些比较有意思的软件,让人看到我的水平,也就不停的Coding,每次给我妈打电话,也就是说在写代码,事实上,也是经常在写代码。

最开始写WiFiHelper 的时候,纯粹是为了帮助朋友们简便的开启和关闭WiFi,笔记本开启了WiFi,如果关机了,那么肯定就没有WiFi了,但是一直开着,笔记本也得休息一下不是,很多人使用计算机,只会简单的玩游戏登QQ,不要高估用户的操作能力,想想看Linux确实高估了。所以,很多人都不会使用shutdown设置定时关机,于是我便在WiFiHelper中添加了定时关机的功能,反正加起来都是支持封装命令(netsh shutdown),并使用管道获取信息输出。

9月份,那个时候Windows8.1出来了,很多人开始装8.1,我就决定写一个USB启动盘制作工具;以前发表过Blog:如何开发一款USB启动盘制作工具 被OSChina推荐过,那次写代码的经历让我学会了Win32 API的窗口编程的流程和细节,最早完全掌握Win32编程是利用超类化修改了Edit控件,因为默认的记事本的菜单不太习惯,所以就自己超了下,子类化因为没掌握好就没有使用。

WNDCLASSEX PreEditEx;
 ZeroMemory(&PreEditEx,sizeof(PreEditEx));
 PreEditEx.cbSize=sizeof(WNDCLASSEX);
 GetClassInfoEx(0,L"EDIT",&PreEditEx);
 OldEditWndProc=PreEditEx.lpfnWndProc;
 PreEditEx.lpfnWndProc=PreEditExWndProc;
 //PreEditEx.lpszMenuName=
 PreEditEx.lpszClassName=L"PreEditControl";
 RegisterClassEx(&PreEditEx);

OldEditWndProc是函数指针,用来保留老的窗口处理函数

LRESULT (CALLBACK* OldEditWndProc)(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);



最后就是自己写窗口函数

LRESULT CALLBACK PreEditExWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
   //PAINTSTRUCT ps;
   //HDC hdc;
   //RECT rt;
   //HGDIOBJ oldPen;
   int mId,mEvent;
   switch (uMsg) 
   {
   case WM_CREATE:
	   {
		   //HMENU PopuMenu=GetMenu(hWnd);
		   //if(PopuMenu==NULL)
			  // MessageBox(NULL,L"Menu is error HM",L"Error",MB_OK);
		   //if(InsertMenu(PopuMenu,2, MF_BYPOSITION, IDM_EXIT,L"Exit")==TRUE)
		   //{
			  // MessageBox(NULL,L"Menu is OK",L"OK",MB_OK);
		   //}
		   //else
		   //{
			  // MessageBox(NULL,L"Menu is error",L"Error",MB_OK);
		   //}
		   //SetMenu(hWnd,PopuMenu);
	   }
	   break;
   case WM_COMMAND:
	   mId    = LOWORD(wParam);
	   mEvent = HIWORD(wParam);
	   switch(mId)
	   {
	   case IDM_EDIT_UNDO:
		   SendMessage(hWnd,EM_UNDO,0,0L);
		   break;
	   case IDM_EDIT_COPY:
		   SendMessage(hWnd,WM_COPY,0,0L);
		   break;
	   case IDM_EDIT_PASTE:
		   SendMessage(hWnd,WM_PASTE,0,0L);
		   break;
	   case IDM_EDIT_CUT:
		   SendMessage(hWnd,WM_CUT,0,0L);
		   break;
	   case IDM_EDIT_SELECTALL:
		   SendMessage(hWnd, EM_SETSEL, 0, -1);
		   SendMessage(hWnd,EM_SCROLLCARET,0,0L);
		   //SendMessage(hWnd,
		   break;
	   case IDM_EDIT_CLEAR:
		   SendMessage(hWnd,WM_CLEAR,0,0L);
		   break;
	   case IDR_SETTING:
		   DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SETBOX), hWnd, OpenOpDlg);
		   break;
	   case IDR_UPDATA:
		   { 
			   MessageBox(NULL,L"Alt+F2 is Update",L"Alt+F2",MB_OK);
			   //std::
		   }
		   break;
	   case IDM_CLEAR_UI:
		   {
			   SetWindowText(hWnd,L"");
			   //WCHAR IJI[5695222]=L"0";
			   //GetWindowText(hWnd,IJI,5695222);
			   //ClearCommandUI(L"PreEditControl",IJI);
		   }
		   break;
	   case IDI_RESTART:
		   RestartShell();
		   break;
	   case IDR_EXIT:
		   PostQuitMessage(0);
		   break;
	   default:
		   break;
	   }
	   break;
   case WM_PAINT:
	   break;
   case WM_RBUTTONUP:
	   {
		   //GetFocus
		   //RECT rect;
		   POINT pt;
		   GetCursorPos(&pt);
		   //rect.left=pt.x;rect.right=pt.y;
		   HMENU EditMenu=LoadMenu(GetModuleHandle(nullptr),MAKEINTRESOURCE(IDR_MENU_POPU));
           HMENU PopuMenu=GetSubMenu(EditMenu,0);
		   if(SendMessage(hWnd,EM_CANUNDO,0,0))
		   {
			   EnableMenuItem(PopuMenu,IDM_EDIT_UNDO,MF_ENABLED);
		   }
		   else
		   {
		     EnableMenuItem(PopuMenu,IDM_EDIT_UNDO,MF_GRAYED);
		   }
		   long long n=0,m=0;
		   SendMessage(hWnd,EM_GETSEL,(WPARAM)&n,(LPARAM)&m);
		   if(n==m)
		   {
			   EnableMenuItem(PopuMenu,IDM_EDIT_CLEAR,MF_GRAYED);
			   EnableMenuItem(PopuMenu,IDM_EDIT_COPY,MF_GRAYED);
			   EnableMenuItem(PopuMenu,IDM_EDIT_CUT,MF_GRAYED);
		   }
		   else
		   {
			   EnableMenuItem(PopuMenu,IDM_EDIT_CLEAR,MF_ENABLED);
			   EnableMenuItem(PopuMenu,IDM_EDIT_COPY,MF_ENABLED);
			   EnableMenuItem(PopuMenu,IDM_EDIT_CUT,MF_ENABLED);
		   }
			   EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_BYCOMMAND|MF_ENABLED);
		   //wstring ClipText;
		   if(OpenClipboard(hWnd))
		   {
			   if(GetClipboardData(CF_TEXT))
			   {
				   EnableMenuItem(PopuMenu,IDM_EDIT_PASTE,MF_ENABLED);
			   }
			   else
			   {
				   EnableMenuItem(PopuMenu,IDM_EDIT_PASTE,MF_GRAYED);
			   }
			   CloseClipboard();
		   }
		   else
		   {
			   EnableMenuItem(PopuMenu,IDM_EDIT_PASTE,MF_GRAYED);
			   CloseClipboard();
		   }
		   if(GetWindowTextLength(hWnd)==0)
		   {
			   EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_GRAYED);
		   }
		   else
		   {
			   if(GetWindowTextLength(hWnd)==(m-n)||m-n==-1)
				   EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_GRAYED);
			   else
				   EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_ENABLED);
		   }
		   //HiliteMenuItem(hWnd,PopuMenu,IDI_RESTART,MF_BYCOMMAND|MF_HILITE);
		   //WCHAR st[10]={'0'};
		   //wsprintf(st,L"ST=: %d",x);
		   //MessageBox(NULL,st,L"Text Long",MB_OK);
          //if(SendMessage(hWnd,WM_,CF_TEXT,0)
		   //InsertMenu(PopuMenu,IDR_SETTING,MF_ENABLED,IDM_ECUT,L"PASTE");
		   TrackPopupMenuEx(PopuMenu,TPM_RIGHTBUTTON,pt.x,pt.y,hWnd,NULL);
	   }
	   return 0;
   case WM_SETFONT:
	   //MessageBox(NULL,L"Font",L"Setting Font",MB_OK);
	   UpdateWindow(hWnd);
	   break;
   //case WM_CREATE:
   case WM_SYSKEYDOWN:
	   switch(wParam)
	   {
	case VK_F1:
			   if(GetKeyState(VK_MENU)<0)
				    DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SETBOX), hWnd, OpenOpDlg);
			   break;
	case VK_F2:
		if(GetKeyState(VK_MENU)<0)
		{
			//MessageBox(NULL,L"Alt+F2 is Update",L"Alt+F2",MB_OK);
			SendMessage(hWnd,WM_COMMAND,IDR_UPDATA,0);
		}
		break;
	   case VK_F3:
		   if(GetKeyState(VK_MENU)<0)
			   RestartShell();
			   break;
	   default:
		   break;
	   }
   case WM_KEYDOWN:
	   {
		   switch(wParam)
		   {
		   case 'A':
			   if(GetKeyState(VK_CONTROL)<0)
			   {
				   //MessageBox(NULL,L"Select All",L"Ctrl+A",MB_OK);
				   int start=0,end=0;
				   SendMessage(hWnd,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
				   if(GetWindowTextLength(hWnd)==(end-start)||end-start==-1)
						   ;
					   else
						   SendMessage(hWnd,EM_SETSEL,0,-1);
			   }
			   break;
		   case VK_BACK:
			   MessageBeep(MB_OK);//Test 
			   break;
		   default:
			   break;
		   }
	   }
	   break;
   case WM_KEYUP:
	   {
		   switch(wParam)
		   {
			   /*http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx wParam Virtual Key Value! */
		   case VK_RETURN:
		   MessageBeep(MB_OK);
		   break;
		   default:
			   break;
		   }
	   }
	   break;
	  // break;
}
return CallWindowProc(OldEditWndProc,hWnd, uMsg, wParam, lParam);
}



一定不要忘记最后调用旧的窗口处理函数,特定消息必须截断不然会调用默认消息,你的努力就白费了。

好吧说到这里有点偏了,这个超类化的经历与WiFiAssistant很重要,首先,用户面对的是一个界面,
以这个界面为例,我给用户提供了以下几个功能:
1.一键开启虚拟WiFi,这个会随机产生随机字符串作为用户名和密码,
2.关闭WiFi
3.开启WiFi
4.显示密码
5.取消定时关机
6.定时关机
7.获取管理员权限

如果要随机产生字符串,一般的方法是先设置一个常字符串数组,里面的字符一般是从a开始的ANSI字符,我的模板是:

const WCHAR* cstr= L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#$%^&*()-=_+,./;\"'<>?~|";

再初始化随即种子srand((unsigned int) GetTickCount());
这里是选取的系统启动的毫秒数,最后使用随机rand()产生随机数,除以常字符串的大小取余,再获取常字符串cstr[i],这里i就是余数,因为C++ string更加好用,所以整个函数最终用string实现,如下:

bool GetRandStringUserOrPwd(PWSTR wstr, UINT Size)
{
	const std::wstring templetstr= L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#$%^&*()-=_+,./;\"'<>?~|";
	UINT i, lstr;
	UINT k;
	std::wstring produce;
	lstr = (UINT)templetstr.size();
	srand((unsigned int) GetTickCount());
	for (i = 1; i < Size; i++)
	{
		k = rand() % lstr;
		produce += templetstr.substr(k,1);
		
	}
	wcscpy_s(wstr, Size, produce.c_str());
	//MessageBox(NULL, produce.c_str(), L"Test", MB_OK);
	return true;
}



我习惯用MessageBox测试程序,当我运行GetRandStringUserOrPwd,开启MessageBox,用户名和密码随机产生获得不一样的结果,但是注释掉MessageBox后,二者的随机数值确是一样,虽然我们选取的是计算机的启动时间,以毫秒计,但是计算机的运行速度是非常快的,所以在产生用户名随机数后,我添加了一段代码:

Sleep(500);



没错就是让它休息一下,500毫秒虽然能够感觉出来,但是对于随机生成的用户名和密码造成差异还是可取的。

WiFi SSID,KEY是否支持中文? 支持,但是,WiFi的SSID Key实质上是32字节的二进制码,在WirelessHostedNetwork API 内部是用ANSI表示,这就意味着,如果用中文标识,充其量也就是MBCS,UTF8或者是其他代码页中读取只会以其编码读取二进制,并不能够转换编码,这就很容易出现“非法的ANSI字符”这个错误,那么如何限制输入中文呢?我们将Edit改造一番,还是上面的超类化,实现过程如下:

LRESULT CALLBACK LimitEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CHAR:
	{
					//if return;
					TCHAR ch = (TCHAR) wParam;
					if (!(ch >= _T('!') && ch <= _T('~')||ch == VK_BACK))
						return 0;
	}
		break;
	case WM_PASTE:
	{
					 OpenClipboard(hWnd);
					 HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT);
					 if (hMem)
					 {
						LPWSTR lpstr=(LPWSTR)GlobalLock(hMem) ;
						GlobalUnlock(hMem);
						if (lpstr != nullptr)
						{
							std::wstring wstr=lpstr;
							GlobalUnlock(hMem);
							//MessageBox(hWnd, wstr.c_str(), L"Paste", MB_OK);
							if (wstr.length() >= 32)
							{
								return 0;
							}
							//check wstr;
						}
					 }
					 CloseClipboard();
					 //GetClipboardData
	}break;
    case WM_MOUSEMOVE:
		break;
	case WM_LBUTTONUP:
		break;
	default:
		break;
	}
	return CallWindowProc(OldEditWndProc, hWnd, message, wParam, lParam);
}



处理了WM_CHAR禁止输入特定字符 和WM_PASTE 中限制字符大小,
关于显示密码,ES_PASSWORD这个消息无法通过GetWindowLongPtr和SetWindowLongPtr进行操作修改,于是我想了一个笨办法,CheckBox 本质是Button,那么就有点击事件,但点击时,就去查看CheckBox是否被选取,如果被选取,就获取密码框的文本,销毁密码框,重新Create一个没有ES_PASSWORD属性的密码框,并将获取的文本SetWindowText发过去,具体代码如下:

HWND hEdKey = GetDlgItem(hWnd, IDC_LIMIT_EDIT);
			if (Button_GetCheck(GetDlgItem(hWnd, IDC_CHECKBT_PAW)) == BST_CHECKED)
			{
				WCHAR text[32] = { 0 };
				GetWindowText(hEdKey, text, 32);
				SendMessage(GetDlgItem(hWnd, IDC_LIMIT_EDIT), WM_CLOSE, wParam, lParam);
				HWND hLimit = CreateWindowEx(WndStyle::dwEditEx, LimitEdit, L"", WndStyle::dwEdit, 110, 120, 200, 25, hWnd, HMENU(IDC_LIMIT_EDIT), hInst, nullptr);
				SetWindowText(hLimit, text);
				SendMessage(hLimit, EM_SETLIMITTEXT, (WPARAM) 32, lParam);
				SendMessage(hLimit, WM_SETFONT, (WPARAM) hFont, lParam);
				SendMessage(hEdKey, WVR_REDRAW, wParam, lParam);
			}
			else
			{
				WCHAR text[32] = { 0 };
				GetWindowText(hEdKey, text, 32);
				SendMessage(GetDlgItem(hWnd, IDC_LIMIT_EDIT), WM_CLOSE, wParam, lParam);
				HWND hLimit = CreateWindowEx(WndStyle::dwEditEx, LimitEdit, L"", WndStyle::dwEdit | ES_PASSWORD, 110, 120, 200, 25, hWnd, HMENU(IDC_LIMIT_EDIT), hInst, nullptr);
				SetWindowText(hLimit, text);
				SendMessage(hLimit, EM_SETLIMITTEXT, (WPARAM) 32, lParam);
			}



一般来说就算频繁的点击也不会造成程序的问题。
开启WiFi和关闭WiFi这两个功能实现了很久,cnblogs有一篇 翻译就详细讲了如何开启无线承载网络,首先一定得注意检查服务是否开启,包括SharedAccess(ICS)WlanSvc,当然还需要检查网络是否畅通,一切准备好了以后,就需要初始化打开无线句柄WlanOpenHandle,WlanHostedNetworkInitSettings,配置WlanHostedNetworkSetProperty,设置第二Key,WlanHostedNetworkSetSecondaryKey,这里提出来,第一key是系统生成的,所谓输入的都是设置的第二key,最后WlanHostedNetworkForceStart。切记句柄得关闭。

关闭也就是先打开句柄,再调用WlanHostedNetworkForceStop,我是用的是强制版本,强制掉线的。

说到这里,开启WiFi过程中有很多错误,如何输出错误代码?我的机制就是定义错误代码常量,通过GetErrorMessageString获得错误代码字符串,在调用结束后,检查错误代码:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WirelessErrorType.h
//
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef WIRELESSERRORTYPE_H
#define WIRELESSERRORTYPE_H

#ifndef MAX_ERROR_STRING
#define MAX_ERROR_STRING                               512
#endif

#define ERRORTYPE_SUCCESS                              (LRESULT)0L
//no Internet Online
#define NO_INTENET_ONLINE                              (LRESULT)21L
//No wireless device was found
#define NO_WIRELESS_DEVICE                             (LRESULT)22L
//Operating systems are not supported
#define SYSTEM_NOT_SUPPORT                             (LRESULT)23L
//No wireless network adapter was found
#define NO_WIRELESS_ADAPTER                            (LRESULT)24L
//Wlan API version is low not support
#define WLAN_API_VERLOW_NOT_SUPPORT                    (LRESULT)25L
#define WLAN_HOSTED_CANNOT_INIT                        (LRESULT)26L
#define INETSHARD_CONNECTION_ERROR                     (LRESULT)27L
#define CLOSE_WIFIHOSTED_ERROR                         (LRESULT)28L
#define SET_SECONDKEY_ERROR                            (LRESULT)29L
#define WLANHOSTED_FORCE_START_ERROR                   (LRESULT)30L
#define HOSTEDNETWORK_DISABLE_BY_GROUPPOLICY           (LRESULT)31L
#define WLANHANDLEOPEN_ALLOCATE_MEMORY                 (LRESULT)32L
#define WLANHANDLEOPEN_ERROR_INVALID_PARAMETER         (LRESULT)33L
#define WHO_ERROR_REMOTE_SESSION_LIMIT_EXCEEDED        (LRESULT)34L
#define SERVICE_NOT_START                              (LRESULT)35L
#define COM_COMPONENT_FAILED_TO_INITIALIZE             (LRESULT)36L
#define SC_HANDLE_OPEN_ERROR                           (LRESULT)37L
#define WLANSVC_START_ERROR                            (LRESULT)38L
#define WLANSVC_STOP_ERROR                          (LRESULT)39L
//Get Error Message String .
void WINAPI GetErrorMessageString(LRESULT hr, PWSTR pstr);

#endif

/////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WirelessErrorType.cpp
//
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define ERROR_INTERNAL
#include "stdafx.h"
#include"WirelessErrorType.h"



void WINAPI GetErrorMessageString(LRESULT hr,PWSTR pstr)
{
	switch (hr)
	{
	case ERRORTYPE_SUCCESS:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"No Error!");
		break;
	case NO_INTENET_ONLINE:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"No network connection!");
		break;
	case NO_WIRELESS_DEVICE:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"No wireless network device driver!");
		break;
	case SYSTEM_NOT_SUPPORT:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Operating systems are not supported!");
		break;
	case WLAN_API_VERLOW_NOT_SUPPORT:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Wlan API version is low not support!");
		break;
	case WLAN_HOSTED_CANNOT_INIT:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Wlan Hosted Network can not Initialize!");
		break;
	case INETSHARD_CONNECTION_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Network sharing can not be achieved!");
		break;
	case CLOSE_WIFIHOSTED_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"WirelessHostedNetwork can not close!");
		break;
	case SET_SECONDKEY_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Failed to set user key!");
		break;
	case WLANHOSTED_FORCE_START_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Wlan can not be forced open!");
		break;
	case HOSTEDNETWORK_DISABLE_BY_GROUPPOLICY:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Hosted Network is disabled by group policy on a domain");
		break;
	case WLANHANDLEOPEN_ALLOCATE_MEMORY:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Failed to allocate memory to create the client context!");
		break;
	case WLANHANDLEOPEN_ERROR_INVALID_PARAMETER:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"pdwNegotiatedVersion is NULL, phClientHandle is NULL, or pReserved is not NULL!");
		break;
	case WHO_ERROR_REMOTE_SESSION_LIMIT_EXCEEDED:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Too many handles have been issued by the server");
		break;
	case SERVICE_NOT_START:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"The service did not start.");
		break;
	case COM_COMPONENT_FAILED_TO_INITIALIZE:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"COM component failed to initialize.");
		break;
	case SC_HANDLE_OPEN_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Service Manager fails to open.");
		break;
	case WLANSVC_START_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Wireless Auto Configuration service failed to start.");
		break;
	case WLANSVC_STOP_ERROR:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Stop Service Error!");
		break;
	default:
		wcscpy_s(pstr, MAX_ERROR_STRING, L"Unknown Error!");
		break;
	}
}



说到定时关机,up/down 控件老费功夫了。最后用CreateUpDownControl解决问题绑定伙伴。
定时关机一定得注意先提权,再调用,最后得把权限恢复,注意,不要把重启和关机搞混了,一个一个TRUE,一个FALSE。具体代码在下面有项目的git地址,所以就不贴代码了。

还有那个以管理员启动按钮,为什么不直接修改清单文件?事实上关闭WiFi,设置定时关机并不需要管理员,所以就没有修改清单文件,有写功能需要管理员运行的,再未取得管理员权限时会通过EnableWindow()禁用,在程序启动后开始用IsUserAnAdmin()检测是否以管理员权限运行,并把值保存在namespace Global{bool IsAdmin}全局变量,(用名称空间限定获得更好的隔离)。那个按钮使用了Button_SetElevationRequiredState宏,这个宏能够是按钮显示UAC图标。

判断系统版本,我直接使用了IsWindows7OrGreater() 结果发现VS2012 WDE不支持,8.0API中没有; 2013(8.1SDK)新增的,于是就用了#if defined(_MSC_VER)&&_MSC_VER>=1800 分别实现2012 2013的;2012使用了OSVERSIONINFO;GetVersionEx,微软MSDN说GetVersionEx以后可能不使用了。XP快要退出舞台了,所以在程序中果断禁止了支持XP。

在设置字体的时候发现,微软雅黑字体在Windows7上耗资太大不美观,于是又分别设置了字体名,Windows8/8.1都是Microsoft Yaihe UI,windows7 是MS Shell Dlg(这个是是个映射,系统查找注册表找到这个字体)

配置文件选了XML,不料XmlLite 这厮并不好玩,一下就是全读取,搞半天没懂,果断用std::wstring 耍了一下小聪明。最后写的时候还是规矩用XmlLite的Write了。

自修改版本写了两个有意思的批处理,互相调用,

:::::::::::::::::::::::::::::::::::::::::::::
:::static.bat
@echo off
::Globa SET
if /i "%1"=="" ( 
set BDT=1 
) else (
SET BDT=%1
)
SET MAX=1
SET MIN=0
SET PATCH=0

::Write upm.bat
echo ^@echo off >upm.bat
echo SET mvr=%MAX% >>upm.bat
echo SET mir=%MIN%  >>upm.bat
echo SET par=%PATCH%  >>upm.bat
echo SET bdt=%BDT%  >>upm.bat
echo echo ^^/^^*Defined PreEdit Version^^*^/ ^>upver.h >>upm.bat
echo echo ^/^/ Please #include ^"upver.h^" ^>^>upver.h >>upm.bat
echo echo #define BUILD_TIME     %%bdt%% ^>^>upver.h >>upm.bat
echo echo #define PATCH_TIME     %%par%% ^>^>upver.h >>upm.bat
echo echo #define MINJOR_VERSION %%mir%% ^>^>upver.h >>upm.bat
echo echo #define MAJOR_VERSION  %%mvr%% ^>^>upver.h >>upm.bat
echo SET /a bdt+=1 >>upm.bat
echo call  %%~dp0static.bat       %%bdt%% >>upm.bat
echo goto :EOF >>upm.bat

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::upm.bat
@echo off 
SET mvr=1 
SET mir=0  
SET par=0  
SET bdt=20  
echo ^/^*Defined PreEdit Version^*/ >upver.h 
echo // Please #include "upver.h" >>upver.h 
echo #define BUILD_TIME     %bdt% >>upver.h 
echo #define PATCH_TIME     %par% >>upver.h 
echo #define MINJOR_VERSION %mir% >>upver.h 
echo #define MAJOR_VERSION  %mvr% >>upver.h 
SET /a bdt+=1 
call  %~dp0static.bat       %bdt% 
goto :EOF



只要双击upm就可以升级版本,并且upm自己也被修改了。利用宏定义可以非常方便的自动更新版本 ,如果要修改大版本则需要修改static.bat
upver.h

/*Defined PreEdit Version*/  
// Please #include "upver.h"  
#define BUILD_TIME     19    
#define PATCH_TIME     0    
#define MINJOR_VERSION 0    
#define MAJOR_VERSION  1




#ifndef VERSION_CONFIG_H
#define VERSION_CONFIG_H

#include "upver.h"

#define TOSTR_(a) L#a
#define TOSTR(a) TOSTR_(a)
#define TOSTRING(str) TOSTR(str)
//Alt+153 ™
#define CAMP L"Huxizero™ Studio. All Rights Reserved.\0"
#ifdef _WIN64
#define APPDEC L"WiFiAssistant™  64BIT\0"
#else
#define APPDEC L"WiFiAssistant™  32BIT\0"
#endif

#define PROJECTNAME L"WiFiAssistant.exe\0"
#define PRODUCTNAME "WiFiAssistant™ VirtualWiFi Auto Setting Assistant\0"
#define LEGALTRADMARKS L"Huxizero™\0"

#define YEAR L"2013"

#ifdef MAJOR_VERSION
#define MAJOR MAJOR_VERSION
#else
#define MAJOR      1
#endif

#ifdef MINJOR_VERSION
#define MINOR MINJOR_VERSION
#else
#define MINOR      0
#endif

#ifdef PATCH_TIME
#define PATCHOR PATCH_TIME
#else
#define PATCHOR   1
#endif

#ifdef BUILD_TIME
#define BUILDTIMER BUILD_TIME
#else
#define BUILDTIMER 1
#endif

#define VERSION_STRING   TOSTRING(MAJOR.MINOR.PATCHOR.BUILDTIMER)
#define VERSION_WORDS  MAJOR,MINOR,PATCHOR,BUILDTIMER

#endif




WiFiAssistant总计2868-2342行,大半个月,还有很多功能,例如,设备接入管理,性能评估模块都没有去实现,临近毕业,也得自己找出路了。软件在百度帖吧分享还是出了些问题,一个是假死,有部分无线网卡确实无法正确开启虚拟Wifi,所以程序假死,设置共享的模块暂时容易出现错误,因为,它找的是连接的网络适配器,所以,有多个连通适配器的,有可能出现错误。

好了,不多说,发代码地址:http://git.oschina.net/ipvb/WiFiAssistant 支持OSChina

顺便贴下最近的错误处理机制:

/****************************************************************************************************************************
* ErrorMessageInvoke.h
*
*
******************************************************************************************************************************/
#ifndef ERRORMESSAGEINVOKE_H
#define ERRORMESSAGEINVOKE_H
#include "InternalOpt.h"

#define EMINVOKE_MAX_STRING 256

/****Error Defined Start****/

#define EMI_NO_ERROR     0
#define EMI_INIT_ERROR    1


/*********End defined*******/


typedef struct _ErrorInfo{
	int LastErrorId;
	uint32_t NumberOfTimes;
}ErrorInfo,*PErrorInfo;

void WINAPI SetErrorCode(const int eId);
void WINAPI ReSetErrorCode();
int  WINAPI GetErrorCodeInformation(PErrorInfo prInfo);
int  WINAPI GetErrorCodeLastId();
bool WINAPI FormatErrorMessageInvoke(int eId,wchar_t *str,int StrSize);


#endif

///////////////////////////////////////////////////////////////////
/****************************************************************************************************************************
* ErrorMessageInvoke
*
*
******************************************************************************************************************************/
#include "stdhd.h"
#include "ErrorMessageInvoke.h"

static ErrorInfo einfo = { 0, 0 };

void WINAPI SetErrorCode(const int eId)
{
	einfo.LastErrorId = eId;
	einfo.NumberOfTimes += 1;
}

void WINAPI ReSetErrorCode()
{
	einfo.LastErrorId = 0;
	einfo.NumberOfTimes = 0;
}

int WINAPI GetErrorCodeInformation(PErrorInfo prInfo)
{
	prInfo->LastErrorId = einfo.LastErrorId;
	prInfo->NumberOfTimes = einfo.NumberOfTimes;
	return prInfo->LastErrorId;
}


int WINAPI GetErrorCodeLastId()
{
	return einfo.LastErrorId;
}

bool WINAPI FormatErrorMessageInvoke(int eId, wchar_t *str, int StrSize)
{
	switch (eId)
	{
	case 0:
		break;
	default:
		break;
	}
	return true;
}



@

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看