我有这个简单的程序:
#include <windows.h>
int WINAPI startMeUp() {
return 0;
}
我使用Visual Studio的命令行工具编译,如下所示:
cl /nologo /GS- /Gs- /c /W4 main.c /Fomain.obj
link /nologo main.obj /subsystem:console /entry:startMeUp /nodefaultlib kernel32.lib user32.lib /OUT:the.exe
当我然后执行.\the.exe
时,会显示一个消息框,指出the.exe已停止工作 - 一个问题导致程序停止正常工作。 Windows将关闭程序并在解决方案可用时通知您
用return 0;
替换ExitProcess(0);
并重新编译/链接后,.\the.exe
运行得很好。
所以,在我看来,需要ExitProcess()
来正确结束一个过程。
因为我很确定我已经通过返回退出值从入口点函数返回了工作程序,所以我不确定可移植可执行文件是否需要ExitProcess()
终止进程。
编辑有趣的是,如果我在MessageBox(NULL, "world", "hello", 0);
之前放置一个return 0;
(因此没有ExitProcess()
调用),可执行文件也运行正常。
编辑II当我添加链接器选项/export:startMeUp
时,链接器用LNK4216
警告我,但我可以执行创建没有问题。
当我在创建的两个exes上使用dumpbin /all
时,我看到错误的可执行文件有
0 [ 0] RVA [size] of Export Directory
而新的,有工作的
2000 [ 40] RVA [size] of Export Directory
此外,工作可执行文件由两部分组成:.text
和.rdata
,而有缺陷的部分只有.text
部分。可执行代码似乎包含在.rdata
部分中,因此它在错误的部分中缺失。
至于为什么,我不知道。
windows进程退出或进程退出时或TerminateProcess
调用时的最后一个线程。因为你的过程中可能有额外的(隐式创建的)线程 - 你需要直接或间接调用TerminateProcess
(或ZwTerminateProcess
)。
ExitProcess
内部调用TerminateProcess
(确实是ZwTerminateProcess
),但在此之前做了一些工作,正确的进程关闭。包括使用DLL_PROCESS_DETACH
通知调用所有DLL入口点
所以一般来说你必须调用ExitProcess
(更正确)或TerminateProcess
如果您自己编写入口点,则必须使用正确的签名
int WINAPI startMeUp(void*)
这是stdcall函数,它占用1个参数(指向PEB的指针)。当你从这个api返回到系统时 - 只调用RtlExitUserThread
,这导致线程退出或所有进程退出,如果这是进程中的最后一个线程。从startMeUp
返回后,甚至在x86系统堆栈指针上设置不正确这不会导致错误,因为只是RtlExitUserThread
并且它永远不会返回。很难说在没有查看二进制文件的情况下导致测试崩溃的原因,但更快需要在具体系统上查看(调试)。但这是不寻常的 - 这绝不是。你的进程必须或者只是退出或者仍然存在(无限或一些时间)后台存在的其他线程
如果你只是问exec中是否需要ExitProcess()我可以严格回答yoo:NO
我写了一个编译器,它生成exe和最小程序(如果不是说exe标题)可能只有一个字节:0xC3即ret - 这样的程序运行时立即返回但是正确
是的,ExitProcess是必需的,否则你最终会抛出异常,因为无处可去,你无法停止处理器。
但是,该条目通常不是用户提供的,它由CRT(WinMainCRTStartup)提供,它在调用WinMain()函数之前也初始化全局变量。
因此,您需要做的就是提供WinMain。
编辑后编辑:ExitProcess可能由MessageBox调用后创建的一些异常处理程序调用。你不(也不能)知道。