从Windows API 到 MFC浅谈

上一篇《一个Demo初识MFC》用一个例程带入对MFC的初探,本篇紧接着上篇,首先对代码进行讲解,然后继续向前进。

《一个Demo初识MFC》代码解析

概念一览:

MFC提供数百个类,最重要的、也是编写任何VC++应用程序都必不可少的两个类 CWinApp 和 CFrameWnd ,这两个类是编写复杂庞大应用程序的基石。

  1. 封装特性:构成MFC框架的是MFC类库而MFC类库又是C++的一个类库。这些类封装WIN32应用程序编程接口,OLE(Object
    Link Embed 对象链接嵌入)特性,ODBC和DAO数据访问的功能。
  2. 继承特性:MFC抽象出了众多类的共同特性,并设计出一些基类作为实现其他类的基础,这些类中最重要的类是CObject类和CCmdTarget类(如图),程序员可以从适当的MFC类中派生出自己的类,实现特定的功能达到编程的目的。
  3. 虚拟和消息映射:MFC是以C++为基础,当然支持虚函数,但作为一个编程框架必须要解决的是效率问题:如果MFC仅仅通过虚函数来支持动态约束必然会产生大量的虚函数表这样编程框架过于臃肿而且消耗更多的内存。但是MFC建立了消息映射机制这样降低了内存的使用却大大提高了效率。消息映射是一个将消息和成员函数相互关联的表,当应用程序的框架窗口接收到一个消息时,MFC将搜索该窗口的消息映射,如果存在一个处理消息的处理程序,那么就调用该处理程序.它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V表),节省内存。

  • MFC消息映射机制

将消息与消息处理函数联系起来,形成一一对应的机制。

消息映射宏

声明: DECLARE_MESSAGE_MAP

定义:

BEGIN_MESSAGE_MAP

   ON_COMMAND

ON_CONTROL

ON_MESSAGE

END_MESSAGE_MAP

  • MFC主要组成部分:类、宏和全局函数。

类是MFC中最主要的内容。MFC类是以层次结构方式组织起来的。MFC中的类分成两部分,除了一些辅助类,大多数的MFC类是直接或间接从根类CObject派生而来。

  • MFC宏主要功能:消息映射、运行时对象类型服务、诊断服务、异常处理。
  • MFC约定:全局函数以“Afx”为前缀,全局变量以“afx”为前缀
  • MFC类的层次关系

CObject项目类)->CCmdTarget(消息响应类)->

{

CWinThread(线程类)->CWinApp(Window应用程序类)

CDocument(文档类)

CWnd(窗体类)->[

CFrameWnd(框架类)

CView(视图类)

]

}

代码解析

  1. CWinApp是应用程序类,在MFC应用程序中必须从这个类派生出一个类,该派生类是MFC应用程序的入口

    必须定义这个派生类的对象,并且只能有一个这个对象代表整个应用程序。

    成员函数:InitInstance()

    功能:初始化应用程序实例和窗口实例,

    虚函数CWinApp::InitInstance必须在派生类中重写。在InitInstance函数中,编写初始化代码,如:

    创建一个窗口

    显示一个窗口

  2. CFrameWnd类 

    作用:为应用程序提供一个窗口,同时实现消息处理功能。

    成员函数: Create()

    功能:创建窗体,将之赋于CFrameWnd对象上。

    BOOL Create(窗口类型, 窗口标题,显示风格,显示区域,符窗口句柄,菜单,扩展显示风格,上下文对象)共有8个参数,前两个必须给出,后6个可以默认。

  3. MFC应用程序的核心就是基于CWinApp类的应用程序对象,CWinApp提供了消息循环来检索消息并将消息调度给应用程序的窗口.我们在编写MFC应用程序时,要包含afxwin.h,

    一个MFC应用程序可以有且仅有一个应用程序对象,对象必须声明为在全局范围内有效(也就是全局对象),以便它在程序开始时即在内存中被实例化

    我们的Hello MFC的应用程序类被命名为CMyApp,它在hello.cpp中用如下语句进行了实例化:

    CMyApp myApp;

  4. CMyApp的类声明在hello.h中代码如下:

    class CMyApp:public CWinApp

    {

    public:

    virtual BOOL InitInstance();

    };

    CMyApp没有声明任何的数据成员,只是重写了一个从CWinApp类中继承来的函数,在应用程序的生存期内InitInstance的调用比较早,是在应用程序开始运行以后而窗口创建之前,除非InitIstance创建一个窗口,否则应用程序是不会有窗口,这正是为什么即使最小的MFC应用程序也必须从CWinApp派生出一个类并重写CWinApp::InitIstance的原因

    InitInstance函数:CWinApp::InitInstance是一个虚函数,其默认操作仅包含一条语句:return TRUE;

    InitInstance是用来执行程序每次开始时都需要进行的初始化工作最好的地方。

  5. 在hello.cpp中,CMyApp的InitInstance通过实例化hello的CMainWindow类来创建hello窗口,语句:

    m_pMainWnd = new CMainWindow;

    构造了一个CMainWindow对象指针,并将其地址复制到了应用程序对象的m_pMainWnd数据成员中,窗口创建以后,InitInstance就会通过CMainWindow指针调用ShowWindow和UpdateWindow函数显示它:

    m_pMainWnd->ShowWindow(m_nCmdShow);

    m_pMainWnd->UpdateWindow();

    ShowWindow和UpdateWindow是所有窗口对象共用的CWnd成员函数其中包括CFrameWnd类的对象,CMainWindow就是从CFrameWnd派生出来的.

  6. 在CMyApp::InitInstance中,hello创建了一个CMainWindow对象,CMainWindow的构造函数生成在屏幕上看到的窗口:

    Create(NULL,”我的第一个MFC应用程序”);

    CPaintDC dc(this);

  7. MFC的CPaintDC类是从MFC的CDC类派生的,CDC类封装了Windows设备环境,以及包含了绘制到屏幕、打印机和其他设备的几十个成员函数。(这有关于
    “设备上下文的内容”会在以后的篇章中写道

从API编程到MFC编程的过渡

接下来给出一通过Window API 过程实现的代码例程

建立Win32控制平台代码,设定->项目属性

源代码

// TestWinAPI.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include<windows.h>
/*   声明窗口过程   */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*   窗口类名   */
TCHAR szClassName[]=TEXT("WindowsApp");

/* 入口函数 */
int WINAPI WinMain (
     HINSTANCE hInstance,      // 实例句柄
     HINSTANCE hPrevInstance,  // 先前的实例, Win32下始终为NULL
     LPSTR lpCmdLine,          // 命令行参数
    int nCmdShow              // 窗口显示命令参数
)
{
     HWND hwnd;             /* 窗口句柄 */
     MSG messages;          /* 消息结构变量 */
     WNDCLASS wincl;        /* 窗口类结构变量 */

    /* 填充窗口类结构变量 */
     wincl.hInstance = hInstance;
     wincl.lpszClassName = szClassName;
     wincl.lpfnWndProc = WindowProcedure;      /* 设置窗口过程 */
     wincl.style = CS_DBLCLKS;                 /* 窗口类样式 */

    /* 设置默认图标光标 */
     wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
     wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
     wincl.lpszMenuName = NULL;                 /* 菜单 */
     wincl.cbClsExtra = 0;                      /* 窗口类额外数据字节数 */
     wincl.cbWndExtra = 0;                      /* 窗口额外数据字节数 */
    /* 窗口默认背景 */
     wincl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

    /* 注册窗口类 */
    if (!RegisterClass(&wincl))
        return 0;

    /* 创建窗口 */
     hwnd = CreateWindow (
            szClassName,         /* 类名 */
            TEXT("我的Windows API应用程序"),/* 标题文本 */
            WS_OVERLAPPEDWINDOW, /* 窗口样式 */
            CW_USEDEFAULT,       /* X坐标 */
            CW_USEDEFAULT,       /* Y坐标 */
            CW_USEDEFAULT,       /* 宽度px */
            CW_USEDEFAULT,       /* 高度px */
            HWND_DESKTOP,        /* 父窗口句柄 */
            NULL,                /* 菜单 */
            hInstance,           /* 程序实例句柄 */
            NULL                 /* 窗口创建参数 */
           );

    /* 按照参数显示窗口 */
     ShowWindow (hwnd, nCmdShow);

    /* 进入消息循环,直到GetMessage()返回0. 即WM_QUIT消息发出 */
    while (GetMessage(&messages, NULL,0,0))
    {
        /* 翻译虚拟键消息成字符消息 */
         TranslateMessage(&messages);
        /* 发送消息给窗口过程 */
         DispatchMessage(&messages);
    }

    return (int)messages.wParam;
}

/* 窗口过程实现 */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:
        {
             PAINTSTRUCT ps;
			 RECT rect;
             HDC hDC = BeginPaint(hwnd,&ps);
             //TCHAR sz[]=TEXT("我的Windows API应用程序");
             //TextOut(hDC,10,10,sz,lstrlen(sz));
			 GetClientRect (hwnd, &rect) ;
			 DrawText(hDC,TEXT("Hello Windows API"),-1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
             EndPaint(hwnd,&ps);
        }
        break;
    case WM_DESTROY:
         PostQuitMessage(0);       /* 向消息队列发出WM_QUIT消息 */
        break;
    default:                      /* 不感兴趣的消息交给DefWindowProc()处理 */
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0;
}

编译运行结果:

WIindows API和MFC的比较见下一篇——《论烦琐与简单:WIindows
API和MFC》

时间: 2024-08-06 00:12:13

从Windows API 到 MFC浅谈的相关文章

Windows Azure HandBook (3) 浅谈Azure安全性

<Windows Azure Platform 系列文章目录> 2015年3月5日-6日,参加了上海的Azure University活动.作为桌长与微软合作伙伴交流了Azure相关的技术,同时通过课程案例,学习了很多的Azure相关知识. 现在就课程中的一个案例,分析一下Azure安全性方面的内容. Azure安全性一直是一个被经常问到的问题,把虚拟机.网站和数据库等都部署到Azure平台,如何保证应用程序的安全,如何保证企业级客户的数据不被泄漏,一直是客户经常询问到的问题. 总的来说,Az

Web API之路由浅谈

Web API的路由,是指明接口地址的方向,是照亮获取数据路上的灯塔,其重要性不言而喻. 本篇文章以vs2015为例,一步步说明路由的创建及使用,其中包括默认路由.自定义路由和特性路由. 我们创建一个新的web api项目,其初始的默认路由是这样的: 不难看出,默认路由的名称(name)是DefaultApi.路由模板(routeTemplate)是api/{controller}{id},api是固定的,{controller}匹配控制器,{id}匹配行为的参数,由defaults可以看出,i

C、C++控制台程序、Windows API程序、MFC程序理解与比较

在编程语言中,函数是一个很重要的概念,其身影无处不在.在面向过程的编程方式中,函数更是程序的基本构建模块,在面向对象的编程方式中,函数演变为类或对象的成员(当然也可以使用与类无关的函数).函数由函数头和函数体组成.函数头包括域属性(如external.static或类域).返回值类型.函数名.及参数.域属性包括其在多文件编程中的可见范围,是否是属于某一个类的成员?返回值类型是指函数返回的值的具体数据类型(可以理解为函数输出的一部分).函数名是函数保存在内存代码区的首地址,用于函数的调用及函数指针

浅谈Windows API编程

WinSDK是编程中的传统难点,个人写的WinAPI程序也不少了,其实之所以难就难在每个调用的API都包含着Windows这个操作系统的潜规则或者是windows内部的运行机制…… WinSDK是编程中的传统难点,曾经听有一个技术不是很好的朋友乱说什么给你API谁都会用,其实并非那么简单,个人写的WinAPI程序也不少了,其实之所以难就难在每个调用的API都包含着Windows这个操作系统的潜规则或者是windows内部的运行机制. 首先来谈谈句柄,初学习WinSDK的朋友刚看到这个词头大了吧?

浅谈Windows平台下C++调用静态链接库的方式

浅谈Windows平台下C++调用静态链接库的方式 1. 什么是静态链接库?为什么要用静态链接库? 维基百科上关于静态库的解释是这样的:在计算机科学里,静态库(英语:Static library, Statically-linked library),或称静态库,是一个外部函数与变量的集合体.静态库的文件内容,通常包含一堆程序员自定的变量与函数,其内容不像动态链接库那么复杂,在编译期间由编译器与连接器将它集成至应用程序内,并制作成目标文件以及可以独立运作的可执行文件. 由上面的解释可以很清楚的看

浅谈REST API

浅谈REST API 说明: 本文部分内容根据其它网络文章编写,如有版权问题请及时通知. 背景 发迹于互联网的REST,在国内国外混得可谓是风生水起,如今又进入电信行业的视野,连TMF都将其作为战略项目Open Digital的一部分. 一种思维方式影响了软件行业的发展.REST软件架构是当今世界上最成功的互联网的超媒体分布式系统.它让人们真正理解我们的网络协议HTTP本来面貌.它正在成为网络服务的主流技术,同时也正在改变互联网的网络软件开发的全新思维方式. 引自:http://www.blog

浅谈Windows Server APPFABRIC

    hi,everyone !真的是好久好久没有update blog了,因为最近忙着备考,没有时间对<数据结构与算法>进行研究学习了.所以,blog一直未更新.today is Friday,心里比较轻松,(哈哈,上班族懂我的感受),有时间写篇技术文章了.正好,最近研究了一些新技术,这篇文章权当对技术的梳理归纳吧.子曰:"温故而知新,可以为师也."对于knowledge,我们一定要时常复习.thought.归纳.practice.只有这样,我们才能真正的掌握它.Ein

模仿MFC封装Windows API

.... 最后添加了两个按钮,分别处理每个按钮的单击事件时,走了弯路,本来想的是在QButton中重写OnLButtonDown方法,但是,无法区分是那个按钮.参考这篇文章: http://zhidao.baidu.com/link?url=hsXHcC9q_tfdf4Ztz_juQR4fxY63UU7Ujsj1Tz1rDPKi2xk8JlnzqX4rfCPNyh-SRK-zeIFgECm9H4PuMn4GoK 在按钮的父窗体的WindowProc中处理WM_COMMAND消息,消息的LOWOR

浅谈 Java Printing

浅谈 Java  Printing 其实怎么说呢?在写这篇博文之前,我对java printing 可以说是一无所知的.以至于我在敲文字时, 基本上是看着api文档翻译过来的.这虽然看起来非常的吃力,但是我相信,有道大哥不会辜负我的.嘻 嘻! Java Printing 技术,也就是我们平时所接触的打印,只不过是说可以用Java实现而已. 一.Java Printing 打印简介 Java Printing API能够使java应用程序实现相关的打印功能,如: 1.打印所有 Java 2D 和