diff --git a/reactos/dll/win32/user32/windows/message.c b/reactos/dll/win32/user32/windows/message.c index a7921e5df35..add13934440 100644 --- a/reactos/dll/win32/user32/windows/message.c +++ b/reactos/dll/win32/user32/windows/message.c @@ -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)) { diff --git a/reactos/include/reactos/win32k/ntuser.h b/reactos/include/reactos/win32k/ntuser.h index 035ee7a985e..4e328ff818e 100644 --- a/reactos/include/reactos/win32k/ntuser.h +++ b/reactos/include/reactos/win32k/ntuser.h @@ -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 diff --git a/reactos/subsystems/win32/win32k/include/ssec.h b/reactos/subsystems/win32/win32k/include/ssec.h deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/reactos/subsystems/win32/win32k/include/window.h b/reactos/subsystems/win32/win32k/include/window.h index ae46e6998d2..74be462f6b2 100644 --- a/reactos/subsystems/win32/win32k/include/window.h +++ b/reactos/subsystems/win32/win32k/include/window.h @@ -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. */ diff --git a/reactos/subsystems/win32/win32k/ntuser/class.c b/reactos/subsystems/win32/win32k/ntuser/class.c index 25ffd83e49f..3fe2fbe5707 100644 --- a/reactos/subsystems/win32/win32k/ntuser/class.c +++ b/reactos/subsystems/win32/win32k/ntuser/class.c @@ -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) diff --git a/reactos/subsystems/win32/win32k/ntuser/message.c b/reactos/subsystems/win32/win32k/ntuser/message.c index 4bfeb369949..b6005ca0e63 100644 --- a/reactos/subsystems/win32/win32k/ntuser/message.c +++ b/reactos/subsystems/win32/win32k/ntuser/message.c @@ -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 { diff --git a/reactos/subsystems/win32/win32k/ntuser/window.c b/reactos/subsystems/win32/win32k/ntuser/window.c index e886057ade5..bc095aa54bd 100644 --- a/reactos/subsystems/win32/win32k/ntuser/window.c +++ b/reactos/subsystems/win32/win32k/ntuser/window.c @@ -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; }