Bug 1391 : Commit w3seek patch for Some Ansi vs. Unicode fixes for window classes

svn path=/trunk/; revision=21593
This commit is contained in:
Magnus Olsen
2006-04-14 18:23:11 +00:00
parent a9161f0913
commit f7f19a1a69
7 changed files with 203 additions and 114 deletions
+6 -1
View File
@@ -1014,8 +1014,9 @@ CallWindowProcA(WNDPROC lpPrevWndFunc,
{
WNDPROC_INFO wpInfo;
/* FIXME - can the first parameter be NULL? */
if (lpPrevWndFunc == NULL)
lpPrevWndFunc = (WNDPROC)NtUserGetWindowLong(hWnd, GWLP_WNDPROC, FALSE);
lpPrevWndFunc = (WNDPROC)NtUserGetWindowLong(hWnd, GWLP_WNDPROC, TRUE);
if (!NtUserDereferenceWndProcHandle((HANDLE)lpPrevWndFunc,
&wpInfo))
@@ -1042,6 +1043,10 @@ CallWindowProcW(WNDPROC lpPrevWndFunc,
{
WNDPROC_INFO wpInfo;
/* FIXME - can the first parameter be NULL? */
if (lpPrevWndFunc == NULL)
lpPrevWndFunc = (WNDPROC)NtUserGetWindowLong(hWnd, GWLP_WNDPROC, FALSE);
if (!NtUserDereferenceWndProcHandle((HANDLE)lpPrevWndFunc,
&wpInfo))
{
+5 -5
View File
@@ -14,7 +14,7 @@ typedef struct _CALLPROC
{
struct _W32PROCESSINFO *pi;
WNDPROC WndProc;
BOOL Unicode : 1;
UINT Unicode : 1;
} CALLPROC, *PCALLPROC;
typedef struct _WINDOWCLASS
@@ -46,10 +46,10 @@ typedef struct _WINDOWCLASS
ULONG_PTR ClassExtraDataOffset;
BOOL Destroying : 1;
BOOL Unicode : 1;
BOOL System : 1;
BOOL Global : 1;
UINT Destroying : 1;
UINT Unicode : 1;
UINT System : 1;
UINT Global : 1;
} WINDOWCLASS, *PWINDOWCLASS;
typedef struct _W32PROCESSINFO
@@ -37,6 +37,9 @@ 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. */
+81 -77
View File
@@ -89,7 +89,7 @@ CreateCallProc(IN PDESKTOP Desktop,
{
NewCallProc->pi = pi;
NewCallProc->WndProc = WndProc;
NewCallProc->Unicode = Unicode;
NewCallProc->Unicode = Unicode != FALSE;
}
return NewCallProc;
@@ -109,13 +109,11 @@ UserGetCallProcInfo(IN HANDLE hCallProc,
otCallProc);
if (CallProc == NULL)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
if (CallProc->pi != GetW32ProcessInfo())
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
return FALSE;
}
@@ -322,12 +320,69 @@ IntSetClassAtom(IN OUT PWINDOWCLASS Class,
return TRUE;
}
static WNDPROC
IntGetClassWndProc(IN PWINDOWCLASS Class,
IN PW32PROCESSINFO pi,
IN BOOL Ansi)
{
/* FIXME - assert for exclusive lock! */
if (Class->System)
{
return (Ansi ? Class->WndProcExtra : Class->WndProc);
}
else
{
if (!Ansi == Class->Unicode)
{
return Class->WndProc;
}
else
{
if (Class->CallProc != NULL)
{
return (WNDPROC)ObmObjectToHandle(Class->CallProc);
}
else
{
PCALLPROC NewCallProc, CallProc;
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,
pi);
if (NewCallProc == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
CallProc = InterlockedCompareExchangePointer(&Class->CallProc,
NewCallProc,
NULL);
if (CallProc != NULL)
{
DestroyCallProc(Class->Desktop,
NewCallProc);
}
return (WNDPROC)ObmObjectToHandle((CallProc == NULL ? NewCallProc : CallProc));
}
}
}
}
static WNDPROC
IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
IN WNDPROC WndProc,
IN BOOL Ansi)
{
WNDPROC Ret = Class->WndProc;
WNDPROC Ret;
if (Class->System)
{
@@ -336,6 +391,14 @@ IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
return NULL;
}
Ret = IntGetClassWndProc(Class,
GetW32ProcessInfo(),
Ansi);
if (Ret == NULL)
{
return NULL;
}
/* update the base class first */
Class = Class->Base;
@@ -733,61 +796,6 @@ IntFindClass(IN RTL_ATOM Atom,
return Class;
}
static WNDPROC
IntGetClassWndProc(IN PWINDOWCLASS Class,
IN PW32PROCESSINFO pi,
IN BOOL Ansi)
{
if (Class->System)
{
return (Ansi ? Class->WndProcExtra : Class->WndProc);
}
else
{
if (!Ansi == Class->Unicode)
{
return Class->WndProc;
}
else
{
if (Class->CallProc != NULL)
{
return (WNDPROC)ObmObjectToHandle(Class->CallProc);
}
else
{
PCALLPROC NewCallProc, CallProc;
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,
pi);
if (NewCallProc == NULL)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
CallProc = InterlockedCompareExchangePointer(&Class->CallProc,
NewCallProc,
NULL);
if (CallProc != NULL)
{
DestroyCallProc(Class->Desktop,
NewCallProc);
}
return (WNDPROC)ObmObjectToHandle((CallProc == NULL ? NewCallProc : CallProc));
}
}
}
}
RTL_ATOM
IntGetClassAtom(IN PUNICODE_STRING ClassName,
IN HINSTANCE hInstance OPTIONAL,
@@ -1760,22 +1768,9 @@ UserGetClassInfo(IN PWINDOWCLASS Class,
{
lpwcx->style = Class->Style;
if (Class->System)
{
lpwcx->lpfnWndProc = (!Ansi ? Class->WndProc : Class->WndProcExtra);
}
else
{
if (!Ansi == Class->Unicode)
{
lpwcx->lpfnWndProc = Class->WndProc;
}
else
{
/* FIXME - return callproc handle or function pointer? */
lpwcx->lpfnWndProc = Class->CallProc->WndProc;
}
}
lpwcx->lpfnWndProc = IntGetClassWndProc(Class,
GetW32ProcessInfo(),
Ansi);
lpwcx->cbClsExtra = Class->ClsExtra;
lpwcx->cbWndExtra = Class->WndExtra;
@@ -1917,7 +1912,14 @@ NtUserGetClassLong(IN HWND hWnd,
PWINDOW_OBJECT Window;
ULONG_PTR Ret = 0;
UserEnterShared();
if (Offset != GCLP_WNDPROC)
{
UserEnterShared();
}
else
{
UserEnterExclusive();
}
Window = UserGetWindowObject(hWnd);
if (Window != NULL)
@@ -2090,7 +2092,9 @@ NtUserGetClassInfo(
PW32PROCESSINFO pi;
BOOL Ret = FALSE;
UserEnterShared();
/* NOTE: need exclusive lock because getting the wndproc might require the
creation of a call procedure handle */
UserEnterExclusive();
pi = GetW32ProcessInfo();
if (pi == NULL)
@@ -380,7 +380,10 @@ NtUserDispatchMessage(PNTUSERDISPATCHMESSAGEINFO UnsafeMsgInfo)
Result = 0;
MsgInfo.Ansi = !Window->Unicode;
MsgInfo.Proc = Window->WndProc;
if (Window->IsSystem)
MsgInfo.Proc = (Window->Unicode ? Window->WndProc : Window->WndProcExtra);
else
MsgInfo.Proc = Window->WndProc;
}
}
}
@@ -1563,7 +1566,10 @@ co_IntDoSendMessage(HWND hWnd,
}
Info.Ansi = !Window->Unicode;
Info.Proc = Window->WndProc;
if (Window->IsSystem)
Info.Proc = (Window->Unicode ? Window->WndProc : Window->WndProcExtra);
else
Info.Proc = Window->WndProc;
}
else
{
+100 -29
View File
@@ -440,6 +440,13 @@ static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
Window->CallProc);
}
if (Window->CallProc2 != NULL)
{
DbgPrint("!!!!! Destroy call proc 0x%p\n", ObmObjectToHandle(Window->CallProc2));
DestroyCallProc(Window->ti->Desktop,
Window->CallProc2);
}
/* dereference the class */
IntDereferenceClass(Window->Class,
Window->ti->Desktop,
@@ -1572,17 +1579,10 @@ co_IntCreateWindowEx(DWORD dwExStyle,
Window->IsSystem = Class->System;
if (Class->System)
{
Window->Unicode = bUnicodeWindow;
if (bUnicodeWindow)
{
Window->WndProc = Class->WndProc;
Window->WndProcExtra = Class->WndProcExtra;
}
else
{
Window->WndProc = Class->WndProcExtra;
Window->WndProcExtra = Class->WndProc;
}
/* NOTE: Always create a unicode window for system classes! */
Window->Unicode = TRUE;
Window->WndProc = Class->WndProc;
Window->WndProcExtra = Class->WndProcExtra;
}
else
{
@@ -3422,7 +3422,93 @@ CLEANUP:
END_CLEANUP;
}
static WNDPROC
IntSetWindowProc(PWINDOW_OBJECT Window,
WNDPROC NewWndProc,
BOOL Ansi)
{
WNDPROC Ret;
/* attempt to get the previous window proc */
if (Window->IsSystem)
{
Ret = (Ansi ? Window->WndProcExtra : Window->WndProc);
}
else
{
if (!Ansi == Window->Unicode)
{
Ret = Window->WndProc;
}
else
{
/* allocate or update an existing call procedure handle to return
the old window proc */
if (Window->CallProc2 != 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)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
}
Ret = (WNDPROC)ObmObjectToHandle(Window->CallProc2);
DbgPrint("!!!!!!!! Returning handle 0x%p\n", Ret);
}
}
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;
Window->WndProcExtra = Window->Class->WndProcExtra;
Window->Unicode = !Ansi;
return Ret;
}
}
ASSERT(!Window->IsSystem);
/* update the window procedure */
Window->WndProc = NewWndProc;
if (Window->CallProc != NULL)
{
Window->CallProc->WndProc = NewWndProc;
Window->CallProc->Unicode = !Ansi;
}
Window->Unicode = !Ansi;
return Ret;
}
LONG FASTCALL
@@ -3490,24 +3576,9 @@ co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
case GWL_WNDPROC:
{
/* FIXME: should check if window belongs to current process */
if (Window->IsSystem)
{
/* the user changes the window procedure, the window is no longer
directly derived from the system class, because it no longer
uses independent window procedures for ansi and unicode */
Window->IsSystem = FALSE;
Window->CallProc = NULL;
}
/* update the window procedure */
OldValue = (LONG)Window->WndProc;
Window->WndProc = (WNDPROC)NewValue;
if (Window->CallProc != NULL)
{
Window->CallProc->WndProc = (WNDPROC)NewValue;
Window->CallProc->Unicode = !Ansi;
}
Window->Unicode = !Ansi;
OldValue = (LONG)IntSetWindowProc(Window,
(WNDPROC)NewValue,
Ansi);
break;
}