文号
t72045
阅读
7487
回复
3
收藏
2
【科普】非常简单的MFC程序
2015/06/17
IP:四川
其实MFC的原理很简单,不要被AppWizard生成的代码吓住了。MFC程序是从CWinApp类和InitInstance()函数开始的。

MFC的原理:
1. 开发者定义一个基于CWinApp的类,初始化它的唯一的对象,内置构造函数会向MFC注册这个对象。
2. MFC会在自身初始化完毕后调用该对象的InitInstance()函数,开发者可以重写这个函数来对程序进行初始化:
(1) InitInstance()可以初始化主窗口m_pMainWnd,也可以进行其它的操作,如显示对话框。
(2) InitInstance()函数初始化并设置主窗口后返回TRUE进入消息循环,等待WM_QUIT退出;如不设置主窗口或返回FALSE,则直接退出。

3. CWinApp可以调用其它类(如CDialog或CFrameWnd)来实现程序的功能,通过继承重写这些类,可以对它们进行编程。
4. 通过BEGIN_MESSAGE_MAP和END_MESSAGE_MAP等宏定义,将各种菜单命令、Windows消息、控件通知映射到成员函数。

而以上这些,基本都可以由Visual C++各种向导自动化地完成。

MFC并不是没有WinMain函数,而是在程序库的内部实现了WinMain函数。MFC也不是没有WndProc函数,实际上也是在内部实现,并通过某种机制,将消息映射到各MFC类的成员函数。

MFC通过message map宏定义来处理消息,其中:
1. CWinApp等继承自CCmdTarget的类均可以收到WM_COMMAND消息——通常是菜单命令
2. CFrameWnd和CDialog等继承自CWnd的类可以收到WM_COMMAND命令消息,WM_NOTIFY控件通知,以及其它窗口消息。

最简单的MFC程序只有25行,简单吧:
// 最简单的MFC程序
                                          
#include "stdafx.h"
                                          
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
                                          
class CSimpleProg1App : public CWinApp
{
public:
    CSimpleProg1App() {
    }
                                          
    virtual BOOL InitInstance() {
        return FALSE; // 直接退出
    }
                                                                            
    DECLARE_MESSAGE_MAP()
};
                                 
BEGIN_MESSAGE_MAP(CSimpleProg1App, CWinApp)
END_MESSAGE_MAP()       
                                 
CSimpleProg1App theApp; // 唯一的一个CSimpleProg1App对象

基于对话框的最简单的程序:
// SimpleProg1.h : PROJECT_NAME 应用程序的主头文件
//
                                                                          
#pragma once
                                                                          
#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif
                                                                          
#define IDD_SIMPLEPROG1_DIALOG 102 // 对话框资源
                                                                          
                                                                          
// CSimpleProg1App:
// 有关此类的实现,请参阅 SimpleProg1.cpp
//
                                                                          
class CSimpleProg1App : public CWinApp
{
public:
    CSimpleProg1App();
                                                                          
// 重写
public:
    virtual BOOL InitInstance();
                                                                          
// 实现
                                                                          
    DECLARE_MESSAGE_MAP()
};
                                                                          
extern CSimpleProg1App theApp;
// SimpleProg1.cpp : 定义应用程序的类行为。
//
                                                                         
#include "stdafx.h"
#include "SimpleProg1.h"
                                                                         
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
                                                                         
                                                                         
// CSimpleProg1App
                                                                         
BEGIN_MESSAGE_MAP(CSimpleProg1App, CWinApp)
END_MESSAGE_MAP()
                                                                         
                                                                         
// CSimpleProg1App 构造
                                                                         
CSimpleProg1App::CSimpleProg1App()
{
    // TODO: 在此处添加构造代码,
    // 将所有重要的初始化放置在 InitInstance 中
}
                                                                         
                                                                         
// 唯一的一个 CSimpleProg1App 对象
                                                                         
CSimpleProg1App theApp;
                                                                         
                                                                         
// CSimpleProg1App 初始化
                                                                         
BOOL CSimpleProg1App::InitInstance()
{
    CDialog dlg(IDD_SIMPLEPROG1_DIALOG);
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // TODO: 在此放置处理何时用
        //  “确定”来关闭对话框的代码
    }
    else if (nResponse == IDCANCEL)
    {
        // TODO: 在此放置处理何时用
        //  “取消”来关闭对话框的代码
    }
                                                                         
    // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
    //  而不是启动应用程序的消息泵。
    return FALSE;
}

上面的是基于对话框的程序,用Win32API编写对话框程序同样比较简单,但是用Win32API编写框架窗口就太困难了——要自己注册窗口类,自己创建窗口,自己显示窗口,自己编写消息循环,还要自己编写WndProc函数,太麻烦了。如果你使用MFC,就会和对话框一样简单:
// SimpleProg2.h : SimpleProg2 应用程序的主头文件
//
#pragma once
                                                                       
#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif
                                                                       
#define IDD_ABOUTBOX                100 // “关于”对话框资源
#define IDR_MAINFRAME               128 // 与主框架有关的菜单、标题文字、图标等资源
                                                                       
// CSimpleProg2App:
// 有关此类的实现,请参阅 SimpleProg2.cpp
//
                                                                       
class CSimpleProg2App : public CWinApp
{
public:
    CSimpleProg2App();
                                                                       
                                                                       
// 重写
public:
    virtual BOOL InitInstance();
                                                                       
// 实现
                                                                       
public:
    afx_msg void OnAppAbout();
    DECLARE_MESSAGE_MAP()
};
                                                                       
extern CSimpleProg2App theApp;
// SimpleProg2.cpp : 定义应用程序的类行为。
//
                                                                       
#include "stdafx.h"
#include "SimpleProg2.h"
                                                                       
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
                                                                       
                                                                       
// CSimpleProg2App
                                                                       
BEGIN_MESSAGE_MAP(CSimpleProg2App, CWinApp)
    ON_COMMAND(ID_APP_ABOUT, &CSimpleProg2App::OnAppAbout)
END_MESSAGE_MAP()
                                                                       
                                                                       
// CSimpleProg2App 构造
                                                                       
CSimpleProg2App::CSimpleProg2App()
{
    // TODO: 在此处添加构造代码,
    // 将所有重要的初始化放置在 InitInstance 中
}
                                                                       
// 唯一的一个 CSimpleProg2App 对象
                                                                       
CSimpleProg2App theApp;
                                                                       
                                                                       
// CSimpleProg2App 初始化
                                                                       
BOOL CSimpleProg2App::InitInstance()
{
    // 若要创建主窗口,此代码将创建新的框架窗口
    // 对象,然后将其设置为应用程序的主窗口对象
    CFrameWnd* pFrame = new CFrameWnd;
    if (!pFrame)
        return FALSE;
    m_pMainWnd = pFrame;
    // 创建并加载框架及其资源
    pFrame->LoadFrame(IDR_MAINFRAME,
        WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
        NULL);
                                                                       
    // 唯一的一个窗口已初始化,因此显示它并对其进行更新
    pFrame->ShowWindow(SW_SHOW);
    pFrame->UpdateWindow();
                                                                         
    return TRUE;
}
                                                                       
// CSimpleProg2App 消息处理程序
                                                                       
// 用于运行对话框的应用程序命令
void CSimpleProg2App::OnAppAbout()
{
    CDialog aboutDlg(IDD_ABOUTBOX);
    aboutDlg.DoModal();
}

可以发现这里根本没有Win32程序繁杂的窗口类注册、消息循环和WndProc函数——因为MFC已经帮我们实现了。我们要做的只是创建窗口并显示它。这里还定义了一个ID_APP_ABOUT“关于”菜单命令并在CWinApp里实现了它。ID_APP_ABOUT的值是系统内置的,所以不用手工定义。
[ 修改于11年6个月前 - 2015/06/22 18:46:15 ]
acmilan作者
11年6个月前IP:四川
773781
1楼
MFC也能编写控制台应用程序,只是控制台应用程序没法新建主窗口,只能新建对话框:
// MfcConsole.cpp : 定义控制台应用程序的入口点。
//
 
#include "stdafx.h"
#include "MfcConsole.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
 
// 唯一的应用程序对象
 
CWinApp theApp;
 
using namespace std;
 
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;
 
    HMODULE hModule = ::GetModuleHandle(NULL);
 
    if (hModule != NULL)
    {
        // 初始化 MFC 并在失败时显示错误
        if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
        {
            // TODO: 更改错误代码以符合您的需要
            _tprintf(_T("错误: MFC 初始化失败\n"));
            nRetCode = 1;
        }
        else
        {
            // TODO: 在此处为应用程序的行为编写代码。
            CDialog dlg(IDD_DIALOG1);
            dlg.DoModal();
        }
    }
    else
    {
        // TODO: 更改错误代码以符合您的需要
        _tprintf(_T("错误: GetModuleHandle 失败\n"));
        nRetCode = 1;
    }
 
    return nRetCode;
}
引用
评论
11年6个月前IP:广东
774161
2楼
能讲得这么清楚,很厉害。
我当年看到MFC的第一反应就是吓死爹了。从此不敢碰。一直都用.NET偷懒。
引用
评论
acmilan作者
11年5个月前修改于 11年5个月前IP:四川
776357
3楼
引用 novakon:
能讲得这么清楚,很厉害。
我当年看到MFC的第一反应就是吓死爹了。从此不敢碰。一直都用.NET偷懒。
实际上国内最流行的小型软件大多是用WTL和DirectUI做的
当然也有一些用MFC的,比如分区助手
就是很少看到用.NET做的流行的,国外反而比较偏爱.NET,可能和国内XP泛滥有关
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的