金山衛士開原始碼—-訊息機制淺析 (上

來源:互聯網
上載者:User

部落格已遷移至:http://kulv.sinaapp.com/,這裡不再使用

金山衛士開原始碼----訊息機制淺析 (上)

 

代碼地址:http://download.csdn.net/source/3301518

 

 今天簡化了金山的開原始碼,用來學習一下,先謝謝金山的開源精神了,呵呵···直接弄最簡單的,視窗見,關鍵代碼如下,全部的代碼放附件裡吧。分析中關於累的繼承機制等沒有詳細的說明了,在函數申明中我會用SON: public BASE ::Func() 的方式指出的.今天主要學習一下其訊息機制和路由。因為沒有學過ATL,所以理解錯了希望大家指教一下哦···
先謝謝了,呵呵···

 

///////////////////////////////////////////////////////////////////////////////<br />//Main.cpp<br />int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow) {<br />if ( FAILED( _Module.Init( hInstance ) ) )<br />return -1;<br />::CoInitializeEx( NULL , COINIT_APARTMENTTHREADED );</p><p>_Module.Run( );<br />_Module.Uninit( );</p><p>::CoUninitialize( );<br />return 0;<br />}</p><p>HRESULT KAppModule::Init( HINSTANCE hInstance ) {<br />HRESULT hRet = __super::Init( NULL, hInstance );<br />if ( FAILED(hRet) )<br />return hRet;<br />return hRet;<br />}<br />HRESULT KAppModule::Run( ) {<br />_InitUIResource( );//載入各種資源,從XML中<br />if ( m_hModRichEdit2 == NULL )<br />m_hModRichEdit2 = ::LoadLibrary( _T( "RICHED20.DLL" ) );<br />//顯示對話方塊<br />CKulvDlg wdlg ;<br />return wdlg.DoModal( ) ;<br />}</p><p>void KAppModule::_InitUIResource() {//載入各種資源,從XML中<br />BkFontPool::SetDefaultFont(_T("宋體"),-12);<br />BkSkin::LoadSkins(IDR_SKIN_DEF);<br />BkStyle::LoadStyles(IDR_STYLE_DEF);<br />BkString::Load(IDR_STRING_DEF);<br />}</p><p>//DLG.h<br />#pragma once<br />class CKulvDlg<br />: public CBkDialogImpl<CKulvDlg><br />{<br />public:<br />CKulvDlg()<br />: CBkDialogImpl<CKulvDlg>(IDR_WARMING_DLG){//IDR_WARMING_DLG : 107, "res//warning_dlg.xml")<br />}<br />~CKulvDlg();<br />protected:<br />BOOLOnInitDialog(CWindow /*wndFocus*/ , LPARAM /*lInitParam*/ );<br />voidOnBtnClose( );<br />voidOnBtnClickText( );<br />public:<br />BK_NOTIFY_MAP(IDC_RICHVIEW_WIN)<br />BK_NOTIFY_ID_COMMAND(100, OnBtnClose)<br />BK_NOTIFY_ID_COMMAND(101, OnBtnClickText)<br />BK_NOTIFY_MAP_END()</p><p>BEGIN_MSG_MAP_EX(CKulvDlg)<br />MSG_BK_NOTIFY(IDC_RICHVIEW_WIN)<br />CHAIN_MSG_MAP(CBkDialogImpl<CKulvDlg>)<br />MSG_WM_INITDIALOG(OnInitDialog)<br />END_MSG_MAP()</p><p>};<br />//DLG.cpp<br />#include "stdafx.h"<br />#include "DLG.h"</p><p>CKulvDlg::~CKulvDlg(){<br />}</p><p>BOOL CKulvDlg::OnInitDialog(CWindow /*wndFocus*/, LPARAM /*lInitParam*/){<br />return TRUE;<br />}</p><p>void CKulvDlg::OnBtnClose(){<br />__super::EndDialog(IDOK);<br />}</p><p>void CKulvDlg::OnBtnClickText(){<br />DontShowWindow() ;<br />CString str = CString(__FILE__) ;<br />str.Format(TEXT("%s : %d"),str.GetBuffer() , __LINE__) ;<br />MessageBox(str);<br />}<br />

 

/////////////////////////////////////////////////////////////////////////////////
/*我們來看如下訊息機制的宏替換,容易看出,其酷像MFC的宏!開始我還看錯了呢,呵呵*/

BK_NOTIFY_MAP(IDC_RICHVIEW_WIN)<br />BK_NOTIFY_ID_COMMAND(100, OnBtnClose)<br />BK_NOTIFY_ID_COMMAND(101, OnBtnClickText)<br />BK_NOTIFY_MAP_END()

/*如上宏聲明替換後實際上就是在類裡面添加了下面這樣的訊息分配機制也就是根據控制項的ID來一個個比較,然後調用相應控制項的處理函數,這個函數就是我們在宏申明的時候指定的。
*/

LRESULT CKulvDlg::OnBkNotify_1000(LPNMHDR pnmh) {<br />UINT_PTR uCode = pnmh->code;<br />if (BKNM_COMMAND == uCode && 100 == ((LPBKNMCOMMAND)pnmh)->uItemID)<br />{<br />OnBtnClose();<br />return TRUE;<br />}<br />if (BKNM_COMMAND == uCode && 101 == ((LPBKNMCOMMAND)pnmh)->uItemID)<br />{<br />OnBtnClickText();<br />return TRUE;<br />}<br />SetMsgHandled(FALSE);<br />return FALSE;<br />}

 

///////////////////////////////////////////////////////////////////////////////<br />///////////////<br />/*在對話方塊類中,還有如下宏申明,看看其到底是什麼吧*/<br />BEGIN_MSG_MAP_EX(CKulvDlg)<br />MSG_BK_NOTIFY(IDC_RICHVIEW_WIN)<br />CHAIN_MSG_MAP(CBkDialogImpl<CKulvDlg>)<br />MSG_WM_INITDIALOG(OnInitDialog)<br />END_MSG_MAP()</p><p>/*替換後變成如下代碼:*/<br />//BEGIN_MSG_MAP_EX(CKulvDlg)<br />public:<br />BOOL m_bMsgHandled;<br />/* "handled" management for cracked handlers */<br />BOOL IsMsgHandled() const {<br />return m_bMsgHandled;<br />}<br />void SetMsgHandled(BOOL bHandled) {<br />m_bMsgHandled = bHandled; //設定訊息處理狀態<br />}<br />BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,<br />LRESULT& lResult, DWORD dwMsgMapID = 0)<br />{ //本對話方塊所有的訊息處理從這開始<br />BOOL bOldMsgHandled = m_bMsgHandled;<br />BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult,<br />dwMsgMapID);<br />m_bMsgHandled = bOldMsgHandled;<br />return bRet;<br />}<br />BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam<br />, LRESULT& lResult, DWORD dwMsgMapID)<br />{ //下面就是短短的訊息長征了,相對於複雜的MFC<br />BOOL bHandled = TRUE;<br />hWnd;<br />uMsg;<br />wParam;<br />lParam;<br />lResult;<br />bHandled;<br />switch(dwMsgMapID)<br />{<br />case 0:<br />//MSG_BK_NOTIFY(IDC_RICHVIEW_WIN)<br />if (uMsg == WM_NOTIFY && 1000 == ((LPNMHDR)lParam)->idFrom)<br />{ //第一步,如果是控制項通告訊息,那麼訊息處理函數是:<br />//OnBkNotify_1000,別忘了,這個東西我們上面說過的,那裡還有所以的控制項訊息映射<br />//實際上就是根據ID,一個個找。<br />SetMsgHandled(TRUE);<br />lResult = OnBkNotify_1000((LPNMHDR)lParam);<br />if(IsMsgHandled())<br />return TRUE;<br />}<br />//CHAIN_MSG_MAP(CBkDialogImpl<CKulvDlg>)<br />if( CBkDialogImpl<CKulvDlg>::ProcessWindowMessage(hWnd, uMsg, wParam, lParam<br />, lResult) )<br />return TRUE; </p><p>//給父類處理一下,我不明白為何這麼早給父類幹嘛,如果有些我們要自己處理呢?哦,這樣沒事的<br />//MSG_WM_INITDIALOG(OnInitDialog)<br />if (uMsg == WM_INITDIALOG)<br />{ //實際上父類沒有處理WM_INITDIALOG訊息,所以一定傳到這裡了,進行自訂初始化<br />SetMsgHandled(TRUE);<br />lResult = (LRESULT)OnInitDialog((HWND)wParam, lParam);<br />if(IsMsgHandled())<br />return TRUE;<br />}<br />//MSG_WM_INITDIALOG(OnInitDialog)<br />break;<br />default://使用者ID寫錯了,那麼在輸出視窗列印錯誤訊息,以便調試<br />ATLTRACE(ATL::atlTraceWindowing, 0, _T("Invalid message map ID (%i)/n"),<br />dwMsgMapID);<br />ATLASSERT(FALSE);<br />break;<br />} //訊息“長征正式結束”<br />return FALSE;<br />}

 

 /*這個訊息分配方法清除了,那驅動在哪呢?對,從源頭開始找吧。下面的函數一般在Winmain裡面調用,是主要的函數,其他都是些初始化什麼的*/

HRESULT KAppModule::Run( )<br />{<br />_InitUIResource( );//這地方初始化各種UI庫什麼的,下回再仔細看看<br />//金山介面庫是如何用XML實現的,不過應該基本也是封裝各種Win32 API<br />if ( m_hModRichEdit2 == NULL )<br />m_hModRichEdit2 = ::LoadLibrary( _T( "RICHED20.DLL" ) );</p><p>CKulvDlg wdlg ;<br />return wdlg.DoModal( ) ;<br />//從這裡開始吧,我們的自訂子類一般不會重定義這個函數,到父類中,看下面:</p><p>}<br />//CBkDialogImpl : public CWindowImpl <T, TBase, TWinTraits></p><p>UINT_PTR CBkDialogImpl::DoModal(HWND hWndParent = NULL, LPRECT rect = NULL)<br />{<br />//····這裡省略··字<br />//Create函數載入了XML資源,然後設定了視窗什麼的,下回在看這部分,專註,專註···<br />HWND hWnd = Create(hWndParent, rect);<br />//····這裡省略··字<br />_ModalMessageLoop();//···看下面<br />//····這裡省略··字<br />DestroyWindow();<br />return m_uRetCode;<br />}</p><p>void CBkDialogImpl::_ModalMessageLoop()<br />{<br />BOOL bRet;<br />MSG msg;<br />for(;;)<br />{//這個迴圈很長····直到接收到WM_QUIT,break為止<br />if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))<br />{//PeekMessage和GetMessage什麼區別去了?對,後者過門不入<br />if (WM_QUIT == msg.message)<br />break;<br />}<br />//···<br />::TranslateMessage(&msg);<br />::DispatchMessage(&msg);<br />}<br />}

 

/*這···無限迴圈取得訊息,這已經到作業系統API層了,那麼具體的DispatchMessage是發給哪個函數去分發了呢??對,某大作說過,Create,RegisterWindow,那一定有一個訊息驅動函數,我們得告訴作業系統的,而且是個回呼函數,by the way ,為什麼要做成回呼函數?直接在dispathMessage 裡我們調不就行了嗎?···恩,侯捷說過,作業系統想有點控制權。
 下面繼續*/


 /*先說下哦,因為我沒看過ATL,WTL,所以不知道哪些部分是屬於庫的,暫且就這樣走到根吧···
 經過訊息追蹤,發現每次DispatchMessage的時候,下一個被調用的使用者自訂函數是:
 c:/Program Files/Microsoft Visual Studio 9.0/VC/atlmfc/include/atlwin.h中的3072行:
 LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)*/

template <class TBase, class TWinTraits><br />LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits ><br />::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)<br />{<br />CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)_AtlWinModule.ExtractCreateWndData();<br />//···<br />pThis->m_hWnd = hWnd;<br />pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);<br />WNDPROC pProc = pThis->m_thunk.GetWNDPROC();<br />WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);<br />//···<br />return pProc(hWnd, uMsg, wParam, lParam);<br />}<br />virtual WNDPROC template <class TBase, class TWinTraits><br />LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits ><br />::GetWindowProc(){<br />return WindowProc;<br />}

 

 

/*實際上StartWindowProc調用的是WindowProc
 c:/Program Files/Microsoft Visual Studio 9.0/VC/atlmfc/include/atlwin.h中的3072行:
 LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 WindowProc,對,這個函數名我們非常熟悉了!!
 對,由此可知,StartWindowProc一定是我們要找的回呼函數,CALLBACK不就告訴我們了嘛,呵呵,其申明也確實是靜態:
 static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 下面貼一下代碼看看:
 */

 

template <class TBase, class TWinTraits><br />LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)<br />{<br />/*把視窗控制代碼強制轉換成基類指標,為什麼呢?首先這個視窗控制代碼應該是視窗類別的首地址?<br />這是window系統的實現方式,許多控制代碼其實都是虛擬位址*/<br />CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;<br />//····此處省略幾行<br />/*注意,ProcessWindowMessage是一個虛函數,<br />所以···實際上調用的是我們自訂的視窗類別!!於是訊息路由跑到我們的CKulvDlg中了,<br />這一點之前的宏展開說過。不過還得提一下,訊息從CKulvDlg中會一步步的往基類中走<br />只要沒被處理,最終如果運氣實在···,還沒處理,那就返回吧···*/<br />BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);<br />//····<br />if(!bRet)<br />{//如果訊息還沒被處理,那麼進入DefWindowProc,如果不是WM_NCDESTROY<br />if(uMsg != WM_NCDESTROY)<br />lRes = pThis->DefWindowProc(uMsg, wParam, lParam);<br />else<br />{//下面準備退出了<br />// unsubclass, if needed<br />LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);<br />lRes = pThis->DefWindowProc(uMsg, wParam, lParam);<br />if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)<br />::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);<br />// mark window as destryed<br />//上面一注釋不是我寫的哦,ATL設計者竟然不小心把destroyed寫錯了,呵呵···<br />pThis->m_dwState |= WINSTATE_DESTROYED;<br />}<br />}<br />//····<br />return lRes;<br />}<br />/*值得說明一下的是: ProcessWindowMessage是一個虛函數.<br />的嗎?宏定義裡面沒寫virtual,但是其基類裡面有就夠了,如下<br />基類CBkWindow中有如下宏定義,確實是虛函數,放心了。*/<br />class CBkWindow BKWIN_BEGIN_MSG_MAP(): public CBkObject<br />#define BKWIN_BEGIN_MSG_MAP() /<br />protected:/<br />virtual BOOL ProcessWindowMessage(/<br />HWND hWnd, UINT uMsg, WPARAM wParam,/<br />LPARAM lParam, LRESULT& lResult)/<br />{

 

 

 

/*讀者看到這也基本明白了這訊息映射的路由。不過總感覺有點彆扭,為什麼訊息處理函數是StartWindowProc??? 誰告訴windows的?作業系統怎麼知道的??那咱們繼續吧:沒記錯的話我們之前說DoModal的時候有如下一句
 HWND hWnd = Create(hWndParent, rect);
  //····這裡省略··字 被我故意省略了很多字···
 下面補上吧,看代碼
  */

 見下文http://blog.csdn.net/hw_henry2008/archive/2011/05/22/6438183.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.