【发布时间】:2016-11-03 18:30:57
【问题描述】:
调用 MessageBoxA() 的应用程序是否应该总是由 ExitProcess() 而不是正常的函数结尾终止?
我无法理解为什么在 Windows 10 x64 上执行 ret 指令后,下面的“MessageBox”程序会挂起。
在 GDB 下调试程序,似乎 Win32 函数NtUserSetCursor 是该行为的原因,即执行ret 0x4 指令后没有任何反应。
0x779c2440 in ?? ()
=> 0x779c2440: ff 25 18 12 a5 77 jmp DWORD PTR ds:0x77a51218
(gdb)
0x6c417000 in ?? ()
=> 0x6c417000: ea 09 70 41 6c 33 00 jmp 0x33:0x6c417009
(gdb)
0x7476262c in win32u!NtUserSetCursor () from C:\WINDOWS\SysWoW64\win32u.dll
=> 0x7476262c <win32u!NtUserSetCursor+12>: c2 04 00 ret 0x4
但是,如果我使用ExitProcess 退出程序,则没有问题。
使用MessageBoxA 函数的应用程序是否应该总是以ExitProcess 终止?
程序:
BITS 32
extern _MessageBoxA@16
section .data
_szTitle: db "This is a test", 0x00
_szMsg: db "Hello World!", 0x00
section .text
global _start
_start:
push ebp
mov ebp, esp
push 0x00
push _szTitle
push _szMsg
push 0x00
call _MessageBoxA@16
leave
ret
组装和链接:
C:\Users\nlykkei\Desktop>nasm -f win32 test.asm
C:\Users\nlykkei\Desktop>ld -o test.exe test.obj "C:\dev\lib\User32.Lib" --entry _start
【问题讨论】:
-
请不要转发问题。如果您想更改某些内容,请使用 edit 链接。
-
Hmya,谁曾期望 MessageBox() 创建另一个线程?或者,如果他不使用 MessageBox(),即使 Win10 仍然使用线程池加载 DLL,它也能正常工作。这个问题与线程无关。这个问题更令人不快的副作用是它使现有程序无法正常运行。就像我链接到的那个 .NET 程序一样。
-
@Shuzheng,你的程序应该总是直接或间接调用ExitProcess。如果你使用微软的 C 运行时库,你可以通过从 main 函数中退出来间接调用 ExitProcess。在 .NET 中,您可以通过退出所有前台线程来间接调用 ExitProcess。但是如果你是用汇编程序编写的,并且没有在 C 运行时中显式链接,你必须自己做。
-
ExitProcess() 应该 可能会被调用,因为鉴于 Windows 10 中的“新行为”,它是最安全的全方位解决方案。话虽如此,我仍然会争论正如@HansPassant 指出的那样,这种行为确实是一个错误,除非有人可以显示说明本机非 C 应用程序必须使用 ExitProcess() 退出的文档。 Windows 加载程序应该清楚地坚持以前的操作系统版本中存在的“更安全”的行为,允许在两种情况下正确清理进程。
-
@byteptr: this has been happening since at least 2007, Windows 10 只是让它更常见。另见If you return from the main thread, does the process exit?。如果他们的语言不适合他们,程序员肯定会调用 ExitProcess。
标签: windows debugging winapi assembly x86