VC定制個(gè)性化的MessageBox解決方法
相信學(xué)過(guò)VC的人都知道MessageBox()函數(shù)的用法:
int MessageBox( HWND hWnd, // handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style );
雖然在參數(shù)uType中可以指定一些樣式,但你在程序中能夠?qū)essageBox的外觀所做的定義卻不多。原因是當(dāng)調(diào)用MessageBox()函數(shù)后,它在內(nèi)部有自己的消息循環(huán)(所有的模式對(duì)話框都有自己的消息循環(huán)),返回時(shí)MessageBox對(duì)話框窗口已經(jīng)被Destroy,所以你沒(méi)有辦法得到MessageBox對(duì)話框的窗口句柄。但你可以根據(jù)自己的不同需求用下面的方法中去定制你的MessageBox:
如果你只是想用自己的icon去代替系統(tǒng)MessageBox提供的那幾種有限的icon,用MessageBoxIndirect()函數(shù)就可以了:
int MessageBoxIndirect( CONST LPMSGBOXPARAMS lpMsgBoxParams // message box parameters ); typedef struct { UINT cbSize; HWND hwndOwner; HINSTANCE hInstance; LPCTSTR lpszText; LPCTSTR lpszCaption; DWORD dwStyle; LPCTSTR lpszIcon; DWORD_PTR dwContextHelpId; MSGBOXCALLBACK lpfnMsgBoxCallback; DWORD dwLanguageId; } MSGBOXPARAMS, *PMSGBOXPARAMS;
看到MSGBOXPARAMS結(jié)構(gòu)中的lpszIcon吧,在使用過(guò)程中你應(yīng)當(dāng)準(zhǔn)備一個(gè)合適的MSGBOXPARAMS結(jié)構(gòu),如果你要用自己的icon,你一定要用MB_USERICON這個(gè)flag。
上面我們也講到不能定制MessageBox對(duì)話框的原因是沒(méi)有辦法得到它的窗口句柄,但我們真的沒(méi)有辦法了嗎?當(dāng)然有辦法,那就是使用HOOK(鉤子)機(jī)制。在windows系統(tǒng)中有多種HOOK,但在這里我們只用到HK_CBT類型的鉤子。HK_CBT鉤子過(guò)程在WM_MOVE、WM_SIZE、WM_ACTIVE、WM_CREATE、WM_DESTROY時(shí)被系統(tǒng)調(diào)用,所以HK_CBT鉤子可以在這里用。下面讓我們看如何實(shí)現(xiàn)MessageBox的定制過(guò)程。
1.安裝HK_CBT鉤子;
2.調(diào)用MessageBox()函數(shù);
3.移除HK_CBT鉤子。
整個(gè)過(guò)程很簡(jiǎn)單吧?我們?cè)谶@里介紹第一步和第三步。
安裝HK_CBT鉤子:
HHOOK hMsgBoxHook = SetWindowsHookEx( WH_CBT, // Type of hook CBTProc, // Hook procedure (see below) NULL, // Module handle. Must be NULL (see docs) GetCurrentThreadId() // Only install for THIS thread!!! );
重要的是SetWindowHookEx()函數(shù)的后邊兩個(gè)參數(shù),用它可以區(qū)別安裝是一個(gè)全局鉤子還是一個(gè)線程鉤子,在這里我們只要安裝一個(gè)線程鉤子。所以我們將Module handle設(shè)置為NULL,同時(shí)將thread ID設(shè)為本線程的ID。
在SetWindowHookEx()函數(shù)中有一個(gè)hook procedure,這是window調(diào)用的一個(gè)回調(diào)函數(shù),在windows系統(tǒng)中有一個(gè)HOOK鏈,我們?cè)诰帉?xiě)hook procedure時(shí)要注意保證此鏈的完整,所以我們的hook procedure要調(diào)用CallNextHookEx()函數(shù)。下面就是我們的hook procedure:
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) { HWND hwnd; if(nCode < 0) return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam); switch(nCode) { case HCBT_ACTIVATE: // 現(xiàn)在wParam中就是message box的句柄 hwnd = (HWND)wParam; // 我們已經(jīng)有了message box的句柄,在這里我們就可以定制message box了! return 0; } // Call the next hook, if there is one return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam); }
移除HK_CBT鉤子:
只要調(diào)用UnhookWindowsHookEx()函數(shù)就可以了
好了,我們將在上面的三步寫(xiě)成一個(gè)函數(shù),如下:
int MsgBoxEx(HWND hwnd, TCHAR *szText, TCHAR *szCaption, UINT uType) { int ret; // Install a thread hook, so we can customize it hMsgBoxHook = SetWindowsHookEx( WH_CBT, CBTProc, NULL, GetCurrentThreadId() ); // Display a standard message box ret = MessageBox(hwnd, szText, szCaption, uType); // remove the window hook UnhookWindowsHookEx(hMsgBoxHook); return ret; }
其實(shí)你也可以鉤住WM_CREATE消息,不過(guò)那樣處理要復(fù)雜一些。在早期的windows platform SDK中就有這樣一個(gè)例子。
你可能說(shuō),定制一個(gè)MessageBox有什么用處,我想有下面的用途:
1.你可以用CreateWindowEx()給MessageBox添加一個(gè)check box控件,并子類化MessageBox來(lái)處理check box的消息
2.通過(guò)子類化改變messagebox、button或icon,以便和你整個(gè)程序的界面風(fēng)格相一致
只要有了MessageBox對(duì)話框的句柄,你能做的很多,很多...
另外,如果你對(duì)模式對(duì)話框的機(jī)理很了解,你可以自己寫(xiě)出一個(gè)"MessageBox"來(lái)代替系統(tǒng)MessageBox用在你的程序中。你可以參考Jeffrey Richter的《Windows 95程式設(shè)計(jì)指南》,在書(shū)中給出了模式對(duì)話框的偽碼。這本書(shū)的繁體電子版可以在候捷的個(gè)人網(wǎng)站上下載。這種方法也比較簡(jiǎn)單(添加一個(gè)消息循環(huán),Enable/Disable Owner窗口),示例代碼這里就不實(shí)現(xiàn)了。讀者可以參考相關(guān)資料加以完善。
- VC6.0常見(jiàn)編譯錯(cuò)誤提示附解決方法
- VC6.0常見(jiàn)鏈接錯(cuò)誤與解決方法
- ASP.NET中MVC使用AJAX調(diào)用JsonResult方法并返回自定義錯(cuò)誤信息
- VC++實(shí)現(xiàn)通過(guò)API來(lái)查看程序錯(cuò)誤信息的方法
- 完美解決IIS 服務(wù)器無(wú)法加載應(yīng)用程序 ‘/LM/W3SVC/1/ROOT’。錯(cuò)誤是:沒(méi)有注冊(cè)類別
- 完美修復(fù)SVCHOST.EXE出現(xiàn)0x745f2780錯(cuò)誤的方法
- vc提示unexpected end of file found的原因分析
- VC外部符號(hào)錯(cuò)誤_main,_WinMain@16,__beginthreadex解決方法
相關(guān)文章
Qt音視頻開(kāi)發(fā)之視頻文件保存功能的實(shí)現(xiàn)
和音頻存儲(chǔ)類似,視頻的存儲(chǔ)也對(duì)應(yīng)三種格式,視頻最原始的數(shù)據(jù)是yuv(音頻對(duì)應(yīng)pcm),視頻壓縮后的數(shù)據(jù)是h264(音頻對(duì)應(yīng)aac)。本文將利用Qt實(shí)現(xiàn)視頻文件保存功能,感興趣的可以了解一下2022-12-12C++中rapidjson組裝繼續(xù)簡(jiǎn)化的方法
今天小編就為大家分享一篇關(guān)于C++中rapidjson組裝繼續(xù)簡(jiǎn)化的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-04-04C語(yǔ)言實(shí)現(xiàn)定時(shí)器控制LED燈閃爍
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)定時(shí)器控制LED燈閃爍,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05C++中memcpy和memmove的區(qū)別總結(jié)
這篇文章主要介紹了C++中memcpy和memmove的區(qū)別總結(jié),這個(gè)問(wèn)題經(jīng)常出現(xiàn)在C++的面試題目中,需要的朋友可以參考下2014-10-10VScode搭建C/C++開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程
最近迷上了vscode,小巧美觀,最主要的是全平臺(tái),但是vscode并不是ide,必須得自己配置環(huán)境,下面這篇文章主要給大家介紹了關(guān)于VScode搭建C/C++開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程,需要的朋友可以參考下2023-06-06Windows安裝配置C/C++(VS2017)OpenSSL開(kāi)發(fā)環(huán)境配置教程
這篇文章主要為大家詳細(xì)介紹了Windows安裝配置C/C++,OpenSSL開(kāi)發(fā)環(huán)境配置教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07