WINMAIN and main() in C++ (Extended)
是的,我看了这篇文章:C ++中的WinMain,main和DllMain之间的区别
我现在知道
我的意思是将不同的主函数分开来启动程序有什么意义? 是由于性能问题引起的吗? 还是什么
关于功能。
C和C ++标准要求任何程序(用于托管C或C ++实现)都具有称为
好。
1 2 | int main() int main( int argc, char* argv[] ) |
加上可能的实现定义的签名(C ++ 11§3.6.1/ 2),但结果类型必须为
好。
作为C ++中唯一这样的函数,
好。
好。
使用
好。
好。
1 2 | int wmain() int wmain( int argc, wchar_t* argv[] ) |
再加上一些不是特别有用的。
好。
即
好。
基于
好。
1 2 3 4 5 6 | int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ); |
其中
好。
参数:
好。
好。
好。
或者,可以从
好。
也可以从
好。
好。
因此,
好。
基于
好。
1 2 3 4 5 6 | int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmdShow ); |
其中
好。
除了最鲜为人知和最不支持的非标准函数,即
好。
为了避免Microsoft链接程序起作用(GNU工具链的链接程序没有作用),只需将
好。
使用标准
通用源代码:
好。
foo.cpp
好。
1 2 3 4 5 6 7 8 | #undef UNICODE #define UNICODE #include <windows.h> int main() { MessageBox( 0, L"Press OK", L"Hi", MB_SETFOREGROUND ); } |
在下面的示例中(首先使用GNU工具链,然后使用Microsoft工具链),该程序首先构建为控制台子系统程序,然后构建为GUI子系统程序。控制台子系统程序,或者简称为控制台程序,是需要控制台窗口的程序。这是我使用过的所有Windows链接程序(当然不是很多)的默认子系统,可能是所有Windows链接程序时期的默认子系统。
好。
对于控制台程序,Windows会根据需要自动创建一个控制台窗口。任何Windows进程,无论子系统如何,都可以有一个关联的控制台窗口,并且最多可以有一个。此外,Windows命令解释器会等待控制台程序完成,以便该程序的文本表示已经完成。
好。
相反,GUI子系统程序是不需要控制台窗口的程序。除了批处理文件外,命令解释器不等待GUI子系统程序。对于两种程序,避免完成等待的一种方法是使用
好。
程序的子系统编码在可执行文件的标头中。 Windows资源管理器未显示它(除了在Windows 9x中可以快速查看可执行文件,它提供的信息几乎与Microsoft的
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | [D:\dev\test] > g++ foo.cpp [D:\dev\test] > objdump -x a.exe | find /i"subsys" MajorSubsystemVersion 4 MinorSubsystemVersion 0 Subsystem 00000003 (Windows CUI) [544](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [612](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000003 __subsystem__ [636](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D:\dev\test] > g++ foo.cpp -mwindows [D:\dev\test] > objdump -x a.exe | find /i"subsys" MajorSubsystemVersion 4 MinorSubsystemVersion 0 Subsystem 00000002 (Windows GUI) [544](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [612](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000002 __subsystem__ [636](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D:\dev\test] > _ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | [D:\dev\test] > set LINK=/entry:mainCRTStartup [D:\dev\test] > cl foo.cpp user32.lib foo.cpp [D:\dev\test] > dumpbin /headers foo.exe | find /i"subsys" 6.00 subsystem version 3 subsystem (Windows CUI) [D:\dev\test] > cl foo.cpp /link user32.lib /subsystem:windows foo.cpp [D:\dev\test] > dumpbin /headers foo.exe | find /i"subsys" 6.00 subsystem version 2 subsystem (Windows GUI) [D:\dev\test] > _ |
使用Microsofts
以下主要代码对于GNU工具链和Microsoft工具链演示都是通用的:
好。
bar.cpp
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #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: "; for( int i = 1; i < argc; ++i ) { text <<" [" << argv[i] <<"]"; } MessageBox( 0, text.str().c_str(), argv[0], MB_SETFOREGROUND ); } |
GNU工具链不支持Microsoft的
好。
1 2 3 4 5 6 7 8 | [D:\dev\test] > g++ bar.cpp d:/bin/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.1/../../../libmingw32.a(main.o):main.c:(.text.startup+0xa3): undefined reference to `WinMain @16' collect2.exe: error: ld returned 1 exit status [D:\dev\test] > _ |
此处有关
好。
但是,添加带有标准
好。
wmain_support.cpp
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 ); } |
现在,
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | [D:\dev\test] > g++ bar.cpp wmain_support.cpp [D:\dev\test] > objdump -x a.exe | find /i"subsystem" MajorSubsystemVersion 4 MinorSubsystemVersion 0 Subsystem 00000003 (Windows CUI) [13134](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [13576](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000003 __subsystem__ [13689](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D:\dev\test] > g++ bar.cpp wmain_support.cpp -mwindows [D:\dev\test] > objdump -x a.exe | find /i"subsystem" MajorSubsystemVersion 4 MinorSubsystemVersion 0 Subsystem 00000002 (Windows GUI) [13134](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000004 __major_subsystem_version__ [13576](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000002 __subsystem__ [13689](sec -1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __minor_subsystem_version__ [D:\dev\test] > _ |
使用Microsoft的工具链,如果未指定入口点并且存在
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [D:\dev\test] > set link=/entry:mainCRTStartup [D:\dev\test] > cl bar.cpp user32.lib bar.cpp LIBCMT.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup bar.exe : fatal error LNK1120: 1 unresolved externals [D:\dev\test] > set link= [D:\dev\test] > cl bar.cpp user32.lib bar.cpp [D:\dev\test] > _ |
但是,对于诸如
好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [D:\dev\test] > cl bar.cpp /link user32.lib /entry:wmainCRTStartup bar.cpp [D:\dev\test] > dumpbin /headers bar.exe | find /i"subsystem" 6.00 subsystem version 3 subsystem (Windows CUI) [D:\dev\test] > cl bar.cpp /link user32.lib /entry:wmainCRTStartup /subsystem:windows bar.cpp [D:\dev\test] > dumpbin /headers bar.exe | find /i"subsystem" 6.00 subsystem version 2 subsystem (Windows GUI) [D:\dev\test] > _ |
好。
根据@RaymondChen
WinMain名称只是一个约定
Although the function WinMain is documented in the Platform SDK, it's
not really part of the platform. Rather, WinMain is the conventional
name for the user-provided entry point to a Windows program.The real entry point is in the C runtime library, which initializes
the runtime, runs global constructors, and then calls your WinMain
function (or wWinMain if you prefer a Unicode entry point).
DllMain和WinMain的原型本身不同。 WinMain接受命令行参数,而另一个则讨论如何将其附加到进程中。
根据MSDN文档
默认情况下,起始地址是C运行时库中的函数名称。链接器根据程序的属性选择它,如下表所示。
-
mainCRTStartup (或wmainCRTStartup )使用
/SUBSYSTEM:CONSOLE; 调用main(或wmain ) -
WinMainCRTStartup (或wWinMainCRTStartup )使用
/SUBSYSTEM:WINDOWS; 调用WinMain (或wWinMain ),该
用__stdcall 定义 -
_DllMainCRTStartup 一个DLL;调用DllMain ,如果存在,则必须使用__stdcall 进行定义
标准C程序在启动时会通过命令行传递2个参数:
1 | int main( int argc, char** argv ) ; |
-
char** argv 是字符串数组(char* ) -
int argc 是argv中char* 的数量
程序员必须为Windows程序编写的引导功能
1 2 3 4 | 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中创建基本窗口。
我隐约记得在某处Windows程序具有
当然,我是WinAPI的新手,所以我希望其他知识渊博的人能够在我输入错误的情况下纠正我。
我有一个使用_tWinMain和Configuration Properties.Linker.System.Subsystem:Windows(/ SUBSYSTEM:WINDOWS)的exe。后来我希望它支持cmdline args并打印到控制台,所以我添加了:
1 2 3 4 | // We need to printf to stdout and we don't have one, so get one AllocConsole(); // Redirect pre-opened STDOUT to the console freopen_s((FILE **)stdout,"CONOUT$","w", stdout); |
但这只能通过在另一个已消失的控制台窗口中进行打印来实现,因此没有什么用。下面是我将其更改为与控制台(/ SUBSYSTEM:CONSOLE)配合使用的方式,可以根据需要进行往返操作。
1 2 3 4 5 6 7 | int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { UNREFERENCED_PARAMETER(argc); UNREFERENCED_PARAMETER(argv); UNREFERENCED_PARAMETER(envp); return (_tWinMain(NULL, NULL, ::GetCommandLineW(), 0)); } |