📄 映射.txt
字号:
//定义一个消息映射的结构
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
//通过链表,把整个消息映射连起来,形成表.为了在各个类之间进行路由
struct AFX_MSGMAP
{
const AFX_MSGMAP* pBaseMap;
const AFX_MSGMAP_ENTRY* lpEntries;
};
When there is a message send to a application,it will follow the following orders:
1.LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); //CWnd的指针和handle相关联
2.LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg, WPARAM wParam = 0, LPARAM lParam = 0)
pWnd->WindowProc(nMsg, wParam, lParam); //调用CWnd的WindowProc来进行真正意义上的消息处理.
3.LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
//窗口过程函数被CWnd类的WindowProc代替
4.BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
// special case for commands
if (message == WM_COMMAND)
{
if (OnCommand(wParam, lParam))
{
lResult = 1;
goto LReturnTrue;
}
return FALSE;
}
// special case for notifies
if (message == WM_NOTIFY)
{
NMHDR* pNMHDR = (NMHDR*)lParam;
if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
goto LReturnTrue;
return FALSE;
}
. . . . . . . .
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
5.const AFX_MSGMAP* theClass::GetMessageMap() const
{
return &theClass::messageMap;
}
6.AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap =
{
&baseClass::messageMap, &theClass::_messageEntries[0]
};
7.AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] =
{
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },
{ WM_MOUSEMOVE, 0, 0, 0, AfxSig_vwp,(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, CPoint))&OnMouseMove },
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};
//5. 6. 7. 就是相应类的BEGIN_MSG_MAP 和 END_MSG_MAP的作用.作用就是让类对象得到MessageEntries一个数组,和一个连接类的指针
8. if((lpEntry=AfxFindMessageEntry(pMessageMap->lpEntries,message,0,0)!=NULL)
//搜寻关联类的MessgeEntries,头指针是lpEntries,如果搜到,关联message和function
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9.上面说的是windows标准消息相应机制,下面说一下WM_COMMAND消息,上面有一个if这么写到:
// special case for commands
if (message == WM_COMMAND)
{
if (OnCommand(wParam, lParam))
{
lResult = 1;
goto LReturnTrue;
}
return FALSE;
}
对于命令消息,实际上是交给OnCommand函数处理。而OnCommand是一个虚函数,即WM_COMMAND消息发生时,
最终是发生该消息所对应的MFC对象去执行OnCommand。比如点框架窗口菜单,即向CFrameWnd发送一个WM_COMMAND,
将会导致CFrameWnd::OnCommand(wParam,lParam)
且看该函数原型
BOOL CFrameWnd::OnCommand(WPARAM wParam,LPARAM lParam)
{
……
return CWnd:: OnCommand(wParam,lParam);
}
可以看出,它最后把该消息交给CWnd:: OnCommand处理。再看:
BOOL CWnd::OnCommand(WPARAM wParam,LPARAM lParam)
{
……
return OnCmdMsg(nID,nCode,NULL,NULL);
}
这里包含了一个C++多态性很经典的问题。在这里,虽然是执行CWnd类的函数,但由于这个函数在CFrameWnd:: OnCmdMsg
里执行,即当前指针是CFrameWnd类指针,再有OnCmdMsg是一个虚函数,所以如果CFrameWnd改写了OnCommand,程序会
执行CFrameWnd::OnCmdMsg(…)。
对CFrameWnd::OnCmdMsg(…)函数原理扼要分析如下:
BOOL CFrameWnd:: OnCmdMsg(…)
{
CView pView = GetActiveView();//得到活动视指针。
if(pView-> OnCmdMsg(…))
return TRUE; //如果CView类对象或其派生类对象已经处理该消息,则返回。
……//否则,同理向下执行,交给文档、框架、及应用程序执行自身的OnCmdMsg。
}
到此,CFrameWnd:: OnCmdMsg完成了把WM_COMMAND消息传递到视对象、文档对象及应用程序对象实现消息响应。
注释:在这里可以看到:接受WM_COMMAND消息的几个基本类的顺序,View->Document->CFrame->App,所以如果重复定义了
多个同样的WM_COMMAND给几个类,只会有一个类做出相应,安装上面的顺序来进行相应
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -