MFC中listbox通过消息传递过来的内容显示顺序怎样让其后添加进去的在后边
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC中listbox通过消息传递过来的内容显示顺序怎样让其后添加进去的在后边相关的知识,希望对你有一定的参考价值。
listbox要设置成不排序 参考技术A insertItem(m_list.GetItemCount,"内容")MFC原理第六讲.消息传递
---恢复内容开始---
MFC原理第六讲.消息传递
一丶简介
通过上一讲我们的消息映射表.我们得知. 消息映射表 会保存父类的MessageMap 以及自己当前的消息结构体数组.
消息传递是一层一层的递进的.那么我们现在要看一下怎么递进的.
要学习的知识
1.窗口创建的流程.以及默认的回调函数
2.消息处理流程
二丶窗口创建的流程.以及默认的回调函数
我们要看窗口创建.那么就需要跟进 MFC源码去看. 首先就是对我们的Create函数下断点.看一下做了什么事情.
进入Create函数内部.
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. "); 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. "); if (hMenu != NULL) DestroyMenu(hMenu); return FALSE; } return TRUE; }
CreateEx查看. 窗口过程处理函数.
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 ", 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; }
总结: 通过上面代码我们得知了.窗口在创建的时候以及窗口回调进行的一些列设置
1.调用Create创建窗口
2.设置窗口类.
3.注册窗口类.
4.通过AfxHookWindowsCreate 将我们的默认窗口回调改成了 afxWndProc
5.窗口创建完毕.
上面五条则是我们创建窗口的时候进行的一系列操作. 所以我们的消息处理函数变成了 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; }
第n层.因为不重要了.所以我们栈回朔到最顶层即可.
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); }
以上是关于MFC中listbox通过消息传递过来的内容显示顺序怎样让其后添加进去的在后边的主要内容,如果未能解决你的问题,请参考以下文章