wglMakeCurrent fails on NVidia

Has anyone ever experienced that wglMakeCurrent failing for a valid context and valid device context?
It happens in my initialization routine for the temporary context that I need to create to obtain any wgl* Extensions.
I create a window class, an (invisible) window, call GetDC() on it, create a minimal PixelFormatDescriptor followed by SetPixelFormat and wglCreateContext.
None of the functions returns an error, but when I finally call wglMakeCurrent() it fails. GetLastError() gives no clue.
I know of an obscure problem, where wglMakeCurrent() (which gets repeatedly called at the beginning of each frame) fails sometimes for no apparent reason. In this case it helped to try again a few times.
Unfortnately it didn’t help me this time. Repeating wglMakeCurrent() 5 times in 5 seconds always returned FALSE :frowning:

I cannot reproduce the bug on my machine, but one of our customers can do it reliably. I could not yet find the ‘trigger’, though.

Any hints on what went wrong?

I’ve seen this error before, but have no idea about its cause. However, I think that contexts become current upon creation, so maybe you don’t need to call wglMakeCurrent at all in this case?

Is this happens all the time or its rare bug? Can you post drivers, version, OS, service pack, hardware, graphics card.

When you create invisible windows did you specify CS_OWNDC in window class?

Here is code that I use for that:

	typedef struct tagPixelFormat
			ColorDepth = 32;
			AlphaDepth = 8;
			ZDepth = 24;
			StencilDepth = 0;
			MultiSample = 0;

			FullScreen = false;
			VSync = false;

		int ColorDepth, AlphaDepth, ZDepth, StencilDepth, MultiSample;
		bool FullScreen;
		bool VSync;
	} tPixelFormat;

BOOL RegisterWindowClass ()												// Register A Window Class For This Application.
{																		// TRUE If Successful
	// Register A Window Class
	WNDCLASSEX windowClass;												// Window Class
	ZeroMemory (&windowClass, sizeof (WNDCLASSEX));						// Make Sure Memory Is Cleared
	windowClass.cbSize			= sizeof (WNDCLASSEX);					// Size Of The windowClass Structure
	windowClass.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// | CS_DBLCLKS;	// Redraws The Window For Any Movement / Resizing
	windowClass.lpfnWndProc		= (WNDPROC)(WindowProc);				// WindowProc Handles Messages
	windowClass.hInstance		= g_hInstance;							// Set The Instance
	windowClass.hbrBackground	= (HBRUSH)(COLOR_APPWORKSPACE);			// Class Background Brush Color
	windowClass.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	windowClass.lpszClassName	= WND_CLASSNAME;						// Sets The Applications Classname
	if (RegisterClassEx (&windowClass) == 0)							// Did Registering The Class Fail?
		// NOTE: Failure, Should Never Happen
		MessageBox (HWND_DESKTOP, "RegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;													// Return False (Failure)
	return TRUE;														// Return True (Success)

static LRESULT CALLBACK PFWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
	return DefWindowProc(hwnd, message, wParam, lParam);

static void initEntryPoints(HWND hwnd, const PIXELFORMATDESCRIPTOR &pfd)
	HDC hdc = GetDC(hwnd);

	int nPixelFormat = ChoosePixelFormat(hdc, &pfd);
	SetPixelFormat(hdc, nPixelFormat, &pfd);

	HGLRC hglrc = wglCreateContext(hdc);
	wglMakeCurrent(hdc, hglrc);


	wglMakeCurrent(NULL, NULL);
	ReleaseDC(hwnd, hdc);

#define elementsOf(x) (sizeof(x) / sizeof(x[0]))

static int GetPixelFormat(IEngine::tPixelFormat& pf)
     PFD_TYPE_RGBA, pf.ColorDepth,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     pf.ZDepth, pf.StencilDepth,
     0, PFD_MAIN_PLANE, 0, 0, 0, 0 };

	WNDCLASS wincl;
	wincl.hInstance = g_hInstance;
	wincl.lpszClassName = "PFrmt";
	wincl.lpfnWndProc = PFWinProc;
	wincl.style = 0;
	wincl.hIcon = NULL;
	wincl.hCursor = NULL;
	wincl.lpszMenuName = NULL;
	wincl.cbClsExtra = 0;
	wincl.cbWndExtra = 0;
	wincl.hbrBackground = NULL;

	HWND hwnd = CreateWindow("PFrmt", "PFormat", WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 8, 8, HWND_DESKTOP, NULL, g_hInstance, NULL);
	initEntryPoints(hwnd, pfd);
	HDC hdc = GetDC(hwnd);

	int iAttribs[] = 
	 WGL_RED_BITS_ARB, (pf.ColorDepth > 16)? 8 : 5,
	 WGL_GREEN_BITS_ARB, (pf.ColorDepth > 16)? 8 : 6,
	 WGL_BLUE_BITS_ARB, (pf.ColorDepth > 16)? 8 : 5,
	 WGL_ALPHA_BITS_ARB, (pf.ColorDepth > 16)? 8 : 0,
	 WGL_STENCIL_BITS_ARB,   pf.StencilDepth,

	int pixelFormats[256];
	int bestFormat = 0;
	int bestSamples = 0;
	unsigned int nPFormats;
	if (	EXTCAPS(WGL_ARB_pixel_format)
		&&  wglChoosePixelFormatARB(hdc, iAttribs, NULL, elementsOf(pixelFormats), pixelFormats, &nPFormats) 
		&&  nPFormats > 0)
		int minDiff = 0x7FFFFFFF;
		int attrib = WGL_SAMPLES_ARB;
		int samples;

	// Find a multisample format as close as possible to the requested
		for (unsigned int i = 0; i < nPFormats; i++)
			wglGetPixelFormatAttribivARB(hdc, pixelFormats[i], 0, 1, &attrib, &samples);
			int diff = abs(pf.MultiSample - samples);
			if (diff < minDiff)
				minDiff = diff;
				bestFormat = i;
				bestSamples = samples;
		SendMessage(hwnd, WM_CLOSE, 0, 0);
		return ChoosePixelFormat(hdc, &pfd);
	pf.MultiSample = bestSamples;
	SendMessage(hwnd, WM_CLOSE, 0, 0);
	return pixelFormats[bestFormat];

We just had a customer report this problem as well. We have never seen it on any machine here in our office, but we have one customer with an NVIDIA 4500 who apparently is experiencing failures on calls to wglMakeCurrent (on visible windows). If I have understood their complaint correctly, if they retry the action that generated the error, it succeeds. The error popup indicates that GetLastError returned ERROR_INVALID_HANDLE.

This is software that is running on Windows XP (probably service pack 2).

So what is the obscure problem that you made mention of?

Its exactly the behaviour your customers seem to experience sometimes, too. I have found no cure yet, though.

Ask client to check its drivers. Default Windows drivers doesnt support OpenGL acceleration.

Even without acceleration, wglMakeCurrent should not fail.

One condition that could cause wglMakeCurrent to fail with ‘error: 6’ (invalid handle) is leakage of Device Contexts. Make sure you are disposing DCs correctly whenever you create/destroy a window or context.

They have Forceware 175.19 installed on a GF7800GTX (AGP). It only seems to happen in the fullscreen mode of their application. In Windowed mode everything works fine. The strange thing is, my code does not distinguish between both modes. Exactly the same code is executed in both modes - the way the application works does not affect the way I open that temporary window and create the temporary context.

How do you switch to fullscreen? Do you modify the style of a normal window or do you create a new window? Do you use the same context or create a new one?

If you open a new window and transfer an existing context, there is a good chance this error may be caused by an invalid (stale) DC.