WINMAIN和main()在C ++(扩展)
对了,我看了这篇文章: WinMain,main和DllMain在C ++中的区别
我现在知道WINMAIN用于窗口应用程序, main()用于控制台。 但是阅读这篇文章并没有真正告诉我为什么有什么不同。 
我的意思是把不同的主要function分开来启动一个程序是什么意思? 这是由于性能问题? 或者是什么?
关于function。
  C和C ++标准要求任何程序(用于“托pipe”C或C ++实现)具有称为main的函数,该函数充当程序的启动function 。  main函数在非局部静态variables的零初始化之后被调用,并且可能但不一定(!,C ++ 11§3.6.2/ 4)这个调用在这些variables的dynamic初始化之后发生。 它可以具有以下签名之一: 
 int main() int main( int argc, char* argv[] ) 
 加上可能的实现定义签名(C ++ 11§3.6.1/ 2),除了结果types必须是int 。 
 因为在C ++ main唯一的这样的函数有一个默认的结果值,即0.如果main函数在普通函数返回exit之后返回,那么以main结果值作为参数被调用。 标准定义了三个保证可以使用的值:0(表示成功), EXIT_SUCCESS (也表示成功,通常定义为0)和EXIT_FAILURE (表示失败),其中两个命名常量由<stdlib.h>定义<stdlib.h>标题,它也声明了exit函数。 
  main参数旨在表示用于启动进程的命令的命令行参数 。  argc (参数计数)是argv (参数值)数组中的项目数。 除了这些项目argv[argc]保证是0.如果argc > 0  – 这是不能保证!  – 然后argv[0]保证是一个指向空string的指针,或者指向“用于调用程序的名字”的指针。 这个名字可能包含一个path,它可能是可执行文件的名字。 
 使用main参数获取命令行参数在* nix中工作正常,因为C和C ++源于* nix。 但是, main参数编码事实上的 Windows标准是Windows ANSI ,它不支持常规的Windows文件名(例如挪威语Windows安装,希腊语或西里尔文字符的文件名)。 因此,微软select使用一个名为wmain的Windows特定启动函数来扩展C和C ++语言,该函数具有以UTF-16编码的基于宽字符的参数,该参数可以表示任何文件名。 
  wmain函数可以具有这些签名之一 ,对应于main的标准签名: 
 int wmain() int wmain( int argc, wchar_t* argv[] ) 
再加上一些不是特别有用的东西。
 也就是说, wmain是一个基于直接宽字符的main替代品。 
  WinMain基于char的函数在20世纪80年代早期被Windows引入: 
 int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ); 
  CALLBACK , HINSTANCE和LPSTR由<windows.h>头文件定义( LPSTR只是char* )。 
参数:
- 
hInstance参数值是可执行文件内存映像的基址,主要用于从可执行文件中加载资源,也可以从GetModuleHandleAPI函数中获取,
- 
hPrevInstance参数始终为0,
- 
lpCmdLine参数也可以从GetCommandLineAPI函数获得,再加上一些奇怪的逻辑来跳过命令行的程序名部分,
- 
也可以从 GetStartupInfoAPI函数获得nCmdShow参数值,但是对于现代Windows,首先创build顶层窗口会自动执行,所以没有任何实际用途。
 因此, WinMain函数与标准main函数有一样的缺点,加上一些(特别是冗长和非标准的),并没有它自己的优点,所以除了可能作为一个供应商locking的东西,它真的是莫名其妙的。 但是,使用Microsoft工具链,它使链接器默认为GUI子系统,有些人认为这是一个优势。 但是,例如GNU工具链,它没有这样的效果,所以这个效果不能被依赖。 
 基于wWinMain wchar_t的函数是WinMain一个宽字符变体,就像wmain是标准main的宽字符变体一样: 
 int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmdShow ); 
  WINAPI与CALLBACK相同,而PWSTR只是wchar_t* 。 
 没有很好的理由使用任何非标准的函数,除了最不为人所知和最不受支持的函数,即wmain ,然后只是为了方便:避免使用GetCommandLine和CommandLineToArgvW API函数来获取UTF-16编码参数。 
 为了避免微软链接器动作(GNU工具链的链接器不),只需将LINK环境variables设置为/entry:mainCRTStartup ,或者直接指定该选项。 这是Microsoft运行时库入口点函数,它在一些初始化之后调用标准的main函数。 其他启动function具有相同的系统方式命名相应的入口点function。 
 使用标准mainfunction的例子。 
常用的源代码:
Foo.cpp中
 #undef UNICODE #define UNICODE #include <windows.h> int main() { MessageBox( 0, L"Press OK", L"Hi", MB_SETFOREGROUND ); } 
在下面的示例中(首先使用GNU工具链,然后使用Microsoft工具链),首先将该程序构build为控制台子系统程序 ,然后作为GUI子系统程序 。 一个控制台子系统程序,简而言之就是一个控制台程序 ,需要一个控制台窗口。 这是我使用的所有Windows链接器(默认不是很多)的默认子系统,可能适用于所有Windows链接器时期。
对于控制台程序,Windows会根据需要自动创build一个控制台窗口 。 任何Windows进程,无论子系统,都可以有一个关联的控制台窗口,最多一个。 此外,Windows命令解释程序等待控制台程序程序完成,以便程序的文本显示已完成。
 相反,GUI子系统程序是不需要控制台窗口的程序。 命令解释程序不会等待GUI子系统程序,batch file除外。 一种避免完成等待的方法,对于这两种程序,都是使用start命令。 从GUI子系统程序呈现控制台窗口文本的一种方法是redirect其标准输出stream。 另一种方法是从程序代码中显式创build一个控制台窗口。 
 程序的子系统编码在可执行文件的头部。 它不会被Windows资源pipe理器显示出来(除了在Windows 9x中可以“快速查看”一个可执行文件,这个可执行文件与微软的dumpbin工具现在提供的信息几乎相同)。 没有相应的C ++概念。 
  main用GNU工具链。 
[d:\ dev的\testing] > g ++ foo.cpp [d:\ dev的\testing] > objdump -x a.exe | find/我“subsys” MajorSubsystem版本4 MinorSubsystemVersion 0 子系统00000003(Windows CUI) (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000004 __major_subsystem_version__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000003 __subsystem__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000000__minor_subsystem_version__ [d:\ dev的\testing] > g ++ foo.cpp -mwindows [d:\ dev的\testing] > objdump -x a.exe | find/我“subsys” MajorSubsystem版本4 MinorSubsystemVersion 0 子系统00000002(Windows GUI) (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000004 __major_subsystem_version__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000002 __subsystem__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000000__minor_subsystem_version__ [d:\ dev的\testing] > _
  main用微软的工具链: 
 [d:\ dev的\testing]
 > set LINK = / entry:mainCRTStartup
 [d:\ dev的\testing]
 > cl foo.cpp user32.lib
 Foo.cpp中
 [d:\ dev的\testing]
 > dumpbin / headers foo.exe |  find/我“subsys”
             6.00子系统版本
                3子系统(Windows CUI)
 [d:\ dev的\testing]
 > cl foo.cpp / link user32.lib / subsystem:windows
 Foo.cpp中
 [d:\ dev的\testing]
 > dumpbin / headers foo.exe |  find/我“subsys”
             6.00子系统版本
                2子系统(Windows GUI)
 [d:\ dev的\testing]
 > _
 使用微软的wmainfunction的例子。 
以下主要代码对于GNU工具链和Microsoft工具链演示都是常见的:
bar.cpp
 #undef UNICODE #define UNICODE #include <windows.h> #include <string> // std::wstring #include <sstream> // std::wostringstream using namespace std; int wmain( int argc, wchar_t* argv[] ) { wostringstream text; text << argc - 1 << L" command line arguments:\n"; for( int i = 1; i < argc; ++i ) { text << "\n[" << argv[i] << "]"; } MessageBox( 0, text.str().c_str(), argv[0], MB_SETFOREGROUND ); } 
使用GNU工具链。
  GNU工具链不支持微软的wmainfunction: 
[d:\ dev的\testing] > g ++ bar.cpp d:/ bin中/ mingw的/ bin中/../ LIB / GCC / i686的-PC-的mingw32 / 4.7.1 /../../../ libmingw32.a(main.o),此:main.c中:(。 text.startup + 0xa3):对WinMain的未定义引用 @ 16' collect2.exe:错误:ld返回1退出状态 [d:\ dev的\testing] > _
 这里的关于WinMain的链接错误消息是因为GNU工具链支持该function(可能是因为古代代码使用了这么多),并且在找不到标准main之后作为最后的手段进行search。 
 但是,添加一个调用wmain的标准main模块是微不足道的: 
wmain_support.cpp
 extern int wmain( int, wchar_t** ); #undef UNICODE #define UNICODE #include <windows.h> // GetCommandLine, CommandLineToArgvW, LocalFree #include <stdlib.h> // EXIT_FAILURE int main() { struct Args { int n; wchar_t** p; ~Args() { if( p != 0 ) { ::LocalFree( p ); } } Args(): p( ::CommandLineToArgvW( ::GetCommandLine(), &n ) ) {} }; Args args; if( args.p == 0 ) { return EXIT_FAILURE; } return wmain( args.n, args.p ); } 
现在,
[d:\ dev的\testing] > g ++ bar.cpp wmain_support.cpp [d:\ dev的\testing] > objdump -x a.exe | find/我“子系统” MajorSubsystem版本4 MinorSubsystemVersion 0 子系统00000003(Windows CUI) (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000004 __major_subsystem_version__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000003 __subsystem__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000000__minor_subsystem_version__ [d:\ dev的\testing] > g ++ bar.cpp wmain_support.cpp -mwindows [d:\ dev的\testing] > objdump -x a.exe | find/我“子系统” MajorSubsystem版本4 MinorSubsystemVersion 0 子系统00000002(Windows GUI) (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000004 __major_subsystem_version__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000002 __subsystem__ (秒-1)(f1x00)(ty0)(sc12)(nx0)0x00000000__minor_subsystem_version__ [d:\ dev的\testing] > _
微软的工具链。
 使用微软的工具链,如果没有指定入口点并且存在一个wmain函数,链接器会自动推断wmainCRTStartup入口点(目前还不清楚如果标准main也存在,会发生什么,我近几年没有检查过): 
[d:\ dev的\testing] > set link = / entry:mainCRTStartup [d:\ dev的\testing] > cl bar.cpp user32.lib bar.cpp LIBCMT.lib(crt0.obj):错误LNK2019:无法parsing的外部符号_main在函数中引用___tmainCRTStartup bar.exe:致命错误LNK1120:1无法parsing的外部 [d:\ dev的\testing] > set link = [d:\ dev的\testing] > cl bar.cpp user32.lib bar.cpp [d:\ dev的\testing] > _
 如果使用非标准的启动函数(如wmain ),则可能最好是明确指定入口点,以便非常明确地expression意图: 
 [d:\ dev的\testing]
 > cl bar.cpp / link user32.lib / entry:wmainCRTStartup
 bar.cpp
 [d:\ dev的\testing]
 > dumpbin / headers bar.exe |  find/我“子系统”
             6.00子系统版本
                3子系统(Windows CUI)
 [d:\ dev的\testing]
 > cl bar.cpp / link user32.lib / entry:wmainCRTStartup / subsystem:windows
 bar.cpp
 [d:\ dev的\testing]
 > dumpbin / headers bar.exe |  find/我“子系统”
             6.00子系统版本
                2子系统(Windows GUI)
 [d:\ dev的\testing]
 > _
根据@RaymondChen
WinMain这个名字只是一个约定
虽然WinMain函数在Platform SDK中有logging,但它并不是平台的一部分。 而WinMain是用户提供的Windows程序入口点的传统名称。
真正的入口点在C运行时库中,它初始化运行时,运行全局构造函数,然后调用你的WinMain函数(或wWinMain,如果你喜欢Unicode入口点)。
DllMain和WinMain在原型本身是不同的。 WinMain接受命令行参数,而另一个则说明它是如何附着在进程上的。
根据MSDN文档
默认情况下,起始地址是C运行时库中的函数名称。 链接器根据程序的属性select它,如下表所示。
- 
mainCRTStartup(或wmainCRTStartup)使用/SUBSYSTEM:CONSOLE;的应用程序/SUBSYSTEM:CONSOLE;调用main(或wmain)
- 
WinMainCRTStartup(或wWinMainCRTStartup)使用/SUBSYSTEM:WINDOWS;的应用程序/SUBSYSTEM:WINDOWS;调用必须用__stdcall定义的WinMain(或wWinMain)
- 
_DllMainCRTStartup一个DLL; 调用DllMain,必须用__stdcall定义,如果存在的话
标准C程序在启动时由命令行传递2个参数:
 int main( int argc, char** argv ) ; 
-   char** argv是一个string数组(char*)
-   int argc是argv中char*的个数
 程序员必须为Windows程序编写的启动函数WinMain略有不同。  WinMain在启动时需要4个由Win O / S传递给程序的参数: 
 int WINAPI WinMain( HINSTANCE hInstance, // HANDLE TO AN INSTANCE. This is the "handle" to YOUR PROGRAM ITSELF. HINSTANCE hPrevInstance,// USELESS on modern windows (totally ignore hPrevInstance) LPSTR szCmdLine, // Command line arguments. similar to argv in standard C programs int iCmdShow ) // Start window maximized, minimized, etc. 
查看我的文章如何在C中创build基本窗口以获取更多信息
 我隐约可以回想起Windows程序有main()函数的地方。 它只是隐藏在某处的标题或库中。 我相信这个main()函数初始化WinMain()所需的所有variables,然后调用它。 
当然,我是一个WinAPI noob,所以我希望如果我错了,那些更有知识的人会纠正我。