我有一个简单的程序:
#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
警告我但是我可以毫无问题地执行创建的操作。
当我在创建的两个exe上都使用dumpbin /all
时,我发现错误的可执行文件具有
0 [ 0] RVA [size] of Export Directory
正在工作的新员工有
2000 [ 40] RVA [size] of Export Directory
此外,工作的可执行文件由两部分组成:.text
和.rdata
,而有故障的可执行文件只有.text
部分。可执行代码似乎包含在.rdata
部分中,因此有故障的代码中缺少该可执行代码。
关于为什么,就是我一无所知。
答案 0 :(得分:0)
windows进程退出或进程中的最后一个线程退出或调用TerminateProcess
时。因为可以在进程中添加(隐式创建的)线程-您需要直接或间接调用TerminateProcess
(或ZwTerminateProcess
)。
ExitProcess
内部调用TerminateProcess
(确实是ZwTerminateProcess
),但是在此之前要做一些工作,以正确关闭进程。包括使用DLL_PROCESS_DETACH
通知调用所有DLL入口点
因此,通常您必须致电ExitProcess
(更正确)或TerminateProcess
如果您自己编写入口点,则正确的签名必须为
int WINAPI startMeUp(void*)
这是 stdcall 函数,它接受1个参数(指向 PEB 的指针)。当您从此api返回系统时,仅调用RtlExitUserThread
,如果这是进程中的最后一个线程,则会导致线程退出或所有进程退出。从startMeUp
返回后,即使x86系统堆栈指针上的desite不正确,也不会导致错误,因为仅RtlExitUserThread
就不会返回。很难说是什么导致了在不查看二进制文件的情况下导致测试崩溃的原因,但是更快地需要在具体系统上进行外观(调试)。但这是不寻常的-一定不能。您的进程必须或只是退出,或者在进程中存在其他线程的情况下仍在后台(无限期或一段时间)存在
答案 1 :(得分:0)
如果您只是询问exe中是否需要ExitProcess(),我可能会严格回答:否
我写了一个生成exe的编译器,并且其中包含最小的程序(如果不说exe头文件)可能只有一个字节:0xC3是ret-这样的程序在运行时立即返回但是正确的
答案 2 :(得分:-2)
是的,必须使用ExitProcess,否则您将最终抛出异常,因为无处可去且无法停止处理器。
但是,该条目通常不是用户提供的,它是由CRT(WinMainCRTStartup)提供的,它还会在调用WinMain()函数之前初始化全局变量。
因此,您所需要做的就是提供一个WinMain。
在编辑后进行编辑:ExitProcess可能由在MessageBox调用之后创建的某些异常处理程序调用。您不(也不知道)。