WiFiAssistant 无线承载网络设置助手的开发历程
WiFiAssistant 无线承载网络设置助手的开发历程
Force武装卫队 发表于4年前
WiFiAssistant 无线承载网络设置助手的开发历程
  • 发表于 4年前
  • 阅读 3807
  • 收藏 64
  • 点赞 8
  • 评论 19

腾讯云 新注册用户 域名抢购1元起>>>   

摘要: 笔者开发WiFi虚拟助手的开发历程。如何使用Win32SDK,开发一个基于Windows COM(无线承载网络)组件的虚拟WiFi图形化助手,对于学习Win32SDK有一定的帮助。

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



@

标签: Win32 C++ WiFi GUI Windows
共有 人打赏支持
Force武装卫队
粉丝 171
博文 33
码字总数 63119
作品 3
评论 (19)
从今以后
嗯,无限~~
岛
虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗
3kqing
顶一个!
Force武装卫队

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?
Force武装卫队

引用来自“从今以后”的评论

嗯,无限~~

已经修改
汉唐
开启的虚拟wifi是ap还是ad-hoc的?
Force武装卫队

引用来自“汉唐”的评论

开启的虚拟wifi是ap还是ad-hoc的?

ap
岛

引用来自“李博文”的评论

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?

游戏公司
Force武装卫队

引用来自“岛”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?

游戏公司

如果能够更详细再好不过了13
萨嘎哥仨发顺丰

引用来自“李博文”的评论

引用来自“岛”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?

游戏公司

如果能够更详细再好不过了13

给你个思路自己搞吧,不要指望哪里何时都能用拿来主义
Force武装卫队

引用来自“isampan”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?

游戏公司

如果能够更详细再好不过了13

给你个思路自己搞吧,不要指望哪里何时都能用拿来主义

岛

引用来自“李博文”的评论

引用来自“岛”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?

游戏公司

如果能够更详细再好不过了13

你学校哪里的? 留个联系方式
Force武装卫队

引用来自“岛”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

引用来自“李博文”的评论

引用来自“岛”的评论

虽然很简单,但这份认真,忍不住赞一个,加油小伙子。我这可以提供实习机会,有兴趣吗

我需要了解一下,毕竟做自己喜欢的才是好的,能否介绍一下具体工作细节?

游戏公司

如果能够更详细再好不过了13

你学校哪里的? 留个联系方式

湖南郴州 湘南学院 Q917833820
wcrack
现在还在搞sdk什么的开发的人好少,记得当时学完c的时候,总是琢磨一些api,热闹了一阵子,感觉写不出有价值的应用,开发效率低。放弃了。不过真心向你致敬,能winsdk编程的人,我估计大部分语言学起来都不费劲,人才人才啊
荒野无灯
不错,LZ是个很认真的人
richardor
博主,太巧了,那篇翻译是我之前写的。。。。
Force武装卫队

引用来自“richardor”的评论

博主,太巧了,那篇翻译是我之前写的。。。。

多谢你的翻译,建议更加详细的写一篇新的,那个翻译确实太简单的,新生难以理解
richardor

引用来自“李博文”的评论

引用来自“richardor”的评论

博主,太巧了,那篇翻译是我之前写的。。。。

多谢你的翻译,建议更加详细的写一篇新的,那个翻译确实太简单的,新生难以理解

没问题,今年春节期间,我会重新整理下的。0
Force武装卫队

引用来自“richardor”的评论

引用来自“李博文”的评论

引用来自“richardor”的评论

博主,太巧了,那篇翻译是我之前写的。。。。

多谢你的翻译,建议更加详细的写一篇新的,那个翻译确实太简单的,新生难以理解

没问题,今年春节期间,我会重新整理下的。0

79
×
Force武装卫队
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: