WiFiAssistant 無線承載網絡設置助手的開發歷程 頂 原 薦

今年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;
}



@

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章