`
isiqi
  • 浏览: 16348220 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

MFC-窗口封装

阅读更多

MFCWindow作了一层比较浅的封装,其创建过程基本与SDK差不多。它简化了窗口的注册,并将窗口过程与类关联起来;后者是比较重要的封装,它使消息能够分流给“类的窗口过程”,既而通过消息映射,才能到达各个处理函数。

使用传统的SDK来创建一个窗口有点繁琐,伪代码是这样的:

if (RegisterClass(…))

{

CreateWindowEx(…);

ShowWindow(…);

UpdateWindow(…);

}

RegisterClass根据一个ClassName注册一个窗口类,并指定窗口过程;CreateWindowEx创建该窗口,其中的参数用于设置样式、位置等。

这段代码的繁琐之处其实在于函数的参数,CreateWindowEx12个参数,这常常让初学者望而生畏。作为良好封装的窗口框架,一个重要任务是简化这些参数,让它成为可分别设置的属性。

窗口的创建

要看MFC如何创建一个窗口,CView应该是最合适的了,CFrameWnd::CreateView创建了一个视图窗口:

CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)

{

CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();

if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,

CRect(0,0,0,0), this, nID, pContext))

... ...

return pView;

}

要创建CView,只需要一个CWnd::Create就可以了,不过这里面必然隐藏着一些事情,包括注册窗口类,指定窗口过程:

BOOL CWnd::Create调用下面的函数

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, ...)

{

//设置创建结构

CREATESTRUCT cs;

cs.dwExStyle = dwExStyle;

cs.lpszClass = lpszClassName;

... ...

//创建之前做了什么?

PreCreateWindow(cs);

//创建窗口

AfxHookWindowCreate(this);

HWND hWnd = ::CreateWindowEx(...);

AfxUnhookWindowCreate();

return TRUE;

}

CreateEx直接调用CreateWindowEx将窗口创建出来,我们注意到上面调用Create时传给lpszClassName的是一个空值,那么窗口类在什么时候注册的呢,只有一个地方,那就是PreCreateWindowPreCreateWindow是一个虚函数,CWnd在这里默认地为窗口注册名字为AfxWnd42的窗口类,而派生类可以覆盖这个函数注册其他的窗口类名,比如CView

BOOL CView::PreCreateWindow(CREATESTRUCT & cs)

{

if (cs.lpszClass == NULL)

{

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

cs.lpszClass = _afxWndFrameOrView;

}

return TRUE;

}

CViewafxWndFrameOrView注册窗口类,它的具体名字是:AfxFrameOrView42。注册的行为就在AfxDeferRegisterClass里面,不过到这里我们可以打住了。

指定窗口过程

注册窗口类的时候要指定窗口过程,AfxDeferRegisterClass是一个宏,会调用AfxEndDeferRegisterClass作具体的调用,在函数里看到这一句代码:wndcls.lpfnWndProc = DefWindowProc;窗口过程竟指定给系统的默认窗口过程,真正的窗口过程是在什么时候指定的呢?

CWnd::CreateEx里面,CreateWindowEx的前后各有一行代码,从字面上可以推断MFC监视了窗口的创建:

void AFXAPI AfxHookWindowCreate(CWnd* pWnd)

{

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();

pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,

_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());

pThreadState->m_pWndInit = pWnd;

}

MFC使用一个CBT钩子来监视窗口的创建,当pWnd的窗口句柄创建时,_AfxCbtFilterHook将被调用,这个函数的用意已经非常明显,将新创建的窗口句柄附加到pWnd,并为pWnd指定窗口过程。这个函数较长,我就不列代码了,只是将大概的几点列举如下:

1. 通过CWnd::Attach将句柄附加给pWndAttach还做了另一件事,建立pWnd与句柄的哈表,这是为了后面处理消息时可以找到正确的CWnd对象。哈表在MFC中大量地被使用。

2. 子类化窗口过程,将窗口过程指定为AfxWndProc,并保存旧的窗口过程;通过PreSubclassWindow,你还可以指定自己的窗口过程,不过似乎只在AfxWndProc之后才能被调用。

由于整个进程的所有窗口创建都会先被_AfxCbtFilterHook钩住,所以里面也进行了一些过滤,比如IME窗口。这种情况对于多线程是否有效呢,也许_afxThreadState可以确保在多线程情况窗口创建的顺序,我并没有去深究。

总而言之,窗口过程最后被替换为AfxWndProc

LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)

{

CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);

if (pWnd == NULL || pWnd->m_hWnd != hWnd)

return ::DefWindowProc(hWnd, nMsg, wParam, lParam);

return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);

}

通过FromHandlePermanent从哈表找到与句柄对应的窗口类,执行点又进入AfxCallWndProc,接下来我们就会看到熟悉的WindowProc,也就是前面文章所说的消息处理的进入点:

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,

WPARAM wParam = 0, LPARAM lParam = 0)

{

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();

MSG oldState = pThreadState->m_lastSentMsg; // save for nesting

pThreadState->m_lastSentMsg.hwnd = hWnd;

pThreadState->m_lastSentMsg.message = nMsg;

pThreadState->m_lastSentMsg.wParam = wParam;

pThreadState->m_lastSentMsg.lParam = lParam;

LRESULT lResult;

// delegate to object's WindowProc

lResult = pWnd->WindowProc(nMsg, wParam, lParam);

pThreadState->m_lastSentMsg = oldState;

return lResult;

}

pThreadState似乎与线程同步有关,从这一点可以看出MFC在多线程方面做得比VCL好得多,找个时间再来探索这个主题。

到此,窗口创建到消息处理就连惯起来了。尽管不同的窗口类在处理上有些差异,但核心流程大概就是这样。

MFC使用哈表将窗口句柄与窗口类关联起来,很多API的对象与MFC的对象即是基于此关联起来的;VCL用了另一种方法,若想了解参见我的另一篇文章从普函数到对象方法

分享到:
评论

相关推荐

    深入浅出MFC--侯捷 深入浅出MFC--侯捷 深入浅出MFC--侯捷

    5. **应用程序向导(Application Wizard)**:MFC应用程序向导简化了新项目的创建,可以自动生成基本的框架代码,包括主框架窗口、文档和视图类等,让开发者能够快速开始编码。 6. **类库和容器(Class Libraries ...

    mfc-动态库-x64.rar

    MFC基于Windows API构建,为开发者提供了许多抽象和封装,使得程序员可以更高效地利用Windows操作系统提供的功能。 MFC的核心概念是基于面向对象编程,它将Windows API中的函数、消息和结构转换为易于使用的C++类。...

    MFC-example-(1).zip_MFC_MFC-example_VC 6.0_VC++6.0 MFC

    MFC封装了Windows API,使得开发者能够更高效地构建Windows桌面应用程序,而无需直接处理底层的Win32 API。在这个"MFC-example-(1).zip"压缩包中,我们看到了一系列针对VC++6.0和MFC的学习实例,这将为我们深入理解...

    MFC-library.zip_MFC封装类库_library mfc_mfc类库封装

    MFC封装了Windows API的许多细节,使代码更易于理解和维护。 在"**MFC-library.zip**"这个压缩包中,我们很可能找到了一系列关于MFC类库的详细资料,这些资料可能是文档、示例代码或教程,特别适合初学者和进阶者...

    MFC--改写的窗口程序

    通过这种方法,我们可以更灵活地控制程序的架构,并学习MFC窗口类的继承与实现。 首先,MFC是微软提供的一套C++类库,用于简化Windows应用程序开发。它封装了Windows API,提供了丰富的控件、文档/视图结构以及事件...

    MFC-简明简版,基础。

    MFC封装了Windows API的复杂性,为开发者提供了面向对象的编程接口,使得创建窗口、对话框、控件等任务变得更加便捷。 **MFC的结构**: MFC主要由以下部分组成: 1. **框架类**:如CWinApp,CFrameWnd,CView,...

    Python库 | mfc-0.4.0-py2.py3-none-any.whl

    在Python世界中,这个库可能是为了在Python中与MFC进行交互或者封装MFC功能而创建的。后端标签暗示这个库可能用于构建服务器端应用,而不是前端用户界面。 Python库的开发者通常会创建这样的接口,以便Python开发者...

    MFC-rpg游戏

    MFC以类的形式封装了Windows窗口、消息处理、控件和文档视图架构。其中,CWinApp类是应用程序的核心,负责程序的初始化和关闭;CFrameWnd或CMDIFrameWnd类用于创建框架窗口,通常作为应用程序主窗口;CDialog类则是...

    MFC 教程 -李久进

    - **Win32 API封装**:MFC通过C++对象封装Windows对象,如CWnd类封装Windows窗口,将API函数转化为成员函数。 - **应用程序概念封装**:MFC引入了文档-视图架构,文档代表用户数据,视图则用于显示和操作这些数据...

    MFC-WndResizerApp.zip

    MFC是微软提供的C++类库,用于简化Windows应用程序的开发,它封装了Windows API,使得开发者能够更高效地构建用户界面。 **MFC基础** MFC基于面向对象编程,提供了许多类,如CWinApp、CWnd、CDialog等,用于创建...

    MFC-MDI程序

    总的来说,MFC-MDI程序的设计与实现涉及到Windows编程的基本概念,如窗口管理、消息处理、文档/视图架构,以及MFC类库的使用。熟练掌握这些知识点,能够帮助开发者高效地构建功能丰富的Windows应用程序。

    MFC-科学计算器

    - MFC通过封装Windows API,为开发者提供了面向对象的编程接口,简化了窗口、消息处理、数据库访问等操作。 - MFC应用程序通常包含几个关键组件:`CWinApp`(应用程序类)、`CFrameWnd`(框架窗口类)、`CView`...

    MFC-calculator-master.rar

    MFC是微软为简化Windows API编程而设计的,它将Windows消息处理、对象模型、文档/视图架构等复杂概念封装在易于使用的C++类中。开发者可以基于这些类创建应用程序,大大减少了编码量和出错可能性。 2. **文档/视图...

    Flash@435_MFC_

    MFC是微软提供的一套C++类库,用于构建Windows应用程序,它封装了Windows API,使开发者能够更容易地编写桌面应用。 【描述】中的"I have to write something so I can"可能是作者在创建压缩包时随意填写的,或者...

    mfc-tutorial.zip

    MFC基于Windows API,它封装了大量的Windows编程接口,使得程序员能够用面向对象的方式来编写Windows程序。 MFC的主要组成部分包括: 1. **基础类**:这些类如CObject,是所有MFC类的基类,提供了序列化、动态类型...

    mfc浮动窗口--类似迅雷半透明的浮动窗口

    1. **MFC库**:MFC是微软为Windows平台开发的应用程序提供的一套C++类库,它基于面向对象编程,封装了Windows API,使得开发者能够更高效地构建Windows应用程序。 2. **CWnd类**:在MFC中,`CWnd`是所有窗口类的...

    mfc-class-library.rar_MFC class libra_MSDN library chm_mfc MSDN

    MFC库包含了大量封装了Windows API的类,涵盖了窗口、对话框、控件、文档/视图架构等多个方面,为开发者提供了丰富的功能和便捷的编程接口。 本资源“mfc-class-library.rar”是针对MFC类库的详细解释,其内容类似...

    MFC-class.rar_MFC

    MFC是基于Windows API的封装,它提供了许多面向对象的类,简化了Windows程序设计。在MFC中,常见的类如CWinApp、CWnd、CDialog、CButton、CEdit等,都是与Windows窗口和控件直接相关的。这些类不仅封装了Windows消息...

    MFC-windows.rar_MFC_MFC 对话框

    "www.pudn.com.txt"可能是文档或链接到更详细教程的资源,而"MFC-windows"可能是一个源码文件夹,里面包含了实现MFC窗口和对话框的C++代码。通过分析这些源代码,可以深入理解MFC的工作原理以及如何在实际项目中应用...

Global site tag (gtag.js) - Google Analytics