[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

@ -261,7 +261,9 @@ IntWinListChildren(PWND Window)
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)
@ -270,10 +272,48 @@ IntWinListChildren(PWND Window)
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL; return NULL;
} }
for (Child = Window->spwndChild, Index = 0;
Child != NULL; Index = 0;
Child = Child->spwndNext, ++Index) for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
List[Index] = Child->head.h; {
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; List[Index] = NULL;
return List; return List;
@ -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)
@ -2684,55 +2724,38 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
} }
/* Recursively destroy owned windows */ /* Recursively destroy owned windows */
if (!(Window->style & WS_CHILD)) if (!(Window->style & WS_CHILD))
{ {
for (;;) HWND* List;
{ HWND* phWnd;
BOOL GotOne = FALSE; PWND pWnd;
HWND *Children;
HWND *ChildHandle;
PWND Child, Desktop;
Desktop = IntIsDesktopWindow(Window) ? Window : List = IntWinListOwnedPopups(Window);
UserGetWindowObject(IntGetDesktopWindow()); if (List)
Children = IntWinListChildren(Desktop);
if (Children)
{ {
for (ChildHandle = Children; *ChildHandle; ++ChildHandle) for (phWnd = List; *phWnd; ++phWnd)
{ {
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);
pWnd->spwndOwner = NULL;
if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
{ {
continue; 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);
}
} }
if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread())) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
{
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;
}
}
ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
}
if (! GotOne)
{
break;
}
} }
} }