接上篇: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) |
08 | TCHAR ch = ( TCHAR ) wParam; |
09 | if (!(ch >= _T( '!' ) && ch <= _T( '~' )||ch == VK_BACK)) |
16 | HGLOBAL hMem = GetClipboardData(CF_UNICODETEXT); |
19 | LPWSTR lpstr=( LPWSTR )GlobalLock(hMem) ; |
23 | std::wstring wstr=lpstr; |
26 | if (wstr.length() >= 32) |
43 | return CallWindowProc(OldEditWndProc, hWnd, message, wParam, lParam); |
处理了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) |
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); |
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); |
一般来说就算频繁的点击也不会造成程序的问题。
开启WiFi和关闭WiFi这两个功能实现了很久,cnblogs有一篇
翻译
就详细讲了如何开启无线承载网络,首先一定得注意检查服务是否开启,包括SharedAccess(ICS)WlanSvc,当然还需要检查网络是否畅通,一切准备好了以后,就需要初始化打开无线句柄WlanOpenHandle,WlanHostedNetworkInitSettings,配置WlanHostedNetworkSetProperty,设置第二Key,WlanHostedNetworkSetSecondaryKey,这里提出来,第一key是系统生成的,所谓输入的都是设置的第二key,最后WlanHostedNetworkForceStart。切记句柄得关闭。
关闭也就是先打开句柄,再调用WlanHostedNetworkForceStop,我是用的是强制版本,强制掉线的。
说到这里,开启WiFi过程中有很多错误,如何输出错误代码?我的机制就是定义错误代码常量,通过GetErrorMessageString获得错误代码字符串,在调用结束后,检查错误代码:
007 | #ifndef WIRELESSERRORTYPE_H |
008 | #define WIRELESSERRORTYPE_H |
010 | #ifndef MAX_ERROR_STRING |
011 | #define MAX_ERROR_STRING 512 |
014 | #define ERRORTYPE_SUCCESS (LRESULT)0L |
016 | #define NO_INTENET_ONLINE (LRESULT)21L |
018 | #define NO_WIRELESS_DEVICE (LRESULT)22L |
020 | #define SYSTEM_NOT_SUPPORT (LRESULT)23L |
022 | #define NO_WIRELESS_ADAPTER (LRESULT)24L |
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 |
040 | void WINAPI GetErrorMessageString( LRESULT hr, PWSTR pstr); |
052 | #define ERROR_INTERNAL |
054 | #include"WirelessErrorType.h" |
058 | void WINAPI GetErrorMessageString( LRESULT hr, PWSTR pstr) |
062 | case ERRORTYPE_SUCCESS: |
063 | wcscpy_s(pstr, MAX_ERROR_STRING, L "No Error!" ); |
065 | case NO_INTENET_ONLINE: |
066 | wcscpy_s(pstr, MAX_ERROR_STRING, L "No network connection!" ); |
068 | case NO_WIRELESS_DEVICE: |
069 | wcscpy_s(pstr, MAX_ERROR_STRING, L "No wireless network device driver!" ); |
071 | case SYSTEM_NOT_SUPPORT: |
072 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Operating systems are not supported!" ); |
074 | case WLAN_API_VERLOW_NOT_SUPPORT: |
075 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Wlan API version is low not support!" ); |
077 | case WLAN_HOSTED_CANNOT_INIT: |
078 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Wlan Hosted Network can not Initialize!" ); |
080 | case INETSHARD_CONNECTION_ERROR: |
081 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Network sharing can not be achieved!" ); |
083 | case CLOSE_WIFIHOSTED_ERROR: |
084 | wcscpy_s(pstr, MAX_ERROR_STRING, L "WirelessHostedNetwork can not close!" ); |
086 | case SET_SECONDKEY_ERROR: |
087 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Failed to set user key!" ); |
089 | case WLANHOSTED_FORCE_START_ERROR: |
090 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Wlan can not be forced open!" ); |
092 | case HOSTEDNETWORK_DISABLE_BY_GROUPPOLICY: |
093 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Hosted Network is disabled by group policy on a domain" ); |
095 | case WLANHANDLEOPEN_ALLOCATE_MEMORY: |
096 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Failed to allocate memory to create the client context!" ); |
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!" ); |
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" ); |
104 | case SERVICE_NOT_START: |
105 | wcscpy_s(pstr, MAX_ERROR_STRING, L "The service did not start." ); |
107 | case COM_COMPONENT_FAILED_TO_INITIALIZE: |
108 | wcscpy_s(pstr, MAX_ERROR_STRING, L "COM component failed to initialize." ); |
110 | case SC_HANDLE_OPEN_ERROR: |
111 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Service Manager fails to open." ); |
113 | case WLANSVC_START_ERROR: |
114 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Wireless Auto Configuration service failed to start." ); |
116 | case WLANSVC_STOP_ERROR: |
117 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Stop Service Error!" ); |
120 | wcscpy_s(pstr, MAX_ERROR_STRING, L "Unknown Error!" ); |
说到定时关机,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 | ::::::::::::::::::::::::::::::::::::::::::::: |
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 |
26 | echo SET /a bdt+=1 >>upm.bat |
27 | echo call %%~dp0static.bat %%bdt%% >>upm.bat |
28 | echo goto :EOF >>upm.bat |
30 | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
37 | echo ^/^*Defined PreEdit Version^*/ >upver.h |
44 | call %~dp0static.bat %bdt% |
只要双击upm就可以升级版本,并且upm自己也被修改了。利用宏定义可以非常方便的自动更新版本
upver.h
5 | #define MINJOR_VERSION 0 |
6 | #define MAJOR_VERSION 1 |
01 | #ifndef VERSION_CONFIG_H |
02 | #define VERSION_CONFIG_H |
07 | #define TOSTR(a) TOSTR_(a) |
08 | #define TOSTRING(str) TOSTR(str) |
10 | #define CAMP L"Huxizero™ Studio. All Rights Reserved.\0" |
12 | #define APPDEC L"WiFiAssistant™ 64BIT\0" |
14 | #define APPDEC L"WiFiAssistant™ 32BIT\0" |
17 | #define PROJECTNAME L"WiFiAssistant.exe\0" |
18 | #define PRODUCTNAME "WiFiAssistant™ VirtualWiFi Auto Setting Assistant\0" |
19 | #define LEGALTRADMARKS L"Huxizero™\0" |
24 | #define MAJOR MAJOR_VERSION |
30 | #define MINOR MINJOR_VERSION |
36 | #define PATCHOR PATCH_TIME |
42 | #define BUILDTIMER BUILD_TIME |
47 | #define VERSION_STRING TOSTRING(MAJOR.MINOR.PATCHOR.BUILDTIMER) |
48 | #define VERSION_WORDS MAJOR,MINOR,PATCHOR,BUILDTIMER |
WiFiAssistant总计2868-2342行,大半个月,还有很多功能,例如,设备接入管理,性能评估模块都没有去实现,临近毕业,也得自己找出路了。软件在百度帖吧分享还是出了些问题,一个是假死,有部分无线网卡确实无法正确开启虚拟Wifi,所以程序假死,设置共享的模块暂时容易出现错误,因为,它找的是连接的网络适配器,所以,有多个连通适配器的,有可能出现错误。
好了,不多说,发代码地址:http://git.oschina.net/ipvb/WiFiAssistant 支持OSChina
顺便贴下最近的错误处理机制:
06 | #ifndef ERRORMESSAGEINVOKE_H |
07 | #define ERRORMESSAGEINVOKE_H |
08 | #include "InternalOpt.h" |
10 | #define EMINVOKE_MAX_STRING 256 |
14 | #define EMI_NO_ERROR 0 |
15 | #define EMI_INIT_ERROR 1 |
21 | typedef struct _ErrorInfo{ |
23 | uint32_t NumberOfTimes; |
24 | }ErrorInfo,*PErrorInfo; |
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); |
42 | #include "ErrorMessageInvoke.h" |
44 | static ErrorInfo einfo = { 0, 0 }; |
46 | void WINAPI SetErrorCode( const int eId) |
48 | einfo.LastErrorId = eId; |
49 | einfo.NumberOfTimes += 1; |
52 | void WINAPI ReSetErrorCode() |
54 | einfo.LastErrorId = 0; |
55 | einfo.NumberOfTimes = 0; |
58 | int WINAPI GetErrorCodeInformation(PErrorInfo prInfo) |
60 | prInfo->LastErrorId = einfo.LastErrorId; |
61 | prInfo->NumberOfTimes = einfo.NumberOfTimes; |
62 | return prInfo->LastErrorId; |
66 | int WINAPI GetErrorCodeLastId() |
68 | return einfo.LastErrorId; |
71 | bool WINAPI FormatErrorMessageInvoke( int eId, wchar_t *str, int StrSize) |