windows进入函数与启动函数

本文详细解析了C/C++应用程序的启动过程,包括不同类型的程序如何选择合适的入口函数(如WinMain、wWinMain、main、wmain),以及链接器如何确定应用程序应连接到的子系统。同时,深入探讨了C/C++运行时启动函数的功能,如初始化全局变量、内存分配和环境设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


操作系统实际上并不调用你编写的进入点函数。它调用的是 C / C + +运行期启动函数。该函 数负责对C / C + +运行期库进行初始化,这样,就可以调用malloc和free之类的函数。它还能够确 保已经声明的任何全局对象和静态C + +对象能够在代码执行以前正确地创建。下面说明源代码 中可以实现哪个进入点以及何时使用该进入点

应用程序类型进入点嵌入可执行文件的启动函数
需要ANSI字符和字符串的GUI应用程序WinMainWinMainCRTStartup
需要Unicode字符和字符串的GUI应用程序wWinMainwWinMainCRTStartup
需要ANSI字符和字符串的CUI应用程序mainmainCRTStartup
需要Unicode字符和字符串的CUI应用程序wmainwmainCRTStratup

应用程序启动进入函数

WinMain – WinMainCRTStartup

int WINAPI WinMain(
	HINSTANCE hinsExe,
	HINSTANCE,
	PSTR pszCmdLine,
	int nCmdShow);

其中hinsExe实际值是系统将可执行文件的映象加载到进程的地址空间时 使用的基本地址空间。可执行文件的映像加载到的基地址是由链接程序决定的,不同的链接程序可以使用不同的默认基地址,VC++链接程序使用默认基地址为0x00400000,因为这是在运行Windows 98时可执行文件的映象可以加载的最低地址,可以使用Microsoft的链接程序中的 /BASE:address链接程序开关改变该地址

wWinMain – wWinMainCRTStartup

int WINAPI wWinMain(
	HINSTANCE hinsExe,
	HINSTANCE,
	PSTR pszCmdLine,
	int nCmdShow);

Main – mainCRTStartup

int __cdecl main(
	int argc,
	char *argv[],
	char *envp[]);

Wmain – wmainCRTStartup

int __cdecl wmain(
	int argc,
	char *argv[],
	char *envp[]);

链接程序负责在它连接可执行文件时选择相应的 C / C + +运行期启动函数。如果设定了 /SUBSYSTEM: WINDOWS链接程序开关,那么该链接程序期望找到一个WinMain或wWinMain 函数。如果这两个函数都不存在,链接程序便返回一个“未转换的外部符号”的错误消息。否 则,它可以分别选择WinMainCRTStartup函数或wWinMainCRTStartup函数。 同样,如果设定了/SUBSYSTEM: CONSOLE链接程序开关,那么该链接程序便期望找到main或wmain函数,并且可以分别选择mainCRTStartup函数或wmainCRTStartup函数。同样, 如果main或wmain都不存在,那么链接程序返回一条“未转换外部符号”的消息。
但是,我们可以从应用程序中全部删除/SUBSYSTEM链接程 序开关。当这样做的时候,链接程序能够自动确定应用程序应该连接到哪个子系统。当进行链 接时,链接程序要查看代码中存在4个函数(WinMain、wWinMain、main或wmain)中的哪一 个。然后确定可执行程序应该是哪一个子系统,并且确定可执行程序中应该嵌入哪个 C / C + +启 动函数。

C/C++ 运行期启动函数

启动函数功能

  • 检索指向新进程的完整命令行的指针
  • 检索指向新进程的环境变量的指针
  • 对C / C + +运行期的全局变量进行初始化。如果包含了StdLib.h文件,代码就能访问这些变 量
  • 对C运行期内存单元分配函数(malloc和calloc)和其他低层输入/输出例程使用的内存栈 进行初始化。
  • 为所有全局和静态C + +类对象调用构造函数
    当所有这些初始化操作完成后,C / C + +启动函数就调用应用程序的进入点函数

调用wWinMain函数

GetStartupInfo(&StartupInfo);
int nMainRetVal = wWinMain(GetMoudleHandle(NULL),NULL,pazCommandLineUnicode,(StartupInfo.dwFlags & STARTF_USESHOWWINDOW) ? StartupInfo.wShowWindow : SW_SHOWDEFAULT);

调用WinMain函数

GetStartupInfo(&StartupInfo);
int nMainRetVal = WinMain(GetMoudleHandle(NULL),NULL,pazCommandLineAnsi,(StartupInfo.dwFlags & STARTF_USESHOWWINDOW) ? StartupInfo.wShowWindow : SW_SHOWDEFAULT);

调用wmain函数

int nMainRetVal = wmain(__argc, __wargv, __wenviron);

调用main函数

int nMainRetVal = main(__argc, __argv, __environ)

exit函数

当进入点函数返回时,启动函数便调用C运行期的exit函数,将返回值(nMainRetVal)传递给它。exit该函数功能如下:

  • 调用由_oneexit函数的调用而注册的任何函数
  • 为所有全局的和静态的C++类对象调用析构函数
  • 调用操作系统的Exitprocess函数,将nMainRetVal传递给它,使操作系统能够取消进程并设置它的exit代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值