关于不同的程序入口,main(), _tmain(),WinMain(),wmain()?

本文探讨了不同程序入口如main(), _tmain(), WinMain(), wmain()的用法和背后的原理。在Windows环境下,编译器和链接器会根据程序类型选择合适的入口点,例如使用/SUBSYSTEM:CONSOLE对应mainCRTStartup,而/SUBSYSTEM:WINDOWS则对应WinMainCRTStartup。这些入口点函数负责初始化运行时库,调用全局对象的构造函数等任务。默认情况下,不应轻易更改入口点,以免增加额外的初始化工作。文章还介绍了加载器如何与链接器协同工作,确保程序正确执行。" 128111226,12569110,Linux操作与配置实践指南,"['Linux操作系统', 'Docker容器', '系统管理', 'Shell脚本', '编程']

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

今天终于有时间来研究一下一个很大很大的工程编译成一个exe和若干dll后,程序是如果执行它的第一条指令的?操作系统以什么规则来找到应该执行的第一条指令(或说如何找到第一个入口函数的)?

   我们以前写windows程序时,都是先写个main()函数,然后再写自己的逻辑,然后编译,然后点击exe就能运行我们的程序了;如果我们用VS2005工具生成一个非空工程,工程会为我们提供一个int_tmain(int argc, _TCHAR*argv[])或WinMain()函数的入口,然后我们在里面添加程序等等。我们上学时这是这样做了,但是很多人这时理所当然的,很少人会去问为什么会这样?

   我读了MSDN里面的讲解才弄出点眉目了,其实我们以前所写的以main()函数开始的程序都是一个半成品,剩下的也是与系统息息相关的工作由编译器帮我们代劳了。怎么回事呢?编译器是如何帮我们代劳的呢?那么程序被系统加载时,准确的说是被系统中的加载器加载时又是如何知道编译器在我们写的程序上做了手脚呢?难道编译器和加载器之间有什么协定吗?这一些列的问题,做为刚入行的你是否在心里问过自己没有!?

   我们以前写的程序在编译器编译成为一个模块(可能是obj文件或其他形式),然后链接器会将一些所需要的库文件和刚才编译器生成的文件进行链接,最终生成一个exe文件,在所链接的库文件中就包含CRT运行时库,这就是我们今天谈论的主角。在运行时库里面有好一个已经定义如下的函数函数:

(1)mainCRTStartup(或wmainCRTStartup)       //使用/SUBSYSTEM:CONSOLE 的应用程序

(2)WinMainCRTStartup(或 wWinMainCRTStartup) //使用/SU

<think>好的,我现在需要帮助用户解决如何在WinMain函数中获取命令行参数的问题。首先,我得回忆一下Windows编程的相关知识。WinMain函数的参数中有一个是hInstance,另一个是lpCmdLine,但用户可能想获取完整的命令行参数,类似于C/C++中的argc和argv。 记得在标准C的main函数里,argc和argv可以直接使用,但WinMain的参数不同WinMain的第三个参数是LPSTR lpCmdLine,但它可能不会正确处理带空格的参数,因为它是整个命令行字符串,需要自己解析。不过Windows提供了GetCommandLineW函数来获取完整的命令行字符串,然后可以用CommandLineToArgvW来分割成数组。 那用户需要的是示例代码,所以应该展示如何正确使用这些API。首先,获取命令行字符串,然后转换为宽字符版本,再分割成参数数组。需要注意的是,使用CommandLineToArgvW后要记得释放内存。 另外,要处理Unicode的情况,可能需要使用宽字符函数,比如wmain或者_tmain,但用户明确问的是WinMain。所以示例应该使用GetCommandLineW和CommandLineToArgvW,并转换成char**,或者保持宽字符。 还需要注意引用问题,用户提供的引用中有提到CefMainArgs和命令行参数的处理,引用[1]里提到了CefMainArgs main_args(hInstance),这可能涉及到CEF框架的处理,但用户的问题更基础,不需要涉及CEF。所以示例应该专注于Windows API的基本用法。 最后,确保代码正确无误,比如检查返回的指针是否为NULL,释放内存等。同时,提醒用户需要包含相关头文件和链接库,比如Shell32.lib,因为CommandLineToArgvW位于Shell32.dll中。 总结步骤:获取命令行字符串,分割成参数数组,处理参数,最后释放内存。示例代码要展示这些步骤,并解释每个部分的作用。可能还需要提到不同字符集(Unicode和多字节)的影响,但用户可能只需要一个基本的示例,所以保持简单。</think>在Windows应用程序开发中,通过`WinMain`函数获取命令行参数需要特别注意其参数传递机制。以下是标准实现方法和示例: ### 实现步骤 1. **使用`GetCommandLineW`函数** 该API返回完整的Unicode格式命令行字符串,可处理带空格的参数 ```cpp LPWSTR lpCmdLine = GetCommandLineW(); ``` 2. **解析命令行参数** 使用`CommandLineToArgvW`将字符串分割为参数数组,注意: - 第一个参数是可执行文件路径 - 需要链接Shell32.lib库 ```cpp int argc; LPWSTR* argv = CommandLineToArgvW(lpCmdLine, &argc); ``` ### 完整代码示例 ```cpp #include <windows.h> #include <shellapi.h> int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 获取完整命令行参数 LPWSTR commandLine = GetCommandLineW(); // 分割为参数数组 int argc = 0; LPWSTR* argv = CommandLineToArgvW(commandLine, &argc); // 参数处理示例 if(argc > 1) { MessageBoxW(NULL, argv[1], L"第一个参数", MB_OK); } // 必须释放内存 LocalFree(argv); return 0; } ``` ### 关键点说明 1. **字符编码处理** `CommandLineToArgvW`返回宽字符数组,如需ANSI字符串可使用`WideCharToMultiByte`转换 2. **参数有效性验证** ```cpp if(argv == NULL) { // 错误处理 DWORD err = GetLastError(); } ``` 3. **内存管理** 必须调用`LocalFree`释放参数数组内存,避免内存泄漏 4. **调试技巧** 可通过`OutputDebugStringW`输出参数到调试器: ```cpp for(int i=0; i<argc; i++){ OutputDebugStringW(argv[i]); OutputDebugStringW(L"\n"); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值