mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
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:
parent
47f240c7fb
commit
3e0b11c4bf
6 changed files with 126 additions and 172 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue