Commit eb6a9f08 authored by Francis Beaudet's avatar Francis Beaudet Committed by Alexandre Julliard

Implemented a more defensive version of WIN_SendDestroyMsg.

parent 0aa2008a
...@@ -1130,21 +1130,90 @@ static void WIN_SendDestroyMsg( WND* pWnd ) ...@@ -1130,21 +1130,90 @@ static void WIN_SendDestroyMsg( WND* pWnd )
if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret(); if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret();
CLIPBOARD_GetDriver()->pResetOwner( pWnd, TRUE ); CLIPBOARD_GetDriver()->pResetOwner( pWnd, TRUE );
/*
* Send the WM_DESTROY to the window.
*/
SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0); SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0);
if( IsWindow(pWnd->hwndSelf) ) /*
{ * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
WND* pChild = WIN_LockWndPtr(pWnd->child); * make sure that the window still exists when we come back.
while( pChild ) */
if (IsWindow(pWnd->hwndSelf))
{
HWND* pWndArray = NULL;
WND* pChild = NULL;
int nKidCount = 0;
/*
* Now, if the window has kids, we have to send WM_DESTROY messages
* recursively to it's kids. It seems that those calls can also
* trigger re-entrant calls to DestroyWindow for the kids so we must
* protect against corruption of the list of siblings. We first build
* a list of HWNDs representing all the kids.
*/
pChild = WIN_LockWndPtr(pWnd->child);
while( pChild )
{
nKidCount++;
WIN_UpdateWndPtr(&pChild,pChild->next);
}
/*
* If there are no kids, we're done.
*/
if (nKidCount==0)
return;
pWndArray = HeapAlloc(GetProcessHeap(), 0, nKidCount*sizeof(HWND));
/*
* Sanity check
*/
if (pWndArray==NULL)
return;
/*
* Now, enumerate all the kids in a list, since we wait to make the SendMessage
* call, our linked list of siblings should be safe.
*/
nKidCount = 0;
pChild = WIN_LockWndPtr(pWnd->child);
while( pChild )
{
pWndArray[nKidCount] = pChild->hwndSelf;
nKidCount++;
WIN_UpdateWndPtr(&pChild,pChild->next);
}
/*
* Now that we have a list, go through that list again and send the destroy
* message to those windows. We are using the HWND to retrieve the
* WND pointer so we are effectively checking that all the kid windows are
* still valid before sending the message.
*/
while (nKidCount>0)
{
pChild = WIN_FindWndPtr(pWndArray[nKidCount]);
if (pChild!=NULL)
{ {
WIN_SendDestroyMsg( pChild ); WIN_SendDestroyMsg( pChild );
WIN_UpdateWndPtr(&pChild,pChild->next); WIN_ReleaseWndPtr(pChild);
} }
WIN_CheckFocus(pWnd);
nKidCount--;
}
/*
* Cleanup
*/
HeapFree(GetProcessHeap(), 0, pWndArray);
WIN_CheckFocus(pWnd);
} }
else else
WARN(win, "\tdestroyed itself while in WM_DESTROY!\n"); WARN(win, "\tdestroyed itself while in WM_DESTROY!\n");
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment