Archived

This topic is now archived and is closed to further replies.

Arrow Mk84

ChoosePixelFormat errors/problems

Recommended Posts

I''m trying to create a basic window and OpenGL window wrapper classes (I''ve posted in the OpenGL forum, but no response). For some reason, I can''t get ChoosePixelFormat to work (even with PFDs from tutorials that I''ve downloaded and verified that they work). GetLastError() tells me that it can''t find choosepixelformat module (error code 126). Here''s the code for the OpenGL window wrapper:
  
class OpenGLWindow : public BaseWindow, public ResolutionManager
{
	public:
		OpenGLWindow();
		virtual ~OpenGLWindow();
		
		/* Initialization */
		void RegisterOGLMessageHandlers(MessageLookupTable* msgTable);

		/* Creation and Display */
		void CreateOGLWindow(int, HINSTANCE, WNDPROC);
		void SetViewPort();
		void ShowOGLWindow(int);

		/* Destruction */
		void ReleaseRenderContext();

		/* Public Vars */
		enum MODE
		{
			OGLW_640x480x32 = 0,
			OGLW_800x600x32,
			OGLW_1024x768x32,
			OGLW_REG_DEFAULT,
			OGLW_CONFIG_SETTING,
		};

		HDC window_hDC;			// window device context
		HGLRC render_hRC;		// render context

	protected:
		static LRESULT OnOGLWSize(OpenGLWindow&, HWND hWnd, WPARAM wParam, LPARAM lParam);
};

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: Constructor
|
|	Purpose: Initializes member variables on instancation. Note that the BaseWindow constructor is called before this 
|		constructor as OpenGLWindow is a subclass of BaseWindow.
-------------------------------------------------------------------------------------------------------------------------------*/
OpenGLWindow::OpenGLWindow()
{
	window_hDC = NULL;
	render_hRC = NULL;
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: Destructor
|
|	Purpose: Cleans up when the OpenGLWindow instance is no longer used - releases rendering context and restores resolution to
|		Windows registry defined values.
-------------------------------------------------------------------------------------------------------------------------------*/
OpenGLWindow::~OpenGLWindow()
{
	ReleaseRenderContext();
	try{
		RestoreResolution();
	}
	catch(ResolutionError re)
	{
		throw OpenGLWindowError(KString("Could not restore resolution -> ") + re.errorMsg, KString("OpenGLWindow Destructor -> ") + re.triggerMethod,
			KString("OpenGLWindow -> ") + re.triggerClass, KString(__FILE__) + KString(" -> ") + re.sourceFile, __LINE__);
	}
}
		
/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: RegisterOGLMessageHandlers
|
|	Purpose: Registers the message handlers for the base window and then registers the message handlers specific to an OpenGL
|		window. Any message handlers specific to an OpenGL window can be found at the bottom of this file.
|
|	Input Parameters:
|		msgTable		MessageLookupTable pointer			pointer to the message handler lookup table being used by the 
|																window procedure for routing messages.
-------------------------------------------------------------------------------------------------------------------------------*/
void OpenGLWindow::RegisterOGLMessageHandlers(MessageLookupTable* msgTable)
{
	if(msgTable != NULL)
	{
		RegisterBWMessageHandlers(msgTable);
		msgTable ->AddMessageHandler(WM_SIZE, (unsigned int)OnOGLWSize);
	}
	else
	{
		throw OpenGLWindowError("Cannot register message handlers - handler table NULL", "RegisterMessageHandlers", "OpenGLWindow",
			__FILE__, __LINE__);
	}

}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: CreateOGLWindow
|
|	Purpose: Creates a fullscreen OpenGL window, via CreateBaseWindow, according to one of the predefined enum modes,
|		and configures the device and rendering contexts. SetViewPort() and ShowOGLWindow() must be called to display any
|		3D graphics.
|
|	Input Parameters:
|		mode			int			the mode to use when displaying 3D graphics (the monitor resolution). Values are:
|											OGLW_640x480x32
|											OGLW_800x600x32,
|											OGLW_1024x768x32,
|											OGLW_REG_DEFAULT - monitor settings from Window''s registry
|											OGLW_CONFIG_SETTING - settings from program config file (under construction - do
|																	NOT use, yet)
|		hInstance			HINSTANCE		handle to the application''s instance (from WinMain).
|		windowsProcedure	WNDPROC			handle to the application''s window procedure.
-------------------------------------------------------------------------------------------------------------------------------*/
void OpenGLWindow::CreateOGLWindow(int mode, HINSTANCE hInstance, WNDPROC windowsProcedure)
{
	/* Create Window */
	try{
		// add in resolution switching and a switch/case statement for mode
		CreateBaseWindow(hInstance, windowsProcedure, CS_HREDRAW | CS_VREDRAW, WS_OVERLAPPEDWINDOW | WS_SYSMENU, 100, 100, 800, 600);
	}
	catch(BaseWindowError bwe)
	{
		throw OpenGLWindowError(KString("Unable to create base window: ") + bwe.errorMsg, KString("CreateOGLWindow -> ") + bwe.triggerMethod, 
			KString("OpenGLWindow -> ") + bwe.triggerClass, KString(__FILE__) + KString(" -> ") + bwe.sourceFile, __LINE__);
	}

	/* Get Device Context */
	window_hDC = GetDC(window_hWnd);

	if(window_hDC == NULL)
		throw OpenGLWindowError("Unable to get device context", "CreateOGLWindow", "OpenGLWindow", __FILE__, __LINE__);

	/* Describe Pixel Format */
	PIXELFORMATDESCRIPTOR pfd = 
	{
		sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd 
		1,                     // version number 
		PFD_DRAW_TO_WINDOW |   // support window 
		PFD_SUPPORT_OPENGL |   // support OpenGL 
		PFD_DOUBLEBUFFER,      // double buffered 
		PFD_TYPE_RGBA,         // RGBA type 
		24,                    // 24-bit color depth 
		0, 0, 0, 0, 0, 0,      // color bits ignored 
		0,                     // no alpha buffer 
		0,                     // shift bit ignored 
		0,                     // no accumulation buffer 
		0, 0, 0, 0,            // accum bits ignored 
		16,                    // 32-bit z-buffer     
		0,                     // no stencil buffer 
		0,                     // no auxiliary buffer 
		PFD_MAIN_PLANE,        // main layer 
		0,                     // reserved 
		0, 0, 0                // layer masks ignored 
	};


	/* Get and Set Pixel Format*/
	int format = 0;

	format = ChoosePixelFormat(window_hDC, &pfd);
	if(format == 0)
	{	int error = GetLastError();
		throw OpenGLWindowError("Could not find pixel format", "CreateOGLWindow", "OpenGLWindow", __FILE__, __LINE__);
	}
	if(!SetPixelFormat( window_hDC, format, &pfd ))
		throw OpenGLWindowError("Could not set pixel format", "CreateOGLWindow", "OpenGLWindow", __FILE__, __LINE__);

	/* Get Rendering Context */
	render_hRC = wglCreateContext( window_hDC );
	if(render_hRC == NULL)
		throw OpenGLWindowError("Could not get rendering context", "CreateOGLWindow", "OpenGLWindow", __FILE__, __LINE__);

	/* Make Context Current*/
    if(!wglMakeCurrent( window_hDC, render_hRC ))
		throw OpenGLWindowError("Could not make rendering context current", "CreateOGLWindow", "OpenGLWindow", __FILE__, __LINE__);
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: SetViewPort
|
|	Purpose: Configures the OpenGL Viewport - defines the area where 3D graphics are rendered.
-------------------------------------------------------------------------------------------------------------------------------*/
void OpenGLWindow::SetViewPort()
{
	/* Setup Viewport */
	RECT rect;					// rectangle of window
	GetWindowRect(window_hWnd, &rect);

	int width = rect.right - rect.left;
	int height = rect.bottom - rect.top;
	if(height == 0)
		height = 1;

	glViewport(0, 0, width, height - rect.top);

	/* Set Projection and View */
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 1.0f, 1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: ShowOGLWindow
|
|	Purpose: Shows the OpenGL window, via ShowBaseWindow, and makes sure the OpenGL viewport is set.
|
|	Input Parameters:
|		showCmd			int			dictates how to display the window - see MSDN ShowWindow, nCmdShow, for possible values -
|										use value specified by WinMain for first call.
-------------------------------------------------------------------------------------------------------------------------------*/
void OpenGLWindow::ShowOGLWindow(int nShowCmd)
{
	try{
		ShowBaseWindow(nShowCmd);
	}
	catch(BaseWindowError bwe)
	{
		throw OpenGLWindowError(KString("Unable to show base window: ") + bwe.errorMsg, KString("ShowOGLWindow -> ") + bwe.triggerMethod,
			KString("OpenGLWindow -> ") + bwe.triggerClass, KString(__FILE__) + " -> " + bwe.sourceFile, __LINE__);
	}
	SetViewPort();
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: ReleaseRenderContext
|
|	Purpose: Releases the OpenGL rendering context when rendering is completed. Basically stops all 3D drawing to the screen.
-------------------------------------------------------------------------------------------------------------------------------*/
void OpenGLWindow::ReleaseRenderContext()
{
	wglMakeCurrent( NULL, NULL );
    if(render_hRC != NULL)
		wglDeleteContext(render_hRC);
	if(window_hWnd != NULL && window_hDC != NULL)
		ReleaseDC(window_hWnd, window_hDC);
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: OnOGLWSize
|
|	Purpose: Resets the viewport when the window size changes.
|
|	Input Parameters:
|		bwnd		BaseWindow reference		reference to the base window that this message handler acts on.
|		hWnd		HWND						handle to a window.
|		wParam		WPARAM						unused (see window procedure documentation)
|		lParam		LPARAM						unused (see window procedure documentation)
|
|	NOTE: This method will work for subclasses of OpenGLWindow without having to be modified in any way. Just have the subclasses
|		call RegisterOGLMessageHandlers and everything is all set.
-------------------------------------------------------------------------------------------------------------------------------*/
LRESULT OpenGLWindow::OnOGLWSize(OpenGLWindow& currentWindow, HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	currentWindow.SetViewPort();	// Reset viewport

	return 0;
}
  
This is my base window wrapper, which works fine:
  
class BaseWindow
{
	public:
		BaseWindow();
		virtual ~BaseWindow();
		void RegisterBWMessageHandlers(MessageLookupTable* msgTable);
		void CreateBaseWindow(HINSTANCE hInstance, WNDPROC windowsProcedure, int classStyle, int windowStyle, int xCoord, int yCoord, int width, int height);
		void ShowBaseWindow(int showCmd);
	
		/* Handle to Window (for Windows) */
		HWND window_hWnd;
	
	protected:
		/* Message Handler Lookup Table */
		bool handlersRegistered;

		/* Message Handlers */
		static LRESULT OnBWClose(BaseWindow&, HWND hWnd, WPARAM wParam, LPARAM lParam);
		static LRESULT OnBWDestroy(BaseWindow&, HWND hWnd, WPARAM wParam, LPARAM lParam);
};

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: Constructor
|
|	Purpose: Creates an instance of BaseWindow with a NULL window handle and no associated message handlers.
-------------------------------------------------------------------------------------------------------------------------------*/
BaseWindow::BaseWindow()
{
	window_hWnd = NULL;
	handlersRegistered = false;
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: Destructor
|
|	
-------------------------------------------------------------------------------------------------------------------------------*/
BaseWindow::~BaseWindow()
{
	// any clean up
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: RegisterBWMessageHandlers
|
|	Purpose: Registers the message handlers for BaseWindow Instances (see below - all static functions with a return value of
|		LRESULT).
|
|	Input Parameters:
|		msgTable		MessageLookupTable pointer			pointer to the message handler lookup table being used by the 
|																window procedure for routing messages.
-------------------------------------------------------------------------------------------------------------------------------*/
void BaseWindow::RegisterBWMessageHandlers(MessageLookupTable* msgTable)
{
	if(msgTable != NULL)
	{
		
		msgTable ->AddMessageHandler(WM_CLOSE, (unsigned int)OnBWClose);
		msgTable ->AddMessageHandler(WM_DESTROY, (unsigned int)OnBWDestroy);
		handlersRegistered = true;
	}
	else
	{
		throw BaseWindowError("Cannot register message handlers - handler table NULL", "RegisterMessageHandlers", "BaseWindow",
			__FILE__, __LINE__);
	}
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: CreateBaseWindow
|
|	Purpose: Creates and registers a window.
|
|	Input Parameters:
|		hInstance			HINSTANCE		handle to the application''s instance (from WinMain).
|		windowsProcedure	WNDPROC			handle to the application''s window procedure.
|		classStyle			int				the window''s behavior and look - see MSDN WNDCLASSEX documentation,
|												style values, for possible arguments - CS_OWNDC is used automatically.
|		windowStyle			int				the more about the window''s look and behavior - see MSND CreateWindowEX 
|												documentation, style values, for possible arguments.
|		xCoord				int				the x pixel coordinate for the window''s upper left-hand corner.
|		yCoord				int				the y pixel coordinate for the window''s upper left-hand corner.
|		width				int				the pixel width of the window.
|		height				int				the pixel height of the window.
|
|		Throws: BaseWindowError
-------------------------------------------------------------------------------------------------------------------------------*/
void BaseWindow::CreateBaseWindow(HINSTANCE hInstance, WNDPROC windowsProcedure, int classStyle, int windowStyle, int xCoord, int yCoord, int width, int height)
{
	if(!handlersRegistered)
		throw BaseWindowError("Message handlers not registered", "CreateBaseWindow", "BaseWindow", __FILE__, __LINE__);

	::WNDCLASSEX wcx;
	wcx.cbSize = sizeof(WNDCLASSEX); 
	wcx.style = classStyle | CS_OWNDC;				// user class style and give window its own device context 
	wcx.lpfnWndProc = windowsProcedure; 
	wcx.cbClsExtra = 0; 
	wcx.cbWndExtra = 0; 
	wcx.hInstance = hInstance; 
	wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);   // replace with an icon resource
	wcx.hCursor = LoadCursor(NULL, IDC_ARROW); 
	wcx.hbrBackground = (HBRUSH)COLOR_BACKGROUND; 
	wcx.lpszMenuName = NULL; 
	wcx.lpszClassName = "BaseWindow";  // replace with a string resource
	wcx.hIconSm = NULL;		// replace with an icon resource

	if(!::RegisterClassEx(&wcx))
		throw BaseWindowError("Unable to register window", "CreateBaseWindow", "BaseWindow", __FILE__, __LINE__);

	window_hWnd = ::CreateWindowEx(NULL, "BaseWindow", "BaseWindow", windowStyle, xCoord, yCoord, width, height, NULL, NULL, hInstance, this);
	if(window_hWnd == NULL)
		throw BaseWindowError("Unable to create window", "CreateBaseWindow", "BaseWindow", __FILE__, __LINE__);
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Method: ShowBaseWindow
|
|	Purpose: Shows the window based on value of showCmd
|
|	Input Parameters:
|		showCmd			int			dictates how to display the window - see MSDN ShowWindow, nCmdShow, for possible values -
|										use value specified by WinMain for first call.
|
|	Throws: BaseWindowError
-------------------------------------------------------------------------------------------------------------------------------*/
void BaseWindow::ShowBaseWindow(int showCmd)
{
	if(window_hWnd != NULL)
	{
		::ShowWindow(window_hWnd, showCmd);
		::UpdateWindow(window_hWnd);
	}
	else
		throw BaseWindowError("Unable to show window - NULL handle", "ShowBaseWindow", "BaseWindow", __FILE__, __LINE__);
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Static Function: OnBWClose
|
|	Purpose: Handles the WM_CLOSE message for a BaseWindow instance.
|
|	Input Parameters:
|		bwnd		BaseWindow reference		reference to the base window that this message handler acts on.
|		hWnd		HWND						handle to a window.
|		wParam		WPARAM						unused (see window procedure documentation)
|		lParam		LPARAM						unused (see window procedure documentation)
|
|	NOTE: This method will work for subclasses of BaseWindow without having to be modified in any way. Just have the subclasses
|		call RegisterBWMessageHandlers and everything is all set.
-------------------------------------------------------------------------------------------------------------------------------*/
LRESULT BaseWindow::OnBWClose(BaseWindow &bwnd, HWND hWnd, WPARAM wParam, LPARAM lParam) 
{
	::DestroyWindow(hWnd);
	return 0;
}

/*-------------------------------------------------------------------------------------------------------------------------------
|	Static Function: OnBWDestroy
|
|	Purpose: Handles the WM_Destroy message for a BaseWindow instance.
|
|	Input Parameters:
|		bwnd		BaseWindow reference		reference to the base window that this message handler acts on.
|		hWnd		HWND						handle to a window.
|		wParam		WPARAM						unused (see window procedure documentation)
|		lParam		LPARAM						unused (see window procedure documentation)
|
|	NOTE: This method will work for subclasses of BaseWindow without having to be modified in any way. Just have the subclasses
|		call RegisterBWMessageHandlers and everything is all set.
-------------------------------------------------------------------------------------------------------------------------------*/
LRESULT BaseWindow::OnBWDestroy(BaseWindow &bwnd, HWND hWnd, WPARAM wParam, LPARAM lParam) 
{
	::PostQuitMessage(0);
	return 0;
}

  
And here is my WinMain and WNDPROC:
  
/* Globals */
MessageLookupTable* MsgHandlerTable = NULL;

/* Prototypes */
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

/*===============================================================================================================================
|	Function: WinMain
|
|	Purpose: Windows entry point for this Win32 appilication. Initializes engine and pumps Windows messages. 
|		See MSDN WinMain for more documentation.
===============================================================================================================================*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
{
	/* Create Error Queue */
	ErrorQueue ErrorLog;

	/* Create Message Handler Lookup Table */
	try{
		MsgHandlerTable = new MessageLookupTable(); // uses default creation parameters
	}
	catch(MemoryAllocationFailed maf)
	{
		ErrorLog.AddErrorMessage(maf);
		return -1;
	}

	/* Create and Display Engine*/
	OpenGLWindow bWin;

	try{
		bWin.RegisterOGLMessageHandlers(MsgHandlerTable);
		bWin.CreateOGLWindow(0, hInstance, (WNDPROC)WindowProc);
		bWin.SetViewPort();
		bWin.ShowOGLWindow(nShowCmd);
	}
	catch(OpenGLWindowError bwe)
	{
		ErrorLog.AddErrorMessage(bwe);
		return -1;
	}

	/* Message Pump and Run Engine */
	MSG Msg;
	while(true)
	{
		if(PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE))  // gets messages, sleeps if no messages  
		{        
			if(!GetMessage(&Msg, NULL, 0, 0))			// breaks the loop on quit message            
				break;        
			else        
			{            
				TranslateMessage(&Msg);            
				DispatchMessage(&Msg);        
			}    
		}
	}

	return 0;
}

/*===============================================================================================================================
|	Function: WindowProc
|
|	Purpose: Window procedure. Sends messages to the appropiate message handler (handles WM_NCCREATE explicitly configure
|		window handle as window is created). See MSDN Window Procedure (WNDPROC) for more. Also see references.
===============================================================================================================================*/
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	OpenGLWindow* currentWindow = NULL;

	if(message == WM_NCCREATE)
	{
		LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;					// get window creation data

		currentWindow = (OpenGLWindow*)lpcs->lpCreateParams;				// configure window

		SetWindowLong(hWnd, GWL_USERDATA,(LONG)currentWindow);			// associate window with currentWIndow

		currentWindow ->window_hWnd = hWnd;								// save handle

		return DefWindowProc(hWnd, message, wParam, lParam);			// return message to Windows


	}
	else
		currentWindow = (OpenGLWindow*)GetWindowLong(hWnd, GWL_USERDATA);	// will be NULL before WM_NCCREATE


	if(currentWindow != NULL)
	{
		if(MsgHandlerTable != NULL)
		{
			if(MsgHandlerTable ->LookUpMessageHandler(message))			// if message handler exists

			{
				unsigned int handler = MsgHandlerTable ->GetMessageHandler(message);		// get it,

				return ((LRESULT (*)(OpenGLWindow&, HWND, WPARAM, LPARAM))handler)(*currentWindow, hWnd, wParam, lParam);		// cast and call it

			}
		}

	}
    return(DefWindowProc(hWnd, message, wParam, lParam));
}
  
The WNDPROC works with a message handler function table (a la the window wrapper tutorial on this site), which has the handler functions defined by BaseWindow and OpenGLWindow. All exceptions are dumped to an ErrorQueue. KString is a string library I wrote for another project and is similar in features to MFC CStrings. I can get an HDC with no problem, but ChoosePixelFormat bombs out (and if makes any difference, I''m using Win98SE with Geforce 3). Anybody have a solution?

Share this post


Link to post
Share on other sites
do the tutorials work? and are you using dll delay-loading by any change? also try putting any gl* call just at the beginning of winmain, before you create your window.

Share this post


Link to post
Share on other sites
The tutorial code works fine. I''m doing delay dll loading. What does moving gl* calls to beginning of WinMain do? I''ve read that other people use a different HDC when choosing a pixel format. Is this what I need to do (and how would I go about doing this)?

Share this post


Link to post
Share on other sites
basically, ChoosePixelFormat is in gdi32.dll. apparently, that function loads opengl32.dll via LoadLibrary to do some stuff, and then releases the reference to it via FreeLibrary. when you''re linking to opengl32.dll implicitly without using delayloading, opengl32.dll will already be loaded into your address space when you call ChoosePixelFormat, so that function just increments and decrements reference count of opengl32.dll. in this case, however, FreeLibrary will actually release opengl32.dll, and using one of wgl functions will load it "from scratch". the result is that your pixel format setup will be in some intermediate non-functioning state.

what you want to do is force loading of opengl32.dll into your address space before you call any gl-related gdi functions. this can be accomplished by calling anything from opengl32.dll just before setting up a pixel format. i told you to put a call to any gl* function in winmain because that was the easiest thing to do. alternatively, you can use LoadLibrary and load opengl32.dll just before setting up pixel format.

Share this post


Link to post
Share on other sites