目录
操作系统实际上并不调用你编写的进入点函数。它调用的是 C / C + +运行期启动函数。该函 数负责对C / C + +运行期库进行初始化,这样,就可以调用malloc和free之类的函数。它还能够确 保已经声明的任何全局对象和静态C + +对象能够在代码执行以前正确地创建。下面说明源代码 中可以实现哪个进入点以及何时使用该进入点
应用程序类型 | 进入点 | 嵌入可执行文件的启动函数 |
---|---|---|
需要ANSI字符和字符串的GUI应用程序 | WinMain | WinMainCRTStartup |
需要Unicode字符和字符串的GUI应用程序 | wWinMain | wWinMainCRTStartup |
需要ANSI字符和字符串的CUI应用程序 | main | mainCRTStartup |
需要Unicode字符和字符串的CUI应用程序 | wmain | wmainCRTStratup |
应用程序启动进入函数
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代码