如何在不使用WinMain的情况下编写Windows应用程序?

17

使用C/C++编写的Windows GUI应用程序入口点是'WinMain'(而不是'main')。我理解的是编译器会生成一个'main'函数,由C运行时库来调用这个函数。这个'main'函数为GUI设置必要的环境,然后调用'WinMain'函数(指定实例句柄等)。

简而言之,控制台应用程序和GUI应用程序的启动方式如下:

控制台应用程序: C运行时库 --> 'main'函数(手工编码)

GUI应用程序: C运行时库 --> 'main'函数(编译器生成)--> 'WinMain'函数(手工编码)

我想验证这个理解,并找出如何只使用一个'main'函数手工编写Windows GUI(即无需编写'WinMain'函数)。

3个回答

16

你的理解是有误的。main和WinMain之间的区别,除了一些不同的初始化代码外,就在于它们接收的参数。

main长成这个样子:

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

WinMain看起来像这样:

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

需要设置这些参数并进行调用,这就是启动代码的作用。当你编译和链接一个程序时,链接器参数之一是入口点,根据控制台或GUI应用程序的不同,它将是不同的启动代码。

你可以编写自己的启动代码,只需进入Visual C++源目录,你就可以找到启动代码,它被称为crt0.c,位于VC\crt\src目录中。


8
只有main函数是不足以编写WinMain的。以下陈述是为了证明这一点,摘自http://blogs.msdn.com/oldnewthing/archive/2007/12/03/6644060.aspx

[In Windows Programming,] Why wasn't the application entry point called main? Well, for one thing, the name main was already taken, and Windows didn't have the authority to reserve an alternate definition. There was no C language standardization committee back then; C was what Dennis said it was, and it was hardly guaranteed that Dennis would take any special steps to preserve Windows source code compatibility in any future version of the C language. Since K&R didn't specify that implementations could extend the acceptable forms of the main function, it was entirely possible that there was a legal C compiler that rejected programs that declared main incorrectly. The current C language standard explicitly permits implementation-specific alternate definitions for main, but requiring all compilers to support this new Windows-specific version in order to compile Windows programs would gratuitously restrict the set of compilers you could use for writing Windows programs.

If you managed to overcome that obstacle, you'd have the problem that the Windows version of main would have to be something like this:

int main(int argc, char *argv[], HINSTANCE hinst,
         HINSTANCE hinstPrev, int nCmdShow);

Due to the way C linkage was performed, all variations of a function had to agree on the parameters they had in common. This means that the Windows version would have to add its parameters onto the end of the longest existing version of main, and then you'd have to cross your fingers and hope that the C language never added another alternate version of main. If you went this route, your crossed fingers failed you, because it turns out that a third parameter was added to main some time later, and it conflicted with your Windows-friendly version.

Suppose you managed to convince Dennis not to allow that three-parameter version of main. You still have to come up with those first two parameters, which means that every program's startup code needs to contain a command line parser. Back in the 16-bit days, people scrimped to save every byte. Telling them, "Oh, and all your programs are going to be 2KB bigger" probably wouldn't make you a lot of friends. I mean, that's four sectors of I/O off a floppy disk!

But probably the reason why the Windows entry point was given a different name is to emphasize that it's a different execution environment. If it were called main, people would take C programs designed for a console environment, throw them into their Windows compiler, and then run them, with disastrous results.

希望这能解决您的疑惑。

6

它的工作方式与此相反。编译器附带一个静态链接的目标文件,其中包含实际的入口点。该入口点进行初始化,然后调用您的入口点(即WinMain)。

该静态部分期望调用的内容可能是可调整的。例如,在Visual Studio中,链接器设置中有一个入口点名称字段。


那么控制台和GUI应用程序的执行顺序是什么?这两种情况下静态部分是否不同?C运行时在哪里适用? - Matthew Murdoch
首先执行静态部分,然后调用用户实现的入口点。它可以是不同的,也可以是相同的,但链接器可以根据设置将调用链接到不同的入口点。您可以将此静态部分视为 C 运行时的一部分。 - sharptooth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接