WinMain函数

WinMain函数原型

Win32应用程序的入口函数为WinMain,函数原型在WinBase.h文件中:

int WINAPI WinMain (

    _In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPSTR lpCmdLine,
    _In_ int nShowCmd
);

WinMain函数原型中的符号

符号 描述 其它
int 返回值  
WINAPI 函数调用约定

WINAPI宏展开:

#define WINAPI      __stdcall

WinMain 函数名  
HINSTANCE hInstance 当前应用程序实例句柄

HINSTANCE宏展开:

DECLARE_HANDLE(HINSTANCE);

#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name

HINSTANCE hPrevInstance 没有意义。 它用于 16 位Windows,但现在始终为零  
LPSTR lpCmdLine 命令行参数  
int nShowCmd 窗口显示控制参数  

程序入口

C/C++语言中,main称为主函数,是程序的入口。Win32应用程序入口为什么是WinMain,而不是main呢?

C/C++语言中,程序入口为什么是main,而不是其它的呢?

CPU控制权传递

CPU是计算机的大脑,CPU读取指令后执行指令,即:控制CPU读指令的位置,就控制了CPU。

计算机加电后,CPU从BIOS指定位置读取并执行开机程序第一条指令,即,CPU被开机程序控制,开机程序获得了CPU的控制权。

开机程序获得CPU控制权后,其它程序如何获得CPU控制权呢?开机程序约定,我会去读取哪个地址的指令来执行。

其它程序把指令写入开机程序约定的地方,CPU的控制权就到了其它程序。

CPU控制权一步一步传递到操作系统。

CPU控制权到了操作系统后,其它程序想要获得控制权,就需要遵循操作系统的约定。

操作系统约定包括PE格式等,首先按PE格式生成可执行文件,如.exe。

双击或者调用进程创建函数启动程序,操作系统将可执行程序装载到内存,将下一条读取地址指向程序的入口地址,这样CPU的控制权传递到了可执行程序。

PE文件生成

要执行自定义的指令,就要遵循与操作系统的约定。

操作系统要求装载PE格式的文件,可以通过编译工具编译生成PE格式文件,如.exe。

编程语言

编译工具负责生成PE格式文件。

编译工具约定了输入的格式,即编程语言。

程序入口

C/C++语言,可执行程序的入口默认是mainCRTStartup,该入口函数可以通过设置重新指定。

入口函数

编程语言约定了程序的入口函数,如main。有程序入口(mainCRTStartup)调用入口函数main

WinMain和main

C/C++语言的入口函数都是main,为什么Win32是WinMain?

程序入口

程序入口可以通过编译器指定,根据情况指定入口mainCRTStartup或WinMainCRTStartup或自定义

main调用

main调用可以通过exe_main.cpp,exe_common.inl文件查看

mainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->main()。

WinMain调用

WinMain调用可以通过exe_winmain.cpp,exe_common.inl文件查看

WinMainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->WinMain()。

构建原理

入口函数缺失

在控制台程序中,不写main函数,编译报错:

1>MSVCRTD.lib(exe_main.obj) : error LNK2019: 无法解析的外部符号 main,函数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了该符号

在Win32程序中,不写WinMain函数,编译报错:

1>MSVCRTD.lib(exe_winmain.obj) : error LNK2019: 无法解析的外部符号 WinMain,函数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了该符号

LIB文件

上面的MSVCRTD.lib(exe_main.obj) 是什么意思?

.lib文件可以是静态链接库,也可以是导入库。

静态链接库包含可执行代码,导入库包含导入库信息。可以通过lib命令查看lib文件的类型。

MSVCRTD.lib是一个静态链接库。

exe_main.obj是MSVCRTD.lib中的一部分。

链接

链接时,由于程序入口为mainCRTStartup或WinMainCRTStartup,因此链接时会对程序入口的依赖进行检查。

main链接时,exe_main.obj包含mainCRTStartup()。

mainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->main()。

如果不写main函数,链接找不到main函数,链接报错。

main链接时,exe_winmain.obj包含WinMainCRTStartup()。

WinMainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->WinMain()。

如果不写WinMain函数,链接找不到WinMain函数,链接报错。

WinMain是如何被调用的的更多相关文章

  1. MFC框架中消失的WinMain()

    学过一段时间的MFC之后,很多人大概都有一个疑问:在MFC中,WinMain()哪去了?因为任何一个使用过Win32 SDK编程的人都知道,WinMain()函数是Win32程序开始的入口点,可是在M ...

  2. Qt Windows下链接子系统与入口函数(终结版)(可同时存在main和WinMain函数)

    Qt Windows下链接子系统与入口函数(终结版) 转载自:http://blog.csdn.net/dbzhang800/article/details/6358996 能力所限,本讨论仅局限于M ...

  3. 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理

    Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services.exe -unregserver Windows服务Release版本 注册 Servi ...

  4. MFC之目录结构及消息流转(一)

    跟上时代,用vs2010, 新建一个MFC应用程序Helloworld. 目录结构: 所有文件分为6个部分:解决方案相关文件.工程相关文件.应用程序头文件和源文件.资源文件.预编译头文件和编译链接生成 ...

  5. VS2010/MFC编程入门之四(MFC应用程序框架分析)

    VS2010/MFC编程入门之四(MFC应用程序框架分析)-软件开发-鸡啄米 http://www.jizhuomi.com/software/145.html   上一讲鸡啄米讲的是VS2010应用 ...

  6. 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理

    原文:玩转Windows服务系列——Debug.Release版本的注册和卸载,及其原理 Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services ...

  7. 使用DirectX作渲染过程

    1. 首先知道渲染代码放置位置.渲染代码放在WinMain消息循环中 while(msg.message!=WM_QUIT) { if(PeekMessage(****) { TranslateMes ...

  8. Win32消息循环机制等【转载】http://blog.csdn.net/u013777351/article/details/49522219

    Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个 ...

  9. 收藏:Win32消息机制

    Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个 ...

随机推荐

  1. 如何查看Python中所有关键字

    一.保留字即关键字,我们不能把它们用作任何标识符名称.Python的标准库提供了一个keyword模块,可以输出当前版本的所有关键字 import keyword print(keyword.kwli ...

  2. [BUUCTF]REVERSE——[MRCTF2020]Xor

    [MRCTF2020]Xor 附件 步骤: 例行检查,32位程序,无壳 32位ida载入,首先检索程序里的字符串,根据字符串的提示,跳转到程序的关键函数 根据flag,跳转到sub_401090函数 ...

  3. C++ happens-before 关系是不可传递的

    P0668R4 对此进行了解释 The definition of plain happens-before became unpleasantly complicated with the intr ...

  4. CF1110A Parity 题解

    Content 求下面式子的奇偶性,其中 \(a_i,k,b\) 会在输入中给定. \[\sum\limits_{i=1}^k a_i\cdot b^{k-i} \] 数据范围:\(2\leqslan ...

  5. MVC中的打印功能

    HTML页面: @{ Layout = "~/Views/Shared/_IframeLayout.cshtml";}@Scripts.Render(ViewBag.ScriptP ...

  6. mpstat 查看多核CPU负载状态

    mpstat是Multiprocessor Statistics的缩写,是实时系统监控工具.其报告与CPU的一些统计信息,这些信息存放在/proc/stat文件中.在多CPUs系统里,其不但能查看所有 ...

  7. pymysql-sqlalchemy-orm

    sqlalchemy示例代码 多对多外键 场景:一个作者映射多个书籍,一个书籍有多个作者 作者表: id name email sex 1 Alex alex@.. M 2 Rail rail@.. ...

  8. 关于Marshal 类的整理

    在两个不同的实体(两个线程或者进程甚至机器.在Managed和Unmanaged之间)进行方法调用和参数传递的时候,具体的调用方法和参数的内存格式可能需要一定的转换,这个转换的过程叫做Marshal. ...

  9. js判断是电脑(pc)访问还是手机(mobile)访问

    <script> if ((navigator.userAgent.match(/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symb ...

  10. 【LeetCode】671. Second Minimum Node In a Binary Tree 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 找出所有值再求次小值 遍历时求次小值 日期 题目地址 ...