C++ C++;(扩展)

C++ C++;(扩展),c++,windows,main,winmain,C++,Windows,Main,Winmain,好的,我看过这篇文章: 我现在知道WINMAIN用于窗口应用程序,而main()用于控制台。但是阅读这篇文章并没有告诉我为什么会有这样的区别 我的意思是,在一个程序开始时分离不同的主功能有什么意义?是因为性能问题吗?或者是什么?标准C程序在启动时由命令行传递两个参数: int main( int argc, char** argv ) ; int WINAPI WinMain( HINSTANCE hInstance, // HANDLE TO AN INSTANCE. This is

好的,我看过这篇文章:

我现在知道
WINMAIN
用于窗口应用程序,而
main()
用于控制台。但是阅读这篇文章并没有告诉我为什么会有这样的区别


我的意思是,在一个程序开始时分离不同的主功能有什么意义?是因为性能问题吗?或者是什么?

标准C程序在启动时由命令行传递两个参数:

int main( int argc, char** argv ) ;
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.
  • char**argv
    是字符串数组(
    char*
  • int argc
    是argv中
    char*
    的编号
程序员必须为windows程序编写的引导函数
WinMain
略有不同
WinMain
获取4个参数,这些参数在启动时由Win O/S传递给程序:

int main( int argc, char** argv ) ;
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.

有关更多信息,请参阅我的文章

我隐约记得在某个地方读到Windows程序有一个
main()
函数。它只是隐藏在某个标题或库中。我相信这个
main()
函数初始化了
WinMain()
所需的所有变量,然后调用它

当然,我是WinAPI noob,所以如果我错了,我希望其他更有知识的人会纠正我。

关于函数。 <> P.C和C++标准要求任何程序(对于托管的C或C++实现)都有一个函数,叫做“代码>主< /代码>,它作为程序的强启动功能< /强>。
main
函数是在非局部静态变量的零初始化之后调用的,可能但不一定是(!,C++11§3.6.2/4),该调用发生在此类变量的动态初始化之后。它可以具有以下签名之一:

int main()
int main( int argc, char* argv[] )
加上可能的实现定义签名(C++11§3.6.1/2),但结果类型必须为
int

作为C++ +代码>中的唯一此类函数,主< <代码>具有<强>默认结果< /强>值,即0。如果

main
返回,则在普通函数return之后,将调用
exit
,并将
main
结果值作为参数。本标准定义了三个可保证使用的值:0(表示成功)、
退出成功(也表示成功,通常定义为0)和
退出失败(表示失败),其中,两个命名常量由
标题定义,该标题还声明了
退出
函数

main
参数用于表示用于启动进程的命令的命令行参数
argc
(参数计数)是
argv
(参数值)数组中的项数。除这些项目外,
argv[argc]
保证为0。如果
argc
>0–这是不保证的!–然后保证
argv[0]
是指向空字符串的指针,或者是指向“用于调用程序的名称”的指针。该名称可以包括路径,也可以是可执行文件的名称

使用<代码>主< /COD>参数获取命令行参数在*NIX中工作良好,因为C和C++源自*NIX。但是,对

参数进行编码的事实上的Windows标准是Windows ANSI,它不支持通用的Windows文件名(例如,对于挪威Windows安装,使用希腊或西里尔文字符的文件名)。因此,微软选择用一个Windows特定的启动函数扩展C和C++语言,称为<强> >代码> WMeN//Cux> <强>,它具有广泛的基于字符的参数,被称为<强> UTF 16 < /强>,它可以表示任何文件名。 与
main
的标准签名相对应的
wmain
功能可以有:

int wmain()
int wmain( int argc, wchar_t* argv[] )
int WINAPI wWinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    PWSTR       lpCmdLine,
    int         nCmdShow
    );
再加上一些不是特别有用的

也就是说,
wmain
是对
main
的直接宽字符替换

基于WinMain
char
的功能是在20世纪80年代早期在Windows中引入的:

int CALLBACK WinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    LPSTR       lpCmdLine,
    int         nCmdShow
    );
其中,
CALLBACK
HINSTANCE
LPSTR
标题()定义

论据:

  • hInstance
    参数值是可执行文件的内存映像的基址,它主要用于从可执行文件加载资源,也可以从
    GetModuleHandle
    API函数获得

  • hPrevInstance
    参数始终为0

  • lpCmdLine
    参数也可以从
    GetCommandLine
    API函数获得,再加上一点奇怪的逻辑来跳过命令行的程序名部分,以及

  • nCmdShow
    参数值也可以从
    GetStartupInfo
    API函数中获取,但对于现代Windows,第一次创建顶级窗口会自动获取,因此没有任何实际用途

因此,
WinMain
函数具有与标准
main
相同的缺点,再加上一些(特别是冗长和非标准),并且没有自身的优点,因此除了可能作为供应商锁定之外,它真的很难解释。然而,通过微软的工具链,它使链接器默认为GUI子系统,有些人认为这是一个优势。但是,例如GNU工具链,它没有这种效果,因此不能依赖这种效果

基于
wWinMain
wchar\u t
的函数是
WinMain
的宽字符变体,正如
wmain
是标准
main
的宽字符变体一样:

int wmain()
int wmain( int argc, wchar_t* argv[] )
int WINAPI wWinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    PWSTR       lpCmdLine,
    int         nCmdShow
    );
其中
WINAPI 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]
> _
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\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] > _ [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] > _ [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] > _
// 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);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
  UNREFERENCED_PARAMETER(argc);
  UNREFERENCED_PARAMETER(argv);
  UNREFERENCED_PARAMETER(envp);
  return (_tWinMain(NULL, NULL, ::GetCommandLineW(), 0));
}