unregister GL windows classes on program termination, fixes problem with wx being used in a DLL which is being unloaded and reloaded again

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@29051 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2004-09-08 12:00:12 +00:00
parent 447fd332c8
commit 53fcd32e57

View File

@ -29,6 +29,8 @@
#include "wx/app.h"
#endif
#include "wx/module.h"
#include "wx/msw/private.h"
// DLL options compatibility check:
@ -66,6 +68,116 @@ static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR");
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
// ----------------------------------------------------------------------------
// wxGLModule is responsible for unregistering wxGLCanvasClass Windows class
// ----------------------------------------------------------------------------
class wxGLModule : public wxModule
{
public:
bool OnInit() { return true; }
void OnExit() { UnregisterClasses(); }
// register the GL classes if not done yet, return true if ok, false if
// registration failed
static bool RegisterClasses();
// unregister the classes, done automatically on program termination
static void UnregisterClasses();
private:
// wxGLCanvas is only used from the main thread so this is MT-ok
static bool ms_registeredGLClasses;
DECLARE_DYNAMIC_CLASS(wxGLModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule)
bool wxGLModule::ms_registeredGLClasses = false;
/* static */
bool wxGLModule::RegisterClasses()
{
if (ms_registeredGLClasses)
return true;
// We have to register a special window class because we need the CS_OWNDC
// style for GLCanvas.
/*
From Angel Popov <jumpo@bitex.com>
Here are two snips from a dicussion in the OpenGL Gamedev list that explains
how this problem can be fixed:
"There are 5 common DCs available in Win95. These are aquired when you call
GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
OWNDC flagged windows do not get their DC from the common DC pool, the issue
is they require 800 bytes each from the limited 64Kb local heap for GDI."
"The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
do), Win95 will actually "steal" it from you. MakeCurrent fails,
apparently, because Windows re-assigns the HDC to a different window. The
only way to prevent this, the only reliable means, is to set CS_OWNDC."
*/
WNDCLASS wndclass;
// the fields which are common to all classes
wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
wndclass.hInstance = wxhInstance;
wndclass.hIcon = (HICON) NULL;
wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
wndclass.lpszMenuName = NULL;
// Register the GLCanvas class name
wndclass.hbrBackground = (HBRUSH)NULL;
wndclass.lpszClassName = wxGLCanvasClassName;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
return false;
}
// Register the GLCanvas class name for windows which don't do full repaint
// on resize
wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
::UnregisterClass(wxGLCanvasClassName, wxhInstance);
return false;
}
ms_registeredGLClasses = true;
return true;
}
/* static */
void wxGLModule::UnregisterClasses()
{
// we need to unregister the classes in case we're in a DLL which is
// unloaded and then loaded again because if we don't, the registration is
// going to fail in wxGLCanvas::Create() the next time we're loaded
if ( ms_registeredGLClasses )
{
::UnregisterClass(wxGLCanvasClassName, wxhInstance);
::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance);
ms_registeredGLClasses = false;
}
}
/*
* GLContext implementation
*/
@ -229,8 +341,7 @@ wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID i
wxGLCanvas::~wxGLCanvas()
{
if (m_glContext)
delete m_glContext;
delete m_glContext;
::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
}
@ -244,90 +355,34 @@ bool wxGLCanvas::Create(wxWindow *parent,
long style,
const wxString& name)
{
static bool s_registeredGLCanvasClass = false;
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
// We have to register a special window class because we need
// the CS_OWNDC style for GLCanvas.
/*
From Angel Popov <jumpo@bitex.com>
Here are two snips from a dicussion in the OpenGL Gamedev list that explains
how this problem can be fixed:
"There are 5 common DCs available in Win95. These are aquired when you call
GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
OWNDC flagged windows do not get their DC from the common DC pool, the issue
is they require 800 bytes each from the limited 64Kb local heap for GDI."
"The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
do), Win95 will actually "steal" it from you. MakeCurrent fails,
apparently, because Windows re-assigns the HDC to a different window. The
only way to prevent this, the only reliable means, is to set CS_OWNDC."
*/
if (!s_registeredGLCanvasClass)
{
WNDCLASS wndclass;
// the fields which are common to all classes
wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
wndclass.hInstance = wxhInstance;
wndclass.hIcon = (HICON) NULL;
wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
wndclass.lpszMenuName = NULL;
// Register the GLCanvas class name
wndclass.hbrBackground = (HBRUSH)NULL;
wndclass.lpszClassName = wxGLCanvasClassName;
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
if ( !::RegisterClass(&wndclass) )
if ( !wxGLModule::RegisterClasses() )
{
wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
return false;
}
// Register the GLCanvas class name for windows which don't do full repaint
// on resize
wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
if ( !::RegisterClass(&wndclass) )
{
wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
::UnregisterClass(wxGLCanvasClassName, wxhInstance);
wxLogError(_("Failed to register OpenGL window class."));
return false;
}
s_registeredGLCanvasClass = true;
}
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
return false;
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
parent->AddChild(this);
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
return false;
DWORD msflags = 0;
parent->AddChild(this);
/*
A general rule with OpenGL and Win32 is that any window that will have a
HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
You can find references about this within the knowledge base and most OpenGL
books that contain the wgl function descriptions.
*/
DWORD msflags = 0;
WXDWORD exStyle = 0;
msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
msflags |= MSWGetStyle(style, & exStyle) ;
/*
A general rule with OpenGL and Win32 is that any window that will have a
HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
You can find references about this within the knowledge base and most OpenGL
books that contain the wgl function descriptions.
*/
WXDWORD exStyle = 0;
msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
msflags |= MSWGetStyle(style, & exStyle) ;
return MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle);
return MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle);
}
static void AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, int *attribList)