【MFC】06.MFC六大机制:窗口创建机制-笔记

这篇具有很好参考价值的文章主要介绍了【MFC】06.MFC六大机制:窗口创建机制-笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

接上文【MFC】05.MFC第一大机制:程序启动机制-笔记,这一篇文章来带领大家逆向分析MFC第二大机制:窗口创建机制的源码。
我们知道,在Win32编程中,如果我们要创建一个窗口,基本步骤为:

  1. 注册窗口
  2. 创建一个窗口,必须要给一个类名称
  3. 消息处理回调函数

那么MFC的窗口创建机制又是怎样的呢?我们来回溯一下MFC源码:

首先,我们继续用上文中创建的MFC程序:

#include <afxwin.h>

//实现我们自己的框架类
class CMyFrameWnd :public CFrameWnd {
public:
};

//实现我们自己的应用程序类
class CMyApp :public CWinApp {
public:
	CMyApp() {};

	//重写虚函数
	virtual BOOL InitInstance() {
		CMyFrameWnd* pFrame = new CMyFrameWnd;
		pFrame->Create(NULL, L"FirstMFC");
		m_pMainWnd = pFrame;
		pFrame->ShowWindow(SW_SHOW);
		pFrame->UpdateWindow();
		return TRUE;
	}
};

CMyApp theApp;

不难猜到,创建窗口的代码在这:pFrame->Create(NULL, L"FirstMFC");我们就在这行代码上下断点,跟过去:

我们知道我们重写的的InitInstance函数在WinMian函数转发的AfxwWimMian函数中会被调用:

这里给的参数,第一个NULL是lpszClassName(窗口类名),第二个参数是lpszWindowName(应用程序类名),但是我们了解Win32编程,我们知道如果想要创建窗口或者是注册窗口,都必须要窗口类名,但是这里给的是NULL,为什么还是能够正常执行过去呢?

virtual BOOL InitInstance(){
  	CMyFrameWnd* pFrame = new CMyFrameWnd;
  	//Create函数是框架类的方法:
  	//我们知道Create方法的参数肯定不止俩,我们跟过去之后,发现其他参数是有默认参数的
		pFrame->Create(NULL, L"FirstMFC")
		{
		  //进入函数第一件事:判断是否包含菜单,如果包含菜单,则加载菜单
		  HMENU hMenu = NULL;
    	if (lpszMenuName != NULL)
    	{
    		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();
    			return FALSE;
    		}
	    }
	    
	    	m_strTitle = lpszWindowName;    // save title for later
        
        //这里的代码很明显是创建窗口了,但是没有窗口类名,怎么能创建窗口呢?我们跟进去看看:
        //这里由于其他参数我们不关注,这里只留下窗口类名
        //这里源代码函数实现实在if语句的条件中执行的,这里直接拉出来
      	CreateEx( lpszClassName, lpszWindowName,...)
      	{
      	    //可以看到在这里有断言:
      	  	ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
          		AfxIsValidAtom(lpszClassName));
          	ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
          
            //这里是创建窗口所需要的类:
          	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;
          	
          	//这里隐含的this指针:框架类窗口
          	PreCreateWindow(cs){
          	  //跟进去函数也能发现是框架类窗口的方法
          	  BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
              {
              	if (cs.lpszClass == NULL)
              	{
              	  //发现这里有一个貌似MFC注册窗口的函数:跟进去看看
              		VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)){
              		  	//这些是所需要的类,相信大家都很熟悉了
              		  	WNDCLASS wndcls;
                    	memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults
                    	wndcls.lpfnWndProc = DefWindowProc;
                    	wndcls.hInstance = AfxGetInstanceHandle();
                    	wndcls.hCursor = afxData.hcurArrow;
                    	
                    	//接下来发现了好多类似的代码,应该是判断一些东西,我们的代码进入了这个if语句,我们就跟进去
                    	if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
                    	{
                    		//这里是对wndcls做一些赋值操作
                    		wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
                    		wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
                    		//代码跟到这里,应该是注册窗口了,因为吧注册窗口所需要的类传进去了,为了以防万一,我们跟进去看看:
                    		if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME)){
                    		    //代码前部分做了一些赋值操作,加载图标
                    		    //我们跟到这个函数中看看注册操作:
                          	return AfxRegisterClass(pWndCls){
                          	  	WNDCLASS wndcls;
                          	  	//这里的GetClassInfo是判断窗口是否已经注册过
                                	GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,&wndcls)
                                  //在这里发现了Win32API:注册窗口
                                	if (!RegisterClass(lpWndClass))
                          	}
                    		}
                    	}
                    	//在注册玩窗口后,发现了这段代码
                    	//这里的_afxWndFrameOrView是一个宏或者数组,跟过去看看,发现是个数组
                    	//跟到最后,发现是FrameOrView
                    	cs.lpszClass = _afxWndFrameOrView;
              		}
              	}
              	
              	...
              	
              	return TRUE;
              }
          	}
      	}
      	  //在创建窗口之前,发现埋下了一个钩子
      		AfxHookWindowCreate(this){
        		  void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
            {
              //MFC的第三个全局变量
            	_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
            	
            	if (pThreadState->m_pWndInit == pWnd)
            		return;
            		//这里是埋下了一个创建窗口的消息钩子
            	pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
            		//如果失败的话,抛出异常
            		if (pThreadState->m_hHookOldCbtFilter == NULL)
            			AfxThrowMemoryException();
            	}
            	//这里保存了我们的框架类窗口对象
            	pThreadState->m_pWndInit = pWnd;
            }
      		}
      		//发现这里是创建窗口
        	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);
		}
}

触发的钩子函数
LRESULT CALLBACK _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
//MFC第三个全局变量的地址
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
//取出结构体参数
LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
//多态 父类指针 指向子类
CWnd* pWndInit = pThreadState->m_pWndInit

//创建的窗口句柄
HWND hWnd = (HWND)wParam;

//窗口句柄传入了进去
//内部this指针是我们的对象
pWndInit->Attach(hWnd);
{
    //MAP对象
    CHandleMap* pMap = afxMapHWND(TRUE); 
    {
        //MFC 第二个全局变量 线程模块状态 
        AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
        //把映射类对象 保存到了 第二个全局变量里面
        pState->m_pmapHWND = new CHandleMap
        return pState->m_pmapHWND;
    }
    
    //内部this指针是谁 pMap映射类对象
    pMap->SetPermanent(this->m_hWnd = hWndNew, 框架类对象);
    {
        inline void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)
        {
            //pMap映射类对象
            this->m_permanentMap[窗口句柄] = 框架类对象 pFrame;
            //stl map  map[key] = val
        }
    }
    
    WNDPROC afxWndProc = AfxGetAfxWndProc();
    oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,(DWORD_PTR)afxWndProc);
}

LRESULT lResult = CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,wParam, lParam);

}

//真正的窗口过程处理函数
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
{
CHandleMap* pMap = afxMapHWND();
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
pState->m_pmapHWND
}

    return (CObject*)m_permanentMap.GetValueAt((LPVOID)h);        
}

AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam)
{
    //父类指针 指向了子类 
    lResult = pWnd->WindowProc(nMsg, wParam, lParam);
}

}文章来源地址https://www.toymoban.com/news/detail-640608.html

到了这里,关于【MFC】06.MFC六大机制:窗口创建机制-笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【MFC】05.MFC第一大机制:程序启动机制-笔记

    MFC程序开发所谓是非常简单,但是对于我们逆向人员来说,如果想要逆向MFC程序,那么我们就必须了解它背后的机制,这样我们才能够清晰地逆向出MFC程序,今天这篇文章就来带领大家了解MFC的第一大机制:程序启动机制: 首先,我们创建一个单文档架构程序,我们来观察一

    2024年02月14日
    浏览(35)
  • 【MFC】07.MFC第三大机制:消息映射-笔记

    本专栏上两篇文章分别介绍了【MFC】05.MFC第一大机制:程序启动机制和【MFC】06.MFC第二大机制:窗口创建机制,这篇文章来为大家介绍MFC的第三大机制:消息映射 typfd要实现消息映射,必须满足的三个条件: 类必须继承于CmdTargert 类必须声明重定义 DECLARE_MESSAGE_MAP 类外必须实

    2024年02月14日
    浏览(41)
  • MFC 非线程创建模态化窗口 实现工具栏拓展

    1.1 在Dlg.h文件中声明变量和定义资源ID 1.2 在资源视图中导入Bitmap资源图片 可以在右击资源符号中查看具体ID值 1.3 在Dlg.cpp文件中的OnInitDialog()方法中导入Bitmap与按钮ID 1.4 开启鼠标停靠信息提示 先在Dlg.h中增加函数声明 再Dlg.cpp中实现 增加消息映射宏开启提示 1.5 效果呈现 2.

    2024年02月10日
    浏览(38)
  • MFC第二十九天 CView类的分支(以及其派生类的功能)、MFC六大关键技术

    对CMainView使用了CEditView类的派生,对其默认字体进行改变。 需要添加#include afxhtml.h头文件 MainFrm.h CMainFrame 类的接口 CMainView .h a)CListCtrl的内部创建原理是通过CWnd::Create(sClassName,…)来实现的。 b)CStatic,CEdit,CButton的内部创建原理无一不是这个原理,即使是拖入对话框的控件底层也

    2024年02月13日
    浏览(43)
  • mfc 浮动窗口

    参考 MFC模拟360悬浮窗加速球窗口

    2024年02月09日
    浏览(41)
  • MFC 隐藏窗口

    亲测能用 改变主窗体的创建方式 将 C***App::InitInstance() 函数中的代码 替换为

    2024年02月11日
    浏览(35)
  • MFC多文档如何分割窗口

    本文记录如何在MFC多文件中分割窗口并实现窗口之间的数据传递 1、在ChildFrame中定义一个分割嵌入一个CSplitterWnd成员变量。 2、创建两个对话框, 设置对话框的属性 :将 ‘样式’ 设置为 ‘下层’; 禁止使用 标题栏; 边框选择‘ 调整大小 ’;其他格式暂时都不设置;      

    2024年02月06日
    浏览(39)
  • MFC窗口透明化以及透明穿透

    MFC编程时,有时候我们需要实现窗口透明化,可以通过SetLayeredWindowAttributes设置窗口透明色和透明度来实现窗口透明化。而要使窗口拥有透明效果,前提是窗口要有WS_EX_LAYERED扩展属性,需用SetWindowLong设置窗口支持拓展风格。 一、窗口透明化说明 1.窗口透明化有三种模式: 第一

    2024年02月09日
    浏览(38)
  • MFC 第二部分 : 窗口类成员接口

    所有窗口类的基类:类 CWnd,封装了 Windows 窗口句柄 HWND。 成员函数 DestroyWindow 可以消毁 Windows 窗口,而不需要消毁 CWnd 对象。 m_hWnd 与该 CWnd 对象相关联的 Windows 窗口句柄(HWND); 窗口大小和位置 GetWindowRgn 获得窗口的窗口区域的拷贝 SetWindowRgn 设置窗口区域 IsIconic 判断窗口是

    2024年02月06日
    浏览(39)
  • 微软MFC技术运行机制

    我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下微软MFC技术运行机制。 很多初学者误以为VC++开发必须使用MFC,其实不一定的。MFC的使用只能是提高程序在某些情况下的开发效率,而不能替代整个Win32程序设计。我认为我们有必要再来好好讲讲MFC的本质、MFC中的

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包