小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

SubClassWindow,SubClassDlgItem

 9loong 2010-09-19
http://changyuangu.blog.sohu.com/56717726.html
 

SubClassWindow,SubClassDlgItem

分類: 工作 2007-07-25 09:47

msdn上的解析

CWnd::SubclassWindow
BOOL SubclassWindow( HWND hWnd );

Return Value

Nonzero if the function is successful; otherwise 0.

Parameters

hWnd

A handle to the window.

Remarks

Call this member function to "dynamically subclass" a window and attach it to this CWnd object. When a window is dynamically subclassed, windows messages will route through the CWnd’s message map and call message handlers in the CWnd’s class first. Messages that are passed to the base class will be passed to the default message handler in the window. 

Subclass(子類化)是MFC中最常用的窗體技術(shù)之一。子類化完成兩個工作:一是把窗體類對象attach到一個windows窗體實(shí)體中(即把一個窗體的hwnd賦給該類)。另外就是把該類對象的消息加入到消息路由中,使得該類可以捕獲消息。

例如一個CEdit的派生類CMyEdit 只允許鍵入0-9, A-F, 則我們可以改寫WM_CHAR消息響應(yīng)函數(shù),然后用SubclassWindow子類化到對話框的一個文本框?qū)嶓w上(可用GetDlgItem), 這樣對話框上文本框的消息就會重定向到CMyEdit上。

SubDlgItem 與 SubclassWindow 區(qū)別不大,但前者只限定于對話框控件,后者是一切具有HWND的窗體

一:超類化概述
在MFC中窗體實(shí)例對某個窗體句柄超類化后,系統(tǒng)提供了這樣兩種能力:
1.我們對該窗體實(shí)例調(diào)用成員函數(shù)將會直接改變相關(guān)窗體句柄對應(yīng)的窗體
2.系統(tǒng)傳給相關(guān)窗體句柄的消息會先經(jīng)過該窗體實(shí)例的消息映射

我舉一個例子來說明:
比如我自己寫了一個類叫CSuperEdit(父類為CEdit),在該類中我聲明了void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);并在消息循環(huán)里添加了ON_WM_CHAR 一行
現(xiàn)在我只要在對話框CProg1Dlg 中聲明CSuperEdit m_edit;然后在CProg1Dlg::OnInitDialog中,添加以下代碼,就完成了“超類化”:
HWND hWndControl = ::GetDlgItem(pParent->m_hWnd, IDC_EDIT1);
m_edit.SubclassWindow (hWndControl);

這樣超類化處理以后:
當(dāng)我們調(diào)用m_edit.SetWindowText("<請輸入A、B、C>");,后IDC_EDIT1窗體上對應(yīng)的文字就會改變?yōu)?<請輸入A、B、C>"
當(dāng)用戶在IDC_EDIT1窗體中敲鍵盤時,系統(tǒng)會調(diào)用我自己寫的CSuperEdit::OnChar函數(shù)(而不是原先的CEdit::OnChar)

二:超類化實(shí)現(xiàn)的概述
所有的秘密都在CWnd::SubclassWindow 中,讓我們查看一下它到底做了些什么吧,以下是函數(shù)體(在WINCORE.CPP文件內(nèi)):
BOOL CWnd::SubclassWindow(HWND hWnd)
{
  if (!Attach(hWnd))
     return FALSE;

   // allow any other subclassing to occur
  PreSubclassWindow ();

  // now hook into the AFX WndProc
  WNDPROC* lplpfn = GetSuperWndProcAddr();
  WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)AfxGetAfxWndProc());
  ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());
  return TRUE;
}

結(jié)合注釋不難想到PreSubclassWindow 是非功能性的函數(shù),所以我們只要研究兩個函數(shù)就可以了解CWnd::SubclassWindow 的大概功能 CWnd::Attach和 ::AfxGetAfxWndProc
兩者中當(dāng)中CWnd::Attach 對應(yīng)于實(shí)現(xiàn)了功能1,即“我們對該窗體實(shí)例調(diào)用成員函數(shù)將會直接改變相關(guān)窗體句柄對應(yīng)的窗體”
::AfxGetAfxWndProc函數(shù)對應(yīng)于實(shí)現(xiàn)了功能2,即“系統(tǒng)傳給相關(guān)窗體句柄的消息會先經(jīng)過該窗體實(shí)例的消息映射”

 

三:功能1的實(shí)現(xiàn)
CWnd::Attach 的函數(shù)體如下(在WINCORE.CPP文件內(nèi)):
BOOL CWnd::Attach(HWND hWndNew)
{
  if (hWndNew == NULL)
     return FALSE;

  CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist

  ASSERT(pMap != NULL);
  pMap->SetPermanent(m_hWnd = hWndNew, this);
  return TRUE;
}
最關(guān)鍵的是m_hWnd = hWndNew 一句(接觸過windows的API的朋友都知道,windows系統(tǒng)所有窗體操作函數(shù)都是把窗體句柄作為一個調(diào)用參數(shù)),顯然只要我把窗體的句柄保存下來,那我就可以在系統(tǒng)中唯一地指定一個窗體,然后對該窗體進(jìn)行操作
是的,思路就是這么簡單。我們現(xiàn)在看到CWnd(別忘了CsuperEdit 是從CWnd繼承的,這里的CWnd實(shí)際就是CsuperEdit )在Attach 函數(shù)中把IDC_EDIT1 的句柄保存在了成員變量m_hWnd 中,那么實(shí)現(xiàn)功能1,自然也就不在話下了

至于CHandleMap::SetPermanent 函數(shù)則是用來延長句柄的使用期的,與“超類化”無關(guān),不在此處討論,其具體實(shí)現(xiàn)可參考WINHAND_.H文件

 


四:功能2的實(shí)現(xiàn)
四點(diǎn)一:窗體句柄的GWL_WNDPROC屬性
在前面的討論中,我說過功能2是跟::AfxGetAfxWndProc 有關(guān)的,該函數(shù)的實(shí)現(xiàn)是這樣的(也是在WINCORE.CPP文件中):
WNDPROC AFXAPI AfxGetAfxWndProc()
{
#ifdef _AFXDLL
 return AfxGetModuleState()->m_pfnAfxWndProc;
#else
 return &AfxWndProc;
#endif
}

這是指在DLL中調(diào)用的話返回AfxGetModuleState()->m_pfnAfxWndProc;否則返回AfxWndProc 函數(shù)的地址。于是在一般的可執(zhí)行文件中CWnd::SubclassWindow 為功能2所做的事可以簡化為一行::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)&AfxWndProc);

該函數(shù)的作用是把窗體句柄hWnd 的GWL_WNDPROC 屬性設(shè)置為AfxWndProc 的地址,那么現(xiàn)在急需解決的問題是:窗體句柄的GWL_WNDPROC 屬性是干什么用的?其實(shí)不用我說,大家都猜得到(因?yàn)槲覀兪窃谟懻摯绑w的消息嘛,而且我也一直在說AfxWndProc是一個函數(shù)),它的作用是指定窗體消息的處理函數(shù)
對于該屬性更準(zhǔn)確地描述如下:對于發(fā)給窗體的所有消息,Windows操作系統(tǒng)將會以該消息為參數(shù)調(diào)用窗體句柄的GWL_WNDPROC屬性所指定的函數(shù)


四點(diǎn)二:被傳遞到MFC環(huán)境中
(本節(jié)參考了侯捷老師《深入淺出MFC》中“消息映射與命令傳遞”一章的“兩萬五千里長征”)
于是功能2可以表述為:AfxWndProc函數(shù)是如何找到我為CSuperEdit 類所寫的消息映射的?還是從函數(shù)體出發(fā)
LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
 // special message which identifies the window as using AfxWndProc
 if (nMsg == WM_QUERYAFXWNDPROC)
  return 1;

 // all other messages route through message map
 CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
 return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}

如上所列::AfxWndProc 整個函數(shù)只有四行,顯然它僅僅是包裝了::AfxCallWndProc 函數(shù),只是把hWnd參數(shù)包裝成pWnd,然后轉(zhuǎn)道::AfxCallWndProc。
::AfxCallWndProc該函數(shù)才是真正做了一些事的,但其中與消息傳遞有關(guān)直接關(guān)系的就一句:
LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
 WPARAM wParam = 0, LPARAM lParam = 0)
{
 ...

 // delegate to object's WindowProc
 lResult = pWnd->WindowProc(nMsg, wParam, lParam);

 ...
 return lResult;
}

現(xiàn)在我們已經(jīng)看到通過::AfxWndProc/::AfxCallWndProc 兩個函數(shù)的接力,操作系統(tǒng)中消息被傳遞到MFC環(huán)境中的。
進(jìn)一步的討論可以把所有的目光都集中到LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

 

四點(diǎn)三:總結(jié)
我們看到轉(zhuǎn)機(jī)了:為了實(shí)現(xiàn)不同的函數(shù)調(diào)用,OOP(面對對象編程)本身提供繼承、虛函數(shù)之類的許多的方法。MFC正是一種面對對象的語言

現(xiàn)在CsuperEdit 是繼承自CEdit,CEdit 又繼承自CWnd,我們要讓程序調(diào)用CsuperEdit::OnChar 也就沒什么技術(shù)難度。比如,可以在CWnd中寫一個響應(yīng)鍵盤消息的虛函數(shù) virtual void CWnd::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);,并在CWnd::WindowProc 中調(diào)用OnChar
那么我只要重載CsuperEdit::OnChar 函數(shù),程序自然而然就會調(diào)用我寫的函數(shù)了

微軟為了減小程序文件的體積,做了一些優(yōu)化工作,它未用virtual 修飾符來修飾所有的函數(shù),而是把“要響應(yīng)的消息和相應(yīng)的響應(yīng)函數(shù)”登記在一張MESSAGE_MAP(稱,消息映射)里。
在AFXMSG_.H文件中ON_WM_CHAR 宏定義被為{WM_CHAR, 0, 0, ... &OnChar},它的作用就是把WM_CHAR和當(dāng)前類(現(xiàn)在指CsuperEdit)的OnChar函數(shù),填加到了消息映射的登記表中
既然有了“消息映射”這樣一張的登記表,對于“讓CWnd在接受到WM_CHAR 消息時調(diào)用CsuperEdit::OnChar”的算法和代碼,估計(jì)你我都能在兩小時內(nèi)實(shí)現(xiàn),我就不在此處羅嗦了,至于MFC中的相關(guān)的代碼請參考“深入淺出”一書。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多