Author: weiden
Date: Tue Oct 30 04:24:47 2007
New Revision: 29967
URL: 
http://svn.reactos.org/svn/reactos?rev=29967&view=rev
Log:
Keep callproc handles valid as long as a window classes exists. Abiword should work again.
Modified:
    trunk/reactos/include/reactos/win32k/ntuser.h
    trunk/reactos/subsystems/win32/win32k/include/class.h
    trunk/reactos/subsystems/win32/win32k/include/window.h
    trunk/reactos/subsystems/win32/win32k/ntuser/callproc.c
    trunk/reactos/subsystems/win32/win32k/ntuser/class.c
    trunk/reactos/subsystems/win32/win32k/ntuser/window.c
Modified: trunk/reactos/include/reactos/win32k/ntuser.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/win32k/ntu…
==============================================================================
--- trunk/reactos/include/reactos/win32k/ntuser.h (original)
+++ trunk/reactos/include/reactos/win32k/ntuser.h Tue Oct 30 04:24:47 2007
@@ -16,6 +16,7 @@
 {
     struct _W32PROCESSINFO *pi;
     WNDPROC WndProc;
+    struct _CALLPROC *Next;
     UINT Unicode : 1;
 } CALLPROC, *PCALLPROC;
@@ -36,6 +37,7 @@
         PCALLPROC CallProc;
     };
     PCALLPROC CallProc2;
+    PCALLPROC CallProcList;
     INT ClsExtra;
     INT WndExtra;
     HINSTANCE hInstance;
@@ -51,8 +53,6 @@
     UINT Unicode : 1;
     UINT System : 1;
     UINT Global : 1;
-    UINT GlobalCallProc : 1;
-    UINT GlobalCallProc2 : 1;
     UINT MenuNameIsString : 1;
 } WINDOWCLASS, *PWINDOWCLASS;
Modified: trunk/reactos/subsystems/win32/win32k/include/class.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/in…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/class.h (original)
+++ trunk/reactos/subsystems/win32/win32k/include/class.h Tue Oct 30 04:24:47 2007
@@ -69,6 +69,15 @@
                 OUT PWINDOWCLASS *BaseClass  OPTIONAL,
                 OUT PWINDOWCLASS **Link  OPTIONAL);
+PCALLPROC
+UserFindCallProc(IN PWINDOWCLASS Class,
+                 IN WNDPROC WndProc,
+                 IN BOOL bUnicode);
+
+VOID
+UserAddCallProcToClass(IN OUT PWINDOWCLASS Class,
+                       IN PCALLPROC CallProc);
+
 BOOL
 IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
                            OUT RTL_ATOM *Atom);
Modified: trunk/reactos/subsystems/win32/win32k/include/window.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/in…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/include/window.h (original)
+++ trunk/reactos/subsystems/win32/win32k/include/window.h Tue Oct 30 04:24:47 2007
@@ -37,9 +37,6 @@
     /* Extra Wnd proc (windows of system classes) */
     WNDPROC WndProcExtra;
   };
-  /* Pointer to another call procedure handle (used for returning the previous
-     window proc in SetWindowLongPtr) */
-  PCALLPROC CallProc2;
   /* Indicates whether the window is derived from a system class */
   BOOL IsSystem;
   /* Pointer to the window class. */
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/callproc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/nt…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/callproc.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/callproc.c Tue Oct 30 04:24:47 2007
@@ -70,6 +70,7 @@
         NewCallProc->pi = CallProc->pi;
         NewCallProc->WndProc = CallProc->WndProc;
         NewCallProc->Unicode = CallProc->Unicode;
+        NewCallProc->Next = NULL;
     }
     return NewCallProc;
@@ -94,6 +95,7 @@
         NewCallProc->pi = pi;
         NewCallProc->WndProc = WndProc;
         NewCallProc->Unicode = Unicode;
+        NewCallProc->Next = NULL;
     }
     return NewCallProc;
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/class.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/nt…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/class.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/class.c Tue Oct 30 04:24:47 2007
@@ -59,17 +59,19 @@
     if (Class->Base == Class)
     {
-        /* destruct resources shared with clones */
-        if (!Class->System && Class->CallProc != NULL)
-        {
-            DestroyCallProc(Class->GlobalCallProc ? NULL : Class->Desktop,
+        PCALLPROC CallProc, NextCallProc;
+
+        /* Destroy allocated callproc handles */
+        CallProc = Class->CallProcList;
+        while (CallProc != NULL)
+        {
+            NextCallProc = CallProc->Next;
+
+            CallProc->Next = NULL;
+            DestroyCallProc(NULL,
                             Class->CallProc);
-        }
-
-        if (Class->CallProc2 != NULL)
-        {
-            DestroyCallProc(Class->GlobalCallProc2 ? NULL : Class->Desktop,
-                            Class->CallProc2);
+
+            CallProc = NextCallProc;
         }
         IntFreeClassMenuName(Class);
@@ -180,6 +182,50 @@
                                       Atom);
 }
+PCALLPROC
+UserFindCallProc(IN PWINDOWCLASS Class,
+                 IN WNDPROC WndProc,
+                 IN BOOL bUnicode)
+{
+    PCALLPROC CallProc;
+
+    CallProc = Class->CallProcList;
+    while (CallProc != NULL)
+    {
+        if (CallProc->WndProc == WndProc &&
+            CallProc->Unicode == (UINT)bUnicode)
+        {
+            return CallProc;
+        }
+
+        CallProc = CallProc->Next;
+    }
+
+    return NULL;
+}
+
+VOID
+UserAddCallProcToClass(IN OUT PWINDOWCLASS Class,
+                       IN PCALLPROC CallProc)
+{
+    PWINDOWCLASS BaseClass;
+
+    ASSERT(CallProc->Next == NULL);
+
+    BaseClass = Class->Base;
+    ASSERT(CallProc->Next == NULL);
+    CallProc->Next = BaseClass->CallProcList;
+    BaseClass->CallProcList = CallProc;
+
+    /* Update all clones */
+    Class = Class->Clone;
+    while (Class != NULL)
+    {
+        Class->CallProcList = BaseClass->CallProcList;
+        Class = Class->Next;
+    }
+}
+
 static BOOL
 IntSetClassAtom(IN OUT PWINDOWCLASS Class,
                 IN PUNICODE_STRING ClassName)
@@ -214,8 +260,7 @@
 static WNDPROC
 IntGetClassWndProc(IN PWINDOWCLASS Class,
                    IN PW32PROCESSINFO pi,
-                   IN BOOL Ansi,
-                   IN BOOL UseCallProc2)
+                   IN BOOL Ansi)
 {
     ASSERT(UserIsEnteredExclusive() == TRUE);
@@ -231,7 +276,6 @@
         }
         else
         {
-            PCALLPROC *CallProcPtr;
             PWINDOWCLASS BaseClass;
             /* make sure the call procedures are located on the desktop
@@ -239,11 +283,9 @@
             BaseClass = Class->Base;
             Class = BaseClass;
-            CallProcPtr = (UseCallProc2 ? &Class->CallProc2 :
&Class->CallProc);
-
-            if (*CallProcPtr != NULL)
-            {
-                return GetCallProcHandle(*CallProcPtr);
+            if (Class->CallProc != NULL)
+            {
+                return GetCallProcHandle(Class->CallProc);
             }
             else
             {
@@ -252,40 +294,32 @@
                 if (pi == NULL)
                     return NULL;
-                NewCallProc = CreateCallProc(Class->Desktop,
-                                             Class->WndProc,
-                                             Class->Unicode,
-                                             pi);
+                NewCallProc = UserFindCallProc(Class,
+                                               Class->WndProc,
+                                               Class->Unicode);
                 if (NewCallProc == NULL)
                 {
-                    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-                    return NULL;
+                    NewCallProc = CreateCallProc(NULL,
+                                                 Class->WndProc,
+                                                 Class->Unicode,
+                                                 pi);
+                    if (NewCallProc == NULL)
+                    {
+                        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+                        return NULL;
+                    }
+
+                    UserAddCallProcToClass(Class,
+                                           NewCallProc);
                 }
-                *CallProcPtr = NewCallProc;
-
-                if (Class->Desktop == NULL)
-                {
-                    if (UseCallProc2)
-                        Class->GlobalCallProc2 = TRUE;
-                    else
-                        Class->GlobalCallProc = TRUE;
-                }
+                Class->CallProc = NewCallProc;
                 /* 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->CallProc = NewCallProc;
                     Class = Class->Next;
                 }
@@ -328,8 +362,7 @@
     Ret = IntGetClassWndProc(Class,
                              GetW32ProcessInfo(),
-                             Ansi,
-                             TRUE);
+                             Ansi);
     if (Ret == NULL)
     {
         return NULL;
@@ -338,11 +371,6 @@
     /* update the class info */
     Class->Unicode = !Ansi;
     Class->WndProc = WndProc;
-    if (Class->CallProc != NULL)
-    {
-        Class->CallProc->WndProc = WndProc;
-        Class->CallProc->Unicode = !Ansi;
-    }
     /* update the clones */
     Class = Class->Clone;
@@ -436,11 +464,6 @@
                 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);
@@ -495,7 +518,6 @@
                       IN OUT PWINDOWCLASS *CloneLink)
 {
     PWINDOWCLASS Clone, BaseClass;
-    PCALLPROC CallProc;
     ASSERT(Class->Base != Class);
     ASSERT(Class->Base->Clone != NULL);
@@ -510,28 +532,6 @@
     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;
@@ -636,7 +636,6 @@
                          IN OUT PWINDOWCLASS **ClassLinkPtr)
 {
     PWINDOWCLASS NewClass;
-    PCALLPROC CallProc;
     SIZE_T ClassSize;
     ASSERT(Class->Base == Class);
@@ -656,32 +655,6 @@
         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,
@@ -1473,8 +1446,7 @@
         case GCLP_WNDPROC:
             Ret = (ULONG_PTR)IntGetClassWndProc(Class,
                                                 GetW32ProcessInfo(),
-                                                Ansi,
-                                                FALSE);
+                                                Ansi);
             break;
         case GCW_ATOM:
@@ -1798,8 +1770,7 @@
     pi = GetW32ProcessInfo();
     lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
                                             pi,
-                                            Ansi,
-                                            FALSE);
+                                            Ansi);
     lpwcx->cbClsExtra = Class->ClsExtra;
     lpwcx->cbWndExtra = Class->WndExtra;
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/window.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/nt…
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/window.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/window.c Tue Oct 30 04:24:47 2007
@@ -434,18 +434,6 @@
    IntDestroyScrollBars(Window);
-   if (!Window->Class->System && Window->CallProc != NULL)
-   {
-       DestroyCallProc(Window->ti->Desktop,
-                       Window->CallProc);
-   }
-
-   if (Window->CallProc2 != NULL)
-   {
-       DestroyCallProc(Window->ti->Desktop,
-                       Window->CallProc2);
-   }
-
    /* dereference the class */
    IntDereferenceClass(Window->Class,
                        Window->ti->Desktop,
@@ -497,6 +485,8 @@
 IntGetWindowProc(IN PWINDOW_OBJECT Window,
                  IN BOOL Ansi)
 {
+    ASSERT(UserIsEnteredExclusive() == TRUE);
+
     if (Window->IsSystem)
     {
         return (Ansi ? Window->WndProcExtra : Window->WndProc);
@@ -517,26 +507,27 @@
             {
                 PCALLPROC NewCallProc, CallProc;
-                /* NOTE: use the interlocked functions, as this operation may be done
even
-                         when only the shared lock is held! */
-                NewCallProc = CreateCallProc(Window->ti->Desktop,
-                                             Window->WndProc,
-                                             Window->Unicode,
-                                             Window->ti->kpi);
+                NewCallProc = UserFindCallProc(Window->Class,
+                                               Window->WndProc,
+                                               Window->Unicode);
                 if (NewCallProc == NULL)
                 {
-                    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-                    return NULL;
+                    NewCallProc = CreateCallProc(Window->ti->Desktop,
+                                                 Window->WndProc,
+                                                 Window->Unicode,
+                                                 Window->ti->kpi);
+                    if (NewCallProc == NULL)
+                    {
+                        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+                        return NULL;
+                    }
+
+                    UserAddCallProcToClass(Window->Class,
+                                           NewCallProc);
                 }
-                CallProc = InterlockedCompareExchangePointer(&Window->CallProc,
-                                                             NewCallProc,
-                                                             NULL);
-                if (CallProc != NULL)
-                {
-                    DestroyCallProc(Window->ti->Desktop,
-                                    NewCallProc);
-                }
+                CallProc = Window->CallProc;
+                Window->CallProc = NewCallProc;
                 return GetCallProcHandle((CallProc == NULL ? NewCallProc : CallProc));
             }
@@ -3533,6 +3524,7 @@
                  BOOL Ansi)
 {
     WNDPROC Ret;
+    PCALLPROC CallProc;
     /* resolve any callproc handle if possible */
     if (IsCallProcHandle(NewWndProc))
@@ -3560,49 +3552,37 @@
         }
         else
         {
-            /* allocate or update an existing call procedure handle to return
-               the old window proc */
-            if (Window->CallProc2 != NULL)
+            CallProc = UserFindCallProc(Window->Class,
+                                        Window->WndProc,
+                                        Window->Unicode);
+            if (CallProc == NULL)
             {
-                Window->CallProc2->WndProc = Window->WndProc;
-                Window->CallProc2->Unicode = Window->Unicode;
-            }
-            else
-            {
-                Window->CallProc2 = CreateCallProc(Window->ti->Desktop,
-                                                   Window->WndProc,
-                                                   Window->Unicode,
-                                                   Window->ti->kpi);
-                if (Window->CallProc2 == NULL)
+                CallProc = CreateCallProc(NULL,
+                                          Window->WndProc,
+                                          Window->Unicode,
+                                          Window->ti->kpi);
+                if (CallProc == NULL)
                 {
                     SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
                     return NULL;
                 }
+
+                UserAddCallProcToClass(Window->Class,
+                                       CallProc);
             }
-            Ret = GetCallProcHandle(Window->CallProc2);
+            Window->CallProc = CallProc;
+
+            Ret = GetCallProcHandle(Window->CallProc);
         }
     }
     if (Window->Class->System)
     {
-        BOOL SysWnd = Window->IsSystem;
-
         /* check if the new procedure matches with the one in the
            window class. If so, we need to restore both procedures! */
         Window->IsSystem = (NewWndProc == Window->Class->WndProc ||
                             NewWndProc == Window->Class->WndProcExtra);
-
-        if (Window->IsSystem != SysWnd)
-        {
-            if (!Window->IsSystem && Window->CallProc != NULL)
-            {
-                /* destroy the callproc, we don't need it anymore */
-                DestroyCallProc(Window->ti->Desktop,
-                                Window->CallProc);
-                Window->CallProc = NULL;
-            }
-        }
         if (Window->IsSystem)
         {
@@ -3617,11 +3597,6 @@
     /* update the window procedure */
     Window->WndProc = NewWndProc;
-    if (Window->CallProc != NULL)
-    {
-        Window->CallProc->WndProc = NewWndProc;
-        Window->CallProc->Unicode = !Ansi;
-    }
     Window->Unicode = !Ansi;
     return Ret;