C++ 中的 WINMAIN 和 main()(扩展)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13871617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:46:51  来源:igfitidea点击:

WINMAIN and main() in C++ (Extended)

c++windowsmainwinmain

提问by Danny

Right, I have looked at this post: Difference between WinMain,main and DllMain in C++

是的,我看过这篇文章:C++ 中 WinMain、main 和 DllMain 的区别

I now know that WINMAINis used for window applications and main()for consoles. But reading the post doesn't really tell me why exactly what is the difference.

我现在知道它WINMAIN用于窗口应用程序和main()控制台。但是阅读这篇文章并没有真正告诉我为什么到底有什么区别。

I mean what's the point of having separating different mains functions to start of a program? Is it due to performance issues? Or what is it?

我的意思是将不同的电源功能分开来启动程序有什么意义?是因为性能问题吗?或者是什么?

回答by Cheers and hth. - Alf

About the functions.

关于功能。

The C and C++ standards require any program (for a “hosted” C or C++ implementation) to have a function called main, which serves as the program's startup function. The mainfunction is called after zero-initializationof non-local static variables, and possibly but not necessarily (!, C++11 §3.6.2/4) this call happens after dynamic initializationof such variables. It can have one of the following signatures:

C 和 C++ 标准要求任何程序(对于“托管”C 或 C++ 实现)具有称为 的函数main,该函数用作程序的启动函数。在非局部静态变量的零初始化main之后调用该函数,并且可能但不一定(!,C++11 §3.6.2/4)该调用发生在此类变量的动态初始化之后。它可以具有以下签名之一:

int main()
int main( int argc, char* argv[] )

plus possible implementation-defined signatures (C++11 §3.6.1/2) except that the result type must be int.

加上可能的实现定义的签名(C++11 §3.6.1/2),但结果类型必须是int.

As the only such function in C++ mainhas a default resultvalue, namely 0. If mainreturns then after the ordinary function return exitis called with the mainresult value as argument. The standard defines three values that guaranteed can be used: 0 (indicates success), EXIT_SUCCESS(also indicates success, and is typically defined as 0), and EXIT_FAILURE(indicates failure), where the two named constants are defined by the <stdlib.h>header which also declares the exitfunction.

由于 C++ 中唯一这样的函数main具有默认结果值,即 0。如果main返回,则在exit调用普通函数之后,以main结果值作为参数返回。该标准定义了三个保证可以使用的值:0(表示成功)、EXIT_SUCCESS(也表示成功,通常定义为 0)和EXIT_FAILURE(表示失败),其中两个命名常量由<stdlib.h>标头定义,标头也声明了exit功能。

The mainarguments are intended to represent the command line argumentsfor the command used to start the process. argc(argument count) is the number of items in the argv(argument values) array. In addition to those items argv[argc]is guaranteed to be 0. If argc> 0 – which is not guaranteed! – then argv[0]is guaranteed to either be a pointer to an empty string, or a pointer to the “name used to invoke the program”. This name may include a path, and it may be the name of the executable.

The mainarguments are intended to represent the command line argumentsfor the command used to start the process. argc(argument count) is the number of items in the argv(argument values) array. In addition to those items argv[argc]is guaranteed to be 0. If argc> 0 – which is not guaranteed! – then argv[0]is guaranteed to either be a pointer to an empty string, or a pointer to the “name used to invoke the program”. This name may include a path, and it may be the name of the executable.

Using the mainarguments to obtain the command line arguments works fine in *nix, because C and C++ originated with *nix. However, the de factoWindows standard for the encoding of the mainarguments is Windows ANSI, which does not support general Windows filenames (such as, for a Norwegian Windows installation, filenames with Greek or Cyrillic characters). Therefore Microsoft chose to extend the C and C++ languages with a Windows-specific startup function called wmain, which has wide character based arguments encoded as UTF-16, which can represent any filename.

使用main参数来获取命令行参数在 *nix 中工作正常,因为 C 和 C++ 起源于 *nix。但是,用于参数编码的事实上的Windows 标准mainWindows ANSI,它不支持一般的 Windows 文件名(例如,对于挪威 Windows 安装,文件名带有希腊或西里尔字符)。因此,Microsoft 选择使用名为 的 Windows 特定启动函数来扩展 C 和 C++ 语言,该函数wmain具有编码为UTF-16 的基于宽字符的参数,可以表示任何文件名。

The wmainfunction can have one of these signatures, corresponding to the standard signatures for main:

wmain函数可以具有以下签名之一,对应于以下的标准签名main

int wmain()
int wmain( int argc, wchar_t* argv[] )

plus a few more that are not especially useful.

再加上一些不是特别有用的东西。

I.e., wmainis a direct wide character based replacement for main.

即,wmainmain.

The WinMaincharbased function was introduced with Windows, in the early 1980's:

该基于函数是在Windows介绍,在80年代初:WinMainchar

int CALLBACK WinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    LPSTR       lpCmdLine,
    int         nCmdShow
    );

where CALLBACK, HINSTANCEand LPSTRare defined by the <windows.h>header (LPSTRis just char*).

其中CALLBACK,HINSTANCELPSTR<windows.h>标头定义( LPSTRis justchar*) 。

Arguments:

参数:

  • the hInstanceargument value is the base address of the memory image of the executable, it's primarily used to load resources from the executable, and it can alternatively be obtained from the GetModuleHandleAPI function,

  • the hPrevInstanceargument is always 0,

  • the lpCmdLineargument can alternatively be obtained from the GetCommandLineAPI function, plus a bit of weird logic to skip the program name part of the command line, and

  • the nCmdShowargument value can alternatively be obtained from the GetStartupInfoAPI function, but with modern Windows the first creation of a top level window does that automatically so it's not of any practical use.

  • hInstance参数值是可执行的存储器图像的基地址,它主要用于负载资源从可执行,并且它可以替代地从所获得的GetModuleHandleAPI函数,

  • hPrevInstance参数始终为0,

  • 所述lpCmdLine参数可以替代地从所获得的GetCommandLineAPI函数,加上有点怪异逻辑的跳过命令行的程序名的一部分,和

  • nCmdShow参数值或者可从所获得的GetStartupInfoAPI函数,但与现代的Windows一个顶层窗口的第一个创造不自动因此它的任何实际用途的不是。

Thus, the WinMainfunction has the same drawbacks as standard main, plus some (in particular the verbosity and being non-standard), and no advantages of its own, so it's really inexplicable except possibly as a vendor lock-in thing. However, with the Microsoft tool chain it makes the linker default to the GUI subsystem, which some see as an advantage. But with e.g. the GNU toolchain it does not have such an effect so this effect cannot be relied on.

因此,该WinMain函数具有与 standard 相同的缺点main,加上一些(特别是冗长和非标准),并且没有自己的优点,所以它真的无法解释,除非可能是供应商锁定的东西。然而,使用 Microsoft 工具链,它使链接器默认为 GUI 子系统,有些人认为这是一个优势。但是对于例如 GNU 工具链,它没有这种效果,因此不能依赖这种效果。

The wWinMainwchar_tbased function is a wide character variant of WinMain, in the same way as wmainis a wide character variant of standard main:

的基于功能是一个宽字符变体,以相同的方式作为是标准的宽字符变体:wWinMainwchar_tWinMainwmainmain

int WINAPI wWinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    PWSTR       lpCmdLine,
    int         nCmdShow
    );

where WINAPIis the same as CALLBACK, and PWSTRis simply wchar_t*.

其中WINAPI与 相同CALLBACK,并且PWSTR只是wchar_t*

There is no good reason to use any of the non-standard functions except the least known and least supported of them, namely wmain, and then just for convenience: that this avoids using the GetCommandLineand CommandLineToArgvWAPI functions to pick up UTF-16 encoded arguments.

没有充分的理由使用任何非标准函数,除了它们中最不为人知和最不受支持的函数,即wmain, 然后只是为了方便:这避免使用GetCommandLineCommandLineToArgvWAPI 函数来获取 UTF-16 编码的参数。

To avoid the Microsoft linker acting up (the GNU toolchain's linker doesn't), just set the LINKenvironment variable to /entry:mainCRTStartup, or specify that option directly. This is the Microsoft runtime library entry point function that, after some initialization, calls the standard mainfunction. The other startup functions have corresponding entry point functions named in the same systematic way.

为避免 Microsoft 链接器起作用(GNU 工具链的链接器不会),只需将LINK环境变量设置为/entry:mainCRTStartup,或直接指定该选项。这是 Microsoft 运行时库入口点函数,经过一些初始化后,会调用标准main函数。其他启动函数都有相应的入口函数,以相同的系统方式命名。



Examples of using the standard mainfunction.

使用标准main函数的示例。

Common source code:

常用源代码:

    foo.cpp

    文件

#undef UNICODE
#define UNICODE
#include <windows.h>

int main()
{
    MessageBox( 0, L"Press OK", L"Hi", MB_SETFOREGROUND );
}

In the examples below (first with the GNU toolchain and then with the Microsoft toolchain) this program is first built as a console subsystem program, and then as a GUI subsystem program. A console subsystem program, or in short just a console program, is one that requires a console window. This is the default subsystem for all Windows linkers I've used (admittedly not a great many), possibly for all Windows linkers period.

在下面的示例中(首先使用 GNU 工具链,然后使用 Microsoft 工具链),该程序首先构建为控制台子系统程序,然后构建为GUI 子系统程序。控制台子系统程序,或简称为控制台程序,是需要控制台窗口的程序。这是我使用过的所有 Windows 链接器的默认子系统(诚然不是很多),可能适用于所有 Windows 链接器时期。

For a console program Windows creates a console windowautomatically if needed. Any Windows process, regardless of subsystem, can have an associated console window, and at most one. Also, the Windows command interpreter waits for a console program program to finish, so that the program's text presentation has finished.

对于控制台程序,如果需要,Windows 会自动创建一个控制台窗口。任何 Windows 进程,不管子系统如何,都可以有一个关联的控制台窗口,最多一个。此外,Windows 命令解释器等待控制台程序程序完成,以便程序的文本演示完成。

Conversely, a GUI subsystem program is one that doesn't require a console window. The command interpreter does not wait for a GUI subsystem program, except in batch files. One way to avoid the completion wait, for both kinds of program, is to use the startcommand. One way to present console window text from a GUI subsystem program is to redirect its standard output stream. Another way is to explicitly create a console window from the program's code.

相反,GUI 子系统程序不需要控制台窗口。命令解释器不等待 GUI 子系统程序,批处理文件除外。对于这两种程序,避免完成等待的一种方法是使用start命令。从 GUI 子系统程序显示控制台窗口文本的一种方法是重定向其标准输出流。另一种方法是从程序代码中显式地创建一个控制台窗口。

The program's subsystem is encoded in the executable's header. It's not shown by Windows Explorer (except that in Windows 9x one could “quick view” an executable, which presented just about the same information as Microsoft's dumpbintool now does). There is no corresponding C++ concept.

程序的子系统被编码在可执行文件的头文件中。它不会在 Windows 资源管理器中显示(除了在 Windows 9x 中可以“快速查看”一个可执行文件,它显示的信息与dumpbin现在的Microsoft工具几乎相同)。没有相应的 C++ 概念。

mainwith the GNU toolchain.

main使用 GNU 工具链。

[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]
> _

mainwith Microsoft's toolchain:

main使用微软的工具链:

[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]
> _


Examples of using Microsoft’s wmainfunction.

使用 Microsoftwmain功能的示例。

The following main code is common to both the GNU toolchain and Microsoft toolchain demonstrations:

以下主要代码对于 GNU 工具链和 Microsoft 工具链演示都是通用的:

    bar.cpp

    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 );
}

wmainwith the GNU toolchain.

wmain使用 GNU 工具链。

The GNU toolchain doesn't support Microsoft's wmainfunction:

GNU 工具链不支持微软的wmain功能:

[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]
> _

The link error message here, about WinMain, is because the GNU toolchain does support thatfunction (presumably because so much ancient code uses it), and searches for it as a last resort after failing to find a standard main.

此处的链接错误消息 aboutWinMain是因为 GNU 工具链确实支持功能(大概是因为有太多古老的代码使用它),并且在找不到标准main.

However, it's trivial to add a module with a standard mainthat calls the wmain:

但是,添加一个具有main调用以下标准的模块是微不足道的wmain

    wmain_support.cpp

    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 );
}

Now,

现在,

[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]
> _

wmainwith Microsoft’s toolchain.

wmain使用微软的工具链。

With Microsoft's toolchain the linker automatically infers the wmainCRTStartupentry point if no entry point is specified and a wmainfunction is present (it's unclear what happens if a standard mainis also present, I haven't checked that in recent years):

使用微软的工具链,wmainCRTStartup如果没有指定入口点并且存在wmain函数,链接器会自动推断入口点(不清楚如果标准main也存在会发生什么,近年来我没有检查过):

[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]
> _

With a non-standard startup function such as wmainit is, however, probably best to specify the entry point explicitly, so as to be very clear about the intention:

wmain然而,对于非标准的启动函数,可能最好明确指定入口点,以便非常清楚意图:

[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]
> _

回答by sarat

According to @RaymondChen

根据@RaymondChen

The name WinMain is just a convention

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).

尽管函数 WinMain 记录在平台 SDK 中,但它实际上并不是平台的一部分。相反,WinMain 是用户提供的 Windows 程序入口点的常规名称。

真正的入口点在 C 运行时库中,它初始化运行时,运行全局构造函数,然后调用您的 WinMain 函数(或 wWinMain,如果您喜欢 Unicode 入口点)。

DllMain and WinMain is different in their prototypes itself. WinMain accepts commandline argument while the other one talks about how it's attached to the process.

DllMain 和 WinMain 的原型本身不同。WinMain 接受命令行参数,而另一个则讨论它如何附加到进程中。

As per MSDN documentation

根据MSDN 文档

By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.

默认情况下,起始地址是来自 C 运行时库的函数名称。链接器根据程序的属性进行选择,如下表所示。

  • mainCRTStartup(or wmainCRTStartup) An application using /SUBSYSTEM:CONSOLE;calls main (or wmain)

  • WinMainCRTStartup(or wWinMainCRTStartup) An application using /SUBSYSTEM:WINDOWS;calls WinMain(or wWinMain), which must be defined with __stdcall

  • _DllMainCRTStartupA DLL; calls DllMain, which must be defined with __stdcall, if it exists

  • mainCRTStartup(或wmainCRTStartup) 使用/SUBSYSTEM:CONSOLE;调用 main (或wmain)的应用程序

  • WinMainCRTStartup(或者wWinMainCRTStartup)使用的应用程序 /SUBSYSTEM:WINDOWS;调用WinMain(或wWinMain),必须以被定义__stdcall

  • _DllMainCRTStartup一个DLL;调用DllMain,必须用 定义__stdcall,如果存在

回答by bobobobo

A standard C program is passed 2 parameters by the command line at start up:

标准 C 程序在启动时通过命令行传递 2 个参数:

int main( int argc, char** argv ) ;
  • char** argvis an array of strings (char*)
  • int argcis the number of char*in argv
  • char** argv是一个字符串数组 ( char*)
  • int argcchar*argv 中的数量

The booting function WinMainthat programmers have to write for a windows program is slightly different. WinMaintakes 4 parameters that are passed to the program by Win O/S at start up:

WinMain程序员必须为 Windows 程序编写的启动函数略有不同。 WinMain接受 Win O/S 在启动时传递给程序的 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.

See my article How to create a basic window in Cfor more

见我的文章如何在C创建一个基本的窗口更多

回答by Code-Apprentice

I vaguely recall reading somewhere that Windows programs have a main()function. It is just hidden in a header or library somewhere. I believe this main()function initializes all of the variables needed by WinMain()and then calls it.

我依稀记得在某处读到过 Windows 程序有一个main()功能。它只是隐藏在某个标题或库中。我相信这个main()函数会初始化所有需要的变量WinMain(),然后调用它。

Of course, I'm a WinAPI noob, so I hope others who are more knowledgeable will correct me if I am wrong.

当然,我是一个WinAPI的菜鸟,所以如果我错了,我希望有更多知识的人能够纠正我。

回答by markyoung

I had an exe using _tWinMain and Configuration Properties.Linker.System.Subsystem: Windows (/SUBSYSTEM:WINDOWS). Later I wanted it to support cmdline args and print to the console so I added:

我有一个使用 _tWinMain 和 Configuration Properties.Linker.System.Subsystem: Windows (/SUBSYSTEM:WINDOWS) 的 exe。后来我希望它支持 cmdline args 并打印到控制台,所以我添加了:

// 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);

but that only worked by printing in another console window that went away so was not that useful. Below is the way I changed it to work with Console (/SUBSYSTEM:CONSOLE) in such a way as I could go back and forth, if I needed to.

但这只能通过在另一个消失的控制台窗口中打印来工作,所以没有那么有用。下面是我将其更改为与 Console (/SUBSYSTEM:CONSOLE) 一起使用的方式,如果需要,我可以来回切换。

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
  UNREFERENCED_PARAMETER(argc);
  UNREFERENCED_PARAMETER(argv);
  UNREFERENCED_PARAMETER(envp);
  return (_tWinMain(NULL, NULL, ::GetCommandLineW(), 0));
}

回答by Ashmita Chaudhary

Main vs WinMain

Main vs WinMain

As I have read from many links:

正如我从许多链接中读到的那样:

WinMain()is the Centry point function of any windows application. Like normal DOS/consolebased application which has main()function as Centry point, in windows we have WinMain()instead. WinMain()is a function which is called by system during creation of a process.

WinMain()C任何 Windows 应用程序的入口点函数。就像普通DOS/console的具有入口点main()功能的应用程序一样C,在 Windows 中我们有WinMain()WinMain()是系统在创建进程期间调用的函数。

First argument is the instance handle of the current process.

第一个参数是当前进程的实例句柄。

Next is the previous instance.

接下来是上一个实例。

Command line arguments comes as next argument.

命令行参数作为下一个参数出现。

Finally shell passes the show/display attribute of main window.

最后 shell 传递了主窗口的 show/display 属性。

Note : WinMain returns success as zero and error as non zero.

注意:WinMain 返回成功为零,错误返回非零。

回答by Lewis Kelsey

The Windows CRT exposes 5 symbols maincrtstartup, wmainCRTStartup, wWinMainCRTStartup, _DllMainCRTStartup, WinMainCRTStartup

Windows CRT 公开了 5 个符号 maincrtstartup、wmainCRTStartup、wWinMainCRTStartup、_DllMainCRTStartup、WinMainCRTStartup

enter image description here

在此处输入图片说明

If the /DLL or /SUBSYSTEM option is not specified, the MSVC linker selects a subsystem and entry point depending on whether main or WinMain is defined. So, presumably the linker makes the entry address one of those 5 functions based on whether main, WinMain or DllMain is present in the symbol table. The functions are statically linked by gcc via crt0.o.

如果未指定 /DLL 或 /SUBSYSTEM 选项,MSVC 链接器将根据是否定义了 main 或 WinMain 来选择子系统和入口点。因此,大概是链接器根据符号表中是否存在 main、WinMain 或 DllMain 使入口地址成为这 5 个函数之一。这些函数由 gcc 通过 crt0.o 静态链接。

MainCRTStartup will call GetStartupInfo()/ access the PEB to get stdin/out handles and command line arguments. _init term()is also called, as well as _init_atexit(). The return value of main is passed to ExitProcess()after the set atexitroutine is called.

MainCRTStartup 将调用GetStartupInfo()/访问 PEB 以获取标准输入/输出句柄和命令行参数。_init term()也称为,以及_init_atexit()。main 的返回值是ExitProcess()atexit调用set例程后传递给的。