Here’s the problem:
I have made a function for painting the contents of a window using OpenGL. This function has both the HDC and the HGLRC declared locally as static variables, and initializes them upon the first call to the function (this awkward way of doing it will be explained below):
VOID GfxProc (HWND hwnd)
{
static HDC hdc=NULL;
static HGLRC hglrc=NULL;
static BOOLEAN ready=FALSE;
if(!ready)
{
// initialize hdc and hglrc, choose pixel format etc...
wglMakeCurrent(hdc,hglrc);
ready=TRUE;
}
if(ready)
{
// paint the window
}
}
When I call the function as a response to a WM_PAINT message in the main thread it works fine. No problemo. But when I handle the painting from another thread, wglMakeCurrent causes the program to crash. Badly, with both Windows “Send Error Report” and “Program Not Responding” messages.
I am aware that the HGLRC can only be current in one thread. The HDC and HGLRC are declared locally in GfxProc. The HWND function parameter to GfxProc is the return value from CreateWindow to the window that is painted. In short: All variables related to the painting process are declared by the thread (in GfxProc), so it isn’t a memory/thread-share issue that causes the crash. Besides, unless we use TLS all global variables are shared among the threads, so if the HWND is valid in the main thread, it is valid in the other thread as well (I tested this).
Thanks in advance for any help/suggestions regarding this problem!
PS: The entire function looks like this:
VOID GfxProc (HWND hwnd)
{
static HDC hdc=NULL;
static HGLRC hglrc=NULL;
static BOOL ready=FALSE;
static BOOL failed=FALSE;
if(!ready&&!failed)
{
ready=TRUE;
if(ready&&!(hdc=GetDC(hwnd)))
ready=FALSE;
auto DISPLAYMODE dspmode;
if(ready&&!dspGetDisplayMode(&dspmode))
ready=FALSE;
if(ready)
{
auto PIXELFORMATDESCRIPTOR pfd={0};
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=dspmode.bpp;
pfd.iLayerType=PFD_MAIN_PLANE;
auto INT pixelformat;
if(ready&&!(pixelformat=ChoosePixelFormat(hdc,&pfd)))
ready=FALSE;
if(ready&&!SetPixelFormat(hdc,pixelformat,&pfd))
ready=FALSE;
if(ready&&!(hglrc=wglCreateContext(hdc)))
ready=FALSE;
if(ready&&!wglMakeCurrent(hdc,hglrc)) // <===-- - - this is where the program crashes
ready=FALSE;
if(ready)
{
glClearColor(0.0,0.2,0.4,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel(GL_FLAT);
}
}
if(!ready)
failed=TRUE;
}
static GLfloat g_flt=-1.0,g_add=0.01;
if(ready)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.5,0);
glBegin(GL_POLYGON);
glVertex3f(-g_flt,-g_flt,-g_flt);
glVertex3f(-g_flt,+g_flt,-g_flt);
glVertex3f(+g_flt,+g_flt,-g_flt);
glVertex3f(+g_flt,-g_flt,-g_flt);
glEnd();
g_flt+=g_add;
if((g_flt>=1.0)||(g_flt<=-1.0))
g_add*=-1;
SwapBuffers(hdc);
}
}