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