_WinMainCRTStartup执行哪些功能?

Tho*_*mas 13 crt winmain entry-point visual-c++

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

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

所以我将Project Properties - > Configuration - > C/C++ - > Advanced - > Omit Default Library Names设置为Yes(编译器标志/Zl)并重建.

然后链接器抱怨外部未解决_WinMainCRTStartup.可以说,我可以告诉链接器使用不同的入口点MyStartup.从我在网上收集的内容,_WinMainCRTStartup做一些初始化的东西,我可能想做MyStartup一个子集.

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

如果您对这些内容有所了解,请查看我的其他问题.谢谢!

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

  1. 我的应用程序没有明确使用任何CRT功能.
  2. 我喜欢精益和平均的应用程序.
  3. 它会教我一些新东西.

Mic*_*ael 6

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

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

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


nfr*_*s88 6

老问题,但答案要么不正确,要么集中在一个特定问题上。

如果程序实际上是从 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();
}
Run Code Online (Sandbox Code Playgroud)

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

C++ 甚至 C 还需要在 main 之前或之后完成其他事情才能工作。main 启动后如何使用 stdin 和 stdout(std::cin 和 std::cout)?atexit 是如何工作的?

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

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

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

你可能想看看 Matt Pietrick 的(古代)关于实现他自己的 C 运行时的文章,详细了解它是如何与 Windows + MSVC 一起工作的(注意:MinGW 和 Cygwin 以不同的方式实现特定的东西,但实际上大多数情况下回退到 MSVCRT ):http : //msdn.microsoft.com/en-us/library/bb985746.aspx


小智 5

一个用C(不是C ++)编写的真正的 Win32程序根本不需要任何初始化,因此您可以使用WinMainCRTStartup()而不是WinMain(HINSTANCE,...)启动项目。

也可以将控制台程序编写为真正的Win32应用程序,但要困难一些。入口点的默认名称是_mainCRTStartup()

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

初始化

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

的nCmdShow参数总是SW_SHOWDEFAULT

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

终止

当您的程序产生线程时(例如,通过调用GetOpenFileName()),使用带有return关键字的WinMainCRTStartup()返回将挂起您的程序— 而是使用ExitProcess()

注意事项

在以下情况下,您将遇到相当大的麻烦:

  • 使用大于4 KB(每个函数)的堆栈帧(即局部变量)
  • 使用浮点运算(例如float-> int转换)
  • 在32位计算机上使用64位整数(乘法,移位操作)
  • 将C ++ newdelete和static对象与non-zero-out-all-members构造函数一起使用
  • 使用标准的库函数等fopen()函数printf()的过程的

疑难排解

在所有Windows系统(自Windows 95起)上都有一个C标准库MSVCRT.DLL

要使用它,请导入其入口点,例如,使用我的msvcrt-light.lib(适用于Google)。但是仍然存在一些警告,尤其是当使用比MSVC6更新的编译器时:

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

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

  • 对于Win32(Win32s除外),它固定为(HINSTANCE)0x400000。- 这不是真的。 (3认同)