相信很多人在VC下開發程序的時候大多都會采用基於對話框的開發吧,我也不例外,大多數的小型測試程序沒有必要開發基於文檔/視圖的結構來測試,只要使用一些基本的對話框程序就可以達到這個目的 。
但是在開發基於對話框的程序時,要使用到一些 Spy++ 的功能檢測的時候,就會出現一些問題。什麼問題呢?當我使用 Spy++ 去檢測一個對話框的窗口類 時,並想得到一個對話框的窗口類,以便我在使用鉤子的時候可以指定一個對話框進行 hook,但是結果出乎我意料之外 ,對話框的窗口類不是我在注冊時所指定的對話框窗口類名。其類名是 "#32770(Dialog)",這是一個MFC自動為基於對話框的程序產生的默認窗口類 ,所有的基於MFC所產生的對話框程序都使用這一個默認類名。即是說,我在使用一個基於對話框的程序時,無論多少個對話框產生,它們的類名都會是 "#32770(Dialog)",這樣我在打開對話框進行測試時,無法指定我需要的對話框的句柄。
但是,當指定一個對話框的窗口標題的時候,這個對話框的名柄就可以找到了:
HWND hWnd = MULL;
hWnd = FindWindow( "#32770",lpszWindowName );
_ASSERT( hWnd != NULL );
//其中 lpszWindowName 是對話框的窗口標題目。
這種方法也有一定的缺點,就是一個對話框的標題不確定時會怎麼樣,或對話框的標題在運行過程中要動態改變呢?這樣根本無法保證所找到 的句柄就是所需要的句柄。我采取的方法就是在對話框的產生過程中為對話框指定一個唯一的窗口類,這樣就可以找到所想要的指定句柄,而不必與其它的對話框混淆。
HWND hWnd = MULL;
hWnd = FindWindow( lpszClassName, NULL );
_ASSERT( hWnd != NULL );
//其中 lpszClassName 是對話框的窗口類名。
那怎麼樣實現自已定制的對話框類呢! 看過《深入淺出MFC》的讀者一定會想到,在重載 CWinApp 的 InitInstance()函數中進行修改 ,不錯,確實要在這兒修改。
// 在派生類的 InitIntace() 中
BOOL CLimitDlgInstanceApp::InitInstance()
{
WNDCLASS wc;
// Get the info for this class。
// #32770 is the default class name for dialogs boxes。
::GetClassInfo(AfxGetInstanceHandle(), "#32770", &wc);
// Change the name of the class。
wc。lpszClassName = "MyPrivateClassName";
// Register this class so that MFC can use it。
AfxRegisterClass(&wc);
// ......
}
這裡采用的方法是在產生注冊窗口時,將注冊窗口的窗口類名修改。再重新注冊窗口類,一切看來很順利,也不是非常難的操作,但是一切都如你預期一樣麼。很不辛,你再打開 Spy++ 觀察窗口的時候 ,仍是 "#32770(Dialog)"。
好了,你有其它辦法嗎? MSDN在這個時候還是最有用的,缺少 MSDN 就如在沒有槳的船,MSDN 中提供了兩種方法讓我們可以定制自已的對話框窗口類。
第一種:
1、打開這個對話框工程文件,打開 ResourceView。
2、打開 Resource Editor,右擊對話框,選擇選項 Properties,在對話框的屬性項中 ,最下角是一個類名的輸入項, 但是這一個選項是禁止的, 你無法在些輸入類名, 因為你在這裡是選擇了 MFC 類庫的
支持。為了使這個選項可以輸入。如圖所示,在Resource View 的最頂項選擇右鍵->屬性,就會彈出
一個資源文件屬性對話框,把其中的 Enable MFC Features 的項設為禁止, 則對話框的類名就可以在在資源編輯器中設定了。(在Visual C++ 。NET,設置 MFC Mode property 屬性為 FALSE)
第二種可供選擇的方法就是修改 RC 文件和源代碼! 在 CWinApp 的派生類的 Initinstance 函數中進行修改:
// 在派生類的 InitIntace() 中
BOOL CLimitDlgInstanceApp::InitInstance()
{
WNDCLASS wc;
// Get the info for this class。
// #32770 is the default class name for dialogs boxes。
::GetClassInfo(AfxGetInstanceHandle(), "#32770", &wc);
// Change the name of the class。
wc。lpszClassName = "MyPrivateClassName";
// Register this class so that MFC can use it。
AfxRegisterClass(&wc);
// ......
}
其中 ::GetClassInfo 保證了即使你的資源文件在不同的 Dll 中也能正確得到 HINSTANCE 跟著就是要修改資源文件了,用文本編輯器打開 rc 文件 ,加上" ClASS 類名 "如下圖所示:
注意,如果你 rc 文件中的類名與 Initinstance 中的類名不一致,程序不會運行,這是非常重要的。切記。
結束語:
這只是一個小技巧,希望對於大家的開發有所幫助,例如在開發基於對話框的程序中,使應用程序只有一個運行實例,注冊唯一的窗口類是非常有用的。或作一個進行程序監控的 時候,可以進行快速定位。