Keep callproc handles valid as long as a window classes exists. Abiword should work again.

svn path=/trunk/; revision=29967
This commit is contained in:
Thomas Bluemel 2007-10-30 01:24:47 +00:00
parent 47f240c7fb
commit 3e0b11c4bf
6 changed files with 126 additions and 172 deletions

View file

@ -16,6 +16,7 @@ typedef struct _CALLPROC
{
struct _W32PROCESSINFO *pi;
WNDPROC WndProc;
struct _CALLPROC *Next;
UINT Unicode : 1;
} CALLPROC, *PCALLPROC;
@ -36,6 +37,7 @@ typedef struct _WINDOWCLASS
PCALLPROC CallProc;
};
PCALLPROC CallProc2;
PCALLPROC CallProcList;
INT ClsExtra;
INT WndExtra;
HINSTANCE hInstance;
@ -51,8 +53,6 @@ typedef struct _WINDOWCLASS
UINT Unicode : 1;
UINT System : 1;
UINT Global : 1;
UINT GlobalCallProc : 1;
UINT GlobalCallProc2 : 1;
UINT MenuNameIsString : 1;
} WINDOWCLASS, *PWINDOWCLASS;

View file

@ -69,6 +69,15 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
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);

View file

@ -37,9 +37,6 @@ typedef struct _WINDOW_OBJECT
/* 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. */

View file

@ -70,6 +70,7 @@ CloneCallProc(IN PDESKTOP Desktop,
NewCallProc->pi = CallProc->pi;
NewCallProc->WndProc = CallProc->WndProc;
NewCallProc->Unicode = CallProc->Unicode;
NewCallProc->Next = NULL;
}
return NewCallProc;
@ -94,6 +95,7 @@ CreateCallProc(IN PDESKTOP Desktop,
NewCallProc->pi = pi;
NewCallProc->WndProc = WndProc;
NewCallProc->Unicode = Unicode;
NewCallProc->Next = NULL;
}
return NewCallProc;

View file

@ -59,17 +59,19 @@ IntDestroyClass(IN OUT PWINDOWCLASS Class)
if (Class->Base == Class)
{
/* destruct resources shared with clones */
if (!Class->System && Class->CallProc != NULL)
{
DestroyCallProc(Class->GlobalCallProc ? NULL : Class->Desktop,
Class->CallProc);
}
PCALLPROC CallProc, NextCallProc;
if (Class->CallProc2 != NULL)
/* Destroy allocated callproc handles */
CallProc = Class->CallProcList;
while (CallProc != NULL)
{
DestroyCallProc(Class->GlobalCallProc2 ? NULL : Class->Desktop,
Class->CallProc2);
NextCallProc = CallProc->Next;
CallProc->Next = NULL;
DestroyCallProc(NULL,
Class->CallProc);
CallProc = NextCallProc;
}
IntFreeClassMenuName(Class);
@ -180,6 +182,50 @@ IntDeregisterClassAtom(IN RTL_ATOM Atom)
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 @@ IntSetClassAtom(IN OUT PWINDOWCLASS Class,
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 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
}
else
{
PCALLPROC *CallProcPtr;
PWINDOWCLASS BaseClass;
/* make sure the call procedures are located on the desktop
@ -239,11 +283,9 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
BaseClass = Class->Base;
Class = BaseClass;
CallProcPtr = (UseCallProc2 ? &Class->CallProc2 : &Class->CallProc);
if (*CallProcPtr != NULL)
if (Class->CallProc != NULL)
{
return GetCallProcHandle(*CallProcPtr);
return GetCallProcHandle(Class->CallProc);
}
else
{
@ -252,40 +294,32 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
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 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
Ret = IntGetClassWndProc(Class,
GetW32ProcessInfo(),
Ansi,
TRUE);
Ansi);
if (Ret == NULL)
{
return NULL;
@ -338,11 +371,6 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
/* 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 @@ IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass,
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 @@ IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
IN OUT PWINDOWCLASS *CloneLink)
{
PWINDOWCLASS Clone, BaseClass;
PCALLPROC CallProc;
ASSERT(Class->Base != Class);
ASSERT(Class->Base->Clone != NULL);
@ -510,28 +532,6 @@ IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
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 @@ IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
IN OUT PWINDOWCLASS **ClassLinkPtr)
{
PWINDOWCLASS NewClass;
PCALLPROC CallProc;
SIZE_T ClassSize;
ASSERT(Class->Base == Class);
@ -657,32 +656,6 @@ IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
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);
@ -1473,8 +1446,7 @@ UserGetClassLongPtr(IN PWINDOWCLASS Class,
case GCLP_WNDPROC:
Ret = (ULONG_PTR)IntGetClassWndProc(Class,
GetW32ProcessInfo(),
Ansi,
FALSE);
Ansi);
break;
case GCW_ATOM:
@ -1798,8 +1770,7 @@ UserGetClassInfo(IN PWINDOWCLASS Class,
pi = GetW32ProcessInfo();
lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
pi,
Ansi,
FALSE);
Ansi);
lpwcx->cbClsExtra = Class->ClsExtra;
lpwcx->cbWndExtra = Class->WndExtra;

View file

@ -434,18 +434,6 @@ static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
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 @@ static WNDPROC
IntGetWindowProc(IN PWINDOW_OBJECT Window,
IN BOOL Ansi)
{
ASSERT(UserIsEnteredExclusive() == TRUE);
if (Window->IsSystem)
{
return (Ansi ? Window->WndProcExtra : Window->WndProc);
@ -517,26 +507,27 @@ IntGetWindowProc(IN PWINDOW_OBJECT Window,
{
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 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
BOOL Ansi)
{
WNDPROC Ret;
PCALLPROC CallProc;
/* resolve any callproc handle if possible */
if (IsCallProcHandle(NewWndProc))
@ -3560,50 +3552,38 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
}
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)
{
Window->WndProc = Window->Class->WndProc;
@ -3617,11 +3597,6 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
/* update the window procedure */
Window->WndProc = NewWndProc;
if (Window->CallProc != NULL)
{
Window->CallProc->WndProc = NewWndProc;
Window->CallProc->Unicode = !Ansi;
}
Window->Unicode = !Ansi;
return Ret;