mirror of
https://github.com/reactos/reactos.git
synced 2025-04-05 05:01:03 +00:00
Bug 1393 : Patch from w3seek Fix moving class objects between desktop heaps and the shared heaps
svn path=/trunk/; revision=21596
This commit is contained in:
parent
88699130d7
commit
299c670648
9 changed files with 452 additions and 131 deletions
|
@ -85,10 +85,10 @@ typedef struct _CHECKLISTWND
|
|||
HTHEME ThemeHandle;
|
||||
#endif
|
||||
|
||||
BOOL HasFocus : 1;
|
||||
BOOL FocusedPushed : 1;
|
||||
BOOL QuickSearchEnabled : 1;
|
||||
BOOL ShowingCaret : 1;
|
||||
UINT HasFocus : 1;
|
||||
UINT FocusedPushed : 1;
|
||||
UINT QuickSearchEnabled : 1;
|
||||
UINT ShowingCaret : 1;
|
||||
} CHECKLISTWND, *PCHECKLISTWND;
|
||||
|
||||
static VOID EscapeQuickSearch(IN PCHECKLISTWND infoPtr);
|
||||
|
|
|
@ -63,7 +63,7 @@ typedef struct _SECURITY_PAGE
|
|||
|
||||
HANDLE SidCacheMgr;
|
||||
LONG SidLookupsPending;
|
||||
BOOL Initializing : 1;
|
||||
UINT Initializing : 1;
|
||||
|
||||
LPCWSTR ServerName;
|
||||
} SECURITY_PAGE, *PSECURITY_PAGE;
|
||||
|
|
|
@ -33,6 +33,7 @@ typedef struct _WINDOWCLASS
|
|||
WNDPROC WndProcExtra;
|
||||
PCALLPROC CallProc;
|
||||
};
|
||||
PCALLPROC CallProc2;
|
||||
INT ClsExtra;
|
||||
INT WndExtra;
|
||||
HINSTANCE hInstance;
|
||||
|
@ -50,6 +51,8 @@ typedef struct _WINDOWCLASS
|
|||
UINT Unicode : 1;
|
||||
UINT System : 1;
|
||||
UINT Global : 1;
|
||||
UINT GlobalCallProc : 1;
|
||||
UINT GlobalCallProc2 : 1;
|
||||
} WINDOWCLASS, *PWINDOWCLASS;
|
||||
|
||||
typedef struct _W32PROCESSINFO
|
||||
|
|
|
@ -32,7 +32,8 @@ void FASTCALL
|
|||
DestroyProcessClasses(PW32PROCESS Process );
|
||||
|
||||
PWINDOWCLASS
|
||||
IntReferenceClass(IN PWINDOWCLASS BaseClass,
|
||||
IntReferenceClass(IN OUT PWINDOWCLASS BaseClass,
|
||||
IN OUT PWINDOWCLASS *ClassLink,
|
||||
IN PDESKTOP Desktop);
|
||||
|
||||
VOID
|
||||
|
@ -64,6 +65,10 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
|
|||
OUT PWINDOWCLASS *BaseClass OPTIONAL,
|
||||
OUT PWINDOWCLASS **Link OPTIONAL);
|
||||
|
||||
BOOL
|
||||
IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
|
||||
IN BOOL FreeOnFailure);
|
||||
|
||||
#endif /* _WIN32K_CLASS_H */
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -93,7 +93,8 @@ IntHideDesktop(PDESKTOP_OBJECT Desktop);
|
|||
HDESK FASTCALL
|
||||
IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject);
|
||||
|
||||
BOOL IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject);
|
||||
BOOL IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject,
|
||||
IN BOOL FreeOnFailure);
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
IntValidateDesktopHandle(
|
||||
|
|
|
@ -203,6 +203,9 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
|
|||
|
||||
DPRINT("Creating W32 thread TID:%d at IRQ level: %lu\n", Thread->Cid.UniqueThread, KeGetCurrentIrql());
|
||||
|
||||
InitializeListHead(&Win32Thread->WindowListHead);
|
||||
InitializeListHead(&Win32Thread->W32CallbackListHead);
|
||||
|
||||
/*
|
||||
* inherit the thread desktop and process window station (if not yet inherited) from the process startup
|
||||
* info structure. See documentation of CreateProcess()
|
||||
|
@ -244,7 +247,8 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
|
|||
NtClose(hDesk);
|
||||
if(NT_SUCCESS(Status))
|
||||
{
|
||||
if (!IntSetThreadDesktop(DesktopObject))
|
||||
if (!IntSetThreadDesktop(DesktopObject,
|
||||
FALSE))
|
||||
{
|
||||
DPRINT1("Unable to set thread desktop\n");
|
||||
}
|
||||
|
@ -260,8 +264,6 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
|
|||
Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
|
||||
Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
|
||||
Win32Thread->MessagePumpHookValue = 0;
|
||||
InitializeListHead(&Win32Thread->WindowListHead);
|
||||
InitializeListHead(&Win32Thread->W32CallbackListHead);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -278,14 +280,6 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
|
|||
MsqDestroyMessageQueue(Win32Thread->MessageQueue);
|
||||
IntCleanupThreadCallbacks(Win32Thread);
|
||||
|
||||
IntSetThreadDesktop(NULL);
|
||||
|
||||
if (Win32Thread->ThreadInfo != NULL)
|
||||
{
|
||||
UserHeapFree(Win32Thread->ThreadInfo);
|
||||
Win32Thread->ThreadInfo = NULL;
|
||||
}
|
||||
|
||||
/* cleanup user object references stack */
|
||||
e = PopEntryList(&Win32Thread->ReferencesList);
|
||||
while (e)
|
||||
|
@ -296,6 +290,16 @@ Win32kThreadCallback(struct _ETHREAD *Thread,
|
|||
|
||||
e = PopEntryList(&Win32Thread->ReferencesList);
|
||||
}
|
||||
|
||||
IntSetThreadDesktop(NULL,
|
||||
TRUE);
|
||||
|
||||
if (Win32Thread->ThreadInfo != NULL)
|
||||
{
|
||||
UserHeapFree(Win32Thread->ThreadInfo);
|
||||
Win32Thread->ThreadInfo = NULL;
|
||||
}
|
||||
|
||||
PsSetThreadWin32Thread(Thread, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
* PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
|
||||
* REVISION HISTORY:
|
||||
* 06-06-2001 CSH Created
|
||||
*
|
||||
* NOTE: Should classes created on a desktop heap be moved to the shared
|
||||
* heap when the desktop is destroyed, or should they be unregistered?
|
||||
*/
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
|
@ -89,7 +86,7 @@ CreateCallProc(IN PDESKTOP Desktop,
|
|||
{
|
||||
NewCallProc->pi = pi;
|
||||
NewCallProc->WndProc = WndProc;
|
||||
NewCallProc->Unicode = Unicode != FALSE;
|
||||
NewCallProc->Unicode = Unicode;
|
||||
}
|
||||
|
||||
return NewCallProc;
|
||||
|
@ -154,33 +151,29 @@ static VOID
|
|||
IntDestroyClass(IN OUT PWINDOWCLASS Class)
|
||||
{
|
||||
/* there shouldn't be any clones anymore */
|
||||
|
||||
ASSERT(Class->Windows == 0);
|
||||
ASSERT(Class->Clone == NULL);
|
||||
|
||||
if (Class->Desktop != NULL)
|
||||
{
|
||||
ASSERT(Class->Clone == NULL);
|
||||
}
|
||||
else if (Class->Clone != NULL)
|
||||
{
|
||||
/* there must not be more than one clone! This can be the case
|
||||
when the base class is on the shared heap */
|
||||
ASSERT(Class->Clone->Next == NULL);
|
||||
|
||||
/* free the clone */
|
||||
IntDestroyClass(Class->Clone);
|
||||
Class->Clone = NULL;
|
||||
}
|
||||
|
||||
if (Class->Base == Class)
|
||||
{
|
||||
/* destruct resources shared with clones */
|
||||
if (!Class->System && Class->CallProc != NULL)
|
||||
{
|
||||
DestroyCallProc(Class->Desktop,
|
||||
DestroyCallProc(Class->GlobalCallProc ? NULL : Class->Desktop,
|
||||
Class->CallProc);
|
||||
}
|
||||
|
||||
if (Class->CallProc2 != NULL)
|
||||
{
|
||||
DestroyCallProc(Class->GlobalCallProc2 ? NULL : Class->Desktop,
|
||||
Class->CallProc2);
|
||||
}
|
||||
|
||||
IntFreeClassMenuName(Class);
|
||||
}
|
||||
|
||||
|
@ -323,7 +316,8 @@ IntSetClassAtom(IN OUT PWINDOWCLASS Class,
|
|||
static WNDPROC
|
||||
IntGetClassWndProc(IN PWINDOWCLASS Class,
|
||||
IN PW32PROCESSINFO pi,
|
||||
IN BOOL Ansi)
|
||||
IN BOOL Ansi,
|
||||
IN BOOL UseCallProc2)
|
||||
{
|
||||
/* FIXME - assert for exclusive lock! */
|
||||
|
||||
|
@ -339,19 +333,27 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (Class->CallProc != NULL)
|
||||
PCALLPROC *CallProcPtr;
|
||||
PWINDOWCLASS BaseClass;
|
||||
|
||||
/* make sure the call procedures are located on the desktop
|
||||
of the base class! */
|
||||
BaseClass = Class->Base;
|
||||
Class = BaseClass;
|
||||
|
||||
CallProcPtr = (UseCallProc2 ? &Class->CallProc2 : &Class->CallProc);
|
||||
|
||||
if (*CallProcPtr != NULL)
|
||||
{
|
||||
return (WNDPROC)ObmObjectToHandle(Class->CallProc);
|
||||
return (WNDPROC)ObmObjectToHandle(*CallProcPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PCALLPROC NewCallProc, CallProc;
|
||||
PCALLPROC NewCallProc;
|
||||
|
||||
if (pi == NULL)
|
||||
return NULL;
|
||||
|
||||
/* NOTE: use the interlocked functions, as this operation may be done even
|
||||
when only the shared lock is held! */
|
||||
NewCallProc = CreateCallProc(Class->Desktop,
|
||||
Class->WndProc,
|
||||
Class->Unicode,
|
||||
|
@ -362,16 +364,35 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CallProc = InterlockedCompareExchangePointer(&Class->CallProc,
|
||||
NewCallProc,
|
||||
NULL);
|
||||
if (CallProc != NULL)
|
||||
*CallProcPtr = NewCallProc;
|
||||
|
||||
if (Class->Desktop == NULL)
|
||||
{
|
||||
DestroyCallProc(Class->Desktop,
|
||||
NewCallProc);
|
||||
if (UseCallProc2)
|
||||
Class->GlobalCallProc2 = TRUE;
|
||||
else
|
||||
Class->GlobalCallProc = TRUE;
|
||||
}
|
||||
|
||||
return (WNDPROC)ObmObjectToHandle((CallProc == NULL ? NewCallProc : CallProc));
|
||||
/* update the clones */
|
||||
Class = Class->Clone;
|
||||
while (Class != NULL)
|
||||
{
|
||||
if (UseCallProc2)
|
||||
{
|
||||
Class->CallProc2 = NewCallProc;
|
||||
Class->GlobalCallProc2 = BaseClass->GlobalCallProc2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Class->CallProc = NewCallProc;
|
||||
Class->GlobalCallProc = BaseClass->GlobalCallProc;
|
||||
}
|
||||
|
||||
Class = Class->Next;
|
||||
}
|
||||
|
||||
return (WNDPROC)ObmObjectToHandle(NewCallProc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -391,17 +412,19 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* update the base class first */
|
||||
Class = Class->Base;
|
||||
|
||||
Ret = IntGetClassWndProc(Class,
|
||||
GetW32ProcessInfo(),
|
||||
Ansi);
|
||||
Ansi,
|
||||
TRUE);
|
||||
if (Ret == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* update the base class first */
|
||||
Class = Class->Base;
|
||||
|
||||
/* update the class info */
|
||||
Class->Unicode = !Ansi;
|
||||
Class->WndProc = WndProc;
|
||||
if (Class->CallProc != NULL)
|
||||
|
@ -424,7 +447,8 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
|
|||
}
|
||||
|
||||
static PWINDOWCLASS
|
||||
IntGetClassForDesktop(IN PWINDOWCLASS BaseClass,
|
||||
IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass,
|
||||
IN OUT PWINDOWCLASS *ClassLink,
|
||||
IN PDESKTOP Desktop)
|
||||
{
|
||||
SIZE_T ClassSize;
|
||||
|
@ -443,6 +467,9 @@ IntGetClassForDesktop(IN PWINDOWCLASS BaseClass,
|
|||
|
||||
if (BaseClass->Desktop == NULL)
|
||||
{
|
||||
ASSERT(BaseClass->Windows == 0);
|
||||
ASSERT(BaseClass->Clone == NULL);
|
||||
|
||||
/* Classes are also located in the shared heap when the class
|
||||
was created before the thread attached to a desktop. As soon
|
||||
as a window is created for such a class located on the shared
|
||||
|
@ -485,13 +512,43 @@ IntGetClassForDesktop(IN PWINDOWCLASS BaseClass,
|
|||
ClassSize);
|
||||
|
||||
/* update some pointers and link the class */
|
||||
Class->Next = BaseClass->Clone;
|
||||
Class->Clone = NULL;
|
||||
Class->Base = BaseClass;
|
||||
Class->Desktop = Desktop;
|
||||
Class->Windows = 0;
|
||||
(void)InterlockedExchangePointer(&BaseClass->Clone,
|
||||
Class);
|
||||
|
||||
if (BaseClass->Desktop == NULL)
|
||||
{
|
||||
/* we don't really need the base class on the shared
|
||||
heap anymore, delete it so the only class left is
|
||||
the clone we just created, which now serves as the
|
||||
new base class */
|
||||
ASSERT(BaseClass->Clone == NULL);
|
||||
ASSERT(Class->Clone == NULL);
|
||||
Class->Base = Class;
|
||||
Class->Next = BaseClass->Next;
|
||||
|
||||
if (!BaseClass->System && BaseClass->CallProc != NULL)
|
||||
Class->GlobalCallProc = TRUE;
|
||||
if (BaseClass->CallProc2 != NULL)
|
||||
Class->GlobalCallProc2 = TRUE;
|
||||
|
||||
/* replace the base class */
|
||||
(void)InterlockedExchangePointer(ClassLink,
|
||||
Class);
|
||||
|
||||
/* destroy the obsolete copy on the shared heap */
|
||||
BaseClass->Base = NULL;
|
||||
BaseClass->Clone = NULL;
|
||||
IntDestroyClass(BaseClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* link in the clone */
|
||||
Class->Clone = NULL;
|
||||
Class->Base = BaseClass;
|
||||
Class->Next = BaseClass->Clone;
|
||||
(void)InterlockedExchangePointer(&BaseClass->Clone,
|
||||
Class);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -503,12 +560,16 @@ IntGetClassForDesktop(IN PWINDOWCLASS BaseClass,
|
|||
}
|
||||
|
||||
PWINDOWCLASS
|
||||
IntReferenceClass(IN PWINDOWCLASS BaseClass,
|
||||
IntReferenceClass(IN OUT PWINDOWCLASS BaseClass,
|
||||
IN OUT PWINDOWCLASS *ClassLink,
|
||||
IN PDESKTOP Desktop)
|
||||
{
|
||||
PWINDOWCLASS Class;
|
||||
|
||||
ASSERT(BaseClass->Base == BaseClass);
|
||||
|
||||
Class = IntGetClassForDesktop(BaseClass,
|
||||
ClassLink,
|
||||
Desktop);
|
||||
if (Class != NULL)
|
||||
{
|
||||
|
@ -518,6 +579,72 @@ IntReferenceClass(IN PWINDOWCLASS BaseClass,
|
|||
return Class;
|
||||
}
|
||||
|
||||
static VOID
|
||||
IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
|
||||
IN OUT PWINDOWCLASS *BaseClassLink,
|
||||
IN OUT PWINDOWCLASS *CloneLink)
|
||||
{
|
||||
PWINDOWCLASS Clone, BaseClass;
|
||||
PCALLPROC CallProc;
|
||||
|
||||
ASSERT(Class->Base != Class);
|
||||
ASSERT(Class->Base->Clone != NULL);
|
||||
ASSERT(Class->Desktop != NULL);
|
||||
ASSERT(Class->Windows != 0);
|
||||
ASSERT(Class->Base->Desktop != NULL);
|
||||
ASSERT(Class->Base->Windows == 0);
|
||||
|
||||
/* unlink the clone */
|
||||
*CloneLink = Class->Next;
|
||||
Class->Clone = Class->Base->Clone;
|
||||
|
||||
BaseClass = Class->Base;
|
||||
|
||||
if (!BaseClass->System && BaseClass->CallProc != NULL &&
|
||||
!BaseClass->GlobalCallProc)
|
||||
{
|
||||
/* we need to move the allocated call procedure */
|
||||
CallProc = BaseClass->CallProc;
|
||||
Class->CallProc = CloneCallProc(Class->Desktop,
|
||||
CallProc);
|
||||
DestroyCallProc(BaseClass->Desktop,
|
||||
CallProc);
|
||||
}
|
||||
|
||||
if (BaseClass->CallProc2 != NULL &&
|
||||
!BaseClass->GlobalCallProc2)
|
||||
{
|
||||
/* we need to move the allocated call procedure */
|
||||
CallProc = BaseClass->CallProc2;
|
||||
Class->CallProc2 = CloneCallProc(Class->Desktop,
|
||||
CallProc);
|
||||
DestroyCallProc(BaseClass->Desktop,
|
||||
CallProc);
|
||||
}
|
||||
|
||||
/* update the class information to make it a base class */
|
||||
Class->Base = Class;
|
||||
Class->Next = (*BaseClassLink)->Next;
|
||||
|
||||
/* update all clones */
|
||||
Clone = Class->Clone;
|
||||
while (Clone != NULL)
|
||||
{
|
||||
ASSERT(Clone->Clone == NULL);
|
||||
Clone->Base = Class;
|
||||
|
||||
if (!Class->System)
|
||||
Clone->CallProc = Class->CallProc;
|
||||
Clone->CallProc2 = Class->CallProc2;
|
||||
|
||||
Clone = Clone->Next;
|
||||
}
|
||||
|
||||
/* link in the new base class */
|
||||
(void)InterlockedExchangePointer(BaseClassLink,
|
||||
Class);
|
||||
}
|
||||
|
||||
VOID
|
||||
IntDereferenceClass(IN OUT PWINDOWCLASS Class,
|
||||
IN PDESKTOP Desktop,
|
||||
|
@ -535,12 +662,10 @@ IntDereferenceClass(IN OUT PWINDOWCLASS Class,
|
|||
|
||||
/* check if there are clones of the class on other desktops,
|
||||
link the first clone in if possible. If there are no clones
|
||||
then leave the class on the desktop heap... */
|
||||
then leave the class on the desktop heap. It will get moved
|
||||
to the shared heap when the thread detaches. */
|
||||
if (BaseClass->Clone != NULL)
|
||||
{
|
||||
PWINDOWCLASS NewBase = BaseClass->Clone;
|
||||
|
||||
/* locate the base class and unlink it */
|
||||
if (BaseClass->System)
|
||||
PrevLink = &pi->SystemClassList;
|
||||
else if (BaseClass->Global)
|
||||
|
@ -548,35 +673,18 @@ IntDereferenceClass(IN OUT PWINDOWCLASS Class,
|
|||
else
|
||||
PrevLink = &pi->LocalClassList;
|
||||
|
||||
CurrentClass = *PrevLink;
|
||||
while (CurrentClass != BaseClass)
|
||||
while (*PrevLink != BaseClass)
|
||||
{
|
||||
ASSERT(CurrentClass != NULL);
|
||||
|
||||
PrevLink = &CurrentClass->Next;
|
||||
CurrentClass = CurrentClass->Next;
|
||||
ASSERT(BaseClass != NULL);
|
||||
PrevLink = &BaseClass->Next;
|
||||
}
|
||||
|
||||
ASSERT(CurrentClass == BaseClass);
|
||||
ASSERT(*PrevLink == BaseClass);
|
||||
|
||||
NewBase->Clone = NewBase->Next;
|
||||
NewBase->Next = BaseClass->Next;
|
||||
NewBase->Base = NewBase;
|
||||
|
||||
/* update all clones */
|
||||
CurrentClass = NewBase->Clone;
|
||||
while (CurrentClass != NULL)
|
||||
{
|
||||
ASSERT(CurrentClass->Clone == NULL);
|
||||
|
||||
CurrentClass->Base = NewBase;
|
||||
|
||||
CurrentClass = CurrentClass->Next;
|
||||
}
|
||||
|
||||
/* link in the new base class */
|
||||
(void)InterlockedExchangePointer(PrevLink,
|
||||
NewBase);
|
||||
/* make the first clone become the new base class */
|
||||
IntMakeCloneBaseClass(BaseClass->Clone,
|
||||
PrevLink,
|
||||
&BaseClass->Clone);
|
||||
|
||||
/* destroy the class, there's still another clone of the class
|
||||
that now serves as a base class. Make sure we don't destruct
|
||||
|
@ -613,6 +721,180 @@ IntDereferenceClass(IN OUT PWINDOWCLASS Class,
|
|||
}
|
||||
}
|
||||
|
||||
static BOOL
|
||||
IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
|
||||
IN OUT PWINDOWCLASS **ClassLinkPtr)
|
||||
{
|
||||
PWINDOWCLASS NewClass;
|
||||
PCALLPROC CallProc;
|
||||
SIZE_T ClassSize;
|
||||
|
||||
ASSERT(Class->Base == Class);
|
||||
ASSERT(Class->Desktop != NULL);
|
||||
ASSERT(Class->Windows == 0);
|
||||
ASSERT(Class->Clone == NULL);
|
||||
|
||||
ClassSize = (SIZE_T)Class->ClassExtraDataOffset +
|
||||
(SIZE_T)Class->ClsExtra;
|
||||
|
||||
/* allocate the new base class on the shared heap */
|
||||
NewClass = UserHeapAlloc(ClassSize);
|
||||
if (NewClass != NULL)
|
||||
{
|
||||
RtlCopyMemory(NewClass,
|
||||
Class,
|
||||
ClassSize);
|
||||
|
||||
NewClass->Desktop = NULL;
|
||||
NewClass->Base = NewClass;
|
||||
|
||||
if (!NewClass->System && NewClass->CallProc != NULL &&
|
||||
!NewClass->GlobalCallProc)
|
||||
{
|
||||
/* we need to move the allocated call procedure to the shared heap */
|
||||
CallProc = NewClass->CallProc;
|
||||
NewClass->CallProc = CloneCallProc(NULL,
|
||||
CallProc);
|
||||
DestroyCallProc(Class->Desktop,
|
||||
CallProc);
|
||||
|
||||
NewClass->GlobalCallProc = TRUE;
|
||||
}
|
||||
|
||||
if (NewClass->CallProc2 != NULL &&
|
||||
!NewClass->GlobalCallProc2)
|
||||
{
|
||||
/* we need to move the allocated call procedure to the shared heap */
|
||||
CallProc = NewClass->CallProc2;
|
||||
NewClass->CallProc2 = CloneCallProc(NULL,
|
||||
CallProc);
|
||||
DestroyCallProc(Class->Desktop,
|
||||
CallProc);
|
||||
|
||||
NewClass->GlobalCallProc2 = TRUE;
|
||||
}
|
||||
|
||||
/* replace the class in the list */
|
||||
(void)InterlockedExchangePointer(*ClassLinkPtr,
|
||||
NewClass);
|
||||
*ClassLinkPtr = &NewClass->Next;
|
||||
|
||||
/* free the obsolete class on the desktop heap */
|
||||
Class->Base = NULL;
|
||||
IntDestroyClass(Class);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static VOID
|
||||
IntCheckDesktopClasses(IN PDESKTOP Desktop,
|
||||
IN OUT PWINDOWCLASS *ClassList,
|
||||
IN BOOL FreeOnFailure,
|
||||
OUT BOOL *Ret)
|
||||
{
|
||||
PWINDOWCLASS Class, NextClass, *Link;
|
||||
|
||||
/* NOTE: We only need to check base classes! When classes are no longer needed
|
||||
on a desktop, the clones will be freed automatically as soon as possible.
|
||||
However, we need to move base classes to the shared heap, as soon as
|
||||
the last desktop heap where a class is allocated on is about to be destroyed.
|
||||
If we didn't move the class to the shared heap, the class would become
|
||||
inaccessible! */
|
||||
|
||||
ASSERT(Desktop != NULL);
|
||||
|
||||
Link = ClassList;
|
||||
Class = *Link;
|
||||
while (Class != NULL)
|
||||
{
|
||||
NextClass = Class->Next;
|
||||
|
||||
ASSERT(Class->Base == Class);
|
||||
|
||||
if (Class->Desktop == Desktop &&
|
||||
Class->Windows == 0)
|
||||
{
|
||||
/* there shouldn't be any clones around anymore! */
|
||||
ASSERT(Class->Clone == NULL);
|
||||
|
||||
/* FIXME - If process is terminating, don't move the class but rather destroy it! */
|
||||
/* FIXME - We could move the class to another desktop heap if there's still desktops
|
||||
mapped into the process... */
|
||||
|
||||
/* move the class to the shared heap */
|
||||
if (IntMoveClassToSharedHeap(Class,
|
||||
&Link))
|
||||
{
|
||||
ASSERT(*Link == NextClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(NextClass == Class->Next);
|
||||
|
||||
if (FreeOnFailure)
|
||||
{
|
||||
/* unlink the base class */
|
||||
(void)InterlockedExchangePointer(Link,
|
||||
Class->Next);
|
||||
|
||||
/* we can free the old base class now */
|
||||
Class->Base = NULL;
|
||||
IntDestroyClass(Class);
|
||||
}
|
||||
else
|
||||
{
|
||||
Link = &Class->Next;
|
||||
*Ret = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Link = &Class->Next;
|
||||
|
||||
Class = NextClass;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
|
||||
IN BOOL FreeOnFailure)
|
||||
{
|
||||
PW32PROCESSINFO pi;
|
||||
BOOL Ret = TRUE;
|
||||
|
||||
pi = GetW32ProcessInfo();
|
||||
if (pi == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* check all local classes */
|
||||
IntCheckDesktopClasses(Desktop,
|
||||
&pi->LocalClassList,
|
||||
FreeOnFailure,
|
||||
&Ret);
|
||||
|
||||
/* check all global classes */
|
||||
IntCheckDesktopClasses(Desktop,
|
||||
&pi->GlobalClassList,
|
||||
FreeOnFailure,
|
||||
&Ret);
|
||||
|
||||
/* check all system classes */
|
||||
IntCheckDesktopClasses(Desktop,
|
||||
&pi->SystemClassList,
|
||||
FreeOnFailure,
|
||||
&Ret);
|
||||
|
||||
if (!Ret)
|
||||
{
|
||||
DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
|
||||
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static PWINDOWCLASS
|
||||
IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
|
||||
IN PUNICODE_STRING ClassName,
|
||||
|
@ -908,24 +1190,14 @@ FoundClass:
|
|||
static PWINDOWCLASS
|
||||
IntClassResizeInternal(IN OUT PWINDOWCLASS Class,
|
||||
IN INT ClsExtraNew,
|
||||
IN PWINDOWCLASS *List)
|
||||
IN PWINDOWCLASS *PrevLink)
|
||||
{
|
||||
PWINDOWCLASS *PrevLink, CurrentClass, NewClass;
|
||||
PWINDOWCLASS NewClass;
|
||||
SIZE_T NewSize;
|
||||
|
||||
/* NOTE: Do *not* access Class->Base here, it may be invalid at this point! */
|
||||
|
||||
/* temporarily unlink the class, as resizing it may change it's location */
|
||||
PrevLink = List;
|
||||
CurrentClass = *PrevLink;
|
||||
while (CurrentClass != Class)
|
||||
{
|
||||
ASSERT(CurrentClass != NULL);
|
||||
|
||||
PrevLink = &CurrentClass->Next;
|
||||
CurrentClass = CurrentClass->Next;
|
||||
}
|
||||
|
||||
ASSERT(CurrentClass == Class);
|
||||
|
||||
(void)InterlockedExchangePointer(PrevLink,
|
||||
Class->Next);
|
||||
|
||||
|
@ -986,7 +1258,7 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
IN PW32PROCESSINFO pi,
|
||||
IN INT ClsExtraNew)
|
||||
{
|
||||
PWINDOWCLASS *List, *CloneList, NewClass, Clone, FailedResize = NULL;
|
||||
PWINDOWCLASS *Link, NewClass, Clone, FailedResize = NULL;
|
||||
BOOL FailOnResize;
|
||||
|
||||
if (pi == NULL)
|
||||
|
@ -1003,18 +1275,18 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
}
|
||||
|
||||
if (Class->System)
|
||||
List = &pi->SystemClassList;
|
||||
Link = &pi->SystemClassList;
|
||||
else if (Class->Global)
|
||||
List = &pi->GlobalClassList;
|
||||
Link = &pi->GlobalClassList;
|
||||
else
|
||||
List = &pi->LocalClassList;
|
||||
Link = &pi->LocalClassList;
|
||||
|
||||
FailOnResize = Class->ClsExtra < ClsExtraNew;
|
||||
|
||||
/* resize the base class */
|
||||
NewClass = IntClassResizeInternal(Class,
|
||||
ClsExtraNew,
|
||||
List);
|
||||
Link);
|
||||
if (NewClass == NULL)
|
||||
{
|
||||
if (FailOnResize)
|
||||
|
@ -1027,13 +1299,13 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
Class = NewClass;
|
||||
|
||||
/* resize the clones */
|
||||
CloneList = &Class->Clone;
|
||||
Link = &Class->Clone;
|
||||
Clone = Class->Clone;
|
||||
while (Clone != NULL)
|
||||
{
|
||||
NewClass = IntClassResizeInternal(Clone,
|
||||
ClsExtraNew,
|
||||
CloneList);
|
||||
Link);
|
||||
|
||||
if (NewClass == NULL)
|
||||
{
|
||||
|
@ -1050,6 +1322,7 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
/* save the pointer to the base class in case it changed */
|
||||
Clone->Base = Class;
|
||||
|
||||
Link = &Clone->Next;
|
||||
Clone = Clone->Next;
|
||||
}
|
||||
|
||||
|
@ -1059,15 +1332,22 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
other clones and to the base class */
|
||||
DPRINT1("Failed to resize the cloned class 0x%p\n", FailedResize);
|
||||
|
||||
if (Class->System)
|
||||
Link = &pi->SystemClassList;
|
||||
else if (Class->Global)
|
||||
Link = &pi->GlobalClassList;
|
||||
else
|
||||
Link = &pi->LocalClassList;
|
||||
|
||||
/* roll back the changes made to the base class */
|
||||
NewClass = IntClassResizeInternal(Class,
|
||||
Class->ClsExtra,
|
||||
List);
|
||||
Link);
|
||||
if (NewClass != NULL)
|
||||
Class = NewClass;
|
||||
|
||||
/* roll back all changes made to the class clones */
|
||||
CloneList = &Class->Clone;
|
||||
Link = &Class->Clone;
|
||||
Clone = Class->Clone;
|
||||
while (Clone != FailedResize)
|
||||
{
|
||||
|
@ -1075,14 +1355,14 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
|
||||
NewClass = IntClassResizeInternal(Clone,
|
||||
Class->ClsExtra,
|
||||
CloneList);
|
||||
Link);
|
||||
if (NewClass != NULL)
|
||||
Clone = NewClass;
|
||||
|
||||
/* save the pointer to the base class in case it changed */
|
||||
Clone->Base = Class;
|
||||
|
||||
CloneList = &Clone->Next;
|
||||
Link = &Clone->Next;
|
||||
Clone = Clone->Next;
|
||||
}
|
||||
|
||||
|
@ -1097,6 +1377,9 @@ IntClassResize(IN OUT PWINDOWCLASS Class,
|
|||
while (Clone != NULL)
|
||||
{
|
||||
Clone->ClsExtra = ClsExtraNew;
|
||||
|
||||
ASSERT(Clone->Base == Class);
|
||||
|
||||
Clone = Clone->Next;
|
||||
}
|
||||
|
||||
|
@ -1166,8 +1449,6 @@ ClassAlreadyExists:
|
|||
}
|
||||
}
|
||||
|
||||
ASSERT(ti->Desktop != NULL);
|
||||
|
||||
Class = IntCreateClass(lpwcx,
|
||||
ClassName,
|
||||
MenuName,
|
||||
|
@ -1447,7 +1728,8 @@ UserGetClassLongPtr(IN PWINDOWCLASS Class,
|
|||
case GCLP_WNDPROC:
|
||||
Ret = (ULONG_PTR)IntGetClassWndProc(Class,
|
||||
GetW32ProcessInfo(),
|
||||
Ansi);
|
||||
Ansi,
|
||||
FALSE);
|
||||
break;
|
||||
|
||||
case GCW_ATOM:
|
||||
|
@ -1770,7 +2052,8 @@ UserGetClassInfo(IN PWINDOWCLASS Class,
|
|||
|
||||
lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
|
||||
GetW32ProcessInfo(),
|
||||
Ansi);
|
||||
Ansi,
|
||||
FALSE);
|
||||
|
||||
lpwcx->cbClsExtra = Class->ClsExtra;
|
||||
lpwcx->cbWndExtra = Class->WndExtra;
|
||||
|
|
|
@ -1757,7 +1757,8 @@ IntMapDesktopView(IN PDESKTOP_OBJECT DesktopObject)
|
|||
}
|
||||
|
||||
BOOL
|
||||
IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject)
|
||||
IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject,
|
||||
IN BOOL FreeOnFailure)
|
||||
{
|
||||
PDESKTOP_OBJECT OldDesktop;
|
||||
PW32THREAD W32Thread;
|
||||
|
@ -1771,6 +1772,13 @@ IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject)
|
|||
{
|
||||
OldDesktop = W32Thread->Desktop;
|
||||
|
||||
if (!IsListEmpty(&W32Thread->WindowListHead))
|
||||
{
|
||||
DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
|
||||
SetLastWin32Error(ERROR_BUSY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
W32Thread->Desktop = DesktopObject;
|
||||
|
||||
if (MapHeap && DesktopObject != NULL)
|
||||
|
@ -1783,6 +1791,20 @@ IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject)
|
|||
}
|
||||
}
|
||||
|
||||
if (OldDesktop != NULL &&
|
||||
!IntCheckProcessDesktopClasses(OldDesktop->DesktopInfo,
|
||||
FreeOnFailure))
|
||||
{
|
||||
DPRINT1("Failed to move process classes to shared heap!\n");
|
||||
|
||||
/* failed to move desktop classes to the shared heap,
|
||||
unmap the view and return the error */
|
||||
if (MapHeap && DesktopObject != NULL)
|
||||
IntUnmapDesktopView(DesktopObject);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (DesktopObject != NULL)
|
||||
{
|
||||
ObReferenceObject(DesktopObject);
|
||||
|
@ -1797,6 +1819,7 @@ IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject)
|
|||
|
||||
ObDereferenceObject(OldDesktop);
|
||||
|
||||
/* update the thread info */
|
||||
if (W32Thread != NULL && W32Thread->ThreadInfo != NULL &&
|
||||
W32Thread->ThreadInfo->Desktop != (DesktopObject != NULL ? DesktopObject->DesktopInfo : NULL))
|
||||
{
|
||||
|
@ -1849,7 +1872,8 @@ NtUserSetThreadDesktop(HDESK hDesktop)
|
|||
|
||||
/* FIXME: Should check here to see if the thread has any windows. */
|
||||
|
||||
if (!IntSetThreadDesktop(DesktopObject))
|
||||
if (!IntSetThreadDesktop(DesktopObject,
|
||||
FALSE))
|
||||
{
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
|
|
@ -442,7 +442,6 @@ static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
|
|||
|
||||
if (Window->CallProc2 != NULL)
|
||||
{
|
||||
DbgPrint("!!!!! Destroy call proc 0x%p\n", ObmObjectToHandle(Window->CallProc2));
|
||||
DestroyCallProc(Window->ti->Desktop,
|
||||
Window->CallProc2);
|
||||
}
|
||||
|
@ -1401,7 +1400,7 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
BOOL bUnicodeWindow)
|
||||
{
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
PWINDOWCLASS Class = NULL;
|
||||
PWINDOWCLASS *ClassLink, Class = NULL;
|
||||
RTL_ATOM ClassAtom;
|
||||
PWINDOW_OBJECT Window = NULL;
|
||||
PWINDOW_OBJECT ParentWindow = NULL, OwnerWindow;
|
||||
|
@ -1482,7 +1481,7 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
hInstance,
|
||||
ti->kpi,
|
||||
&Class,
|
||||
NULL);
|
||||
&ClassLink);
|
||||
|
||||
if (ClassAtom == (RTL_ATOM)0)
|
||||
{
|
||||
|
@ -1500,6 +1499,7 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
}
|
||||
|
||||
Class = IntReferenceClass(Class,
|
||||
ClassLink,
|
||||
ti->Desktop);
|
||||
if (Class == NULL)
|
||||
{
|
||||
|
@ -1541,6 +1541,8 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
*/
|
||||
Window->ti = ti;
|
||||
Window->Class = Class;
|
||||
Class = NULL;
|
||||
|
||||
Window->SystemMenu = (HMENU)0;
|
||||
Window->ContextHelpId = 0;
|
||||
Window->IDMenu = 0;
|
||||
|
@ -1548,7 +1550,7 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
Window->hSelf = hWnd;
|
||||
|
||||
if (!hMenu)
|
||||
hMenu = Class->hMenu;
|
||||
hMenu = Window->Class->hMenu;
|
||||
|
||||
if (0 != (dwStyle & WS_CHILD))
|
||||
{
|
||||
|
@ -1576,18 +1578,18 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
|
||||
Window->UserData = 0;
|
||||
|
||||
Window->IsSystem = Class->System;
|
||||
if (Class->System)
|
||||
Window->IsSystem = Window->Class->System;
|
||||
if (Window->Class->System)
|
||||
{
|
||||
/* NOTE: Always create a unicode window for system classes! */
|
||||
Window->Unicode = TRUE;
|
||||
Window->WndProc = Class->WndProc;
|
||||
Window->WndProcExtra = Class->WndProcExtra;
|
||||
Window->WndProc = Window->Class->WndProc;
|
||||
Window->WndProcExtra = Window->Class->WndProcExtra;
|
||||
}
|
||||
else
|
||||
{
|
||||
Window->Unicode = Class->Unicode;
|
||||
Window->WndProc = Class->WndProc;
|
||||
Window->Unicode = Window->Class->Unicode;
|
||||
Window->WndProc = Window->Class->WndProc;
|
||||
Window->CallProc = NULL;
|
||||
}
|
||||
|
||||
|
@ -1596,10 +1598,10 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
Window->LastChild = NULL;
|
||||
Window->PrevSibling = NULL;
|
||||
Window->NextSibling = NULL;
|
||||
Window->ExtraDataSize = Class->WndExtra;
|
||||
Window->ExtraDataSize = Window->Class->WndExtra;
|
||||
|
||||
/* extra window data */
|
||||
if (Class->WndExtra)
|
||||
if (Window->Class->WndExtra)
|
||||
Window->ExtraData = (PCHAR)(Window + 1);
|
||||
|
||||
InitializeListHead(&Window->PropListHead);
|
||||
|
@ -3463,7 +3465,6 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
|
|||
}
|
||||
|
||||
Ret = (WNDPROC)ObmObjectToHandle(Window->CallProc2);
|
||||
DbgPrint("!!!!!!!! Returning handle 0x%p\n", Ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue