Don't assert if HWND is invalid in wxWindow::DissociateHandle()

There was no safe way to prevent wxWindow from trying to destroy the
HWND again if it had been already destroyed, for whatever reason, as
UnsubclassWin() asserted if it was called and calling SetHWND(0) before
calling it as some (but not all) existing code did, resulted in not
removing the association using the old HWND as key.

Allow to use DissociateHandle() for safely detaching HWND from the
window, without assuming that it is valid.
This commit is contained in:
Vadim Zeitlin 2023-03-31 01:56:38 +01:00
parent 13ebaee247
commit 82729cb93a
2 changed files with 33 additions and 7 deletions

View file

@ -749,6 +749,9 @@ private:
// common part of all ctors
void Init();
// common part of UnsubclassWin() and DissociateHandle()
WXHWND DoDetachHWND();
// the (non-virtual) handlers for the events
bool HandleMove(int x, int y);
bool HandleMoving(wxRect& rect);

View file

@ -1364,14 +1364,10 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd)
void wxWindowMSW::UnsubclassWin()
{
wxRemoveHandleAssociation(this);
HWND hwnd = DoDetachHWND();
// Restore old Window proc
HWND hwnd = GetHwnd();
if ( hwnd )
{
SetHWND(0);
wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
if ( m_oldWndProc )
@ -1386,6 +1382,20 @@ void wxWindowMSW::UnsubclassWin()
}
}
WXHWND wxWindowMSW::DoDetachHWND()
{
wxRemoveHandleAssociation(this);
// Restore old Window proc
HWND hwnd = GetHwnd();
if ( hwnd )
{
SetHWND(0);
}
return hwnd;
}
void wxWindowMSW::AssociateHandle(WXWidget handle)
{
if ( m_hWnd )
@ -1404,8 +1414,21 @@ void wxWindowMSW::AssociateHandle(WXWidget handle)
void wxWindowMSW::DissociateHandle()
{
// this also calls SetHWND(0) for us
UnsubclassWin();
// Unlike in UnsubclassWin() we don't assume that the old HWND was valid,
// it could have been already destroyed, but if it is valid, we can just
// forward to it.
if ( ::IsWindow(GetHwnd()) )
{
UnsubclassWin();
}
else // Otherwise just forget about the old HWND.
{
DoDetachHWND();
// We shouldn't try to restore it later as it corresponded to a HWND
// which doesn't exist any longer.
m_oldWndProc = nullptr;
}
}