一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

WM_NOTIFY與消息反射—耗費我兩天時間才解決的問題

 DCW 2010-12-16
關于WM_NOTIFY與消息反射—耗費我兩天時間才解決的問題
www. 時間 : 2010-06-22 作者:佚名 編輯:壹枝雪糕 點擊: 1306 [ 評論 ]
綜合資源電子書社區(qū) 其實,問題很簡單,我想在listctrl響應NM_SETFOCUS的同時通知其父窗口(其實我這句話說錯了,listctrl只能響應=NM_SETFOCUS,為什么有個“=”呢?稍后解釋),最幼稚的想法是讓在listctrl和父窗口中都添加對此消息的響應,很不幸,我在一開始就是這么想的-_-| 。。。很明顯我失敗了!
后來我又發(fā)現(xiàn),如果在listctrl中添加對=NM_SETFOCUS的響應,父窗口就無法響應NM_SETFOCUS,反之就可以響應。于是很容易想到在listctrl的消息響應中SendMessage給父窗口,控件發(fā)送的消息有兩種:WM_COMMAND和WM_NOTIFY,像button,edit,combobox等控件,主要使用WM_COMMAND消息,而listctrl這類控件主要使用WM_NOTIFY消息,發(fā)送消息時有兩個很重要的參數(shù)wParam和lParam,MSDN說明如下:
lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) WM_NOTIFY, // message ID
(WPARAM) wParam, // = (WPARAM) (int) idCtrl;
(LPARAM) lParam // = (LPARAM) (LPNMHDR) pnmh;
);
結果我還是失敗了!折騰了一天一夜,直到晚上熄燈,我就不信我弄不出來,第二天上CSDN求救,有一個同志的回答提醒了我:消息反射。消息反射是個什么東西,我還是第一次聽到,看來我真是菜鳥。于是查閱了一下消息反射的資料,原來,控件根本無法直接給自己發(fā)送消息,這樣就導致控件無法控制自己,所有的控制必須在父窗口類中實現(xiàn),這樣不符合面向對象的思想,于是出現(xiàn)了消息反射;即子控件發(fā)送給父窗口的消息被父窗口馬上反射回來,如果子控件響應了反射消息,父窗口就不響應,反之則響應。這就和我剛才發(fā)現(xiàn)的現(xiàn)象吻合了。
 那么,消息反射是怎樣實現(xiàn)的呢?源代碼說明一切!父窗口在接收到子控件的通知消息時調用虛的消息響應函數(shù)CWnd::OnNotify(),代碼如下:
BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
{
 ASSERT(pResult != NULL);
 NMHDR* pNMHDR = (NMHDR*)lParam;
 HWND hWndCtrl = pNMHDR->hwndFrom;
 // get the child ID from the window itself
 UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
 int nCode = pNMHDR->code;
 ASSERT(hWndCtrl != NULL);
 ASSERT(::IsWindow(hWndCtrl));
 if (_afxThreadState->m_hLockoutNotifyWindow == m_hWnd)
 return TRUE; // locked out - ignore control notification
 // reflect notification to child window control
 if (ReflectLastMsg(hWndCtrl, pResult))
 return TRUE; // eaten by child
 AFX_NOTIFY notify;
 notify.pResult = pResult;
 notify.pNMHDR = pNMHDR;
 return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), &notify, NULL);
}
接著看ReflectLastMsg()函數(shù):
BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
{
 // get the map, and if no map, then this message does not need reflection
 CHandleMap* pMap = afxMapHWND();
 if (pMap == NULL)
 return FALSE;
 // check if in permanent map, if it is reflect it (could be OLE control)
 CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
 ASSERT(pWnd == NULL || pWnd->m_hWnd == hWndChild);
 if (pWnd == NULL)
 {
#ifndef _AFX_NO_OCC_SUPPORT
 // check if the window is an OLE control
 CWnd* pWndParent = (CWnd*)pMap->LookupPermanent(::GetParent(hWndChild));
 if (pWndParent != NULL && pWndParent->m_pCtrlCont != NULL)
 {
 // If a matching control site exists, it''s an OLE control
 COleControlSite* pSite = (COleControlSite*)pWndParent->
 m_pCtrlCont->m_siteMap.GetValueAt(hWndChild);
 if (pSite != NULL)
 {
 CWnd wndTemp(hWndChild);
 wndTemp.m_pCtrlSite = pSite;
 LRESULT lResult = wndTemp.SendChildNotifyLastMsg(pResult);
 wndTemp.m_hWnd = NULL;
 return lResult;
 }
 }
#endif //!_AFX_NO_OCC_SUPPORT
 return FALSE;
 }
 // only OLE controls and permanent windows will get reflected msgs
 ASSERT(pWnd != NULL);
 return pWnd->SendChildNotifyLastMsg(pResult);
}
注意紅色代碼!此時調用的是子控件的SendChildNotifyLastMsg() 。繼續(xù)看SendChildNotifyLastMsg():
BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)
{
 _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
 return OnChildNotify(pThreadState->m_lastSentMsg.message,
 pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam, pResult);
}
調用子控件的虛函數(shù)OnChildNotify函數(shù),進行處理。 如果沒有處理,則調用ReflectChildNotify(...)函數(shù)進行標準的反射消息的消息映射處理。 如果在ReflectChildNotify(...)中此消息還沒被處理,就返回到CWnd::OnNotify(...)中調用OnCmdMsg(...)處理,這樣,父窗口就可以響應此消息了。
 下面回到我最初的問題中來,我想在listctrl和父窗口中都處理此消息,因此我們可以重載OnNotify(...)如下:
BOOL CWellListView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
 // TODO: Add your specialized code here and/or call the base class
 ASSERT(pResult != NULL);
 NMHDR* pNMHDR = (NMHDR*)lParam;
 HWND hWndCtrl = pNMHDR->hwndFrom;
 
ReflectLastMsg(hWndCtrl, pResult);
 
UINT nID = _AfxGetDlgCtrlID(hWndCtrl);
 int nCode = pNMHDR->code;
 
AFX_NOTIFY notify;
 notify.pResult = pResult;
 notify.pNMHDR = pNMHDR;
 return OnCmdMsg(nID, MAKELONG(nCode, WM_NOTIFY), &notify, NULL);
 }//CWellListView繼承子CFormView,相當與對話框
還要添加兩個頭文件:
#include "AFXPRIV.H"
#include "C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC\AFXIMPL.H"
看到它和CWnd::OnNotify(...)的區(qū)別了沒?恩,就是這樣!
 但是,很不幸,我最終沒有采取這種辦法,因為我在一開始就沒有想到最佳方案,我完全可以用指針來實現(xiàn)我的需求,在子控件類中需要的地方添加如下代碼就可以操作父窗口了:
CWellListView* listview=(CWellListView*)GetParent();
 因此,在以后的編程學習中,我們應該盡量用指針操作來代替發(fā)送消息來實現(xiàn)我們的需求!

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产亚洲欧美自拍中文自拍| 亚洲欧美日韩国产成人 | 少妇人妻精品一区二区三区| 中文字幕中文字幕一区二区| 91欧美激情在线视频| 国产乱淫av一区二区三区| 欧美性高清一区二区三区视频 | 女厕偷窥一区二区三区在线| 中文字幕一二区在线观看| 亚洲高清中文字幕一区二三区| 国产高清一区二区不卡| 国产精品视频一区二区秋霞| 国产av大片一区二区三区| 国产日韩熟女中文字幕| 久草视频这里只是精品| 91天堂免费在线观看| 亚洲欧美日韩在线看片| 91日韩在线视频观看| 精品人妻久久一品二品三品| 免费啪视频免费欧美亚洲| 国产一级精品色特级色国产| 精品国产一区二区欧美| 久久99热成人网不卡| 日本少妇aa特黄大片| 丁香七月啪啪激情综合| 久久99这里只精品热在线| 日本一品道在线免费观看| 亚洲中文字幕视频在线播放| 欧美日韩国产黑人一区| 国产麻豆一区二区三区在| 欧洲精品一区二区三区四区| 日本高清不卡一二三区| 中文字幕在线区中文色| 开心久久综合激情五月天| 人妻偷人精品一区二区三区不卡| 这里只有九九热精品视频| 天堂av一区一区一区| a久久天堂国产毛片精品| 91精品日本在线视频| 色综合久久超碰色婷婷| 91亚洲国产成人久久|