【问题标题】:64-bit Windows: longjmp lands in a wrong place64 位 Windows:longjmp 位于错误的位置
【发布时间】:2015-12-08 03:19:29
【问题描述】:

当我在 Windows 64 位 (Windows 7) 上的 32 位应用程序中使用 longjmp 时出现问题。它没有返回到最后一次 setjmp() 调用的某个点,而是在最后一次 DispatchMessage() 调用之后着陆。这是代码示例,如果由 64 位编译器编译,则可以正常工作,而在 32 位版本中编译失败。

有什么解决方法的想法吗?微软似乎在这里对一个切题的问题保持沉默:https://social.msdn.microsoft.com/Forums/vstudio/en-US/b63a573f-007e-43a3-877c-b06280aa8bcc/0x80000026-application-error-when-exiting-after-using-longjmp-on-windows8-x64?forum=windowscompatibility

// Compile as: cl a.c user32.lib kernel32.lib 

#include <windows.h>
#include <setjmp.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

jmp_buf jump_buffer;
int flag = 0;

int main()
{
    WNDCLASS wc = {0, };
    ATOM atom = 0;
    HWND wnd;
    MSG msg;
    int ret;
    wc.lpfnWndProc = &WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = "ExitWindows() handler";
    atom = RegisterClass(&wc);
    wnd = CreateWindow(wc.lpszClassName, wc.lpszClassName,
                        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wc.hInstance, NULL);

    ret = setjmp(jump_buffer);

    switch ( ret ) {
    case 0:
        ShowWindow(wnd,SW_SHOW);
        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            if ( flag ) {
                printf("not ok\n");
                break;
            }
        }
        break;
    case 1:
        printf("ok\n");
        break;
    }
    return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case WM_PAINT:
        flag = 1;
        longjmp(jump_buffer, 1);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

【问题讨论】:

  • 您正在跨越不受您控制的代码。使用setjmp/longjmp 时,您必须确保每个人都在开玩笑。在您拨打DispatchMessageWndProc 之间的所有事情都没有为这个噱头做好准备。如果它似乎在 64 位版本中工作,那只是巧合。
  • 如果 goto 被认为是有害的,这是什么?你为什么要重新输入main()?如果目标是在您获得第一次绘画时退出您的消息循环...there are better ways
  • ret = setjmp(jump_buffer); 您可以在 conditional测试 setjmp() 的“返回”值,但您不应该在作业中使用它
  • 它在 C 标准中,从 c89,IIRC 开始。也许 c.l.c 存档/常见问题解答? GIYF BTW:MSDN 不是信息来源。 (好吧,也许是关于实现或使用的东西)另外:你的flag 应该真的是不稳定的,

标签: c winapi 32bit-64bit setjmp


【解决方案1】:

在 WndProc 中使用longjmp不安全的,因为窗口过程的性质:

  • if 可以通过SendMessage 函数调用,在这种情况下,它不会使用与setjmp 相同的上下文(堆栈)调用。在这种情况下,我认为任何事情都可能发生...... - 好的 WM_PAINT 正常发布而不发送,因此不应该在这里适用,即使恕我直言,这是不这样做的主要原因
  • 系统可以在调用窗口过程(在 DispatchMessage 中)之前为您准备一些内部结构,并期望在 WndProc 返回后能够清除它们。使用 longjmp 会破坏这一点。

WindowProc 函数上的 Windows API 说:返回值是消息处理的结果,取决于发送的消息。

我的理解是一个窗口过程应该返回并且永远不会调用longjmpexit。它在 Windows 文档中没有明确说明,但我不敢使用不会返回的窗口过程。

正确退出消息循环的正确方法是发布 WM_QUIT 消息(使用 PostQuitMessage 函数退出消息循环)。它使GetMessage 函数返回0,并允许系统清理在第一次调用GetMessage 时安装的消息循环。

【讨论】:

    猜你喜欢
    • 2010-10-23
    • 2019-03-18
    • 1970-01-01
    • 2016-07-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2021-08-28
    • 1970-01-01
    相关资源
    最近更新 更多