牛骨文教育服务平台(让学习变的简单)
博文笔记

入口函数 main 和 WinMain 的返回值

创建时间:2012-04-18 投稿人: 浏览次数:1258

http://blog.csdn.net/brantyou/article/details/7308004

自一开始接触 C 语言 和后来的 Windows 编程,我们就知道必须为程序定义一个入口函数 main 或 WinMain 。且已知的 main 函数可以提供一个返回值 int 或者不返回任何数值,即定义为 void main() / void main (int argc, char* argv[] /*, char* env[]*/)等形式。而相对应的WinMain函数作为窗口程序的入口函数,它的返回值必须定义成int 类型 ,且程序返回时,应当返回一个数值。

我们知道,当 main 或 WinMain 的return语句被执行后,应用程序也就退出了,那么既然程序已经退出了,return后面的那个值究竟又到什么地方去了,谁又会等候该值呢?毕竟在一般的函数譬如: HDC GetDC(); 返回的 HDC 自然是给调用 GetDC() 函数的主调程序所使用的,因此在设计 GetDC 这个函数时,设计者很明确返回值会被谁使用,可是,入口函数的返回值被谁使用并不是很明确。

在著作《Windows核心编程》中,作者J.Richter在进程这一章指出, 入口函数会被C运行时库(CRT)调用。且VS配套提供了这个库函数mainCRTStartup / WinMainCRTStartup 的源代码文件<crtexe.c>。顺着作者的指引,在该书中可以找到 mainCRTStrartup / WinMainCRTStartup 这个 exe 文件真正的入口函数以及它会调用我们的 main / WinMain 函数这一事实。顺着调用 main / WinMain 函数的代码往下继续查看,会发现,如果 mainCRTStartup / WinMainCRTStartup 在后续的清理过程中未检测到其它的错误,它会把 main / WinMain 函数返回的这个 int 值放到 exit(int) 这个标准的C函数中,自从学C语言以来,我们就知道,exit 函数是应用程序退出的标准函数,且查看 MSDN 关于 exit 函数的说明,文档明确指出返回值可以被 Windows 的 batch command (批处理命令)所使用。

即,如果有个程序名为c:/a.exe,我们可以为该程序建立一个批处理文件 exec_a.bat, 在文件中输入一行命令 a.exe , 就可以执行该程序,在第二行中输入@echo %errorlevel%。当a.exe结束后,echo命令会把a.exe通过 main / WinMain 函数返回的值打印在控制台上,原理是当exit(int)执行后,退出码会被放到 errorlevel 中,我们只需查看 errorlevel 就能知道程序的返回值究竟是多少,从而在批处理中,根据程序的返回值做其他的工作,譬如可以写一个这样的批处理文件:

 

::关闭回显。

@echo off

::执行a.exe。

@a.exe

::如果返回值是0,打印 正确 ,如果返回1,打印 错误 。

@if errorlevel 1 echo 错误 & goto end

@echo 正确

:end

::打开回显

echo on

 

对于控制台程序,我们不必建立批处理文件,可以直接在命令提示符后面执行程序 a 回车,然后等程序执行完了立即再执行 echo %errorlevel% ,就能知道入口函数的返回值是多少了。但由于控制台程序无法调用win32程序,因此不能使用 echo %errorlevel% 的办法来查看返回值。只能提供一个批处理文件,然后以批处理文件为媒介,执行a.exe和返回值的查看工作。当然,批处理文件本身可以通过在资源管理器中双击执行或在控制台上执行,不管被执行的是控制台程序还是win32窗口程序都不会有问题。

 

以下,给出两个测试程序,它将解析命令提示符传送给它的参数,如果能解析成一个数字,就将结果显示在控制台上(ConsoleApp.exe)或通过消息框(WindowsApp.exe)进行显示,最后返回 0,表示没有错误。遇上错误,会返回 1 或 2。最后建立两个批处理文件 ConsoleAppTest.bat 和 WindowsAppTest.bat 来进行测试。

 

ConsoleApp:

[cpp] view plaincopy
  1. // C++ code  
  2. // ConsoleApp.cpp  
  3. #include <stdio.h>  
  4. #include <tchar.h>  
  5. #include <Windows.h>  
  6.   
  7. // 函数前导声明。  
  8. void Usage();  
  9. BOOL __stdcall Str2iNumW(LPCWSTR, int *, BOOL);  
  10. BOOL __stdcall Str2iNumA(LPCSTR, int *, BOOL);  
  11.   
  12. // 宏定义。  
  13. #undef Str2iNum  
  14. #ifdef _UNICODE  
  15. #define Str2iNum Str2iNumW  
  16. #else  
  17. #define Str2iNum Str2iNumA  
  18. #endif  
  19.   
  20. int _tmain(int argc, _TCHAR* argv[])  
  21. {  
  22.     int nRet = 0;  
  23.     int num = 0;  
  24.     BOOL bRet = FALSE;  
  25.     DWORD dwErr = 0;  
  26.     LPCTSTR pParam = NULL;  
  27.   
  28.     _tprintf(_T("/r/nConsole App is running.../r/n/r/n"));  
  29.   
  30.     if (argc == 2)  
  31.     {  
  32.         pParam = argv[1];  
  33.         if (*pParam == _T("/"))  
  34.         {  
  35.             pParam++;  
  36.             bRet = Str2iNum(pParam, &num, FALSE);  
  37.             if (bRet != FALSE)  
  38.             {  
  39.                 _tprintf(_T("The number is %d./r/n"), num);  
  40.             }  
  41.             else  
  42.             {  
  43.                 dwErr = GetLastError();  
  44.                 if (dwErr == ERROR_INVALID_DATA)  
  45.                 {  
  46.                     _tprintf(_T("ERROR: the number "%s" is too large./r/n"), pParam);  
  47.                     _tprintf(_T("Please use the number between -2147483648 and 2147483647 !/r/n"));  
  48.                 }  
  49.                 else  
  50.                 {  
  51.                     _tprintf(_T("ERROR: invalid parameter "%s"./r/n"), argv[1]);  
  52.                     Usage();  
  53.                 }  
  54.                 nRet = 2;  
  55.             }  
  56.         }  
  57.         else  
  58.         {  
  59.             _tprintf(_T("ERROR: invalid parameter "%s"./r/n"), argv[1]);  
  60.             Usage();  
  61.             nRet = 2;  
  62.         }  
  63.     }  
  64.     else if (argc == 1)  
  65.     {  
  66.         Usage();  
  67.         nRet = 1;  
  68.     }  
  69.     else  
  70.     {  
  71.         _tprintf(_T("ERROR: invalid parameter ""));  
  72.         for (int i = 1; i < argc; i++)  
  73.         {  
  74.             if (i != 1) _puttchar(_T(" "));  
  75.             _tprintf(argv[i]);  
  76.         }  
  77.         _tprintf(_T(""./r/n"));  
  78.         Usage();  
  79.         nRet = 2;  
  80.     }  
  81.   
  82.     _tprintf(_T("/r/nConsole App will return with value "%d"./r/n/r/n"), nRet);  
  83.     //返回值为0,表示没有错误。  
  84.     //返回值为1,表示一般错误。  
  85.     //返回值为2,表示较严重错误。                          
  86.     return nRet;  
  87. }  
  88.   
  89. // 程序使用方法。  
  90. void Usage()  
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。