Steven De Bock
Steven De Bock

Reputation: 429

OpenGL -> wglCreateContext, wglMakeCurrent in WndProc's WM_CREATE makes rendering fail

OS: Windows 7, 64 bit Visual Studio 2010, debug, 32 bit

I'm trying out a simple Windows program to start working with openGL: all the program should do is clear the color buffer with glClear(GL_COLOR_BUFFER_BIT).

In the tutorials I found on the web, I find that people are creating and setting the openGL context during the creation of the window (and thus during the treatment of the WM_CREATE message). Somehow, I find that this doesn't work for my code and I don't seem to be able to figure it out. So if anyone could point me in the right direction.

Please find hereafter the code how I expect that it should work based on tutorials:

#include <windows.h>
#include <GL\glew.h>
#include <GL\wglew.h>

#include "Application.h"

HWND ghMainWnd = 0;

bool InitWindowsApp(HINSTANCE instanceHandle, int show);

int Run();

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

HDC hDC;
HGLRC hGLRC;
HPALETTE hPalette;

void SetupPixelFormat()
{
    PIXELFORMATDESCRIPTOR pfd = {};
    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cAlphaBits = 8;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int pixelFormat = ChoosePixelFormat(hDC, &pfd);
    if(pixelFormat == 0)
    {
        MessageBox(ghMainWnd, L"ChoosePixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    if(!SetPixelFormat(hDC, pixelFormat, &pfd))
    {
        MessageBox(ghMainWnd, L"SetPixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }
}

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
    if(!InitWindowsApp(hInstance, nShowCmd))
        return 0;

    return Run();
}

bool InitWindowsApp(HINSTANCE instanceHandle, int show)
{
    WNDCLASS wc;
    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instanceHandle;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"BasicWndClass";

    if(!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass failed", 0, 0);
        return false;
    }

    ghMainWnd = CreateWindow(
        L"BasicWndClass",
        L"BasicWindowsApp",
        WS_OVERLAPPEDWINDOW, 
        0,
        0,
        600,
        600,
        0,
        0,
        instanceHandle,
        0);

    if(ghMainWnd == 0)
    {   
        MessageBox(0, L"CreateWindow failed", 0, 0);
        return false;
    }

    ShowWindow(ghMainWnd, show);
    UpdateWindow(ghMainWnd);

    return true;

}

int Run()
{
    MSG msg = {0};

    Application *pApp = new Application();
    pApp->Init();

    while(msg.message != WM_QUIT)
    {
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //Do Other stuff
            pApp->Draw();
            SwapBuffers(hDC);
        }
    }

    if(pApp)
    {
        delete pApp;
        pApp = nullptr;
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch(msg)
    {
    case WM_CREATE:

        hDC = GetDC(ghMainWnd);

        SetupPixelFormat();

        hGLRC = wglCreateContext(hDC);
        if(!hGLRC)
        {
            MessageBox(ghMainWnd, L"wglCreateContext() failed", L"Error", MB_ICONERROR | MB_OK);
            exit(1);
        }

        if(!wglMakeCurrent(hDC, hGLRC))
        {
            MessageBox(ghMainWnd, L"wglMakeCurrent() failed", L"Error", MB_ICONERROR | MB_OK);
            exit(1);
        }

        glViewport(0, 0, 600, 600);
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

        return 0;

    case WM_LBUTTONDOWN:

        return 0;

    case WM_KEYDOWN:
        if(wParam == VK_ESCAPE)
            DestroyWindow(ghMainWnd);

        return 0;

    case WM_DESTROY:
        if(hGLRC)
        {
            wglMakeCurrent(nullptr, nullptr);
            wglDeleteContext(hGLRC);
        }

        ReleaseDC(ghMainWnd, hDC);

        PostQuitMessage(0);

        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

Below, I found a "hack" to make it work: I basically move the opengl context creation into the InitWindowsApp() function... But why does the code above doesn't work?

#include <windows.h>
#include <GL\glew.h>
#include <GL\wglew.h>

#include "Application.h"

HWND ghMainWnd = 0;

bool InitWindowsApp(HINSTANCE instanceHandle, int show);

int Run();

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

HDC hDC;
HGLRC hGLRC;
HPALETTE hPalette;

void SetupPixelFormat()
{
    PIXELFORMATDESCRIPTOR pfd = {};
    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cAlphaBits = 8;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int pixelFormat = ChoosePixelFormat(hDC, &pfd);
    if(pixelFormat == 0)
    {
        MessageBox(ghMainWnd, L"ChoosePixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    if(!SetPixelFormat(hDC, pixelFormat, &pfd))
    {
        MessageBox(ghMainWnd, L"SetPixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }
}

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
    if(!InitWindowsApp(hInstance, nShowCmd))
        return 0;

    return Run();
}

bool InitWindowsApp(HINSTANCE instanceHandle, int show)
{
    WNDCLASS wc;
    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instanceHandle;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"BasicWndClass";

    if(!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass failed", 0, 0);
        return false;
    }

    ghMainWnd = CreateWindow(
        L"BasicWndClass",
        L"BasicWindowsApp",
        WS_OVERLAPPEDWINDOW, 
        0,
        0,
        600,
        600,
        0,
        0,
        instanceHandle,
        0);

    if(ghMainWnd == 0)
    {   
        MessageBox(0, L"CreateWindow failed", 0, 0);
        return false;
    }

    ShowWindow(ghMainWnd, show);
    UpdateWindow(ghMainWnd);

    hDC = GetDC(ghMainWnd);

    SetupPixelFormat();

    hGLRC = wglCreateContext(hDC);
    if(!hGLRC)
    {
        MessageBox(ghMainWnd, L"wglCreateContext() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    if(!wglMakeCurrent(hDC, hGLRC))
    {
        MessageBox(ghMainWnd, L"wglMakeCurrent() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    glViewport(0, 0, 600, 600);
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

    return true;

}

int Run()
{
    MSG msg = {0};

    Application *pApp = new Application();
    pApp->Init();

    while(msg.message != WM_QUIT)
    {
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //Do Other stuff
            pApp->Draw();
            SwapBuffers(hDC);
        }
    }

    if(pApp)
    {
        delete pApp;
        pApp = nullptr;
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch(msg)
    {
    case WM_CREATE:

        return 0;

    case WM_LBUTTONDOWN:

        return 0;

    case WM_KEYDOWN:
        if(wParam == VK_ESCAPE)
            DestroyWindow(ghMainWnd);

        return 0;

    case WM_DESTROY:
        if(hGLRC)
        {
            wglMakeCurrent(nullptr, nullptr);
            wglDeleteContext(hGLRC);
        }

        ReleaseDC(ghMainWnd, hDC);

        PostQuitMessage(0);

        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

Upvotes: 2

Views: 2243

Answers (1)

Daniel Flassig
Daniel Flassig

Reputation: 698

When WM_CREATE arrives, your ghMainWnd is still NULL (the message is sent before the CreateWindow call returns). Instead, use the hWnd parameter of the message in your GetDC call.

Upvotes: 4

Related Questions