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

View file

@ -69,6 +69,15 @@ IntGetClassAtom(IN PUNICODE_STRING ClassName,
OUT PWINDOWCLASS *BaseClass OPTIONAL, OUT PWINDOWCLASS *BaseClass OPTIONAL,
OUT PWINDOWCLASS **Link 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 BOOL
IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName, IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
OUT RTL_ATOM *Atom); OUT RTL_ATOM *Atom);

View file

@ -37,9 +37,6 @@ typedef struct _WINDOW_OBJECT
/* Extra Wnd proc (windows of system classes) */ /* Extra Wnd proc (windows of system classes) */
WNDPROC WndProcExtra; 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 */ /* Indicates whether the window is derived from a system class */
BOOL IsSystem; BOOL IsSystem;
/* Pointer to the window class. */ /* Pointer to the window class. */

View file

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

View file

@ -59,17 +59,19 @@ IntDestroyClass(IN OUT PWINDOWCLASS Class)
if (Class->Base == Class) if (Class->Base == Class)
{ {
/* destruct resources shared with clones */ PCALLPROC CallProc, NextCallProc;
if (!Class->System && Class->CallProc != NULL)
{
DestroyCallProc(Class->GlobalCallProc ? NULL : Class->Desktop,
Class->CallProc);
}
if (Class->CallProc2 != NULL) /* Destroy allocated callproc handles */
CallProc = Class->CallProcList;
while (CallProc != NULL)
{ {
DestroyCallProc(Class->GlobalCallProc2 ? NULL : Class->Desktop, NextCallProc = CallProc->Next;
Class->CallProc2);
CallProc->Next = NULL;
DestroyCallProc(NULL,
Class->CallProc);
CallProc = NextCallProc;
} }
IntFreeClassMenuName(Class); IntFreeClassMenuName(Class);
@ -180,6 +182,50 @@ IntDeregisterClassAtom(IN RTL_ATOM 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 static BOOL
IntSetClassAtom(IN OUT PWINDOWCLASS Class, IntSetClassAtom(IN OUT PWINDOWCLASS Class,
IN PUNICODE_STRING ClassName) IN PUNICODE_STRING ClassName)
@ -214,8 +260,7 @@ IntSetClassAtom(IN OUT PWINDOWCLASS Class,
static WNDPROC static WNDPROC
IntGetClassWndProc(IN PWINDOWCLASS Class, IntGetClassWndProc(IN PWINDOWCLASS Class,
IN PW32PROCESSINFO pi, IN PW32PROCESSINFO pi,
IN BOOL Ansi, IN BOOL Ansi)
IN BOOL UseCallProc2)
{ {
ASSERT(UserIsEnteredExclusive() == TRUE); ASSERT(UserIsEnteredExclusive() == TRUE);
@ -231,7 +276,6 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
} }
else else
{ {
PCALLPROC *CallProcPtr;
PWINDOWCLASS BaseClass; PWINDOWCLASS BaseClass;
/* make sure the call procedures are located on the desktop /* make sure the call procedures are located on the desktop
@ -239,11 +283,9 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
BaseClass = Class->Base; BaseClass = Class->Base;
Class = BaseClass; Class = BaseClass;
CallProcPtr = (UseCallProc2 ? &Class->CallProc2 : &Class->CallProc); if (Class->CallProc != NULL)
if (*CallProcPtr != NULL)
{ {
return GetCallProcHandle(*CallProcPtr); return GetCallProcHandle(Class->CallProc);
} }
else else
{ {
@ -252,40 +294,32 @@ IntGetClassWndProc(IN PWINDOWCLASS Class,
if (pi == NULL) if (pi == NULL)
return NULL; return NULL;
NewCallProc = CreateCallProc(Class->Desktop, NewCallProc = UserFindCallProc(Class,
Class->WndProc, Class->WndProc,
Class->Unicode, Class->Unicode);
pi);
if (NewCallProc == NULL) if (NewCallProc == NULL)
{ {
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); NewCallProc = CreateCallProc(NULL,
return NULL; Class->WndProc,
Class->Unicode,
pi);
if (NewCallProc == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
UserAddCallProcToClass(Class,
NewCallProc);
} }
*CallProcPtr = NewCallProc; Class->CallProc = NewCallProc;
if (Class->Desktop == NULL)
{
if (UseCallProc2)
Class->GlobalCallProc2 = TRUE;
else
Class->GlobalCallProc = TRUE;
}
/* update the clones */ /* update the clones */
Class = Class->Clone; Class = Class->Clone;
while (Class != NULL) while (Class != NULL)
{ {
if (UseCallProc2) Class->CallProc = NewCallProc;
{
Class->CallProc2 = NewCallProc;
Class->GlobalCallProc2 = BaseClass->GlobalCallProc2;
}
else
{
Class->CallProc = NewCallProc;
Class->GlobalCallProc = BaseClass->GlobalCallProc;
}
Class = Class->Next; Class = Class->Next;
} }
@ -328,8 +362,7 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
Ret = IntGetClassWndProc(Class, Ret = IntGetClassWndProc(Class,
GetW32ProcessInfo(), GetW32ProcessInfo(),
Ansi, Ansi);
TRUE);
if (Ret == NULL) if (Ret == NULL)
{ {
return NULL; return NULL;
@ -338,11 +371,6 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
/* update the class info */ /* update the class info */
Class->Unicode = !Ansi; Class->Unicode = !Ansi;
Class->WndProc = WndProc; Class->WndProc = WndProc;
if (Class->CallProc != NULL)
{
Class->CallProc->WndProc = WndProc;
Class->CallProc->Unicode = !Ansi;
}
/* update the clones */ /* update the clones */
Class = Class->Clone; Class = Class->Clone;
@ -436,11 +464,6 @@ IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass,
Class->Base = Class; Class->Base = Class;
Class->Next = BaseClass->Next; Class->Next = BaseClass->Next;
if (!BaseClass->System && BaseClass->CallProc != NULL)
Class->GlobalCallProc = TRUE;
if (BaseClass->CallProc2 != NULL)
Class->GlobalCallProc2 = TRUE;
/* replace the base class */ /* replace the base class */
(void)InterlockedExchangePointer(ClassLink, (void)InterlockedExchangePointer(ClassLink,
Class); Class);
@ -495,7 +518,6 @@ IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
IN OUT PWINDOWCLASS *CloneLink) IN OUT PWINDOWCLASS *CloneLink)
{ {
PWINDOWCLASS Clone, BaseClass; PWINDOWCLASS Clone, BaseClass;
PCALLPROC CallProc;
ASSERT(Class->Base != Class); ASSERT(Class->Base != Class);
ASSERT(Class->Base->Clone != NULL); ASSERT(Class->Base->Clone != NULL);
@ -510,28 +532,6 @@ IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
BaseClass = Class->Base; 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 */ /* update the class information to make it a base class */
Class->Base = Class; Class->Base = Class;
Class->Next = (*BaseClassLink)->Next; Class->Next = (*BaseClassLink)->Next;
@ -636,7 +636,6 @@ IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
IN OUT PWINDOWCLASS **ClassLinkPtr) IN OUT PWINDOWCLASS **ClassLinkPtr)
{ {
PWINDOWCLASS NewClass; PWINDOWCLASS NewClass;
PCALLPROC CallProc;
SIZE_T ClassSize; SIZE_T ClassSize;
ASSERT(Class->Base == Class); ASSERT(Class->Base == Class);
@ -657,32 +656,6 @@ IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
NewClass->Desktop = NULL; NewClass->Desktop = NULL;
NewClass->Base = NewClass; 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 */ /* replace the class in the list */
(void)InterlockedExchangePointer(*ClassLinkPtr, (void)InterlockedExchangePointer(*ClassLinkPtr,
NewClass); NewClass);
@ -1473,8 +1446,7 @@ UserGetClassLongPtr(IN PWINDOWCLASS Class,
case GCLP_WNDPROC: case GCLP_WNDPROC:
Ret = (ULONG_PTR)IntGetClassWndProc(Class, Ret = (ULONG_PTR)IntGetClassWndProc(Class,
GetW32ProcessInfo(), GetW32ProcessInfo(),
Ansi, Ansi);
FALSE);
break; break;
case GCW_ATOM: case GCW_ATOM:
@ -1798,8 +1770,7 @@ UserGetClassInfo(IN PWINDOWCLASS Class,
pi = GetW32ProcessInfo(); pi = GetW32ProcessInfo();
lpwcx->lpfnWndProc = IntGetClassWndProc(Class, lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
pi, pi,
Ansi, Ansi);
FALSE);
lpwcx->cbClsExtra = Class->ClsExtra; lpwcx->cbClsExtra = Class->ClsExtra;
lpwcx->cbWndExtra = Class->WndExtra; lpwcx->cbWndExtra = Class->WndExtra;

View file

@ -434,18 +434,6 @@ static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
IntDestroyScrollBars(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 */ /* dereference the class */
IntDereferenceClass(Window->Class, IntDereferenceClass(Window->Class,
Window->ti->Desktop, Window->ti->Desktop,
@ -497,6 +485,8 @@ static WNDPROC
IntGetWindowProc(IN PWINDOW_OBJECT Window, IntGetWindowProc(IN PWINDOW_OBJECT Window,
IN BOOL Ansi) IN BOOL Ansi)
{ {
ASSERT(UserIsEnteredExclusive() == TRUE);
if (Window->IsSystem) if (Window->IsSystem)
{ {
return (Ansi ? Window->WndProcExtra : Window->WndProc); return (Ansi ? Window->WndProcExtra : Window->WndProc);
@ -517,26 +507,27 @@ IntGetWindowProc(IN PWINDOW_OBJECT Window,
{ {
PCALLPROC NewCallProc, CallProc; PCALLPROC NewCallProc, CallProc;
/* NOTE: use the interlocked functions, as this operation may be done even NewCallProc = UserFindCallProc(Window->Class,
when only the shared lock is held! */ Window->WndProc,
NewCallProc = CreateCallProc(Window->ti->Desktop, Window->Unicode);
Window->WndProc,
Window->Unicode,
Window->ti->kpi);
if (NewCallProc == NULL) if (NewCallProc == NULL)
{ {
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); NewCallProc = CreateCallProc(Window->ti->Desktop,
return NULL; 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, CallProc = Window->CallProc;
NewCallProc, Window->CallProc = NewCallProc;
NULL);
if (CallProc != NULL)
{
DestroyCallProc(Window->ti->Desktop,
NewCallProc);
}
return GetCallProcHandle((CallProc == NULL ? NewCallProc : CallProc)); return GetCallProcHandle((CallProc == NULL ? NewCallProc : CallProc));
} }
@ -3533,6 +3524,7 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
BOOL Ansi) BOOL Ansi)
{ {
WNDPROC Ret; WNDPROC Ret;
PCALLPROC CallProc;
/* resolve any callproc handle if possible */ /* resolve any callproc handle if possible */
if (IsCallProcHandle(NewWndProc)) if (IsCallProcHandle(NewWndProc))
@ -3560,50 +3552,38 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
} }
else else
{ {
/* allocate or update an existing call procedure handle to return CallProc = UserFindCallProc(Window->Class,
the old window proc */ Window->WndProc,
if (Window->CallProc2 != NULL) Window->Unicode);
if (CallProc == NULL)
{ {
Window->CallProc2->WndProc = Window->WndProc; CallProc = CreateCallProc(NULL,
Window->CallProc2->Unicode = Window->Unicode; Window->WndProc,
} Window->Unicode,
else Window->ti->kpi);
{ if (CallProc == NULL)
Window->CallProc2 = CreateCallProc(Window->ti->Desktop,
Window->WndProc,
Window->Unicode,
Window->ti->kpi);
if (Window->CallProc2 == NULL)
{ {
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL; return NULL;
} }
UserAddCallProcToClass(Window->Class,
CallProc);
} }
Ret = GetCallProcHandle(Window->CallProc2); Window->CallProc = CallProc;
Ret = GetCallProcHandle(Window->CallProc);
} }
} }
if (Window->Class->System) if (Window->Class->System)
{ {
BOOL SysWnd = Window->IsSystem;
/* check if the new procedure matches with the one in the /* check if the new procedure matches with the one in the
window class. If so, we need to restore both procedures! */ window class. If so, we need to restore both procedures! */
Window->IsSystem = (NewWndProc == Window->Class->WndProc || Window->IsSystem = (NewWndProc == Window->Class->WndProc ||
NewWndProc == Window->Class->WndProcExtra); 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) if (Window->IsSystem)
{ {
Window->WndProc = Window->Class->WndProc; Window->WndProc = Window->Class->WndProc;
@ -3617,11 +3597,6 @@ IntSetWindowProc(PWINDOW_OBJECT Window,
/* update the window procedure */ /* update the window procedure */
Window->WndProc = NewWndProc; Window->WndProc = NewWndProc;
if (Window->CallProc != NULL)
{
Window->CallProc->WndProc = NewWndProc;
Window->CallProc->Unicode = !Ansi;
}
Window->Unicode = !Ansi; Window->Unicode = !Ansi;
return Ret; return Ret;