[ros-diffs] [greatlrd] 21596: Bug 1393 : Patch from w3seek Fix moving class objects between desktop heaps and the shared heaps

greatlrd at svn.reactos.org greatlrd at svn.reactos.org
Sat Apr 15 12:41:59 CEST 2006


Author: greatlrd
Date: Sat Apr 15 14:41:58 2006
New Revision: 21596

URL: http://svn.reactos.ru/svn/reactos?rev=21596&view=rev
Log:
Bug 1393 : Patch from w3seek Fix moving class objects between desktop heaps and the shared heaps

Modified:
    trunk/reactos/dll/win32/aclui/checklist.c
    trunk/reactos/dll/win32/aclui/precomp.h
    trunk/reactos/include/reactos/win32k/ntuser.h
    trunk/reactos/subsystems/win32/win32k/include/class.h
    trunk/reactos/subsystems/win32/win32k/include/desktop.h
    trunk/reactos/subsystems/win32/win32k/main/dllmain.c
    trunk/reactos/subsystems/win32/win32k/ntuser/class.c
    trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c
    trunk/reactos/subsystems/win32/win32k/ntuser/window.c

Modified: trunk/reactos/dll/win32/aclui/checklist.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/dll/win32/aclui/checklist.c?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/dll/win32/aclui/checklist.c (original)
+++ trunk/reactos/dll/win32/aclui/checklist.c Sat Apr 15 14:41:58 2006
@@ -85,10 +85,10 @@
     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);

Modified: trunk/reactos/dll/win32/aclui/precomp.h
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/dll/win32/aclui/precomp.h?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/dll/win32/aclui/precomp.h (original)
+++ trunk/reactos/dll/win32/aclui/precomp.h Sat Apr 15 14:41:58 2006
@@ -63,7 +63,7 @@
 
     HANDLE SidCacheMgr;
     LONG SidLookupsPending;
-    BOOL Initializing : 1;
+    UINT Initializing : 1;
 
     LPCWSTR ServerName;
 } SECURITY_PAGE, *PSECURITY_PAGE;

Modified: trunk/reactos/include/reactos/win32k/ntuser.h
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/include/reactos/win32k/ntuser.h?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/include/reactos/win32k/ntuser.h (original)
+++ trunk/reactos/include/reactos/win32k/ntuser.h Sat Apr 15 14:41:58 2006
@@ -33,6 +33,7 @@
         WNDPROC WndProcExtra;
         PCALLPROC CallProc;
     };
+    PCALLPROC CallProc2;
     INT ClsExtra;
     INT WndExtra;
     HINSTANCE hInstance;
@@ -50,6 +51,8 @@
     UINT Unicode : 1;
     UINT System : 1;
     UINT Global : 1;
+    UINT GlobalCallProc : 1;
+    UINT GlobalCallProc2 : 1;
 } WINDOWCLASS, *PWINDOWCLASS;
 
 typedef struct _W32PROCESSINFO

Modified: trunk/reactos/subsystems/win32/win32k/include/class.h
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/subsystems/win32/win32k/include/class.h?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/class.h (original)
+++ trunk/reactos/subsystems/win32/win32k/include/class.h Sat Apr 15 14:41:58 2006
@@ -32,7 +32,8 @@
 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 @@
                 OUT PWINDOWCLASS *BaseClass  OPTIONAL,
                 OUT PWINDOWCLASS **Link  OPTIONAL);
 
+BOOL
+IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
+                              IN BOOL FreeOnFailure);
+
 #endif /* _WIN32K_CLASS_H */
 
 /* EOF */

Modified: trunk/reactos/subsystems/win32/win32k/include/desktop.h
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/subsystems/win32/win32k/include/desktop.h?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/desktop.h (original)
+++ trunk/reactos/subsystems/win32/win32k/include/desktop.h Sat Apr 15 14:41:58 2006
@@ -93,7 +93,8 @@
 HDESK FASTCALL
 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject);
 
-BOOL IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject);
+BOOL IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject,
+                         IN BOOL FreeOnFailure);
 
 NTSTATUS FASTCALL
 IntValidateDesktopHandle(

Modified: trunk/reactos/subsystems/win32/win32k/main/dllmain.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/subsystems/win32/win32k/main/dllmain.c?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/main/dllmain.c (original)
+++ trunk/reactos/subsystems/win32/win32k/main/dllmain.c Sat Apr 15 14:41:58 2006
@@ -203,6 +203,9 @@
 
       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 @@
           NtClose(hDesk);
           if(NT_SUCCESS(Status))
           {
-            if (!IntSetThreadDesktop(DesktopObject))
+            if (!IntSetThreadDesktop(DesktopObject,
+                                     FALSE))
             {
               DPRINT1("Unable to set thread desktop\n");
             }
@@ -260,8 +264,6 @@
       Win32Thread->MessageQueue = MsqCreateMessageQueue(Thread);
       Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout();
       Win32Thread->MessagePumpHookValue = 0;
-      InitializeListHead(&Win32Thread->WindowListHead);
-      InitializeListHead(&Win32Thread->W32CallbackListHead);
     }
   else
     {
@@ -278,14 +280,6 @@
       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 @@
          
          e = PopEntryList(&Win32Thread->ReferencesList);
       }
+
+      IntSetThreadDesktop(NULL,
+                          TRUE);
+
+      if (Win32Thread->ThreadInfo != NULL)
+      {
+          UserHeapFree(Win32Thread->ThreadInfo);
+          Win32Thread->ThreadInfo = NULL;
+      }
+
       PsSetThreadWin32Thread(Thread, NULL);
     }
 

Modified: trunk/reactos/subsystems/win32/win32k/ntuser/class.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/class.c?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/class.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/class.c Sat Apr 15 14:41:58 2006
@@ -25,9 +25,6 @@
  * PROGRAMER:        Thomas Weidenmueller <w3seek at 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 @@
     {
         NewCallProc->pi = pi;
         NewCallProc->WndProc = WndProc;
-        NewCallProc->Unicode = Unicode != FALSE;
+        NewCallProc->Unicode = Unicode;
     }
 
     return NewCallProc;
@@ -154,22 +151,12 @@
 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)
@@ -177,8 +164,14 @@
         /* 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 @@
 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 @@
         }
         else
         {
-            if (Class->CallProc != NULL)
-            {
-                return (WNDPROC)ObmObjectToHandle(Class->CallProc);
+            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(*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 @@
                     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 @@
         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 @@
 }
 
 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 @@
 
     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 @@
                           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 @@
 }
 
 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)
     {
@@ -516,6 +577,72 @@
     }
 
     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
@@ -535,12 +662,10 @@
 
             /* 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 @@
                 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);
-
-                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);
+                ASSERT(*PrevLink == BaseClass);
+
+                /* 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
@@ -611,6 +719,180 @@
             IntDestroyClass(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
@@ -908,24 +1190,14 @@
 static PWINDOWCLASS
 IntClassResizeInternal(IN OUT PWINDOWCLASS Class,
                        IN INT ClsExtraNew,
-                       IN PWINDOWCLASS *List)
-{
-    PWINDOWCLASS *PrevLink, CurrentClass, NewClass;
+                       IN PWINDOWCLASS *PrevLink)
+{
+    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 @@
                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 @@
     }
 
     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 @@
         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 @@
         /* save the pointer to the base class in case it changed */
         Clone->Base = Class;
 
+        Link = &Clone->Next;
         Clone = Clone->Next;
     }
 
@@ -1059,15 +1332,22 @@
            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 @@
 
             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 @@
         while (Clone != NULL)
         {
             Clone->ClsExtra = ClsExtraNew;
+
+            ASSERT(Clone->Base == Class);
+
             Clone = Clone->Next;
         }
 
@@ -1165,8 +1448,6 @@
             }
         }
     }
-
-    ASSERT(ti->Desktop != NULL);
 
     Class = IntCreateClass(lpwcx,
                            ClassName,
@@ -1447,7 +1728,8 @@
         case GCLP_WNDPROC:
             Ret = (ULONG_PTR)IntGetClassWndProc(Class,
                                                 GetW32ProcessInfo(),
-                                                Ansi);
+                                                Ansi,
+                                                FALSE);
             break;
 
         case GCW_ATOM:
@@ -1770,7 +2052,8 @@
 
     lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
                                             GetW32ProcessInfo(),
-                                            Ansi);
+                                            Ansi,
+                                            FALSE);
 
     lpwcx->cbClsExtra = Class->ClsExtra;
     lpwcx->cbWndExtra = Class->WndExtra;

Modified: trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/desktop.c Sat Apr 15 14:41:58 2006
@@ -1757,7 +1757,8 @@
 }
 
 BOOL
-IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject)
+IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject,
+                    IN BOOL FreeOnFailure)
 {
     PDESKTOP_OBJECT OldDesktop;
     PW32THREAD W32Thread;
@@ -1770,6 +1771,13 @@
     if (W32Thread->Desktop != 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;
 
@@ -1783,6 +1791,20 @@
             }
         }
 
+        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 @@
 
             ObDereferenceObject(OldDesktop);
 
+            /* update the thread info */
             if (W32Thread != NULL && W32Thread->ThreadInfo != NULL &&
                 W32Thread->ThreadInfo->Desktop != (DesktopObject != NULL ? DesktopObject->DesktopInfo : NULL))
             {
@@ -1849,7 +1872,8 @@
 
    /* FIXME: Should check here to see if the thread has any windows. */
 
-   if (!IntSetThreadDesktop(DesktopObject))
+   if (!IntSetThreadDesktop(DesktopObject,
+                            FALSE))
    {
        RETURN(FALSE);
    }

Modified: trunk/reactos/subsystems/win32/win32k/ntuser/window.c
URL: http://svn.reactos.ru/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/window.c?rev=21596&r1=21595&r2=21596&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/window.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/window.c Sat Apr 15 14:41:58 2006
@@ -442,7 +442,6 @@
 
    if (Window->CallProc2 != NULL)
    {
-       DbgPrint("!!!!! Destroy call proc 0x%p\n", ObmObjectToHandle(Window->CallProc2));
        DestroyCallProc(Window->ti->Desktop,
                        Window->CallProc2);
    }
@@ -1401,7 +1400,7 @@
                      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 @@
                                hInstance,
                                ti->kpi,
                                &Class,
-                               NULL);
+                               &ClassLink);
 
    if (ClassAtom == (RTL_ATOM)0)
    {
@@ -1500,6 +1499,7 @@
    }
 
    Class = IntReferenceClass(Class,
+                             ClassLink,
                              ti->Desktop);
    if (Class == NULL)
    {
@@ -1541,6 +1541,8 @@
     */
    Window->ti = ti;
    Window->Class = Class;
+   Class = NULL;
+
    Window->SystemMenu = (HMENU)0;
    Window->ContextHelpId = 0;
    Window->IDMenu = 0;
@@ -1548,7 +1550,7 @@
    Window->hSelf = hWnd;
 
    if (!hMenu)
-       hMenu = Class->hMenu;
+       hMenu = Window->Class->hMenu;
 
    if (0 != (dwStyle & WS_CHILD))
    {
@@ -1576,18 +1578,18 @@
    
    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 @@
    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 @@
             }
 
             Ret = (WNDPROC)ObmObjectToHandle(Window->CallProc2);
-            DbgPrint("!!!!!!!! Returning handle 0x%p\n", Ret);
         }
     }
 




More information about the Ros-diffs mailing list