原文:http://blog.csdn.net/weiwenhp/article/details/8455471

习惯的思维

用习惯了C的人要看一个程序时首先会想到找到那个main函数在哪,然后再顺着往下看.因为main函数作为程序的入口点,整个程序都是从那开始执行的.当在C++中SDK(win32 API project)开发时也继承沿用C的思维,是有个main函数,不过现在的main函数改名字了,叫WinMain,当然有时还有变体,比如叫_tWinMain,反正名字中总会带个Main,让我们一看就知道.而在QT中就跟C一样,就老实的来个标准的main函数.

我们会发现C++中可以有一个单独的main函数,不用包含在哪个类中,另外还有不属于任何类的全局变量或全局函数这自然就不是纯粹的面向对象语言了.所以说C++支持多种编程范式嘛,可以是跟C完全一样的面向过程范式,或者再加些普通的类就是基于对象的范式了,如果再用到继承和多态就是面向对象了,而要是用到模板就是泛型范式了.而且这些范式可以互相混合用.而C#就是纯的面向对象,所以它里面虽然也有main函数,但也是要放在一个类里面去,至于具体放哪个类无所谓,你随便放.一般默认是放Program这个类里.当然并不是说纯的面向对象就比混合的范式好,应该各有优缺点.

哎扯得有点远了,言归正传.

SDK中的流程

开发一个带界面的SDK程序大致流程是这样的.首先自然是要有个main函数做入口点.然后按下面的步骤来(为了讨论方便,只说大概流程,代码也是不完整的)

int _tWinain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{

MSG msg;

 InitApplicatio(HINSTANCE hInstance)   //第1步,注册窗体类,并在这里指定了窗体过程WndProc

 InitInstance(HINSTANCE hInstance, int nCmdShow)   //第2步,创建窗体

while (GetMessage(&msg, NULL, 0, 0))    //第3步消息循环,分派消息

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return (int) msg.wParam;  //第4步,退出程序

}

BOOL InitApplicatio(HINSTANCE hInstance)

{

return RegisterClass(...);

}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

CreateWindow(...); //创建窗体

ShowWindow(...); //显示窗体

UpdateWindow(...); //送出WM_PAINT

return TRUE;

}

LRESULT CALLBACK WndProc(...){ }

在MFC中生成一个有界面的程序大体过程也一样,只不过封装起来了.那我们感兴趣的就是两个问题.

1.MFC中有没有main函数了,如果有它跑哪去了

2.如果有main函数,它里面的那4步涉及到的具体操作是否也跟win32 API一样?

下面我们就来一一解答下

MFC封装背后流程

实际上候捷那本深入浅出MFC里面有讲的很清楚了.不过由于讲的太详细了,有几十页,看的容易晕,而且他举的例都是老版本的MFC类,在新版本中一些类的函数会有一点点变化.

我这里就只概括的讲下最简洁的流程.先假如有类CMyApp继承自CWinApp吧

1.针对第一个问题,MFC里是有用到main函数的

// export WinMain to force linkage to this module

extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

_In_ LPTSTR lpCmdLine, int nCmdShow);

就是这一个函数,在MFC的源文件appmodul.cpp中能看到这些代码,那这个main怎么被MFC调用的呢,你看那注释,是linkage to this module,也就是被链接器去调用的.准确说是被C-Runtime DLL,C运行时动态链接库调用的.

调用main的顺序

我们知道在MFC中能从代码里看到的入口点是定义一个全局的继承于CWinApp的类.比如CMyApp theApp;这样定义下.在C++中全局变量是先于main被执行的,所以先初始化theApp后才接着调用main

2.针对第2个问题,main函数里具体的操作.

知道了有main函数,你心里可能有一丝安慰了.但还是有些觉得不安的是这main函数里的具体操作是否跟SDK中的一样,是不是也来那么几步,先注册窗口再创建窗口之类的.

答案是MFC调用的main函数大概流程差不多是那样,但实现细节很不一样.我们看下上面说的AfxWinMain里面的内容是啥吧.你可以在winmain.cpp中看到详细代码.

把这个main函数简化一下,做的操作大概是这样,

AfxWinMain(...)

{

//先通过一个全局函数获得CWinApp和CWinThread的指针,因为调用main之前已经初始化了这两个类.CMyApp初始化时也会初始化他的父类CWinApp,及父类的父类CWinThread

CWinThread* pThread = AfxGetThread();

CWinApp* pApp = AfxGetApp();

//这下面几个函数就差不多是完成前面讲的SDK中的所有步骤

pApp->InitApplication();

pThread->InitInstance();

pThread->Run();

AfxWinTerm(); //结束程序

}

反正结束程序我们就不用管了,重点关心前面的三步,注册窗口,创建窗口,还有消息分派.

前面的SDK程序中也恰好有函数InitApplication 注册窗口, InitInstance创建并显示窗口.而Run函数你猜想可能是分派消息的..其实大体思路还是没错,但实现细节还是有蛮多区别.

pApp->InitApplication();这函数实际上并没有注册窗口.注册窗口,创建显示窗口全是在pThread->InitInstance();这函数中完成,InitInstance是个虚函数,而且我们在自己的代码中会重写它.所以最后调用的是我们自己写的那个InitInstance函数,这就是面向对象里多态的功能了啊.你指针最终指向对应的子类定义的函数.

BOOL CMyApp::InitInstance()

{

m_pMainWnd = new CMyFrameWnd; //这张操作会注册并创建窗口,m_pMainWnd就是返回的窗口句柄

m_pMainWnd->ShowWindow(m_nCmdShow); //显示窗口

m_pMainWnd->UpdateWindow();

}

pThread->Run();是分派消息,你可以在thrdcore.cpp中查看CWinThreed的run函数的源码,下面摘了一点点.

// acquire and dispatch messages until a WM_QUIT message is received.

for (;;)

{}

不过关于消息的处理MFC用到了消息映射机制,比如复杂.这里不讨论了,反正大概就把CMyFrameWnd当成是窗口过程就行了.

MFC怎么封装CreateWindowhttp://blog.csdn.net/weiwenhp/article/details/8796337

总结起来可以这样简单的说,MFC中有main函数,但是由系统去调用.然后main函数里面执行的操作差不多,只不过它是通过CWinAppCWinThread的指针去调用一些相关的函数.而指针嘛由于调用了虚函数,所以用到了面向对象中的多态,于是转来转去的.然后最难的地方可能就是消息机制在这里更复杂一点了.不能简单的与SDK中做一对一的对比.

【转载】MFC的Main函数跑哪去了的更多相关文章

  1. java中main函数解析(转载)

    从写java至今,写的最多的可能就是主函数 public static void main(String[] args) {} 但是以前一直都没有问自己,为什么要这么写,因为在c语言中就没有这样子的要 ...

  2. 在纯C工程的main函数之前跑代码(手工找到程序入口点, 替换为我们自己的函数)

    在main函数之前跑代码的方法 方法: 手工找到程序入口点, 替换为我们自己的函数 写测试程序 // test.cpp : Defines the entry point for the consol ...

  3. 在C++工程中main函数之前跑代码的廉价方法(使用全局变量和全局函数)

    // test.cpp : Defines the entry point for the console application. // #include "stdafx.h" ...

  4. IntelliJ创建main函数、for循环,System.out.println()等快捷建(转载)

    在编写代码的时候直接输入psv就会看到一个psvm的提示,此时点击tab键一个main方法就写好了. psvm 也就是public static void main的首字母. 依次还有在方法体内键入f ...

  5. 【转载】linux操作系统与应用程序的main函数

    来源:https://blog.csdn.net/h542723151/article/details/52154871 这几天一直在纠结: main函数是程序的入口,一个程序启动后,经过bootlo ...

  6. 单片机main函数退出后发生什么——以stm32为例

    STM32:main函数退出后发生什么? 我们都在说单片机要运行在无限循环里,不能退出,可退出之后会发生什么? 讨论STM32启动过程的文章数不胜数,可main函数结束之后会发生什么却少有讨论. 几日 ...

  7. SequoiaDB 系列之五 :源码分析之main函数

    好久好久没有写博客了,因为一直要做各种事,工作上的,生活上的,这一下就是半年. 时光如梭. 这两天回头看了看写的博客,感觉都是贻笑大方. 但是还是想坚持把SequoiaDB系列写完. 初步的打算已经确 ...

  8. [置顶] Embedded Server:像写main函数一样写Web Server

    1.传统的JEE Web Server 传统的JEE中,如果我们想要部署一个Web Application,我们需要首先安装一个Container Server,如JBoss,WebLogic,Tom ...

  9. node源码详解(五) —— 在main函数之前 —— js和C++的边界,process.binding

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource5 本博客同步在https://cnodejs.o ...

随机推荐

  1. Squid安装配置和使用

    文:铁乐与猫 环境 centos 6.5 x64 安装 最简单的一种就是yum安装. yum install squid 版本 rpm -qa | grep squid squid-3.1.23-16 ...

  2. 【Alpha】事后诸葛亮

    一. 项目的预期计划 / 项目的现实进展 详见Alpha冲刺博客第一篇 二. 完成项目过程中的体会 详见Alpha冲刺博客第十二篇 三. 团队成员的分工及在Alpha阶段的工作量比例 成员 职务 博客 ...

  3. 1.3 Essential Python Libraries(一些重要的Python库)

    1.3 Essential Python Libraries(一些重要的Python库) 如果不了解Python的数据生态,以及本书中即将用到的一些库,这里会做一个简单的介绍: Numpy 这里就不过 ...

  4. linq to sql 中增删改查

    首先我先说一下,如果真的要用linq做项目的话,也会是比较方便的.已经尝试了在三层架构中应用linq to sql 比较方便. //有三个不同的数据库表,所以写法不一样 public class Li ...

  5. 微信小程序、安卓APP、苹果APP对比分析

    今天的话题主要是关于微信小程序.安卓APP.苹果APP对比分析.既然是对比分析肯定是将它们一个一个说明. 本篇不涉及技术话题,只讲解微信小程序.安卓APP.苹果APP它们各自的优缺点及其应用场景. 一 ...

  6. 专家PID控制

    1.专家PID控制原理 PID专家控制的实质是,基于受控对象和控制规律的各种知识,无需知道被控对象的精确模型,利用专家经验来设计PID参数.专家PID控制是一种直接型专家控制器. 典型的二阶系统单位阶 ...

  7. java final使用

    一:final 1:有时候 我们需要一些类,不要被继承.即阻止定义子类.不允许扩展的类叫做final类,如果一个类在定义的时候,用final定义的时候,表示这个类是final类.无法定义子类. 语法 ...

  8. Jmeter之post上传文件

    上周五东西都收拾好了,然后被叫住加班,直接搞到凌晨一两点,原因是另一个项目的性能出了点问题.为此我抓包写了一下主业务流的接口,涉及到文件上传,记录一下吧. 一.创建线程组,添加各类组件 这个就不用说了 ...

  9. Android working with Volley Library

    Volley提供了优美的框架,使得Android应用程序网络访问更容易和更快.Volley抽象实现了底层的HTTP Client库,让你不关注HTTP Client细节,专注于写出更加漂亮.干净的RE ...

  10. Ural 1183 Brackets Sequence(区间DP+记忆化搜索)

    题目地址:Ural 1183 最终把这题给A了.. .拖拉了好长时间,.. 自己想还是想不出来,正好紫书上有这题. d[i][j]为输入序列从下标i到下标j最少须要加多少括号才干成为合法序列.0< ...