[0.4.9][WIN32K:NTUSER] Fix CORE-12243 OS-freezing when closing nLite

This fixes CORE-12243 and allows .NET applications like nLite 1.4.9.3
to exit properly without freezing the whole OS.

The actual fix was picked from 0.4.11-dev-78-g
4d48b88bfb
"[WIN32K:NTUSER] co_UserDestroyWindow(): Simplify the destruction of the owned windows."

but it made sense to also pick the related 0.4.11-dev-77-g
e286c4c520
"[WIN32K:NTUSER] Optimize IntWinListOwnedPopups() a little bit. Improve a trace."

and 0.4.11-dev-76-g
f644a50cd7
"[WIN32K:NTUSER] Code formatting only."
This commit is contained in:
Joachim Henze 2020-11-03 03:54:16 +01:00
parent 2a9249b546
commit bf8cbe2769

View file

@ -254,29 +254,69 @@ IntEnableWindow( HWND hWnd, BOOL bEnable )
HWND* FASTCALL HWND* FASTCALL
IntWinListChildren(PWND Window) IntWinListChildren(PWND Window)
{ {
PWND Child; PWND Child;
HWND *List; HWND *List;
UINT Index, NumChildren = 0; UINT Index, NumChildren = 0;
if (!Window) return NULL; if (!Window) return NULL;
for (Child = Window->spwndChild; Child; Child = Child->spwndNext) for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
++NumChildren; {
++NumChildren;
}
List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST); List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
if(!List) if(!List)
{ {
ERR("Failed to allocate memory for children array\n"); ERR("Failed to allocate memory for children array\n");
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL; return NULL;
} }
for (Child = Window->spwndChild, Index = 0;
Child != NULL;
Child = Child->spwndNext, ++Index)
List[Index] = Child->head.h;
List[Index] = NULL;
return List; Index = 0;
for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
{
List[Index++] = Child->head.h;
}
List[Index] = NULL;
return List;
}
HWND* FASTCALL
IntWinListOwnedPopups(PWND Window)
{
PWND Child, Desktop;
HWND *List;
UINT Index, NumOwned = 0;
Desktop = co_GetDesktopWindow(Window);
if (!Desktop)
return NULL;
for (Child = Desktop->spwndChild; Child; Child = Child->spwndNext)
{
if (Child->spwndOwner == Window)
++NumOwned;
}
List = ExAllocatePoolWithTag(PagedPool, (NumOwned + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
if (!List)
{
ERR("Failed to allocate memory for children array\n");
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
Index = 0;
for (Child = Desktop->spwndChild; Child; Child = Child->spwndNext)
{
if (Child->spwndOwner == Window)
List[Index++] = Child->head.h;
}
List[Index] = NULL;
return List;
} }
PWND FASTCALL PWND FASTCALL
@ -2572,7 +2612,7 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
hWnd = Window->head.h; hWnd = Window->head.h;
ti = PsGetCurrentThreadWin32Thread(); ti = PsGetCurrentThreadWin32Thread();
TRACE("co_UserDestroyWindow \n"); TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
/* Check for owner thread */ /* Check for owner thread */
if ( Window->head.pti != PsGetCurrentThreadWin32Thread()) if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
@ -2632,7 +2672,7 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
} }
} }
// Adjust last active. /* Adjust last active */
if ((pwndTemp = Window->spwndOwner)) if ((pwndTemp = Window->spwndOwner))
{ {
while (pwndTemp->spwndOwner) while (pwndTemp->spwndOwner)
@ -2683,58 +2723,41 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
return TRUE; return TRUE;
} }
/* Recursively destroy owned windows */ /* Recursively destroy owned windows */
if (!(Window->style & WS_CHILD))
{
HWND* List;
HWND* phWnd;
PWND pWnd;
if (! (Window->style & WS_CHILD)) List = IntWinListOwnedPopups(Window);
{ if (List)
for (;;) {
{ for (phWnd = List; *phWnd; ++phWnd)
BOOL GotOne = FALSE;
HWND *Children;
HWND *ChildHandle;
PWND Child, Desktop;
Desktop = IntIsDesktopWindow(Window) ? Window :
UserGetWindowObject(IntGetDesktopWindow());
Children = IntWinListChildren(Desktop);
if (Children)
{
for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
{ {
Child = UserGetWindowObject(*ChildHandle); pWnd = ValidateHwndNoErr(*phWnd);
if (Child == NULL) if (pWnd == NULL)
continue; continue;
if (Child->spwndOwner != Window) ASSERT(pWnd->spwndOwner == Window);
{ ASSERT(pWnd != Window);
continue;
}
if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
{
USER_REFERENCE_ENTRY ChildRef;
UserRefObjectCo(Child, &ChildRef); // Temp HACK?
co_UserDestroyWindow(Child);
UserDerefObjectCo(Child); // Temp HACK?
GotOne = TRUE;
continue;
}
if (Child->spwndOwner != NULL)
{
Child->spwndOwner = NULL;
}
pWnd->spwndOwner = NULL;
if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
{
USER_REFERENCE_ENTRY Ref;
UserRefObjectCo(pWnd, &Ref); // Temp HACK?
co_UserDestroyWindow(pWnd);
UserDerefObjectCo(pWnd); // Temp HACK?
}
else
{
ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
}
} }
ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
} ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
if (! GotOne) }
{ }
break;
}
}
}
/* Generate mouse move message for the next window */ /* Generate mouse move message for the next window */
msg.message = WM_MOUSEMOVE; msg.message = WM_MOUSEMOVE;