64位Windows:longjmp登陆错误的地方

时间:2015-09-11 14:13:28

标签: c winapi 32bit-64bit longjmp setjmp

在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);
    }
}

1 个答案:

答案 0 :(得分:2)

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

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

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

我对它的理解是,窗口过程应该返回并且永远不会调用longjmp的{​​{1}}。它在Windows文档中并不明确,但我不敢使用不会返回的窗口过程。

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