Implemented a more defensive version of WIN_SendDestroyMsg.

diff --git a/windows/win.c b/windows/win.c
index 702d036..529bb6d 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -1130,21 +1130,90 @@
 
     if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret();
     CLIPBOARD_GetDriver()->pResetOwner( pWnd, TRUE ); 
-  
+
+    /*
+     * Send the WM_DESTROY to the window.
+     */
     SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0);
 
-    if( IsWindow(pWnd->hwndSelf) )
+    /*
+     * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
+     * make sure that the window still exists when we come back.
+     */
+    if (IsWindow(pWnd->hwndSelf))
     {
-	WND* pChild = WIN_LockWndPtr(pWnd->child);
-	while( pChild )
+      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_UpdateWndPtr(&pChild,pChild->next);
+	  WIN_SendDestroyMsg( pChild );
+	  WIN_ReleaseWndPtr(pChild);	  
 	}
-	WIN_CheckFocus(pWnd);
+       
+	nKidCount--;
+      }
+
+      /*
+       * Cleanup
+       */
+      HeapFree(GetProcessHeap(), 0, pWndArray);
+      WIN_CheckFocus(pWnd);	
     }
     else
-	WARN(win, "\tdestroyed itself while in WM_DESTROY!\n");
+      WARN(win, "\tdestroyed itself while in WM_DESTROY!\n");
 }