diff --git a/reactos/dll/win32/aclui/checklist.c b/reactos/dll/win32/aclui/checklist.c index 5756971b878..65aef081812 100644 --- a/reactos/dll/win32/aclui/checklist.c +++ b/reactos/dll/win32/aclui/checklist.c @@ -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); diff --git a/reactos/dll/win32/aclui/precomp.h b/reactos/dll/win32/aclui/precomp.h index 84258975e2d..a35ff087039 100644 --- a/reactos/dll/win32/aclui/precomp.h +++ b/reactos/dll/win32/aclui/precomp.h @@ -63,7 +63,7 @@ typedef struct _SECURITY_PAGE HANDLE SidCacheMgr; LONG SidLookupsPending; - BOOL Initializing : 1; + UINT Initializing : 1; LPCWSTR ServerName; } SECURITY_PAGE, *PSECURITY_PAGE; diff --git a/reactos/include/reactos/win32k/ntuser.h b/reactos/include/reactos/win32k/ntuser.h index 4e328ff818e..9c9a4e1e7e0 100644 --- a/reactos/include/reactos/win32k/ntuser.h +++ b/reactos/include/reactos/win32k/ntuser.h @@ -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 diff --git a/reactos/subsystems/win32/win32k/include/class.h b/reactos/subsystems/win32/win32k/include/class.h index f6a33a5febe..3b13b34148c 100644 --- a/reactos/subsystems/win32/win32k/include/class.h +++ b/reactos/subsystems/win32/win32k/include/class.h @@ -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 */ diff --git a/reactos/subsystems/win32/win32k/include/desktop.h b/reactos/subsystems/win32/win32k/include/desktop.h index a0a4c035353..3909dee749c 100644 --- a/reactos/subsystems/win32/win32k/include/desktop.h +++ b/reactos/subsystems/win32/win32k/include/desktop.h @@ -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( diff --git a/reactos/subsystems/win32/win32k/main/dllmain.c b/reactos/subsystems/win32/win32k/main/dllmain.c index 10c7c74994f..b112b396c85 100644 --- a/reactos/subsystems/win32/win32k/main/dllmain.c +++ b/reactos/subsystems/win32/win32k/main/dllmain.c @@ -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); } diff --git a/reactos/subsystems/win32/win32k/ntuser/class.c b/reactos/subsystems/win32/win32k/ntuser/class.c index 3fe2fbe5707..9bb2753d8b6 100644 --- a/reactos/subsystems/win32/win32k/ntuser/class.c +++ b/reactos/subsystems/win32/win32k/ntuser/class.c @@ -25,9 +25,6 @@ * PROGRAMER: Thomas Weidenmueller * 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; diff --git a/reactos/subsystems/win32/win32k/ntuser/desktop.c b/reactos/subsystems/win32/win32k/ntuser/desktop.c index 55310d9840f..a1422c5ca65 100644 --- a/reactos/subsystems/win32/win32k/ntuser/desktop.c +++ b/reactos/subsystems/win32/win32k/ntuser/desktop.c @@ -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); } diff --git a/reactos/subsystems/win32/win32k/ntuser/window.c b/reactos/subsystems/win32/win32k/ntuser/window.c index bc095aa54bd..1d0ef87ca2e 100644 --- a/reactos/subsystems/win32/win32k/ntuser/window.c +++ b/reactos/subsystems/win32/win32k/ntuser/window.c @@ -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); } }