MFC原理第六讲.消息传递
2021-06-30 14:06
标签:mfc when thread 操作 down atom 函数 deb sage ---恢复内容开始--- 通过上一讲我们的消息映射表.我们得知. 消息映射表 会保存父类的MessageMap 以及自己当前的消息结构体数组. 消息传递是一层一层的递进的.那么我们现在要看一下怎么递进的. 要学习的知识 1.窗口创建的流程.以及默认的回调函数 2.消息处理流程 我们要看窗口创建.那么就需要跟进 MFC源码去看. 首先就是对我们的Create函数下断点.看一下做了什么事情. 进入Create函数内部. CreateEx查看. 窗口过程处理函数. 新的结构 新的类跟注册窗口的时候很相似. 我们看一下窗口回调在哪里设置的吧. 窗口回调函数 是通过 看一下函数内部 总结: 通过上面代码我们得知了.窗口在创建的时候以及窗口回调进行的一些列设置 1.调用Create创建窗口 2.设置窗口类. 3.注册窗口类. 4.通过AfxHookWindowsCreate 将我们的默认窗口回调改成了 afxWndProc 5.窗口创建完毕. 上面五条则是我们创建窗口的时候进行的一系列操作. 所以我们的消息处理函数变成了 afxWndProc了这个消息处理函数就会在发生消息的时候第一个来到. 通过上面我们得知了窗口处理回调已经更改了. 现在我们直接对我们的消息下段点.就可以验证一下.是否是我们的函数首次来到. 对我们的按钮点击下段点. 通过栈回朔一层一层往上看. 第一层 第一层级就是判断我们的消息.进行不同的处理. 所以不重要.跳过. 第二层消息处理层 第n层.因为不重要了.所以我们栈回朔到最顶层即可. MFC原理第六讲.消息传递 标签:mfc when thread 操作 down atom 函数 deb sage 原文地址:https://www.cnblogs.com/iBinary/p/9641589.html MFC原理第六讲.消息传递
一丶简介
二丶窗口创建的流程.以及默认的回调函数
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{
HMENU hMenu = NULL;
if (lpszMenuName != NULL) //首先判断我们有彩蛋吗.如果有加载我们的菜单.
{
// load in a menu that will get destroyed when window gets destroyed
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, ATL_RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
}
m_strTitle = lpszWindowName; // save title for later
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, //内部还是调用的CreateEx函数.所以我们继续跟进去查看.
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
AfxIsValidAtom(lpszClassName));
ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
// allow modification of several common create parameters
CREATESTRUCT cs; //熟悉的窗口类创建但是是一个新的结构.
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth; //其中高版本在这里就会设置默认的窗口回调.
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
if (!PreCreateWindow(cs)) //内部进行风格设置以及注册窗口类.
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this); //Hook 窗口回调函数.设置窗口回调函数. Create消息来到的时候
HWND hWnd = CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
#ifdef _DEBUG
if (hWnd == NULL)
{
TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
GetLastError());
}
#endif
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
return TRUE;
}
typedef struct tagCREATESTRUCTA {
LPVOID lpCreateParams;
HINSTANCE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCSTR lpszName;
LPCSTR lpszClass;
DWORD dwExStyle;
} CREATESTRUCTA, *LPCREATESTRUCTA;
AfxHookWindowCreate 函数来进行设置.而这个函数本身就是一个Windows自带的HOOK. 其真正的窗口回调函数.是在内部中.设置回调的时候 新的回调函数进行设置的.
void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_pWndInit == pWnd)
return;
if (pThreadState->m_hHookOldCbtFilter == NULL)
{
pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT, //设置CBT HOOK . _AfxCbtFilterHook里面才是真正的替换窗口过程处理函数.
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
if (pThreadState->m_hHookOldCbtFilter == NULL)
AfxThrowMemoryException();
}
ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);
ASSERT(pWnd != NULL);
ASSERT(pWnd->m_hWnd == NULL); // only do once
ASSERT(pThreadState->m_pWndInit == NULL); // hook not already in progress
pThreadState->m_pWndInit = pWnd;
}
LRESULT CALLBACK
_AfxCbtFilterHook( int code, WPARAM wParam, LPARAM lParam) {
// …
WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,(DWORD_PTR)afxWndProc); //重要的位置就是这里.使用的SetWindowLong这个函数.将窗口过程函数替换为了 afxWndProc
// …
}
WNDPROC AFXAPI AfxGetAfxWndProc() {
// …
return & AfxWndProc;
}
三丶消息处理流程
这一层就是我们要进行的消息处理的一层.如果消息不处理则默认交给默认的处理函数进行处理LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// OnWndMsg does most of the work, except for DefWindowProc call
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, &lResult))
lResult = DefWindowProc(message, wParam, lParam);
return lResult;
}
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);
ASSERT(pWnd != NULL);
ASSERT(pWnd==NULL || pWnd->m_hWnd == hWnd);
if (pWnd == NULL || pWnd->m_hWnd != hWnd)
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}