WiFiAssistant 無線承載網絡設置助手的開發歷程(二)

接上篇:WiFiAssistant 無線承載網絡設置助手的開發歷程(一)

http://blog.csdn.net/huxizero10/article/details/17521327

WiFi SSID,KEY是否支持中文? 支持,但是,WiFi的SSID Key實質上是32字節的二進制碼,在WirelessHostedNetwork API 內部是用ANSI表示,這就意味着,如果用中文標識,充其量也就是MBCS,UTF8或者是其他代碼頁中讀取只會以其編碼讀取二進制,並不能夠轉換編碼,這就很容易出現“非法的ANSI字符”這個錯誤,那麼如何限制輸入中文呢?我們將Edit改造一番,還是上面的超類化,實現過程如下:

01 LRESULT CALLBACK LimitEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
02 {
03     switch (message)
04     {
05     case WM_CHAR:
06     {
07                     //if return;
08                     TCHAR ch = (TCHAR) wParam;
09                     if (!(ch >= _T('!') && ch <= _T('~')||ch == VK_BACK))
10                         return 0;
11     }
12         break;
13     case WM_PASTE:
14     {
15                      OpenClipboard(hWnd);
16                      HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT);
17                      if (hMem)
18                      {
19                         LPWSTR lpstr=(LPWSTR)GlobalLock(hMem) ;
20                         GlobalUnlock(hMem);
21                         if (lpstr != nullptr)
22                         {
23                             std::wstring wstr=lpstr;
24                             GlobalUnlock(hMem);
25                             //MessageBox(hWnd, wstr.c_str(), L"Paste", MB_OK);
26                             if (wstr.length() >= 32)
27                             {
28                                 return 0;
29                             }
30                             //check wstr;
31                         }
32                      }
33                      CloseClipboard();
34                      //GetClipboardData
35     }break;
36     case WM_MOUSEMOVE:
37         break;
38     case WM_LBUTTONUP:
39         break;
40     default:
41         break;
42     }
43     return CallWindowProc(OldEditWndProc, hWnd, message, wParam, lParam);
44 }
處理了WM_CHAR禁止輸入特定字符 和WM_PASTE 中限制字符大小, 
關於顯示密碼,ES_PASSWORD這個消息無法通過GetWindowLongPtr和SetWindowLongPtr進行操作修改,於是我想了一個笨辦法,CheckBox 本質是Button,那麼就有點擊事件,但點擊時,就去查看CheckBox是否被選取,如果被選取,就獲取密碼框的文本,銷燬密碼框,重新Create一個沒有ES_PASSWORD屬性的密碼框,並將獲取的文本SetWindowText發過去,具體代碼如下: 
01 HWND hEdKey = GetDlgItem(hWnd, IDC_LIMIT_EDIT);
02 if (Button_GetCheck(GetDlgItem(hWnd, IDC_CHECKBT_PAW)) == BST_CHECKED)
03 {
04     WCHAR text[32] = { 0 };
05     GetWindowText(hEdKey, text, 32);
06     SendMessage(GetDlgItem(hWnd, IDC_LIMIT_EDIT), WM_CLOSE, wParam, lParam);
07     HWND hLimit = CreateWindowEx(WndStyle::dwEditEx, LimitEdit, L"", WndStyle::dwEdit, 110, 120, 200, 25, hWnd, HMENU(IDC_LIMIT_EDIT), hInst, nullptr);
08     SetWindowText(hLimit, text);
09     SendMessage(hLimit, EM_SETLIMITTEXT, (WPARAM) 32, lParam);
10     SendMessage(hLimit, WM_SETFONT, (WPARAM) hFont, lParam);
11     SendMessage(hEdKey, WVR_REDRAW, wParam, lParam);
12 }
13 else
14 {
15     WCHAR text[32] = { 0 };
16     GetWindowText(hEdKey, text, 32);
17     SendMessage(GetDlgItem(hWnd, IDC_LIMIT_EDIT), WM_CLOSE, wParam, lParam);
18     HWND hLimit = CreateWindowEx(WndStyle::dwEditEx, LimitEdit, L"", WndStyle::dwEdit | ES_PASSWORD, 110, 120, 200, 25, hWnd, HMENU(IDC_LIMIT_EDIT), hInst, nullptr);
19     SetWindowText(hLimit, text);
20     SendMessage(hLimit, EM_SETLIMITTEXT, (WPARAM) 32, lParam);
21 }
一般來說就算頻繁的點擊也不會造成程序的問題。 
開啓WiFi和關閉WiFi這兩個功能實現了很久,cnblogs有一篇 翻譯就詳細講了如何開啓無線承載網絡,首先一定得注意檢查服務是否開啓,包括SharedAccess(ICS)WlanSvc,當然還需要檢查網絡是否暢通,一切準備好了以後,就需要初始化打開無線句柄WlanOpenHandle,WlanHostedNetworkInitSettings,配置WlanHostedNetworkSetProperty,設置第二Key,WlanHostedNetworkSetSecondaryKey,這裏提出來,第一key是系統生成的,所謂輸入的都是設置的第二key,最後WlanHostedNetworkForceStart。切記句柄得關閉。

關閉也就是先打開句柄,再調用WlanHostedNetworkForceStop,我是用的是強制版本,強制掉線的。

說到這裏,開啓WiFi過程中有很多錯誤,如何輸出錯誤代碼?我的機制就是定義錯誤代碼常量,通過GetErrorMessageString獲得錯誤代碼字符串,在調用結束後,檢查錯誤代碼:

001 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
002 // WirelessErrorType.h
003 //
004 //
005 //
006 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
007 #ifndef WIRELESSERRORTYPE_H
008 #define WIRELESSERRORTYPE_H
009  
010 #ifndef MAX_ERROR_STRING
011 #define MAX_ERROR_STRING                               512
012 #endif
013  
014 #define ERRORTYPE_SUCCESS                              (LRESULT)0L
015 //no Internet Online
016 #define NO_INTENET_ONLINE                              (LRESULT)21L
017 //No wireless device was found
018 #define NO_WIRELESS_DEVICE                             (LRESULT)22L
019 //Operating systems are not supported
020 #define SYSTEM_NOT_SUPPORT                             (LRESULT)23L
021 //No wireless network adapter was found
022 #define NO_WIRELESS_ADAPTER                            (LRESULT)24L
023 //Wlan API version is low not support
024 #define WLAN_API_VERLOW_NOT_SUPPORT                    (LRESULT)25L
025 #define WLAN_HOSTED_CANNOT_INIT                        (LRESULT)26L
026 #define INETSHARD_CONNECTION_ERROR                     (LRESULT)27L
027 #define CLOSE_WIFIHOSTED_ERROR                         (LRESULT)28L
028 #define SET_SECONDKEY_ERROR                            (LRESULT)29L
029 #define WLANHOSTED_FORCE_START_ERROR                   (LRESULT)30L
030 #define HOSTEDNETWORK_DISABLE_BY_GROUPPOLICY           (LRESULT)31L
031 #define WLANHANDLEOPEN_ALLOCATE_MEMORY                 (LRESULT)32L
032 #define WLANHANDLEOPEN_ERROR_INVALID_PARAMETER         (LRESULT)33L
033 #define WHO_ERROR_REMOTE_SESSION_LIMIT_EXCEEDED        (LRESULT)34L
034 #define SERVICE_NOT_START                              (LRESULT)35L
035 #define COM_COMPONENT_FAILED_TO_INITIALIZE             (LRESULT)36L
036 #define SC_HANDLE_OPEN_ERROR                           (LRESULT)37L
037 #define WLANSVC_START_ERROR                            (LRESULT)38L
038 #define WLANSVC_STOP_ERROR                          (LRESULT)39L
039 //Get Error Message String .
040 void WINAPI GetErrorMessageString(LRESULT hr, PWSTR pstr);
041  
042 #endif
043  
044 /////////////////////////////////////////////////////////////////////
045 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
046 // WirelessErrorType.cpp
047 //
048 //
049 //
050 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
051  
052 #define ERROR_INTERNAL
053 #include "stdafx.h"
054 #include"WirelessErrorType.h"
055  
056  
057  
058 void WINAPI GetErrorMessageString(LRESULT hr,PWSTR pstr)
059 {
060     switch (hr)
061     {
062     case ERRORTYPE_SUCCESS:
063         wcscpy_s(pstr, MAX_ERROR_STRING, L"No Error!");
064         break;
065     case NO_INTENET_ONLINE:
066         wcscpy_s(pstr, MAX_ERROR_STRING, L"No network connection!");
067         break;
068     case NO_WIRELESS_DEVICE:
069         wcscpy_s(pstr, MAX_ERROR_STRING, L"No wireless network device driver!");
070         break;
071     case SYSTEM_NOT_SUPPORT:
072         wcscpy_s(pstr, MAX_ERROR_STRING, L"Operating systems are not supported!");
073         break;
074     case WLAN_API_VERLOW_NOT_SUPPORT:
075         wcscpy_s(pstr, MAX_ERROR_STRING, L"Wlan API version is low not support!");
076         break;
077     case WLAN_HOSTED_CANNOT_INIT:
078         wcscpy_s(pstr, MAX_ERROR_STRING, L"Wlan Hosted Network can not Initialize!");
079         break;
080     case INETSHARD_CONNECTION_ERROR:
081         wcscpy_s(pstr, MAX_ERROR_STRING, L"Network sharing can not be achieved!");
082         break;
083     case CLOSE_WIFIHOSTED_ERROR:
084         wcscpy_s(pstr, MAX_ERROR_STRING, L"WirelessHostedNetwork can not close!");
085         break;
086     case SET_SECONDKEY_ERROR:
087         wcscpy_s(pstr, MAX_ERROR_STRING, L"Failed to set user key!");
088         break;
089     case WLANHOSTED_FORCE_START_ERROR:
090         wcscpy_s(pstr, MAX_ERROR_STRING, L"Wlan can not be forced open!");
091         break;
092     case HOSTEDNETWORK_DISABLE_BY_GROUPPOLICY:
093         wcscpy_s(pstr, MAX_ERROR_STRING, L"Hosted Network is disabled by group policy on a domain");
094         break;
095     case WLANHANDLEOPEN_ALLOCATE_MEMORY:
096         wcscpy_s(pstr, MAX_ERROR_STRING, L"Failed to allocate memory to create the client context!");
097         break;
098     case WLANHANDLEOPEN_ERROR_INVALID_PARAMETER:
099         wcscpy_s(pstr, MAX_ERROR_STRING, L"pdwNegotiatedVersion is NULL, phClientHandle is NULL, or pReserved is not NULL!");
100         break;
101     case WHO_ERROR_REMOTE_SESSION_LIMIT_EXCEEDED:
102         wcscpy_s(pstr, MAX_ERROR_STRING, L"Too many handles have been issued by the server");
103         break;
104     case SERVICE_NOT_START:
105         wcscpy_s(pstr, MAX_ERROR_STRING, L"The service did not start.");
106         break;
107     case COM_COMPONENT_FAILED_TO_INITIALIZE:
108         wcscpy_s(pstr, MAX_ERROR_STRING, L"COM component failed to initialize.");
109         break;
110     case SC_HANDLE_OPEN_ERROR:
111         wcscpy_s(pstr, MAX_ERROR_STRING, L"Service Manager fails to open.");
112         break;
113     case WLANSVC_START_ERROR:
114         wcscpy_s(pstr, MAX_ERROR_STRING, L"Wireless Auto Configuration service failed to start.");
115         break;
116     case WLANSVC_STOP_ERROR:
117         wcscpy_s(pstr, MAX_ERROR_STRING, L"Stop Service Error!");
118         break;
119     default:
120         wcscpy_s(pstr, MAX_ERROR_STRING, L"Unknown Error!");
121         break;
122     }
123 }
說到定時關機,up/down 控件老費功夫了。最後用CreateUpDownControl解決問題綁定夥伴。 
定時關機一定得注意先提權,再調用,最後得把權限恢復,注意,不要把重啓和關機搞混了,一個一個TRUE,一個FALSE。具體代碼在下面有項目的git地址,所以就不貼代碼了。

還有那個以管理員啓動按鈕,爲什麼不直接修改清單文件?事實上關閉WiFi,設置定時關機並不需要管理員,所以就沒有修改清單文件,有寫功能需要管理員運行的,再未取得管理員權限時會通過EnableWindow()禁用,在程序啓動後開始用IsUserAnAdmin()檢測是否以管理員權限運行,並把值保存在namespace Global{bool IsAdmin}全局變量,(用名稱空間限定獲得更好的隔離)。那個按鈕使用了Button_SetElevationRequiredState宏,這個宏能夠是按鈕顯示UAC圖標。

判斷系統版本,我直接使用了IsWindows7OrGreater() 結果發現VS2012 WDE不支持,API中沒有 2013新增的,於是就用了#if defined(_MSC_VER)&&_MSC_VER>=1800 分別實現2012 2013的;2012使用了OSVERSIONINFO;GetVersionEx,微軟MSDN說GetVersionEx以後可能不使用了。在程序中果斷禁止了支持XP。

在設置字體的時候發現,微軟雅黑字體在W7上耗資太大不美觀,於是果斷又分別設置了字體名,W8 8.1都是Microsoft Yaihe UI;

配置文件選了XML,不料XmlLite 這廝並不好玩,一下就是全讀取,搞半天沒懂,果斷用std::wstring 耍了一下小聰明。最後寫的時候還是規矩重寫了。

自修改版本卸了兩個有意思的批處理:

01 :::::::::::::::::::::::::::::::::::::::::::::
02 :::static.bat
03 @echo off
04 ::Globa SET
05 if /i "%1"=="" (
06 set BDT=1
07 else (
08 SET BDT=%1
09 )
10 SET MAX=1
11 SET MIN=0
12 SET PATCH=0
13  
14 ::Write upm.bat
15 echo ^@echo off >upm.bat
16 echo SET mvr=%MAX% >>upm.bat
17 echo SET mir=%MIN%  >>upm.bat
18 echo SET par=%PATCH%  >>upm.bat
19 echo SET bdt=%BDT%  >>upm.bat
20 echo echo ^^/^^*Defined PreEdit Version^^*^/ ^>upver.h >>upm.bat
21 echo echo ^/^/ Please #include ^"upver.h^" ^>^>upver.h >>upm.bat
22 echo echo #define BUILD_TIME     %%bdt%% ^>^>upver.h >>upm.bat
23 echo echo #define PATCH_TIME     %%par%% ^>^>upver.h >>upm.bat
24 echo echo #define MINJOR_VERSION %%mir%% ^>^>upver.h >>upm.bat
25 echo echo #define MAJOR_VERSION  %%mvr%% ^>^>upver.h >>upm.bat
26 echo SET /a bdt+=1 >>upm.bat
27 echo call  %%~dp0static.bat       %%bdt%% >>upm.bat
28 echo goto :EOF >>upm.bat
29  
30 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
31 ::upm.bat
32 @echo off
33 SET mvr=1
34 SET mir=0 
35 SET par=0 
36 SET bdt=20 
37 echo ^/^*Defined PreEdit Version^*/ >upver.h
38 echo // Please #include "upver.h" >>upver.h
39 echo #define BUILD_TIME     %bdt% >>upver.h
40 echo #define PATCH_TIME     %par% >>upver.h
41 echo #define MINJOR_VERSION %mir% >>upver.h
42 echo #define MAJOR_VERSION  %mvr% >>upver.h
43 SET /a bdt+=1
44 call  %~dp0static.bat       %bdt%
45 goto :EOF
只要雙擊upm就可以升級版本,並且upm自己也被修改了。利用宏定義可以非常方便的自動更新版本 
upver.h 
1 /*Defined PreEdit Version*/ 
2 // Please #include "upver.h" 
3 #define BUILD_TIME     19   
4 #define PATCH_TIME     0   
5 #define MINJOR_VERSION 0   
6 #define MAJOR_VERSION  1  

01 #ifndef VERSION_CONFIG_H
02 #define VERSION_CONFIG_H
03  
04 #include "upver.h"
05  
06 #define TOSTR_(a) L#a
07 #define TOSTR(a) TOSTR_(a)
08 #define TOSTRING(str) TOSTR(str)
09 //Alt+153 ™
10 #define CAMP L"Huxizero™ Studio. All Rights Reserved.\0"
11 #ifdef _WIN64
12 #define APPDEC L"WiFiAssistant™  64BIT\0"
13 #else
14 #define APPDEC L"WiFiAssistant™  32BIT\0"
15 #endif
16  
17 #define PROJECTNAME L"WiFiAssistant.exe\0"
18 #define PRODUCTNAME "WiFiAssistant™ VirtualWiFi Auto Setting Assistant\0"
19 #define LEGALTRADMARKS L"Huxizero™\0"
20  
21 #define YEAR L"2013"
22  
23 #ifdef MAJOR_VERSION
24 #define MAJOR MAJOR_VERSION
25 #else
26 #define MAJOR      1
27 #endif
28  
29 #ifdef MINJOR_VERSION
30 #define MINOR MINJOR_VERSION
31 #else
32 #define MINOR      0
33 #endif
34  
35 #ifdef PATCH_TIME
36 #define PATCHOR PATCH_TIME
37 #else
38 #define PATCHOR   1
39 #endif
40  
41 #ifdef BUILD_TIME
42 #define BUILDTIMER BUILD_TIME
43 #else
44 #define BUILDTIMER 1
45 #endif
46  
47 #define VERSION_STRING   TOSTRING(MAJOR.MINOR.PATCHOR.BUILDTIMER)
48 #define VERSION_WORDS  MAJOR,MINOR,PATCHOR,BUILDTIMER
49  
50 #endif

WiFiAssistant總計2868-2342行,大半個月,還有很多功能,例如,設備接入管理,性能評估模塊都沒有去實現,臨近畢業,也得自己找出路了。軟件在百度帖吧分享還是出了些問題,一個是假死,有部分無線網卡確實無法正確開啓虛擬Wifi,所以程序假死,設置共享的模塊暫時容易出現錯誤,因爲,它找的是連接的網絡適配器,所以,有多個連通適配器的,有可能出現錯誤。

好了,不多說,發代碼地址:http://git.oschina.net/ipvb/WiFiAssistant 支持OSChina

順便貼下最近的錯誤處理機制:

01 /****************************************************************************************************************************
02 * ErrorMessageInvoke.h
03 *
04 *
05 ******************************************************************************************************************************/
06 #ifndef ERRORMESSAGEINVOKE_H
07 #define ERRORMESSAGEINVOKE_H
08 #include "InternalOpt.h"
09  
10 #define EMINVOKE_MAX_STRING 256
11  
12 /****Error Defined Start****/
13  
14 #define EMI_NO_ERROR     0
15 #define EMI_INIT_ERROR    1
16  
17  
18 /*********End defined*******/
19  
20  
21 typedef struct _ErrorInfo{
22     int LastErrorId;
23     uint32_t NumberOfTimes;
24 }ErrorInfo,*PErrorInfo;
25  
26 void WINAPI SetErrorCode(const int eId);
27 void WINAPI ReSetErrorCode();
28 int  WINAPI GetErrorCodeInformation(PErrorInfo prInfo);
29 int  WINAPI GetErrorCodeLastId();
30 bool WINAPI FormatErrorMessageInvoke(int eId,wchar_t *str,int StrSize);
31  
32  
33 #endif
34  
35 ///////////////////////////////////////////////////////////////////
36 /****************************************************************************************************************************
37 * ErrorMessageInvoke
38 *
39 *
40 ******************************************************************************************************************************/
41 #include "stdhd.h"
42 #include "ErrorMessageInvoke.h"
43  
44 static ErrorInfo einfo = { 0, 0 };
45  
46 void WINAPI SetErrorCode(const int eId)
47 {
48     einfo.LastErrorId = eId;
49     einfo.NumberOfTimes += 1;
50 }
51  
52 void WINAPI ReSetErrorCode()
53 {
54     einfo.LastErrorId = 0;
55     einfo.NumberOfTimes = 0;
56 }
57  
58 int WINAPI GetErrorCodeInformation(PErrorInfo prInfo)
59 {
60     prInfo->LastErrorId = einfo.LastErrorId;
61     prInfo->NumberOfTimes = einfo.NumberOfTimes;
62     return prInfo->LastErrorId;
63 }
64  
65  
66 int WINAPI GetErrorCodeLastId()
67 {
68     return einfo.LastErrorId;
69 }
70  
71 bool WINAPI FormatErrorMessageInvoke(int eId, wchar_t *str, int StrSize)
72 {
73     switch (eId)
74     {
75     case 0:
76         break;
77     default:
78         break;
79     }
80     return true;
81 }

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