x64 平台下,wglCreateContextAttribsARB 在调试模式下崩溃

Posted

技术标签:

【中文标题】x64 平台下,wglCreateContextAttribsARB 在调试模式下崩溃【英文标题】:wglCreateContextAttribsARB crashes in debug mode, under x64 platform 【发布时间】:2016-01-09 13:06:43 【问题描述】:

我在尝试在 Visual Studio 2015 下调试我的 64 位应用程序时遇到了问题。当我将其切换到调试模式时,它在创建窗口时崩溃。这在 32 位模式下没有发生;

这里是编辑过的窗口初始化代码:

int indexPF;
WNDCLASS WinClass;

WinClass.style = CS_OWNDC | CS_PARENTDC;
WinClass.lpfnWndProc = WndProc;
WinClass.cbClsExtra = 0;
WinClass.cbWndExtra = 0;
WinClass.hInstance = hInstance;
WinClass.hIcon = LoadIcon(NULL, IDC_ICON);
WinClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WinClass.hbrBackground = (HBRUSH)GetStockObject(5);
WinClass.lpszMenuName = NULL;
WinClass.lpszClassName = "N2";

if (!RegisterClass(&WinClass))

    ...report error and terminate...


Logger::Inst() << " ~RegisterClass;" << endl;

//CREATE WINDOW

if (fullScreen)

    if ((hwnd = CreateWindowEx(WS_EX_LEFT, "N2", "N2",
        WS_POPUP,
        0, 0, width, height,
        NULL, NULL, hInstance, NULL)) == 0)
    
        ...report error and terminate...
    

else

    if ((hwnd = CreateWindowEx(WS_EX_LEFT, "N2", "N2",
        WS_OVERLAPPEDWINDOW,
        0, 0, width, height,
        NULL, NULL, hInstance, NULL)) == 0)
    
        ...report error and terminate...
    


Logger::Inst() << " ~CreateWindow;" << endl;

//PFD SETUP
PIXELFORMATDESCRIPTOR pfd =

    sizeof(PIXELFORMATDESCRIPTOR),
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
    PFD_TYPE_RGBA,
    32,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    24,
    8, 0, PFD_MAIN_PLANE, 0, 0, 0x00FF00FF, 0
;

//HDC
if ((hdc = GetDC(hwnd)) == NULL)

    ...report error and terminate...


Logger::Inst() << " ~GotHDC;" << endl;

//SET PIXEL FORMAT
indexPF = ChoosePixelFormat(hdc, &pfd);
if (!indexPF)

    ...report error and terminate...


if (!SetPixelFormat(hdc, indexPF, &pfd))

    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE;
    indexPF = ChoosePixelFormat(hdc, &pfd);

    if (!SetPixelFormat(hdc, indexPF, &pfd))
    
        ...report error and terminate...
    


Logger::Inst() << " ~SetPFD;" << endl;

//TEMP CONTEXT TO ACQUIRE POINTER
HGLRC tempContext = wglCreateContext(hdc);

if (!tempContext) 
    ...report error and terminate...


if (!wglMakeCurrent(hdc, tempContext)) 
    ...report error and terminate...


int major, minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major < 4 || minor < 1) 
    ...report error and terminate...


const int attribs[] =

    WGL_CONTEXT_MAJOR_VERSION_ARB, major,
    WGL_CONTEXT_MINOR_VERSION_ARB, minor,
    WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
    0, 0
;

PFNWGLCREATEBUFFERREGIONARBPROC wglCreateContextAttribsARB = (PFNWGLCREATEBUFFERREGIONARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
if (!wglCreateContextAttribsARB) 
    ...report error and terminate...


**!!! CRASH HERE !!!**
if (!(hglrc = (HGLRC)wglCreateContextAttribsARB(hdc, 0, (UINT)attribs))) 
    ...report error and terminate...

调试器显示它恰好发生在 wglCreateContextAttribsARB(nvoglv64.dll!0000000074ccbdfa)。这对我来说完全是个谜。我唯一的线索是,在切换到 x64 后,它需要作为“UINT”而不是“const int*”传递的属性,我没有得到那部分,甚至不确定彼此之间的转换应该如何工作,看起来很可疑。想法?

【问题讨论】:

【参考方案1】:

您打错了:wglCreateContextAttribsARB 的类型错误。应该是PFNWGLCREATECONTEXTATTRIBSARBPROC

当您针对 32 位时它起作用的原因是因为两者的签名在 32 位中基本相同:

wglCreateContextAttribsARB:

typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);

wglCreateBufferRegionARB:

typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType);

wglCreateContextAttribsARB 的第二个和第三个参数是指针(HGLRC 是一个句柄,它只是一个指针),wglCreateBufferRegionARB 的第二个和第三个参数是整数。在 32 位中,指针大小为 32 位,因此签名本质上是相同的。

在 64 位中,指针的大小为 64 位,但整数仍然是 32 位(假设您使用的是 MSVC),因此您传入的这两个指针被截断了。

【讨论】:

PFNWGLTHANKYOUWOWIFEELLIKEADUMBAS... ARB...PROC。但真的很好奇它最初是如何工作的......多年来。 我添加了一些注释,说明它之前为何有效。

以上是关于x64 平台下,wglCreateContextAttribsARB 在调试模式下崩溃的主要内容,如果未能解决你的问题,请参考以下文章

VS2012下X64平台嵌入汇编程序

x86平台转x64平台关于内联汇编不再支持的解决

x86 x64下调用约定浅析

IOCP 无法在 x64 平台上运行

模块计算机类型“X86”与目标计算机类型“x64”冲突,用的是vs2010

size_t和unsigned int区别