17

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

简而言之,我相信控制台和 GUI 应用程序启动在以下方面有所不同:

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

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

我想验证这种理解并找出我如何仅使用“main”函数(即无需编写“WinMain”)手动编写 Windows GUI。

4

3 回答 3

16

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

主要看起来像这样:

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 目录中。

于 2009-02-19T10:32:25.753 回答
8

使用 Just main,您不能编写 Winmain。出于正当理由,以下陈述取自 http://blogs.msdn.com/oldnewthing/archive/2007/12/03/6644060.aspx

[在 Windows 编程中] 为什么应用程序入口点不叫 main?好吧,一方面,名称 main 已经被使用,并且 Windows 无权保留备用定义。那时还没有 C 语言标准化委员会;C 就是 Dennis 所说的那样,并且很难保证 Dennis 会采取任何特殊措施来保持 Windows 源代码在任何未来版本的 C 语言中的兼容性。由于 K&R 没有指定实现可以扩展 main 函数的可接受形式,因此完全有可能存在合法的 C 编译器拒绝错误声明 main 的程序。当前的 C 语言标准明确允许 main 的特定于实现的替代定义,

如果你设法克服了这个障碍,你就会遇到 Windows 版本的 main 必须是这样的问题:

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

由于执行 C 链接的方式,函数的所有变体都必须就它们的共同参数达成一致。这意味着 Windows 版本必须将其参数添加到现有最长的 main 版本的末尾,然后您必须祈祷并希望 C 语言永远不会添加另一个 main 的替代版本。如果你走这条路,你的交叉手指会让你失望,因为事实证明第三个参数是在一段时间后添加到 main 的,它与你的 Windows 友好版本冲突。

假设您设法说服 Dennis 不允许使用 main 的三参数版本。您仍然必须提出前两个参数,这意味着每个程序的启动代码都需要包含一个命令行解析器。回到 16 位时代,人们节俭地保存每个字节。告诉他们,“哦,你所有的程序都会变大 2KB”可能不会让你交到很多朋友。我的意思是,那是软盘上的四个 I/O 扇区!

但是,Windows 入口点被赋予不同名称的原因可能是为了强调它是一个不同的执行环境。如果它被称为 main,人们会将为控制台环境设计的 C 程序放入 Windows 编译器中,然后运行它们,结果是灾难性的。

希望这能消除您的疑虑。

于 2009-02-19T10:40:17.027 回答
6

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

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

于 2009-02-19T10:05:43.257 回答