Windows支持两种类型的应用程序:GUI程序和CUI程序,即图形用户界面和控制台用户界面。
Windows应有程序必须有一个入口点函数,应用程序开始运行时,这个函数会被调用。以下为应用程序类型和入口点啊函数:
| 应用程序类型 | 入口点函数(入口) | 嵌入可执行文件的启动函数 |
| 处理ANSI字符和字符串的GUI应用程序 | _tWinMain(WinMain) | WinMainCRTStartup |
| 处理Unicode字符和字符串的GUI应用程序 | _tWinMain(wWinMain) | wWinMainCRTStartup |
| 处理ANSI字符和字符串的CUI应用程序 | _tmain(Main) | mainCRTStartup |
| 处理Unicode字符和字符串的CUI应用程序 | _tmain(wMain) | wmainCRTStartup |
操作系统实际并不调用我们所写的入口点函数。它会调用由C/C++运行库实现并在链接时使用-entry:命令行选项来设置的一个C/C++运行时启动函数。该函数将初始化C/C++运行库,使我们能调用malloc和free之类的函数。它还确保了在我们的代码开始执行之前,我们声明的任何全局和静态C++对象都被正确地构造。
所有的C/C++运行库启动函数所做的事情基本都是一样的,用途简单总结如下:
在完成了所有的这些初始化操作之后,C/C++启动函数就会调用应用程先生的入口点函数。
当入口点函数返回之后,启动函数将调用C运行库函数exit,向其传递返回值(nMainRetVal)。exit函数执行以下任务:
- int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
- _In_opt_ HINSTANCE hPrevInstance,
- _In_ LPWSTR lpCmdLine,
- _In_ int nCmdShow)
- {
- ....
- }
上面是我生成一个GUI程序的main函数。
HINSTANCE hInstance:称为“实例句柄”或“模块句柄”。操作系统使用此值在内存中加载可执行文件时标识可执行文件 (EXE) 。 某些Windows函数需要实例句柄,例如加载图标或位图。
HINSTANCE hPrevInstance:C/C++运行库启动代码总是向此参数传递NULL,该参数用于16位操作系统,因而仍然保留,目的只是方便我们移植16位Windows应该程序。
LPWSTR lpCmdLine:C运行库启动代码开始执行一个GUI应用程序时,会调用Windows函数GetCommandLine来获取进程的完整命令行,忽略可执行文件的名称,然后将指向命令行剩余的部分的一个指针传给此参数。
int nCmdShow:是一个标志,指示主应用程序窗口是最小化、最大化还是正常显示。
使用函数CommandLineToArgvW()解析,CommandLineToArgvW在内部分配内存,许多应用程序不会释放这块内存——它们依靠操作系统在进程终止时释放这块内存。如果想要自己释放内存,正确的做法就是调用HeapFree。