_WinMainCRTStartup执行哪些功能?

时间:2009-10-17 20:59:32

标签: visual-c++ crt entry-point winmain

这是一系列至少两个密切相关但又截然不同的问题的一部分。我希望我能分别问他们做对了。

我正在尝试让我的Visual C ++ 2008应用程序在没有C运行时库的情况下工作。它是一个没有MFC或其他花哨东西的Win32 GUI应用程序,只是简单的Windows API。

所以我设置项目属性 - >配置 - > C / C ++ - >高级 - >将默认库名称省略为是(编译器标志/Zl)并重建。

然后链接器抱怨未解析的外部_WinMainCRTStartup。很公平,我可以告诉链接器使用不同的入口点,比如MyStartup。根据我在网络上收集的内容,_WinMainCRTStartup执行了一些初始化操作,我可能希望MyStartup执行其中的一部分。

所以我的问题是: _WinMainCRTStartup执行哪些功能,如果我不使用CRT,我可以省略哪些功能?

如果您对这些内容有所了解,请查看my other question。谢谢!

旁白:我为什么要首先这样做?

  1. 我的应用未明确使用任何CRT功能。
  2. 我喜欢精益求精的应用程序。
  3. 它会教给我一些新东西。

3 个答案:

答案 0 :(得分:6)

CRT的入口点执行以下操作(此列表未完成):

  • 初始化CRT所需的全局状态。如果不这样做,则不能使用CRT提供的任何功能或状态。
  • 初始化编译器使用的某个全局状态。诸如/ GS使用的安全cookie之类的运行时检查在这里肯定很突出。不过,您可以自己致电__security_init_cookie。您可能需要为其他运行时检查添加其他代码。
  • 在C ++对象上调用构造函数。如果您正在编写C ++代码,则可能需要模拟它。
  • 检索命令行并启动操作系统提供的信息并将其传递给您的主要信息。默认情况下,操作系统不会将任何参数传递给程序的入口点 - 它们都由CRT提供。

CRT源代码可以在Visual Studio中使用,您可以在调试器中单步执行CRT的入口点,并确切了解它正在做什么。

答案 1 :(得分:5)

用C(非C ++)编写的 true Win32程序根本不需要任何初始化,因此您可以使用 WinMainCRTStartup()而不是<来启动项目强>的WinMain(HINSTANCE,...)

将控制台程序编写为真正的Win32应用程序也可能有点困难;入口点的默认名称是 _mainCRTStartup()

禁用所有额外的代码生成功能,如堆栈探测,数组检查等。仍然可以进行调试。

初始化

有时您需要第一个 HINSTANCE 参数。对于Win32(Win32s除外),它固定为(HINSTANCE)0x400000

nCmdShow 参数始终为 SW_SHOWDEFAULT

如有必要,请使用 GetCommandLine()检索命令行。

终止

当你的程序产生线程时,例如通过调用 GetOpenFileName(),使用返回关键字从 WinMainCRTStartup()返回将挂起您的程序 - 使用 ExitProcess()而不是。

注意事项

在以下情况下你会遇到相当大的麻烦:

  • 使用大于4 KB(每个函数)的堆栈帧(即局部变量)
  • 使用浮点运算(例如float-&gt; int转换)
  • 在32位机器上使用64位整数(乘法,位移操作)
  • 使用C ++ new 删除,以及具有非零out-all-members构造函数的静态对象
  • 使用标准库函数,例如 fopen() printf()

故障排除

所有Windows系统(自Windows 95以来)都有一个C标准库, MSVCRT.DLL

要使用它,请导入他们的入口点,例如使用我的 msvcrt-light.lib (google for it)。但是仍然有一些警告,特别是当使用比MSVC6更新的编译器时:

  • 堆栈帧仍限制为4 KB
  • _ftol_sse _ftol2_sse 必须路由至 _ftol
  • _iob_func 必须路由到 _iob

它的初始化似乎在加载时运行。至少文件函数将无缝运行。

答案 2 :(得分:2)

旧问题,但答案不正确或关注一个特定问题。

如果程序实际上是在main / WinMain上启动的话,有很多C和C ++功能在Windows(或大多数操作系统)上都无法使用。

举个简单的例子:

class my_class
{
public:
    my_class() { m_val = 5; }
    int my_func(){ return m_val }
private:
    int m_val;
}

my_class g_class;

int main(int argc, char **argv)
{
     return g_class.my_func();
}

为了使该程序按预期运行,必须在main之前调用my_class的构造函数。如果程序完全在main处启动,则需要编译器hack(注意:GCC在某些情况下这样做)在main的最开始插入一个函数调用。相反,在大多数操作系统上,在大多数情况下,不同的函数构造g_class然后调用main(在Windows上,这是mainCRTStartup或WinMainCRTStartup;在我习惯的大多数其他操作系统上,它是一个名为_start的函数)。

在主要工作之前或之后,C ++甚至C还需要完成其他工作。 一旦main启动,stdin和stdout(std :: cin和std :: cout)如何可用? atexit如何运作?

C标准要求标准库具有类似POSIX的信号API,在Windows上必须在main()之前“安装”。

在大多数操作系统上,没有系统提供的堆; C运行时实现自己的堆(Microsoft的C运行时只包装Kernel32堆函数)。

即使传递给main,argc和argv的参数也必须以某种方式从系统中获取。

你可能想看一下Matt Pietrick(古代)关于如何使用Windows + MSVC实现自己的C运行时的文章(注意:MinGW和Cygwin以不同的方式实现特定的东西,但实际上回归到MSVCRT对于大多数事情): http://msdn.microsoft.com/en-us/library/bb985746.aspx