【转】MFC消息处理(一)

原文网址:http://blog.csdn.net/hyhnoproblem/article/details/6182120

1、MFC窗口如何与AfxWndProc建立联系。

当一个新的CWnd派生类创建时,在调用CWnd::CreateEx()过程中,MFC都会安装AfxCbtFilterHook()。这个Hook将拦截HCBT_CREATEWND,将窗体的消息处理函数设置为AfxWndProc()。

[cpp] view plaincopy

  1. // wincore.cpp 651
  2. // CWnd::CreateEx函数通过AfxHookWindowCreate函数安插Hook
  3. BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
  4. LPCTSTR lpszWindowName, DWORD dwStyle,
  5. int x, int y, int nWidth, int nHeight,
  6. HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
  7. {
  8. // ...
  9. // 如果cs中窗体类名为空,PreCreateWindow (见wincore.cpp 714) 将调用
  10. // AfxEndDeferRegisterClass (见wincore.cpp 4431)注册默认窗口类,
  11. // 默认注册的窗口消息处理函数是DefWindowProc
  12. if (!PreCreateWindow(cs))
  13. {
  14. PostNcDestroy();
  15. return FALSE;
  16. }
  17. // 安插AfxCbtFilterHook
  18. AfxHookWindowCreate(this);
  19. HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
  20. cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
  21. cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
  22. if (!AfxUnhookWindowCreate())
  23. PostNcDestroy();        // cleanup if CreateWindowEx fails too soon
  24. // ...
  25. }
  26. // wincore.cpp 609
  27. void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
  28. {
  29. _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  30. if (pThreadState->m_pWndInit == pWnd)
  31. return;
  32. if (pThreadState->m_hHookOldCbtFilter == NULL)
  33. {
  34. // 安插_AfxCbtFilterHook,因为_AfxCbtFilterHook()是一个基于计算机训练的hook,
  35. // 所以windows在激活、创建、销毁、最大化、最小化、移动窗口或改变窗口大小之前,
  36. // 会调用_AfxCbtFilterHook()
  37. pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,
  38. _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
  39. if (pThreadState->m_hHookOldCbtFilter == NULL)
  40. AfxThrowMemoryException();
  41. }
  42. pThreadState->m_pWndInit = pWnd;
  43. }

_AfxCbtFilterHook通过SetWindowLongPtr函数将窗口的处理函数替换成AfxWndProc(),同时,在CWnd::m_pfnSuper中保存原来的窗口消息处理函数指针。

[cpp] view plaincopy

  1. // wincore.cpp 472
  2. LRESULT CALLBACK
  3. _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
  4. {
  5. _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  6. if (code != HCBT_CREATEWND)
  7. {
  8. // 如果不是HCBT_CREATEWND消息,直接忽略。接收到该消息意味着窗口要创建了
  9. return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
  10. wParam, lParam);
  11. }
  12. LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
  13. CWnd* pWndInit = pThreadState->m_pWndInit;
  14. BOOL bContextIsDLL = afxContextIsDLL;
  15. if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !bContextIsDLL))
  16. {
  17. // ...
  18. HWND hWnd = (HWND)wParam;
  19. WNDPROC oldWndProc;
  20. if (pWndInit != NULL)
  21. {
  22. AFX_MANAGE_STATE(pWndInit->m_pModuleState);
  23. // connect the HWND to pWndInit...
  24. pWndInit->Attach(hWnd);
  25. // allow other subclassing to occur first
  26. pWndInit->PreSubclassWindow();
  27. // 消息处理函数指针,用于存储原来的消息处理函数
  28. WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr();
  29. // 将窗口的消息处理函数设置成AfxWndProc()
  30. WNDPROC afxWndProc = AfxGetAfxWndProc();
  31. oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,
  32. (DWORD_PTR)afxWndProc);
  33. if (oldWndProc != afxWndProc)
  34. *pOldWndProc = oldWndProc;      // 保存原来的指针
  35. pThreadState->m_pWndInit = NULL;
  36. }
  37. // ...
  38. }
  39. // ...
  40. }
  41. // wincore.cpp 1048
  42. WNDPROC* CWnd::GetSuperWndProcAddr()
  43. {
  44. // Note: it is no longer necessary to override GetSuperWndProcAddr
  45. //  for each control class with a different WNDCLASS.
  46. //  This implementation now uses instance data, such that the previous
  47. //  WNDPROC can be anything.
  48. return &m_pfnSuper;
  49. }
  50. // wincore.cpp 392
  51. WNDPROC AFXAPI AfxGetAfxWndProc()
  52. {
  53. // 静态库版本的消息处理函数
  54. return &AfxWndProc;
  55. }

微软不将AfxWndProc()做为注册窗口过程的原因是DefWindowPorc()可以支持3D控件。这些控件都在微软的CTL3D.dll中。如果系统具有CTL3D功能已经是一种迫切需要,那么应用程序就要覆盖CTL3D的功能(在处理WM_CTLCOLOR消息方面)。为了确保这一点,MFC必须按照以下顺序调用:AfxWndProc()、CTL3D的WndProc()和最后的DefWindowProc()。可见为了确保这一点,微软不得不允许CTL3D在AfxWndProc()之前分类,这就意味着延迟AfxWndProc()的引入。

2、处理消息

MFC用两种方式表示窗口:(1)用统一的系统定义的窗口句柄;(2)用表示窗口的C++类。窗口句柄由CWnd和CWnd的派生类包装。因为窗口句柄是CWnd的成员变量。

MFC用CMapPtrToPtr对象将窗口句柄映射成CWnd对象。MFC在窗口存在期间维护这个链接。如果使用CWnd创建一个窗口,窗口句柄就会和CWnd对象关联在一起,也就是说二者通过句柄映射表关联在一起,MFC这样做就使得框架可以使用C++对象,而不是窗口句柄。

AfxWndProc()处理一个特定消息:WM_QUERYAFXWNDPROC,如果消息是WM_QUERYAFXWNDPROC,AfxWndProc()就返回1。应用程序可以通过发送WM_QUERYAFXWNDPROC消息来查询该窗口是否是使用MFC消息映射系统的MFC窗口。

[cpp] view plaincopy

  1. // wincore.cpp 375
  2. LRESULT CALLBACK
  3. AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  4. {
  5. // special message which identifies the window as using AfxWndProc
  6. if (nMsg == WM_QUERYAFXWNDPROC)
  7. return 1;
  8. // all other messages route through message map
  9. CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  10. if (pWnd == NULL || pWnd->m_hWnd != hWnd)
  11. return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
  12. return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);    // 调用AfxCallWndProc
  13. }
  14. // wincore.cpp 208
  15. LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
  16. WPARAM wParam = 0, LPARAM lParam = 0)
  17. {
  18. _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  19. MSG oldState = pThreadState->m_lastSentMsg;   // 保存最后发送消息
  20. pThreadState->m_lastSentMsg.hwnd = hWnd;
  21. pThreadState->m_lastSentMsg.message = nMsg;
  22. pThreadState->m_lastSentMsg.wParam = wParam;
  23. pThreadState->m_lastSentMsg.lParam = lParam;
  24. // Catch exceptions thrown outside the scope of a callback
  25. // in debug builds and warn the user.
  26. LRESULT lResult;
  27. #ifndef _AFX_NO_OCC_SUPPORT
  28. // special case for WM_DESTROY
  29. if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL))
  30. pWnd->m_pCtrlCont->OnUIActivate(NULL);
  31. #endif
  32. // special case for WM_INITDIALOG
  33. CRect rectOld;
  34. DWORD dwStyle = 0;
  35. if (nMsg == WM_INITDIALOG)
  36. _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);        // 使对话框自动置于窗口中间
  37. // 委托给对象的WindowProc,覆盖该函数,可以在MFC查看某个消息之前处理这个消息
  38. lResult = pWnd->WindowProc(nMsg, wParam, lParam);
  39. // more special case for WM_INITDIALOG
  40. if (nMsg == WM_INITDIALOG)
  41. _AfxPostInitDialog(pWnd, rectOld, dwStyle);
  42. pThreadState->m_lastSentMsg = oldState;
  43. return lResult;
  44. }
  45. // wincore.cpp 1737
  46. LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  47. {
  48. // OnWndMsg does most of the work, except for DefWindowProc call
  49. LRESULT lResult = 0;
  50. if (!OnWndMsg(message, wParam, lParam, &lResult))   // wincore.cpp 1746
  51. lResult = DefWindowProc(message, wParam, lParam);
  52. return lResult;
  53. }

OnWndMsg函数很大,它首先过滤出WM_COMMAND、WM_NOTIFY、WM_ACTIVE和WM_SETCURSOR。对于这几个消息,框架有自己的处理方法。如果不是这几个,OnWndMsg会在消息映射表中查找消息。MFC维护着一个消息映射表入口缓存,可以通过散列值访问它。

时间: 2024-08-24 05:11:07

【转】MFC消息处理(一)的相关文章

MFC消息处理机制

1.如果要在一个代表窗口的类(代表窗口的类,都派生于CWnd)中处理消息,那么: 1.1.如果处理的Windows消息是WM_XXX,那么可以在MSDN中通过ON_WM_XXX来查找到相关说明. 1.2.将和ON_WM_XXX消息关联的函数声明,写到类方法中,这个方法就对应于Windows的WM_XXX消息,响应该消息就会调用该方法. 1.3.在代表窗口类中,添加一个宏:DESCLARE_MESSAGE_MAP():声明类定义了消息映射, 每个 CCmdTarget(在程序的派生类必须提供消息映

windows消息机制(MFC)

windows消息机制(MFC) 消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样. time表示产生消息的时间,pt表示产生消息时鼠标的位置. 按照类型,Windows将消息分为: (0) 消息ID范围 系统定义消息ID范围:[0x0000, 0x03ff]用户自定义的消息ID范围: WM_USER: 0x0400-0x7FFF 

MFC程序逆向 – 消息篇(上)

标 题: [原创]MFC程序逆向 – 消息篇(上)+(下) 11楼作 者: szdbg时 间: 2007-10-31,06:26:02链 接: http://bbs.pediy.com/showthread.php?t=54150 前言:记得前一段时间,我刚接触软件破解和逆向这一行时,对于一些软件不知从何处跟踪按钮消息,试了好多方法,就是断不下来,在系统模块中经常转得晕头转向,而一无所获. MFC程序是一种常见类型的程序,我静下心来,潜心研究了一下MFC消息流程.弄清原委之后,一切豁然开朗,发现

sizeof函数详解

原文链接http://blog.csdn.net/wzy198852/article/details/7246836 sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少犯迷糊,秉着“辛苦我一个,幸福千万人”的伟大思想,我决定将其尽可能详细的总结一下.但当我总结的时候才发现,这个问题既可以简单,又可以复杂,所以本文有的地方并不适合初学者,甚至都没有必要大作文章.但如果你想“知其然,更知其所以然”的话,那么这篇文章对你或许有所帮助.菜鸟我对C++的掌握尚未深入,其中不乏错误,欢迎各

sizeof()详解

1. 定义:sizeof是何方神圣sizeof乃C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数.MSDN上的解释为:The sizeof keyword gives the amount of storage, in bytes, associated with avariable or a type (including aggregate types). This keyword returns a value of type size_

sizeof,终极无惑(上)

0. 前向声明 sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少犯迷糊,秉着“辛苦我一个,幸福千万人”的伟大思想,我决定将其尽可能具体的总结一下. 但当我总结的时候才发现,这个问题既能够简单,又能够复杂,所以本文有的地方并不适合刚開始学习的人,甚至都没有必要大作文章.但假设你想“知其然,更知其所以然”的话,那么这篇文章对你也许有所帮助. 菜鸟我对C++的掌握尚未深入,当中不乏错误,欢迎各位扔砖砸蛋. 1. 定义 sizeof是何方神圣?sizeof乃C/C++中的一个操作符(

C语言结构体的字节对齐原则

转载:http://blog.csdn.net/shenbin1430/article/details/4292463 为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址

sizeof进行结构体大小的判断

typedef struct{    int a;    char b;}A_t;typedef struct{    int a;    char b;    char c;}B_t;typedef struct{    char a;    int b;    char c;}C_t;void main(){    char*a=0;    cout<<sizeof(a)<<endl;//4    cout<<sizeof(*a)<<endl;//1--

数组强制转换成结构体指针,结构体内部指针的指向问题

如果直接操作结构体成员是不会取到不期望的值 但是对于要求连续数据格式的时候需要考虑对齐的问题 例如通讯中的数据帧格式等 ,如 ip数据包等#pragma   pack(1) struct   tagStruct {     ... } t; #pragma   pack() 的方式来强制连续存放 其中前面   pack(1)   是指对齐边界为   1 1.几个结构体例子: struct{short a1;short a2;short a3;}A; struct{long a1;short a2