64 位 Windows:longjmp 位于错误的位置

Posted

技术标签:

【中文标题】64 位 Windows:longjmp 位于错误的位置【英文标题】:64-bit Windows: longjmp lands in a wrong place 【发布时间】: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 应该真的是不稳定的, ***.com/questions/16636206/… 你去... 【参考方案1】:

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

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

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

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

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

【讨论】:

以上是关于64 位 Windows:longjmp 位于错误的位置的主要内容,如果未能解决你的问题,请参考以下文章

OmniORB 编译错误 Windows 7 64 位

使用 Perl64 在 Windows 7(64 位)上构建 BerkeleyDB 时出现编译/链接错误

webRTC编译windows 7 64位

Windows 2008 R2 64 位机器 (Tridion 5.3) 上的 ComponentPresentationAssembler 错误

Windows 7 64 位 libsvm 和 python 错误:函数 'svm_get_sv_indices' 未找到

Delphi 在 Windows 7 64 上使用 LockFile