diff --git a/MUNGA_L4/L4VB16.cpp b/MUNGA_L4/L4VB16.cpp index fad4f98..f0e60a5 100644 --- a/MUNGA_L4/L4VB16.cpp +++ b/MUNGA_L4/L4VB16.cpp @@ -3828,6 +3828,13 @@ static LRESULT CALLBACK //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static WNDPROC gCockpitBaseProc = NULL; +// +// Which window we subclassed, so the destructor can put its own proc +// back. The shell is the GAME window: it outlives the cockpit and +// carries the console screen from one race to the next. +// +static HWND gCockpitShellWindow = NULL; + static LRESULT CALLBACK CockpitShellProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -4688,9 +4695,25 @@ SVGA16::SVGA16( GetClientRect(cockpit, &inner); LayoutCockpit(inner.right, inner.bottom); - // catch maximise / restore / drag-resize and re-fit - gCockpitBaseProc = (WNDPROC) SetWindowLongPtrA( - cockpit, GWLP_WNDPROC, (LONG_PTR) CockpitShellProc); + // + // Catch maximise / restore / drag-resize and re-fit - ONCE. + // + // The destructor puts the original proc back, so ordinarily + // this window is unsubclassed by the time a second race + // builds a new cockpit. The guard is for the case where it + // was not: subclassing an already-subclassed window makes + // SetWindowLongPtr hand back CockpitShellProc itself as the + // "original", and the proc below then chains to itself on + // every single message until the stack runs out. That is a + // stack overflow a few frames into the second race, with no + // hint of a cause in the log. + // + if (gCockpitShellWindow != cockpit) + { + gCockpitBaseProc = (WNDPROC) SetWindowLongPtrA( + cockpit, GWLP_WNDPROC, (LONG_PTR) CockpitShellProc); + gCockpitShellWindow = cockpit; + } // // Sticky placement for the shell. Position AND size: nothing @@ -4926,6 +4949,30 @@ SVGA16::~SVGA16() cockpitViewscreen = NULL; } + // + // Give the game window its own proc back, and stop answering for a + // cockpit that is about to stop existing. + // + // The window survives us - it is the one that shows the console + // screen between races - so both of these outlived their subject. + // The subclass was the worse of the two: the next race re-subclassed + // the same window and CockpitShellProc ended up chained to itself. + // activeCockpit was the quieter one, left pointing at this object + // after it was freed, ready for the next WM_SIZE to lay out a + // cockpit that had already gone. + // + if (gCockpitShellWindow != NULL) + { + SetWindowLongPtrA( + gCockpitShellWindow, GWLP_WNDPROC, (LONG_PTR) gCockpitBaseProc); + gCockpitShellWindow = NULL; + gCockpitBaseProc = NULL; + } + if (activeCockpit == this) + { + activeCockpit = NULL; + } + Check_Fpu(); }