WinMain是如何被调用的
WinMain函数
WinMain函数原型
Win32应用程序的入口函数为WinMain,函数原型在WinBase.h文件中:
int WINAPI WinMain ( _In_ HINSTANCE hInstance, |
![]() |
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是如何被调用的的更多相关文章
- MFC框架中消失的WinMain()
学过一段时间的MFC之后,很多人大概都有一个疑问:在MFC中,WinMain()哪去了?因为任何一个使用过Win32 SDK编程的人都知道,WinMain()函数是Win32程序开始的入口点,可是在M ...
- Qt Windows下链接子系统与入口函数(终结版)(可同时存在main和WinMain函数)
Qt Windows下链接子系统与入口函数(终结版) 转载自:http://blog.csdn.net/dbzhang800/article/details/6358996 能力所限,本讨论仅局限于M ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services.exe -unregserver Windows服务Release版本 注册 Servi ...
- MFC之目录结构及消息流转(一)
跟上时代,用vs2010, 新建一个MFC应用程序Helloworld. 目录结构: 所有文件分为6个部分:解决方案相关文件.工程相关文件.应用程序头文件和源文件.资源文件.预编译头文件和编译链接生成 ...
- VS2010/MFC编程入门之四(MFC应用程序框架分析)
VS2010/MFC编程入门之四(MFC应用程序框架分析)-软件开发-鸡啄米 http://www.jizhuomi.com/software/145.html 上一讲鸡啄米讲的是VS2010应用 ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
原文:玩转Windows服务系列——Debug.Release版本的注册和卸载,及其原理 Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services ...
- 使用DirectX作渲染过程
1. 首先知道渲染代码放置位置.渲染代码放在WinMain消息循环中 while(msg.message!=WM_QUIT) { if(PeekMessage(****) { TranslateMes ...
- Win32消息循环机制等【转载】http://blog.csdn.net/u013777351/article/details/49522219
Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个 ...
- 收藏:Win32消息机制
Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个 ...
随机推荐
- 根据注释生成xml和从nuget包中复制xml显示到swagger
生成xml到输出目录 从注释生成xml 在要生成xml的项目的csproj中添加如下代码, 生成的xml名称为项目名称.xml. 比如该项目叫做Abp.Application, 则xml名为 Abp. ...
- 前端避坑指南丨辛辛苦苦开发的 APP 竟然被判定为简单网页打包?
传统混合移动App开发模式,通常会使用WebView作为桥接层,但随着iOS和Android应用商店审核政策日趋严格,有时会被错误判定为简单网页打包成App,上架容易遭到拒绝. 既然可能存在风险,那我 ...
- 使用 scipy.fft 进行Fourier Transform:Python 信号处理
摘要:Fourier transform 是一个强大的概念,用于各种领域,从纯数学到音频工程甚至金融. 本文分享自华为云社区<使用 scipy.fft 进行Fourier Transform:P ...
- 例外日期(Project)
<Project2016 企业项目管理实践>张会斌 董方好 编著 日历无论怎么样自定义,只要仍是存在固化规律的,就铁定会坏事,因为人类的历史就是在大规律中掺杂着无数无规律,再由无数无规律凝 ...
- Log4j2又爆雷!2.16.0存在DOS风险,升级2.17.0可解决
本以为,经过上周的2.16.0版本升级,Log4j2的漏洞修复工作,大家基本都要告一段落了. 万万没想到,就在周末,Log4j官方又发布了新版本:2.17.0 该版本主要修复安全漏洞:CVE-2021 ...
- k8s daemonset controller源码分析
daemonset controller分析 daemonset controller简介 daemonset controller是kube-controller-manager组件中众多控制器中的 ...
- 如何在服务器上新建一个svn的目录工程文件
如何在服务器上新建一个svn的目录工程文件
- 使用docker-compose一起安装kafka(zookeeper)
要先安装docker-compose Linux安装docker-compose 参考:https://www.cnblogs.com/pxblog/p/15049362.html 创建docker- ...
- 【LeetCode】NO.376 摆动序列 (Python) [贪心算法]
376. 摆动序列 题目 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 .第一个差(如果存在的话)可能是正数或负数.仅有一个元素或者含两个不等元素的序列也视作摆动序列. 例 ...
- 【LeetCode】441. Arranging Coins 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 模拟计算 二分查找 数学公式 日期 题目地址:htt ...