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控件,因爲默認的記事本的菜單不太習慣,所以就自己超了下,子類化因爲沒掌握好就沒有使用。

1 WNDCLASSEX PreEditEx;
2  ZeroMemory(&PreEditEx,sizeof(PreEditEx));
3  PreEditEx.cbSize=sizeof(WNDCLASSEX);
4  GetClassInfoEx(0,L"EDIT",&PreEditEx);
5  OldEditWndProc=PreEditEx.lpfnWndProc;
6  PreEditEx.lpfnWndProc=PreEditExWndProc;
7  //PreEditEx.lpszMenuName=
8  PreEditEx.lpszClassName=L"PreEditControl";
9  RegisterClassEx(&PreEditEx);

OldEditWndProc是函數指針,用來保留老的窗口處理函數

1 LRESULT (CALLBACK* OldEditWndProc)(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
最後就是自己寫窗口函數 
001 LRESULT CALLBACK PreEditExWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
002 {
003    //PAINTSTRUCT ps;
004    //HDC hdc;
005    //RECT rt;
006    //HGDIOBJ oldPen;
007    int mId,mEvent;
008    switch (uMsg)
009    {
026    case WM_COMMAND:
027        mId    = LOWORD(wParam);
028        mEvent = HIWORD(wParam);
029        switch(mId)
030        {
031        case IDM_EDIT_UNDO:
032            SendMessage(hWnd,EM_UNDO,0,0L);
033            break;
034        case IDM_EDIT_COPY:
035            SendMessage(hWnd,WM_COPY,0,0L);
036            break;
037        case IDM_EDIT_PASTE:
038            SendMessage(hWnd,WM_PASTE,0,0L);
039            break;
040        case IDM_EDIT_CUT:
041            SendMessage(hWnd,WM_CUT,0,0L);
042            break;
043        case IDM_EDIT_SELECTALL:
044            SendMessage(hWnd, EM_SETSEL, 0, -1);
045            SendMessage(hWnd,EM_SCROLLCARET,0,0L);
046            //SendMessage(hWnd,
047            break;
048        case IDM_EDIT_CLEAR:
049            SendMessage(hWnd,WM_CLEAR,0,0L);
050            break;
051        case IDR_SETTING:
052            DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SETBOX), hWnd, OpenOpDlg);
053            break;
054        case IDR_UPDATA:
055            {
056                MessageBox(NULL,L"Alt+F2 is Update",L"Alt+F2",MB_OK);
057                //std::
058            }
059            break;
060        case IDM_CLEAR_UI:
061            {
062                SetWindowText(hWnd,L"");
063                //WCHAR IJI[5695222]=L"0";
064                //GetWindowText(hWnd,IJI,5695222);
065                //ClearCommandUI(L"PreEditControl",IJI);
066            }
067            break;
068        case IDI_RESTART:
069            RestartShell();
070            break;
071        case IDR_EXIT:
072            PostQuitMessage(0);
073            break;
074        default:
075            break;
076        }
077        break;
078    case WM_PAINT:
079        break;
080    case WM_RBUTTONUP:
081        {
082            //GetFocus
083            //RECT rect;
084            POINT pt;
085            GetCursorPos(&pt);
086            //rect.left=pt.x;rect.right=pt.y;
087            HMENU EditMenu=LoadMenu(GetModuleHandle(nullptr),MAKEINTRESOURCE(IDR_MENU_POPU));
088            HMENU PopuMenu=GetSubMenu(EditMenu,0);
089            if(SendMessage(hWnd,EM_CANUNDO,0,0))
090            {
091                EnableMenuItem(PopuMenu,IDM_EDIT_UNDO,MF_ENABLED);
092            }
093            else
094            {
095              EnableMenuItem(PopuMenu,IDM_EDIT_UNDO,MF_GRAYED);
096            }
097            long long n=0,m=0;
098            SendMessage(hWnd,EM_GETSEL,(WPARAM)&n,(LPARAM)&m);
099            if(n==m)
100            {
101                EnableMenuItem(PopuMenu,IDM_EDIT_CLEAR,MF_GRAYED);
102                EnableMenuItem(PopuMenu,IDM_EDIT_COPY,MF_GRAYED);
103                EnableMenuItem(PopuMenu,IDM_EDIT_CUT,MF_GRAYED);
104            }
105            else
106            {
107                EnableMenuItem(PopuMenu,IDM_EDIT_CLEAR,MF_ENABLED);
108                EnableMenuItem(PopuMenu,IDM_EDIT_COPY,MF_ENABLED);
109                EnableMenuItem(PopuMenu,IDM_EDIT_CUT,MF_ENABLED);
110            }
111                EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_BYCOMMAND|MF_ENABLED);
112            //wstring ClipText;
113            if(OpenClipboard(hWnd))
114            {
115                if(GetClipboardData(CF_TEXT))
116                {
117                    EnableMenuItem(PopuMenu,IDM_EDIT_PASTE,MF_ENABLED);
118                }
119                else
120                {
121                    EnableMenuItem(PopuMenu,IDM_EDIT_PASTE,MF_GRAYED);
122                }
123                CloseClipboard();
124            }
125            else
126            {
127                EnableMenuItem(PopuMenu,IDM_EDIT_PASTE,MF_GRAYED);
128                CloseClipboard();
129            }
130            if(GetWindowTextLength(hWnd)==0)
131            {
132                EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_GRAYED);
133            }
134            else
135            {
136                if(GetWindowTextLength(hWnd)==(m-n)||m-n==-1)
137                    EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_GRAYED);
138                else
139                    EnableMenuItem(PopuMenu,IDM_EDIT_SELECTALL,MF_ENABLED);
140            }
141            //HiliteMenuItem(hWnd,PopuMenu,IDI_RESTART,MF_BYCOMMAND|MF_HILITE);
142            //WCHAR st[10]={'0'};
143            //wsprintf(st,L"ST=: %d",x);
144            //MessageBox(NULL,st,L"Text Long",MB_OK);
145           //if(SendMessage(hWnd,WM_,CF_TEXT,0)
146            //InsertMenu(PopuMenu,IDR_SETTING,MF_ENABLED,IDM_ECUT,L"PASTE");
147            TrackPopupMenuEx(PopuMenu,TPM_RIGHTBUTTON,pt.x,pt.y,hWnd,NULL);
148        }
149        return 0;
150    case WM_SETFONT:
151        //MessageBox(NULL,L"Font",L"Setting Font",MB_OK);
152        UpdateWindow(hWnd);
153        break;
154    //case WM_CREATE:
155    case WM_SYSKEYDOWN:
156        switch(wParam)
157        {
158     case VK_F1:
159                if(GetKeyState(VK_MENU)<0)
160                     DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SETBOX), hWnd, OpenOpDlg);
161                break;
162     case VK_F2:
163         if(GetKeyState(VK_MENU)<0)
164         {
165             //MessageBox(NULL,L"Alt+F2 is Update",L"Alt+F2",MB_OK);
166             SendMessage(hWnd,WM_COMMAND,IDR_UPDATA,0);
167         }
168         break;
169        case VK_F3:
170            if(GetKeyState(VK_MENU)<0)
171                RestartShell();
172                break;
173        default:
174            break;
175        }
176    case WM_KEYDOWN:
177        {
178            switch(wParam)
179            {
180            case 'A':
181                if(GetKeyState(VK_CONTROL)<0)
182                {
183                    //MessageBox(NULL,L"Select All",L"Ctrl+A",MB_OK);
184                    int start=0,end=0;
185                    SendMessage(hWnd,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
186                    if(GetWindowTextLength(hWnd)==(end-start)||end-start==-1)
187                            ;
188                        else
189                            SendMessage(hWnd,EM_SETSEL,0,-1);
190                }
191                break;
192            case VK_BACK:
193                MessageBeep(MB_OK);//Test
194                break;
195            default:
196                break;
197            }
198        }
199        break;
200    case WM_KEYUP:
201        {
202            switch(wParam)
203            {
204                /*http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx wParam Virtual Key Value! */
205            case VK_RETURN:
206            MessageBeep(MB_OK);
207            break;
208            default:
209                break;
210            }
211        }
212        break;
213       // break;
214 }
215 return CallWindowProc(OldEditWndProc,hWnd, uMsg, wParam, lParam);
216 }
一定不要忘記最後調用舊的窗口處理函數,特定消息必須截斷不然會調用默認消息,你的努力就白費了。 

好吧說到這裏有點偏了,這個超類化的經歷與WiFiAssistant很重要,首先,用戶面對的是一個界面,
以這個界面爲例,我給用戶提供了以下幾個功能:
1.一鍵開啓虛擬WiFi,這個會隨機產生隨機字符串作爲用戶名和密碼,
2.關閉WiFi
3.開啓WiFi
4.顯示密碼
5.取消定時關機
6.定時關機
7.獲取管理員權限

如果要隨機產生字符串,一般的方法是先設置一個常字符串數組,裏面的字符一般是從a開始的ANSI字符,我的模板是:

1 const WCHAR* cstr= L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#$%^&*()-=_+,./;\"'<>?~|";

再初始化隨即種子srand((unsigned int) GetTickCount());
這裏是選取的系統啓動的毫秒數,最後使用隨機rand()產生隨機數,除以常字符串的大小取餘,再獲取常字符串cstr[i],這裏i就是餘數,因爲C++ string更加好用,所以整個函數最終用string實現,如下:

01 bool GetRandStringUserOrPwd(PWSTR wstr, UINT Size)
02 {
03     const std::wstring templetstr= L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#$%^&*()-=_+,./;\"'<>?~|";
04     UINT i, lstr;
05     UINT k;
06     std::wstring produce;
07     lstr = (UINT)templetstr.size();
08     srand((unsigned int) GetTickCount());
09     for (i = 1; i < Size; i++)
10     {
11         k = rand() % lstr;
12         produce += templetstr.substr(k,1);
13          
14     }
15     wcscpy_s(wstr, Size, produce.c_str());
16     //MessageBox(NULL, produce.c_str(), L"Test", MB_OK);
17     return true;
18 }
我習慣用MessageBox測試程序,當我運行GetRandStringUserOrPwd,開啓MessageBox,用戶名和密碼隨機產生獲得不一樣的結果,但是註釋掉MessageBox後,二者的隨機數值確是一樣,雖然我們選取的是計算機的啓動時間,以毫秒計,但是計算機的運行速度是非常快的,所以在產生用戶名隨機數後,我添加了一段代碼: 
1 Sleep(500);
沒錯就是讓它休息一下,500毫秒雖然能夠感覺出來,但是對於隨機生成的用戶名和密碼造成差異還是可取的。

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