mirror of
https://github.com/reactos/reactos.git
synced 2025-04-25 16:10:29 +00:00
-include/ndk/rtltypes.h: add MAX_ATOM_LEN define
-win32k: remove some NtUser syscalls and merge some NtUser syscalls -crt/include/internal/file.h: correct spelling -RtlAddAtomToAtomTable: check for max atom len -RtlQueryAtomInAtomTable: fix bug. somehow lock wasnt always released. -fix/reword windows classes impl. based on Wine. All but 2 winetests pass. -ntoskrnl/rtl/atom.c: add fixme about global atom table -remove desktop object lock -dont link windows into the class object -co_IntShellHookNotify: safely send notify messages -misc win32k reorg/cleanup svn path=/trunk/; revision=18022
This commit is contained in:
parent
ff4f5a654b
commit
5fa3cc8c0f
23 changed files with 780 additions and 881 deletions
|
@ -107,6 +107,8 @@
|
|||
#define NLS_MB_OEM_CODE_PAGE_TAG NlsMbOemCodePageTag
|
||||
#define NLS_OEM_LEAD_BYTE_INFO NlsOemLeadByteInfo
|
||||
|
||||
#define MAX_ATOM_LEN 255 /* TCHARS not including nullterm */
|
||||
|
||||
/* List Macros */
|
||||
static __inline
|
||||
VOID
|
||||
|
|
|
@ -212,7 +212,6 @@ NtUserCallOneParam(
|
|||
#define TWOPARAM_ROUTINE_UNKNOWN 0x54
|
||||
#define TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS 0x55
|
||||
#define TWOPARAM_ROUTINE_SWITCHTOTHISWINDOW 0x56
|
||||
#define TWOPARAM_ROUTINE_VALIDATERGN 0x57
|
||||
#define TWOPARAM_ROUTINE_SETWNDCONTEXTHLPID 0x58
|
||||
#define TWOPARAM_ROUTINE_SETCARETPOS 0x60
|
||||
#define TWOPARAM_ROUTINE_GETWINDOWINFO 0x61
|
||||
|
@ -894,11 +893,6 @@ NtUserGetWOWClass(
|
|||
DWORD Unknown0,
|
||||
DWORD Unknown1);
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserHideCaret(
|
||||
HWND hWnd);
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserImpersonateDdeClientWindow(
|
||||
|
@ -935,20 +929,6 @@ NtUserInternalGetWindowText(
|
|||
LPWSTR lpString,
|
||||
INT nMaxCount);
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserInvalidateRect(
|
||||
HWND hWnd,
|
||||
CONST RECT *lpRect,
|
||||
BOOL bErase);
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserInvalidateRgn(
|
||||
HWND hWnd,
|
||||
HRGN hRgn,
|
||||
BOOL bErase);
|
||||
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
|
@ -1575,7 +1555,8 @@ NtUserSetWinEventHook(
|
|||
BOOL
|
||||
STDCALL
|
||||
NtUserShowCaret(
|
||||
HWND hWnd);
|
||||
HWND hWnd,
|
||||
BOOL bShow);
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
|
@ -1681,9 +1662,6 @@ NtUserUpdateInstance(
|
|||
DWORD Unknown1,
|
||||
DWORD Unknown2);
|
||||
|
||||
BOOL STDCALL
|
||||
NtUserUpdateWindow( HWND hWnd );
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserUpdateLayeredWindow(
|
||||
|
@ -1715,10 +1693,6 @@ STDCALL
|
|||
NtUserValidateHandleSecure(
|
||||
DWORD Unknown0);
|
||||
|
||||
VOID STDCALL
|
||||
NtUserValidateRect(HWND Wnd, const RECT* Rect);
|
||||
|
||||
|
||||
DWORD
|
||||
STDCALL
|
||||
NtUserVkKeyScanEx(
|
||||
|
|
|
@ -102,7 +102,7 @@ typedef struct _FDINFO
|
|||
#define fdinfo_bucket_idx(i) ((i) >> FDINFO_ENTRIES_PER_BUCKET_SHIFT)
|
||||
/* get position inside a bucket (0-31) from an fd */
|
||||
#define fdinfo_bucket_entry_idx(i) ((i) & (FDINFO_ENTRIES_PER_BUCKET - 1))
|
||||
/* get bucket ptr. (ptr. to fist fdinfo inside a bucket) from an fd */
|
||||
/* get bucket ptr. (ptr. to first fdinfo inside a bucket) from an fd */
|
||||
#define fdinfo_bucket(i) ( __pioinfo[fdinfo_bucket_idx(i)])
|
||||
/* get fdinfo ptr. from an fd */
|
||||
#define fdinfo(i) (fdinfo_bucket(i) + fdinfo_bucket_entry_idx(i))
|
||||
|
|
|
@ -347,6 +347,12 @@ RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
|
|||
if (HashLink != NULL)
|
||||
{
|
||||
ULONG AtomNameLen = wcslen(AtomName);
|
||||
|
||||
if (AtomNameLen > MAX_ATOM_LEN)
|
||||
{
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Entry = RtlpAllocAtomTableEntry(sizeof(RTL_ATOM_TABLE_ENTRY) -
|
||||
sizeof(Entry->Name) +
|
||||
|
@ -390,7 +396,7 @@ RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
|
|||
Status = STATUS_OBJECT_NAME_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
RtlpUnlockAtomTable(AtomTable);
|
||||
|
||||
return Status;
|
||||
|
@ -592,6 +598,8 @@ RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
|
|||
PULONG NameLength)
|
||||
{
|
||||
ULONG Length;
|
||||
BOOL Unlock = FALSE;
|
||||
|
||||
union
|
||||
{
|
||||
/* A RTL_ATOM_TABLE_ENTRY has a "WCHAR Name[1]" entry at the end.
|
||||
|
@ -616,6 +624,7 @@ RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
|
|||
else
|
||||
{
|
||||
RtlpLockAtomTable(AtomTable);
|
||||
Unlock = TRUE;
|
||||
|
||||
Entry = RtlpGetAtomEntry(AtomTable,
|
||||
(ULONG)((USHORT)Atom - 0xC000));
|
||||
|
@ -676,10 +685,7 @@ RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
|
|||
Status = STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (NULL != Entry && Entry != &NumberEntry.AtomTableEntry)
|
||||
{
|
||||
RtlpUnlockAtomTable(AtomTable);
|
||||
}
|
||||
if (Unlock) RtlpUnlockAtomTable(AtomTable);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ GetCaretPos(LPPOINT lpPoint)
|
|||
BOOL STDCALL
|
||||
HideCaret(HWND hWnd)
|
||||
{
|
||||
return (BOOL)NtUserHideCaret(hWnd);
|
||||
return NtUserShowCaret(hWnd, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,7 +139,7 @@ SetCaretPos(int X,
|
|||
BOOL STDCALL
|
||||
ShowCaret(HWND hWnd)
|
||||
{
|
||||
return (BOOL)NtUserShowCaret(hWnd);
|
||||
return NtUserShowCaret(hWnd, TRUE);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -87,7 +87,14 @@ static BOOL GetClassInfoExCommon(
|
|||
|
||||
w.lpszMenuName = (LPCWSTR)&str2;
|
||||
w.lpszClassName = (LPCWSTR)&str3;
|
||||
|
||||
/* get info about system classes? */
|
||||
if (!hInst) hInst = User32Instance;
|
||||
|
||||
retval = (BOOL)NtUserGetClassInfo(hInst, str, &w, TRUE, 0);
|
||||
|
||||
w.hInstance = (hInst == User32Instance) ? 0 : hInst;
|
||||
|
||||
if ( !IS_ATOM(str) )
|
||||
HEAP_free(str);
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ InvalidateRect(
|
|||
CONST RECT *lpRect,
|
||||
BOOL bErase)
|
||||
{
|
||||
return NtUserInvalidateRect( hWnd, lpRect, bErase );
|
||||
return RedrawWindow( hWnd, lpRect, 0, RDW_INVALIDATE | (bErase ? RDW_ERASE : 0) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -171,7 +171,7 @@ InvalidateRgn(
|
|||
HRGN hRgn,
|
||||
BOOL bErase)
|
||||
{
|
||||
return NtUserInvalidateRgn( hWnd, hRgn, bErase );
|
||||
return RedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase ? RDW_ERASE : 0) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -224,7 +224,7 @@ STDCALL
|
|||
UpdateWindow(
|
||||
HWND hWnd)
|
||||
{
|
||||
return NtUserUpdateWindow( hWnd );
|
||||
return RedrawWindow( hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
|
||||
}
|
||||
|
||||
|
||||
|
@ -237,6 +237,8 @@ ValidateRect(
|
|||
HWND hWnd,
|
||||
CONST RECT *lpRect)
|
||||
{
|
||||
/* FIXME: should RDW_NOCHILDREN be included too? Ros used to,
|
||||
but Wine dont so i removed it... */
|
||||
return RedrawWindow(hWnd, lpRect, 0, RDW_VALIDATE);
|
||||
}
|
||||
|
||||
|
@ -250,7 +252,9 @@ ValidateRgn(
|
|||
HWND hWnd,
|
||||
HRGN hRgn)
|
||||
{
|
||||
return NtUserValidateRgn(hWnd, hRgn);
|
||||
/* FIXME: should RDW_NOCHILDREN be included too? Ros used to,
|
||||
but Wine dont so i removed it... */
|
||||
return RedrawWindow( hWnd, NULL, hRgn, RDW_VALIDATE );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ CreateWindowExA(DWORD dwExStyle,
|
|||
nHeight,
|
||||
hWndParent,
|
||||
hMenu,
|
||||
hInstance,
|
||||
hInstance,
|
||||
lpParam,
|
||||
SW_SHOW,
|
||||
FALSE);
|
||||
|
@ -304,7 +304,7 @@ CreateWindowExW(DWORD dwExStyle,
|
|||
nHeight,
|
||||
hWndParent,
|
||||
hMenu,
|
||||
hInstance,
|
||||
hInstance,
|
||||
lpParam,
|
||||
SW_SHOW,
|
||||
TRUE);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
|
||||
/* PROTOTYPES ****************************************************************/
|
||||
|
||||
static PRTL_ATOM_TABLE RtlpGetGlobalAtomTable(VOID);
|
||||
|
@ -38,6 +39,12 @@ RtlQueryAtomListInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
|
|||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
/* FIXME: this is WRONG! The global atom table should live in the WinSta struct
|
||||
* and accessed thru win32k callouts.
|
||||
* NOTE: There is a session/win32k global atom table also, but its private to
|
||||
* win32k. Its used for RegisterWindowMessage() and for window classes.
|
||||
* -Gunnar
|
||||
*/
|
||||
static PRTL_ATOM_TABLE GlobalAtomTable = NULL;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
typedef struct _WNDCLASS_OBJECT
|
||||
{
|
||||
UINT cbSize;
|
||||
LONG refs; /* windows using this class (is 0 after class creation) */
|
||||
UINT style;
|
||||
WNDPROC lpfnWndProcA;
|
||||
WNDPROC lpfnWndProcW;
|
||||
|
@ -21,10 +22,8 @@ typedef struct _WNDCLASS_OBJECT
|
|||
HICON hIconSm;
|
||||
BOOL Unicode;
|
||||
BOOL Global;
|
||||
LIST_ENTRY ListEntry;
|
||||
LIST_ENTRY ListEntry; /* linked into owning process */
|
||||
PCHAR ExtraData;
|
||||
/* list of windows */
|
||||
LIST_ENTRY ClassWindowsListHead;
|
||||
} WNDCLASS_OBJECT, *PWNDCLASS_OBJECT;
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
|
@ -33,24 +32,26 @@ InitClassImpl(VOID);
|
|||
NTSTATUS FASTCALL
|
||||
CleanupClassImpl(VOID);
|
||||
|
||||
#define ClassDereferenceObject(ClassObj) \
|
||||
ObmDereferenceObject(ClassObj)
|
||||
void FASTCALL DestroyProcessClasses(PW32PROCESS Process );
|
||||
|
||||
BOOL FASTCALL
|
||||
ClassReferenceClassByAtom(
|
||||
PWNDCLASS_OBJECT* Class,
|
||||
inline VOID FASTCALL
|
||||
ClassDerefObject(PWNDCLASS_OBJECT Class);
|
||||
|
||||
inline VOID FASTCALL
|
||||
ClassRefObject(PWNDCLASS_OBJECT Class);
|
||||
|
||||
PWNDCLASS_OBJECT FASTCALL
|
||||
ClassGetClassByAtom(
|
||||
RTL_ATOM Atom,
|
||||
HINSTANCE hInstance);
|
||||
|
||||
BOOL FASTCALL
|
||||
ClassReferenceClassByName(
|
||||
PWNDCLASS_OBJECT *Class,
|
||||
PWNDCLASS_OBJECT FASTCALL
|
||||
ClassGetClassByName(
|
||||
LPCWSTR ClassName,
|
||||
HINSTANCE hInstance);
|
||||
|
||||
BOOL FASTCALL
|
||||
ClassReferenceClassByNameOrAtom(
|
||||
PWNDCLASS_OBJECT *Class,
|
||||
PWNDCLASS_OBJECT FASTCALL
|
||||
ClassGetClassByNameOrAtom(
|
||||
LPCWSTR ClassNameOrAtom,
|
||||
HINSTANCE hInstance);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ typedef struct _DESKTOP_OBJECT
|
|||
CSHORT Type;
|
||||
CSHORT Size;
|
||||
LIST_ENTRY ListEntry;
|
||||
KSPIN_LOCK Lock;
|
||||
|
||||
UNICODE_STRING Name;
|
||||
/* Pointer to the associated window station. */
|
||||
struct _WINSTATION_OBJECT *WindowStation;
|
||||
|
|
|
@ -22,7 +22,7 @@ typedef struct _W32THREAD
|
|||
|
||||
typedef struct _W32PROCESS
|
||||
{
|
||||
LIST_ENTRY ClassListHead;
|
||||
LIST_ENTRY ClassList;
|
||||
LIST_ENTRY MenuListHead;
|
||||
FAST_MUTEX PrivateFontListLock;
|
||||
LIST_ENTRY PrivateFontListHead;
|
||||
|
|
|
@ -28,8 +28,6 @@ typedef struct _WINDOW_OBJECT
|
|||
{
|
||||
/* Pointer to the window class. */
|
||||
PWNDCLASS_OBJECT Class;
|
||||
/* entry in the window list of the class object */
|
||||
LIST_ENTRY ClassListEntry;
|
||||
/* Extended style. */
|
||||
DWORD ExStyle;
|
||||
/* Window name. */
|
||||
|
|
|
@ -70,7 +70,7 @@ Win32kProcessCallback(struct _EPROCESS *Process,
|
|||
{
|
||||
DPRINT("Creating W32 process PID:%d at IRQ level: %lu\n", Process->UniqueProcessId, KeGetCurrentIrql());
|
||||
|
||||
InitializeListHead(&Win32Process->ClassListHead);
|
||||
InitializeListHead(&Win32Process->ClassList);
|
||||
|
||||
InitializeListHead(&Win32Process->MenuListHead);
|
||||
|
||||
|
@ -99,7 +99,9 @@ Win32kProcessCallback(struct _EPROCESS *Process,
|
|||
IntCleanupCurIcons(Process, Win32Process);
|
||||
IntEngCleanupDriverObjs(Process, Win32Process);
|
||||
CleanupMonitorImpl();
|
||||
|
||||
|
||||
/* no process windows should exist at this point, or the function will assert! */
|
||||
DestroyProcessClasses(Win32Process);
|
||||
|
||||
GDI_CleanupForProcess(Process);
|
||||
|
||||
|
|
|
@ -9,17 +9,24 @@
|
|||
* 10/15/2003 Created
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <w32k.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* DEFINES *****************************************************************/
|
||||
|
||||
#define MIN_CARETBLINKRATE 100
|
||||
#define MAX_CARETBLINKRATE 10000
|
||||
#define DEFAULT_CARETBLINKRATE 530
|
||||
#define CARET_REGKEY L"\\Registry\\User\\.Default\\Control Panel\\Desktop"
|
||||
#define CARET_VALUENAME L"CursorBlinkRate"
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
static
|
||||
BOOL FASTCALL
|
||||
co_IntHideCaret(PTHRDCARETINFO CaretInfo)
|
||||
{
|
||||
|
@ -69,6 +76,7 @@ IntSetCaretBlinkTime(UINT uMSeconds)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
UINT FASTCALL
|
||||
IntQueryCaretBlinkRate(VOID)
|
||||
{
|
||||
|
@ -134,6 +142,7 @@ IntQueryCaretBlinkRate(VOID)
|
|||
return (UINT)Val;
|
||||
}
|
||||
|
||||
static
|
||||
UINT FASTCALL
|
||||
IntGetCaretBlinkTime(VOID)
|
||||
{
|
||||
|
@ -158,6 +167,7 @@ IntGetCaretBlinkTime(VOID)
|
|||
return Ret;
|
||||
}
|
||||
|
||||
|
||||
BOOL FASTCALL
|
||||
co_IntSetCaretPos(int X, int Y)
|
||||
{
|
||||
|
@ -197,6 +207,8 @@ IntSwitchCaretShowing(PVOID Info)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#if 0 //unused
|
||||
static
|
||||
VOID FASTCALL
|
||||
co_IntDrawCaret(HWND hWnd)
|
||||
{
|
||||
|
@ -210,9 +222,79 @@ co_IntDrawCaret(HWND hWnd)
|
|||
ThreadQueue->CaretInfo->Showing = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
BOOL FASTCALL co_UserHideCaret(PWINDOW_OBJECT Window OPTIONAL)
|
||||
{
|
||||
PUSER_MESSAGE_QUEUE ThreadQueue;
|
||||
|
||||
if (Window) ASSERT_REFS_CO(Window);
|
||||
|
||||
if(Window && Window->OwnerThread != PsGetCurrentThread())
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
||||
|
||||
if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(ThreadQueue->CaretInfo->Visible)
|
||||
{
|
||||
IntKillTimer(ThreadQueue->CaretInfo->hWnd, IDCARETTIMER, TRUE);
|
||||
|
||||
co_IntHideCaret(ThreadQueue->CaretInfo);
|
||||
ThreadQueue->CaretInfo->Visible = 0;
|
||||
ThreadQueue->CaretInfo->Showing = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL FASTCALL co_UserShowCaret(PWINDOW_OBJECT Window OPTIONAL)
|
||||
{
|
||||
PUSER_MESSAGE_QUEUE ThreadQueue;
|
||||
|
||||
if (Window) ASSERT_REFS_CO(Window);
|
||||
|
||||
if(Window && Window->OwnerThread != PsGetCurrentThread())
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
||||
|
||||
if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!ThreadQueue->CaretInfo->Visible)
|
||||
{
|
||||
ThreadQueue->CaretInfo->Visible = 1;
|
||||
if(!ThreadQueue->CaretInfo->Showing)
|
||||
{
|
||||
co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
|
||||
}
|
||||
IntSetTimer(ThreadQueue->CaretInfo->hWnd, IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* SYSCALLS *****************************************************************/
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserCreateCaret(
|
||||
|
@ -317,105 +399,10 @@ CLEANUP:
|
|||
}
|
||||
|
||||
|
||||
BOOL FASTCALL co_UserHideCaret(PWINDOW_OBJECT Window OPTIONAL)
|
||||
{
|
||||
PUSER_MESSAGE_QUEUE ThreadQueue;
|
||||
|
||||
if (Window) ASSERT_REFS_CO(Window);
|
||||
|
||||
if(Window && Window->OwnerThread != PsGetCurrentThread())
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
||||
|
||||
if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(ThreadQueue->CaretInfo->Visible)
|
||||
{
|
||||
IntKillTimer((Window ? Window->hSelf : 0), IDCARETTIMER, TRUE);
|
||||
|
||||
co_IntHideCaret(ThreadQueue->CaretInfo);
|
||||
ThreadQueue->CaretInfo->Visible = 0;
|
||||
ThreadQueue->CaretInfo->Showing = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserHideCaret(HWND hWnd OPTIONAL)
|
||||
{
|
||||
PWINDOW_OBJECT Window = NULL;
|
||||
DECLARE_RETURN(BOOL);
|
||||
BOOL ret;
|
||||
|
||||
DPRINT("Enter NtUserHideCaret\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
if(hWnd && !(Window = UserGetWindowObject(hWnd)))
|
||||
{
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
if (Window) UserRefObjectCo(Window);
|
||||
ret = co_UserHideCaret(Window);
|
||||
if (Window) UserDerefObjectCo(Window);
|
||||
|
||||
RETURN(ret);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserHideCaret, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
||||
BOOL FASTCALL co_UserShowCaret(PWINDOW_OBJECT Window OPTIONAL)
|
||||
{
|
||||
PUSER_MESSAGE_QUEUE ThreadQueue;
|
||||
|
||||
if (Window) ASSERT_REFS_CO(Window);
|
||||
|
||||
if(Window && Window->OwnerThread != PsGetCurrentThread())
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
|
||||
|
||||
if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
|
||||
{
|
||||
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!ThreadQueue->CaretInfo->Visible)
|
||||
{
|
||||
ThreadQueue->CaretInfo->Visible = 1;
|
||||
if(!ThreadQueue->CaretInfo->Showing)
|
||||
{
|
||||
co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
|
||||
}
|
||||
IntSetTimer((Window ? Window->hSelf : 0), IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
STDCALL
|
||||
NtUserShowCaret(HWND hWnd OPTIONAL)
|
||||
NtUserShowCaret(HWND hWnd OPTIONAL, BOOL bShow)
|
||||
{
|
||||
PWINDOW_OBJECT Window = NULL;
|
||||
DECLARE_RETURN(BOOL);
|
||||
|
@ -430,7 +417,12 @@ NtUserShowCaret(HWND hWnd OPTIONAL)
|
|||
}
|
||||
|
||||
if (Window) UserRefObjectCo(Window);
|
||||
ret = co_UserShowCaret(Window);
|
||||
|
||||
if (bShow)
|
||||
ret = co_UserShowCaret(Window);
|
||||
else
|
||||
ret = co_UserHideCaret(Window);
|
||||
|
||||
if (Window) UserDerefObjectCo(Window);
|
||||
|
||||
RETURN(ret);
|
||||
|
|
|
@ -47,64 +47,85 @@ CleanupClassImpl(VOID)
|
|||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
BOOL FASTCALL
|
||||
ClassReferenceClassByAtom(
|
||||
PWNDCLASS_OBJECT* Class,
|
||||
RTL_ATOM Atom,
|
||||
HINSTANCE hInstance)
|
||||
|
||||
/* return TRUE if class became destroyed */
|
||||
inline VOID FASTCALL
|
||||
ClassDerefObject(PWNDCLASS_OBJECT Class)
|
||||
{
|
||||
PWNDCLASS_OBJECT Current, BestMatch = NULL;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PW32PROCESS Process = PsGetWin32Process();
|
||||
|
||||
CurrentEntry = Process->ClassListHead.Flink;
|
||||
while (CurrentEntry != &Process->ClassListHead)
|
||||
{
|
||||
Current = CONTAINING_RECORD(CurrentEntry, WNDCLASS_OBJECT, ListEntry);
|
||||
|
||||
if (Current->Atom == Atom && (hInstance == NULL || Current->hInstance == hInstance))
|
||||
{
|
||||
*Class = Current;
|
||||
ObmReferenceObject(Current);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (Current->Atom == Atom && Current->Global)
|
||||
BestMatch = Current;
|
||||
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
|
||||
if (BestMatch != NULL)
|
||||
{
|
||||
*Class = BestMatch;
|
||||
ObmReferenceObject(BestMatch);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
ASSERT(Class->refs >= 1);
|
||||
Class->refs--;
|
||||
}
|
||||
|
||||
BOOL FASTCALL
|
||||
ClassReferenceClassByName(
|
||||
PWNDCLASS_OBJECT *Class,
|
||||
LPCWSTR ClassName,
|
||||
HINSTANCE hInstance)
|
||||
|
||||
inline VOID FASTCALL
|
||||
ClassRefObject(PWNDCLASS_OBJECT Class)
|
||||
{
|
||||
PWINSTATION_OBJECT WinStaObject;
|
||||
ASSERT(Class->refs >= 0);
|
||||
Class->refs++;
|
||||
}
|
||||
|
||||
|
||||
VOID FASTCALL DestroyClass(PWNDCLASS_OBJECT Class)
|
||||
{
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
ASSERT(Class->refs == 0);
|
||||
RemoveEntryList(&Class->ListEntry);
|
||||
//FIXME: release ATOM
|
||||
RtlDeleteAtomFromAtomTable(WinSta->AtomTable, Class->Atom);
|
||||
ExFreePool(Class);
|
||||
}
|
||||
|
||||
|
||||
/* clean all process classes. all process windows must cleaned first!! */
|
||||
void FASTCALL DestroyProcessClasses(PW32PROCESS Process )
|
||||
{
|
||||
PWNDCLASS_OBJECT Class;
|
||||
|
||||
while (!IsListEmpty(&Process->ClassList))
|
||||
{
|
||||
Class = CONTAINING_RECORD(RemoveHeadList(&Process->ClassList), WNDCLASS_OBJECT, ListEntry);
|
||||
DestroyClass(Class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PWNDCLASS_OBJECT FASTCALL
|
||||
ClassGetClassByAtom(RTL_ATOM Atom, HINSTANCE hInstance)
|
||||
{
|
||||
PWNDCLASS_OBJECT Class;
|
||||
PW32PROCESS Process = PsGetWin32Process();
|
||||
|
||||
LIST_FOR_EACH(Class, &Process->ClassList, WNDCLASS_OBJECT, ListEntry)
|
||||
{
|
||||
if (Class->Atom != Atom) continue;
|
||||
|
||||
if (!hInstance || Class->Global || Class->hInstance == hInstance) return Class;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PWNDCLASS_OBJECT FASTCALL
|
||||
ClassGetClassByName(LPCWSTR ClassName, HINSTANCE hInstance)
|
||||
{
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
NTSTATUS Status;
|
||||
BOOL Found;
|
||||
RTL_ATOM ClassAtom;
|
||||
RTL_ATOM Atom;
|
||||
|
||||
if (!ClassName || !PsGetWin32Thread()->Desktop)
|
||||
return FALSE;
|
||||
|
||||
WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
Status = RtlLookupAtomInAtomTable(
|
||||
WinStaObject->AtomTable,
|
||||
WinSta->AtomTable,
|
||||
(LPWSTR)ClassName,
|
||||
&ClassAtom);
|
||||
&Atom);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
|
@ -112,369 +133,136 @@ ClassReferenceClassByName(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
Found = ClassReferenceClassByAtom(Class, ClassAtom, hInstance);
|
||||
|
||||
return Found;
|
||||
return ClassGetClassByAtom(Atom, hInstance);
|
||||
}
|
||||
|
||||
BOOL FASTCALL
|
||||
ClassReferenceClassByNameOrAtom(
|
||||
PWNDCLASS_OBJECT *Class,
|
||||
LPCWSTR ClassNameOrAtom,
|
||||
HINSTANCE hInstance)
|
||||
{
|
||||
BOOL Found;
|
||||
|
||||
if (IS_ATOM(ClassNameOrAtom))
|
||||
Found = ClassReferenceClassByAtom(Class, (RTL_ATOM)((ULONG_PTR)ClassNameOrAtom), hInstance);
|
||||
else
|
||||
Found = ClassReferenceClassByName(Class, ClassNameOrAtom, hInstance);
|
||||
|
||||
return Found;
|
||||
}
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetClassInfo(
|
||||
HINSTANCE hInstance,
|
||||
LPCWSTR lpClassName,
|
||||
LPWNDCLASSEXW lpWndClassEx,
|
||||
BOOL Ansi,
|
||||
DWORD unknown3)
|
||||
{
|
||||
PWNDCLASS_OBJECT Class;
|
||||
RTL_ATOM Atom;
|
||||
DECLARE_RETURN(DWORD);
|
||||
|
||||
if (IS_ATOM(lpClassName))
|
||||
DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName, hInstance);
|
||||
else
|
||||
DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName, hInstance);
|
||||
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!ClassReferenceClassByNameOrAtom(&Class, lpClassName, hInstance))
|
||||
{
|
||||
SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
lpWndClassEx->cbSize = sizeof(WNDCLASSEXW);
|
||||
lpWndClassEx->style = Class->style;
|
||||
if (Ansi)
|
||||
lpWndClassEx->lpfnWndProc = Class->lpfnWndProcA;
|
||||
else
|
||||
lpWndClassEx->lpfnWndProc = Class->lpfnWndProcW;
|
||||
lpWndClassEx->cbClsExtra = Class->cbClsExtra;
|
||||
lpWndClassEx->cbWndExtra = Class->cbWndExtra;
|
||||
/* This is not typo, we're really not going to use Class->hInstance here. */
|
||||
lpWndClassEx->hInstance = hInstance;
|
||||
lpWndClassEx->hIcon = Class->hIcon;
|
||||
lpWndClassEx->hCursor = Class->hCursor;
|
||||
lpWndClassEx->hbrBackground = Class->hbrBackground;
|
||||
if (Class->lpszMenuName.MaximumLength)
|
||||
RtlCopyUnicodeString((PUNICODE_STRING)lpWndClassEx->lpszMenuName, &Class->lpszMenuName);
|
||||
else
|
||||
lpWndClassEx->lpszMenuName = Class->lpszMenuName.Buffer;
|
||||
lpWndClassEx->lpszClassName = lpClassName;
|
||||
lpWndClassEx->hIconSm = Class->hIconSm;
|
||||
Atom = Class->Atom;
|
||||
|
||||
ObmDereferenceObject(Class);
|
||||
|
||||
RETURN(Atom);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
ULONG FASTCALL
|
||||
IntGetClassName(struct _WINDOW_OBJECT *WindowObject, LPWSTR lpClassName,
|
||||
ULONG nMaxCount)
|
||||
{
|
||||
ULONG Length;
|
||||
LPWSTR Name;
|
||||
PWINSTATION_OBJECT WinStaObject;
|
||||
NTSTATUS Status;
|
||||
|
||||
if(!PsGetWin32Thread()->Desktop)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
Length = 0;
|
||||
Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,
|
||||
WindowObject->Class->Atom, NULL, NULL,
|
||||
NULL, &Length);
|
||||
Length += sizeof(WCHAR);
|
||||
Name = ExAllocatePoolWithTag(PagedPool, Length, TAG_STRING);
|
||||
Status = RtlQueryAtomInAtomTable(WinStaObject->AtomTable,
|
||||
WindowObject->Class->Atom, NULL, NULL,
|
||||
Name, &Length);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("IntGetClassName: RtlQueryAtomInAtomTable failed\n");
|
||||
return 0;
|
||||
}
|
||||
Length /= sizeof(WCHAR);
|
||||
if (Length > nMaxCount)
|
||||
{
|
||||
Length = nMaxCount;
|
||||
}
|
||||
wcsncpy(lpClassName, Name, Length);
|
||||
/* FIXME: Check buffer size before doing this! */
|
||||
*(lpClassName + Length) = 0;
|
||||
ExFreePool(Name);
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetClassName (
|
||||
HWND hWnd,
|
||||
LPWSTR lpClassName,
|
||||
ULONG nMaxCount)
|
||||
{
|
||||
PWINDOW_OBJECT Window;
|
||||
DECLARE_RETURN(DWORD);
|
||||
|
||||
UserEnterShared();
|
||||
DPRINT("Enter NtUserGetClassName\n");
|
||||
|
||||
if (!(Window = UserGetWindowObject(hWnd)))
|
||||
{
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
RETURN( IntGetClassName(Window, lpClassName, nMaxCount));
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetWOWClass(DWORD Unknown0,
|
||||
DWORD Unknown1)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(0);
|
||||
}
|
||||
|
||||
PWNDCLASS_OBJECT FASTCALL
|
||||
IntCreateClass(
|
||||
ClassGetClassByNameOrAtom(LPCWSTR ClassNameOrAtom, HINSTANCE hInstance)
|
||||
{
|
||||
if (!ClassNameOrAtom) return NULL;
|
||||
|
||||
if (IS_ATOM(ClassNameOrAtom))
|
||||
return ClassGetClassByAtom((RTL_ATOM)((ULONG_PTR)ClassNameOrAtom), hInstance);
|
||||
else
|
||||
return ClassGetClassByName(ClassNameOrAtom, hInstance);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
BOOL FASTCALL
|
||||
IntRegisterClass(
|
||||
CONST WNDCLASSEXW *lpwcx,
|
||||
DWORD Flags,
|
||||
WNDPROC wpExtra,
|
||||
PUNICODE_STRING MenuName,
|
||||
RTL_ATOM Atom)
|
||||
{
|
||||
PWNDCLASS_OBJECT ClassObject;
|
||||
PWNDCLASS_OBJECT Class;
|
||||
ULONG objectSize;
|
||||
BOOL Global;
|
||||
|
||||
Global = (Flags & REGISTERCLASS_SYSTEM) || (lpwcx->style & CS_GLOBALCLASS) ? TRUE : FALSE;
|
||||
ASSERT(lpwcx);
|
||||
ASSERT(Atom);
|
||||
ASSERT(lpwcx->hInstance);
|
||||
|
||||
Global = (Flags & REGISTERCLASS_SYSTEM) || (lpwcx->style & CS_GLOBALCLASS);
|
||||
|
||||
/* Check for double registration of the class. */
|
||||
if (PsGetWin32Process() != NULL)
|
||||
Class = ClassGetClassByAtom(Atom, lpwcx->hInstance);
|
||||
if (Class && Global == Class->Global)
|
||||
{
|
||||
if (ClassReferenceClassByAtom(&ClassObject, Atom, lpwcx->hInstance))
|
||||
{
|
||||
/*
|
||||
* NOTE: We may also get a global class from
|
||||
* ClassReferenceClassByAtom. This simple check
|
||||
* prevents that we fail valid request.
|
||||
*/
|
||||
if (ClassObject->hInstance == lpwcx->hInstance)
|
||||
{
|
||||
SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
|
||||
ObmDereferenceObject(ClassObject);
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
/* can max have one class of each type (global/local) */
|
||||
SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
objectSize = sizeof(WNDCLASS_OBJECT) + lpwcx->cbClsExtra;
|
||||
ClassObject = ObmCreateObject(&gHandleTable, NULL, otClass, objectSize);
|
||||
if (ClassObject == 0)
|
||||
|
||||
//FIXME: allocate in session heap (or possibly desktop heap)
|
||||
Class = ExAllocatePool(PagedPool, objectSize);
|
||||
if (!Class)
|
||||
{
|
||||
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return(NULL);
|
||||
return(FALSE);
|
||||
}
|
||||
RtlZeroMemory(Class, objectSize);
|
||||
|
||||
ClassObject->cbSize = lpwcx->cbSize;
|
||||
ClassObject->style = lpwcx->style;
|
||||
ClassObject->cbClsExtra = lpwcx->cbClsExtra;
|
||||
ClassObject->cbWndExtra = lpwcx->cbWndExtra;
|
||||
ClassObject->hInstance = lpwcx->hInstance;
|
||||
ClassObject->hIcon = lpwcx->hIcon;
|
||||
ClassObject->hCursor = lpwcx->hCursor;
|
||||
ClassObject->hbrBackground = lpwcx->hbrBackground;
|
||||
ClassObject->Unicode = !(Flags & REGISTERCLASS_ANSI);
|
||||
ClassObject->Global = Global;
|
||||
ClassObject->hIconSm = lpwcx->hIconSm;
|
||||
ClassObject->Atom = Atom;
|
||||
Class->cbSize = lpwcx->cbSize;
|
||||
Class->style = lpwcx->style;
|
||||
Class->cbClsExtra = lpwcx->cbClsExtra;
|
||||
Class->cbWndExtra = lpwcx->cbWndExtra;
|
||||
Class->hInstance = lpwcx->hInstance;
|
||||
Class->hIcon = lpwcx->hIcon;
|
||||
Class->hCursor = lpwcx->hCursor;
|
||||
Class->hbrBackground = lpwcx->hbrBackground;
|
||||
Class->Unicode = !(Flags & REGISTERCLASS_ANSI);
|
||||
Class->Global = Global;
|
||||
Class->hIconSm = lpwcx->hIconSm;
|
||||
Class->Atom = Atom;
|
||||
|
||||
if (wpExtra == NULL)
|
||||
{
|
||||
if (Flags & REGISTERCLASS_ANSI)
|
||||
{
|
||||
ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
|
||||
ClassObject->lpfnWndProcW = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,FALSE);
|
||||
Class->lpfnWndProcA = lpwcx->lpfnWndProc;
|
||||
Class->lpfnWndProcW = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
|
||||
ClassObject->lpfnWndProcA = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,TRUE);
|
||||
Class->lpfnWndProcW = lpwcx->lpfnWndProc;
|
||||
Class->lpfnWndProcA = (WNDPROC)IntAddWndProcHandle(lpwcx->lpfnWndProc,TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Flags & REGISTERCLASS_ANSI)
|
||||
{
|
||||
ClassObject->lpfnWndProcA = lpwcx->lpfnWndProc;
|
||||
ClassObject->lpfnWndProcW = wpExtra;
|
||||
Class->lpfnWndProcA = lpwcx->lpfnWndProc;
|
||||
Class->lpfnWndProcW = wpExtra;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassObject->lpfnWndProcW = lpwcx->lpfnWndProc;
|
||||
ClassObject->lpfnWndProcA = wpExtra;
|
||||
Class->lpfnWndProcW = lpwcx->lpfnWndProc;
|
||||
Class->lpfnWndProcA = wpExtra;
|
||||
}
|
||||
}
|
||||
|
||||
if (MenuName->Length == 0)
|
||||
{
|
||||
ClassObject->lpszMenuName.Length =
|
||||
ClassObject->lpszMenuName.MaximumLength = 0;
|
||||
ClassObject->lpszMenuName.Buffer = MenuName->Buffer;
|
||||
Class->lpszMenuName.Length =
|
||||
Class->lpszMenuName.MaximumLength = 0;
|
||||
Class->lpszMenuName.Buffer = MenuName->Buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassObject->lpszMenuName.Length =
|
||||
ClassObject->lpszMenuName.MaximumLength = MenuName->MaximumLength;
|
||||
ClassObject->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, ClassObject->lpszMenuName.MaximumLength, TAG_STRING);
|
||||
RtlCopyUnicodeString(&ClassObject->lpszMenuName, MenuName);
|
||||
Class->lpszMenuName.Length =
|
||||
Class->lpszMenuName.MaximumLength = MenuName->MaximumLength;
|
||||
Class->lpszMenuName.Buffer = ExAllocatePoolWithTag(PagedPool, Class->lpszMenuName.MaximumLength, TAG_STRING);
|
||||
RtlCopyUnicodeString(&Class->lpszMenuName, MenuName);
|
||||
}
|
||||
|
||||
/* Extra class data */
|
||||
if (ClassObject->cbClsExtra != 0)
|
||||
if (Class->cbClsExtra)
|
||||
Class->ExtraData = (PCHAR)(Class + 1);
|
||||
|
||||
if (Global)
|
||||
{
|
||||
ClassObject->ExtraData = (PCHAR)(ClassObject + 1);
|
||||
RtlZeroMemory(ClassObject->ExtraData, (ULONG)ClassObject->cbClsExtra);
|
||||
/* global classes go last (incl. system classes) */
|
||||
InsertTailList(&PsGetWin32Process()->ClassList, &Class->ListEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassObject->ExtraData = NULL;
|
||||
/* local classes have priority so we put them first */
|
||||
InsertHeadList(&PsGetWin32Process()->ClassList, &Class->ListEntry);
|
||||
}
|
||||
|
||||
InitializeListHead(&ClassObject->ClassWindowsListHead);
|
||||
|
||||
return(ClassObject);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
RTL_ATOM STDCALL
|
||||
NtUserRegisterClassExWOW(
|
||||
CONST WNDCLASSEXW* lpwcx,
|
||||
PUNICODE_STRING ClassName,
|
||||
PUNICODE_STRING ClassNameCopy,
|
||||
PUNICODE_STRING MenuName,
|
||||
WNDPROC wpExtra, /* FIXME: Windows uses this parameter for something different. */
|
||||
DWORD Flags,
|
||||
DWORD Unknown7)
|
||||
|
||||
/*
|
||||
* FUNCTION:
|
||||
* Registers a new class with the window manager
|
||||
* ARGUMENTS:
|
||||
* lpwcx = Win32 extended window class structure
|
||||
* bUnicodeClass = Whether to send ANSI or unicode strings
|
||||
* to window procedures
|
||||
* wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
|
||||
* RETURNS:
|
||||
* Atom identifying the new class
|
||||
*/
|
||||
{
|
||||
WNDCLASSEXW SafeClass;
|
||||
PWINSTATION_OBJECT WinStaObject;
|
||||
PWNDCLASS_OBJECT ClassObject;
|
||||
NTSTATUS Status;
|
||||
RTL_ATOM Atom;
|
||||
DECLARE_RETURN(RTL_ATOM);
|
||||
|
||||
DPRINT("Enter NtUserRegisterClassExWOW\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!lpwcx)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
if (Flags & ~REGISTERCLASS_ALL)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_FLAGS);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
Status = MmCopyFromCaller(&SafeClass, lpwcx, sizeof(WNDCLASSEXW));
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastNtError(Status);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
/* Deny negative sizes */
|
||||
if (lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
if (ClassName->Length > 0)
|
||||
{
|
||||
DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer);
|
||||
/* FIXME - Safely copy/verify the buffer first!!! */
|
||||
Status = RtlAddAtomToAtomTable(WinStaObject->AtomTable,
|
||||
ClassName->Buffer,
|
||||
&Atom);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed adding class name (%S) to atom table\n",
|
||||
ClassName->Buffer);
|
||||
SetLastNtError(Status);
|
||||
RETURN((RTL_ATOM)0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Atom = (RTL_ATOM)(ULONG)ClassName->Buffer;
|
||||
}
|
||||
ClassObject = IntCreateClass(&SafeClass, Flags, wpExtra, MenuName, Atom);
|
||||
if (ClassObject == NULL)
|
||||
{
|
||||
if (ClassName->Length)
|
||||
{
|
||||
RtlDeleteAtomFromAtomTable(WinStaObject->AtomTable, Atom);
|
||||
}
|
||||
DPRINT("Failed creating window class object\n");
|
||||
RETURN((RTL_ATOM)0);
|
||||
}
|
||||
|
||||
InsertTailList(&PsGetWin32Process()->ClassListHead, &ClassObject->ListEntry);
|
||||
|
||||
RETURN(Atom);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
ULONG FASTCALL
|
||||
IntGetClassLong(struct _WINDOW_OBJECT *Window, ULONG Offset, BOOL Ansi)
|
||||
IntGetClassLong(PWINDOW_OBJECT Window, ULONG Offset, BOOL Ansi)
|
||||
{
|
||||
LONG Ret;
|
||||
|
||||
|
@ -540,28 +328,7 @@ IntGetClassLong(struct _WINDOW_OBJECT *Window, ULONG Offset, BOOL Ansi)
|
|||
return(Ret);
|
||||
}
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
|
||||
{
|
||||
PWINDOW_OBJECT Window;
|
||||
DECLARE_RETURN(DWORD);
|
||||
|
||||
DPRINT("Enter NtUserGetClassLong\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!(Window = UserGetWindowObject(hWnd)))
|
||||
{
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
RETURN(IntGetClassLong(Window, Offset, Ansi));
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
static
|
||||
void FASTCALL
|
||||
co_IntSetClassLong(PWINDOW_OBJECT Window, ULONG Offset, LONG dwNewLong, BOOL Ansi)
|
||||
{
|
||||
|
@ -643,6 +410,144 @@ co_IntSetClassLong(PWINDOW_OBJECT Window, ULONG Offset, LONG dwNewLong, BOOL Ans
|
|||
break;
|
||||
}
|
||||
}
|
||||
/* SYSCALLS *****************************************************************/
|
||||
|
||||
|
||||
RTL_ATOM STDCALL
|
||||
NtUserRegisterClassExWOW(
|
||||
CONST WNDCLASSEXW* lpwcx,
|
||||
PUNICODE_STRING ClassName,
|
||||
PUNICODE_STRING ClassNameCopy,//huhuhuhu???
|
||||
PUNICODE_STRING MenuName,
|
||||
WNDPROC wpExtra,
|
||||
DWORD Flags,
|
||||
DWORD Unknown7)
|
||||
|
||||
/*
|
||||
* FUNCTION:
|
||||
* Registers a new class with the window manager
|
||||
* ARGUMENTS:
|
||||
* lpwcx = Win32 extended window class structure
|
||||
* bUnicodeClass = Whether to send ANSI or unicode strings
|
||||
* to window procedures
|
||||
* wpExtra = Extra window procedure, if this is not null, its used for the second window procedure for standard controls.
|
||||
* RETURNS:
|
||||
* Atom identifying the new class
|
||||
*/
|
||||
{
|
||||
WNDCLASSEXW SafeClass;
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
NTSTATUS Status;
|
||||
RTL_ATOM Atom;
|
||||
DECLARE_RETURN(RTL_ATOM);
|
||||
|
||||
DPRINT("Enter NtUserRegisterClassExWOW\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!lpwcx)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
if (Flags & ~REGISTERCLASS_ALL)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_FLAGS);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
Status = MmCopyFromCaller(&SafeClass, lpwcx, sizeof(WNDCLASSEXW));
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastNtError(Status);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
/* Deny negative sizes */
|
||||
if (lpwcx->cbClsExtra < 0 || lpwcx->cbWndExtra < 0)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
if (!lpwcx->hInstance)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN( (RTL_ATOM)0);
|
||||
}
|
||||
|
||||
WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
//FIXME: make ClassName ptr the atom, not buffer
|
||||
if (ClassName->Length > 0)
|
||||
{
|
||||
DPRINT("NtUserRegisterClassExWOW(%S)\n", ClassName->Buffer);
|
||||
/* FIXME - Safely copy/verify the buffer first!!! */
|
||||
Status = RtlAddAtomToAtomTable(WinSta->AtomTable,
|
||||
ClassName->Buffer,
|
||||
&Atom);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed adding class name (%S) to atom table\n",
|
||||
ClassName->Buffer);
|
||||
SetLastNtError(Status);
|
||||
RETURN((RTL_ATOM)0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Atom = (RTL_ATOM)(ULONG)ClassName->Buffer;
|
||||
}
|
||||
|
||||
if (!Atom)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
if (!IntRegisterClass(&SafeClass, Flags, wpExtra, MenuName, Atom))
|
||||
{
|
||||
if (ClassName->Length)
|
||||
{
|
||||
RtlDeleteAtomFromAtomTable(WinSta->AtomTable, Atom);
|
||||
}
|
||||
DPRINT("Failed creating window class object\n");
|
||||
RETURN((RTL_ATOM)0);
|
||||
}
|
||||
|
||||
RETURN(Atom);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserRegisterClassExWOW, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetClassLong(HWND hWnd, DWORD Offset, BOOL Ansi)
|
||||
{
|
||||
PWINDOW_OBJECT Window;
|
||||
DECLARE_RETURN(DWORD);
|
||||
|
||||
DPRINT("Enter NtUserGetClassLong\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!(Window = UserGetWindowObject(hWnd)))
|
||||
{
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
RETURN(IntGetClassLong(Window, Offset, Ansi));
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetClassLong, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserSetClassLong(HWND hWnd,
|
||||
|
@ -689,56 +594,50 @@ NtUserSetClassWord(DWORD Unknown0,
|
|||
BOOL STDCALL
|
||||
NtUserUnregisterClass(
|
||||
LPCWSTR ClassNameOrAtom,
|
||||
HINSTANCE hInstance,
|
||||
HINSTANCE hInstance, /* can be 0 */
|
||||
DWORD Unknown)
|
||||
{
|
||||
PWNDCLASS_OBJECT Class;
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
DECLARE_RETURN(BOOL);
|
||||
|
||||
DPRINT("Enter NtUserUnregisterClass(%S)\n", ClassNameOrAtom);
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!ClassNameOrAtom || !PsGetWin32Thread()->Desktop)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN( FALSE);
|
||||
}
|
||||
|
||||
WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
if (!ClassReferenceClassByNameOrAtom(&Class, ClassNameOrAtom, hInstance))
|
||||
if (!ClassNameOrAtom)
|
||||
{
|
||||
SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
|
||||
RETURN( FALSE);
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
if (Class->hInstance && Class->hInstance != hInstance)
|
||||
if (!(Class = ClassGetClassByNameOrAtom(ClassNameOrAtom, hInstance)))
|
||||
{
|
||||
ClassDereferenceObject(Class);
|
||||
SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
|
||||
RETURN( FALSE);
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
if (!IsListEmpty(&Class->ClassWindowsListHead))
|
||||
/* this was probably ment to prevent sysclass dereg
|
||||
Seems wrong. Any class can have NULL hInst, not only sysclasses
|
||||
|
||||
*/
|
||||
// if (Class->hInstance && Class->hInstance != hInstance)
|
||||
// {
|
||||
// SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
|
||||
// RETURN( FALSE);
|
||||
// }
|
||||
|
||||
if (Class->refs)
|
||||
{
|
||||
/* Dereference the ClassReferenceClassByNameOrAtom() call */
|
||||
ObmDereferenceObject(Class);
|
||||
/* NOTE: the class will not be freed when its refs become 0 ie. no more
|
||||
* windows are using it. I dunno why that is but its how Windows does it (and Wine).
|
||||
* The class will hang around until the process exit. -Gunnar
|
||||
*/
|
||||
SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
|
||||
RETURN( FALSE);
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
/* Dereference the ClassReferenceClassByNameOrAtom() call */
|
||||
ClassDereferenceObject(Class);
|
||||
|
||||
RemoveEntryList(&Class->ListEntry);
|
||||
|
||||
RtlDeleteAtomFromAtomTable(WinSta->AtomTable, Class->Atom);
|
||||
|
||||
/* Free the object */
|
||||
ClassDereferenceObject(Class);
|
||||
|
||||
RETURN( TRUE);
|
||||
DestroyClass(Class);
|
||||
|
||||
RETURN(TRUE);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserUnregisterClass, ret=%i\n",_ret_);
|
||||
|
@ -746,4 +645,119 @@ CLEANUP:
|
|||
END_CLEANUP;
|
||||
}
|
||||
|
||||
/* NOTE: for system classes hInstance is not NULL here, but User32Instance */
|
||||
DWORD STDCALL
|
||||
NtUserGetClassInfo(
|
||||
HINSTANCE hInstance,
|
||||
LPCWSTR lpClassName,
|
||||
LPWNDCLASSEXW lpWndClassEx,
|
||||
BOOL Ansi,
|
||||
DWORD unknown3)
|
||||
{
|
||||
PWNDCLASS_OBJECT Class;
|
||||
RTL_ATOM Atom;
|
||||
DECLARE_RETURN(DWORD);
|
||||
|
||||
if (IS_ATOM(lpClassName))
|
||||
DPRINT("NtUserGetClassInfo - %x (%lx)\n", lpClassName, hInstance);
|
||||
else
|
||||
DPRINT("NtUserGetClassInfo - %S (%lx)\n", lpClassName, hInstance);
|
||||
|
||||
UserEnterExclusive();
|
||||
|
||||
if (!hInstance)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
if (!(Class = ClassGetClassByNameOrAtom(lpClassName, hInstance)))
|
||||
{
|
||||
SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
lpWndClassEx->cbSize = sizeof(WNDCLASSEXW);
|
||||
lpWndClassEx->style = Class->style;
|
||||
if (Ansi)
|
||||
lpWndClassEx->lpfnWndProc = Class->lpfnWndProcA;
|
||||
else
|
||||
lpWndClassEx->lpfnWndProc = Class->lpfnWndProcW;
|
||||
lpWndClassEx->cbClsExtra = Class->cbClsExtra;
|
||||
lpWndClassEx->cbWndExtra = Class->cbWndExtra;
|
||||
/* This is not typo, we're really not going to use Class->hInstance here. */
|
||||
/* Well, i think its wrong so i changed it -Gunnar */
|
||||
lpWndClassEx->hInstance = Class->hInstance;
|
||||
lpWndClassEx->hIcon = Class->hIcon;
|
||||
lpWndClassEx->hCursor = Class->hCursor;
|
||||
lpWndClassEx->hbrBackground = Class->hbrBackground;
|
||||
if (Class->lpszMenuName.MaximumLength)
|
||||
RtlCopyUnicodeString((PUNICODE_STRING)lpWndClassEx->lpszMenuName, &Class->lpszMenuName);
|
||||
else
|
||||
lpWndClassEx->lpszMenuName = Class->lpszMenuName.Buffer;
|
||||
lpWndClassEx->lpszClassName = lpClassName;
|
||||
lpWndClassEx->hIconSm = Class->hIconSm;
|
||||
Atom = Class->Atom;
|
||||
|
||||
RETURN(Atom);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetClassInfo, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetClassName (
|
||||
HWND hWnd,
|
||||
LPWSTR lpClassName,
|
||||
ULONG nMaxCount /* in TCHARS */
|
||||
)
|
||||
{
|
||||
PWINDOW_OBJECT Window;
|
||||
DECLARE_RETURN(DWORD);
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
NTSTATUS Status;
|
||||
|
||||
UserEnterShared();
|
||||
DPRINT("Enter NtUserGetClassName\n");
|
||||
|
||||
if (!(Window = UserGetWindowObject(hWnd)))
|
||||
{
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
nMaxCount *= sizeof(WCHAR);
|
||||
|
||||
//FIXME: wrap in SEH to protect lpClassName access
|
||||
Status = RtlQueryAtomInAtomTable(WinSta->AtomTable,
|
||||
Window->Class->Atom, NULL, NULL,
|
||||
lpClassName, &nMaxCount);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastNtError(Status);
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
RETURN(nMaxCount / sizeof(WCHAR));
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetClassName, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserGetWOWClass(DWORD Unknown0,
|
||||
DWORD Unknown1)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -95,30 +95,6 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
|
|||
return CurIcon;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static
|
||||
PCURICON_OBJECT FASTCALL IntGetCurIconObject(HCURSOR hCursor)
|
||||
{
|
||||
PCURICON_OBJECT Cursor;
|
||||
|
||||
if (!hCursor) return NULL;
|
||||
|
||||
Cursor = (PCURICON_OBJECT)UserGetObject(&gHandleTable, hCursor, otCursorIcon);
|
||||
if (!Cursor)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_CURSOR_HANDLE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASSERT(USER_BODY_TO_HEADER(Cursor)->RefCount >= 0);
|
||||
|
||||
USER_BODY_TO_HEADER(Cursor)->RefCount++;
|
||||
|
||||
return Cursor;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define COLORCURSORS_ALLOWED FALSE
|
||||
HCURSOR FASTCALL
|
||||
|
@ -355,21 +331,17 @@ static BOOLEAN FASTCALL
|
|||
ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
|
||||
{
|
||||
PW32PROCESS Win32Process;
|
||||
PLIST_ENTRY Search;
|
||||
PCURICON_PROCESS Current;
|
||||
|
||||
Win32Process = PsGetWin32Process();
|
||||
|
||||
Search = CurIcon->ProcessList.Flink;
|
||||
while (Search != &CurIcon->ProcessList)
|
||||
LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
|
||||
{
|
||||
Current = CONTAINING_RECORD(Search, CURICON_PROCESS, ListEntry);
|
||||
if (Current->Process == Win32Process)
|
||||
{
|
||||
/* Already registered for this process */
|
||||
return TRUE;
|
||||
}
|
||||
Search = Search->Flink;
|
||||
}
|
||||
|
||||
/* Not registered yet */
|
||||
|
@ -388,14 +360,10 @@ PCURICON_OBJECT FASTCALL
|
|||
IntFindExistingCurIconObject(PWINSTATION_OBJECT WinSta, HMODULE hModule,
|
||||
HRSRC hRsrc, LONG cx, LONG cy)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PCURICON_OBJECT CurIcon;
|
||||
|
||||
CurrentEntry = gCurIconList.Flink;
|
||||
while (CurrentEntry != &gCurIconList)
|
||||
LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
|
||||
{
|
||||
CurIcon = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
|
||||
// if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon))) //<- huh????
|
||||
// ObmReferenceObject( CurIcon);
|
||||
|
@ -460,7 +428,6 @@ IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL
|
|||
PSYSTEM_CURSORINFO CurInfo;
|
||||
HBITMAP bmpMask, bmpColor;
|
||||
BOOLEAN Ret;
|
||||
PLIST_ENTRY Search;
|
||||
PCURICON_PROCESS Current = NULL;
|
||||
PW32PROCESS W32Process = PsGetWin32Process();
|
||||
|
||||
|
@ -483,18 +450,15 @@ IntDestroyCurIconObject(PWINSTATION_OBJECT WinSta, PCURICON_OBJECT CurIcon, BOOL
|
|||
|
||||
/* Now find this process in the list of processes referencing this object and
|
||||
remove it from that list */
|
||||
Search = CurIcon->ProcessList.Flink;
|
||||
while (Search != &CurIcon->ProcessList)
|
||||
LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
|
||||
{
|
||||
Current = CONTAINING_RECORD(Search, CURICON_PROCESS, ListEntry);
|
||||
if (Current->Process == W32Process)
|
||||
{
|
||||
RemoveEntryList(&Current->ListEntry);
|
||||
break;
|
||||
}
|
||||
Search = Search->Flink;
|
||||
}
|
||||
ASSERT(Search != &CurIcon->ProcessList);
|
||||
RemoveEntryList(Search);
|
||||
|
||||
ExFreeToPagedLookasideList(&gProcessLookasideList, Current);
|
||||
|
||||
/* If there are still processes referencing this object we can't destroy it yet */
|
||||
|
@ -541,9 +505,7 @@ VOID FASTCALL
|
|||
IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
|
||||
{
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PCURICON_OBJECT CurIcon;
|
||||
PLIST_ENTRY ProcessEntry;
|
||||
PCURICON_OBJECT CurIcon, tmp;
|
||||
PCURICON_PROCESS ProcessData;
|
||||
|
||||
WinSta = IntGetWinStaObj();
|
||||
|
@ -552,27 +514,19 @@ IntCleanupCurIcons(struct _EPROCESS *Process, PW32PROCESS Win32Process)
|
|||
return;
|
||||
}
|
||||
|
||||
CurrentEntry = gCurIconList.Flink;
|
||||
while (CurrentEntry != &gCurIconList)
|
||||
LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
|
||||
{
|
||||
CurIcon = CONTAINING_RECORD(CurrentEntry, CURICON_OBJECT, ListEntry);
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
|
||||
|
||||
// ObmReferenceObject(CurIcon);
|
||||
// if(NT_SUCCESS(ObmReferenceObjectByPointer(Object, otCursorIcon)))
|
||||
{
|
||||
ProcessEntry = CurIcon->ProcessList.Flink;
|
||||
while (ProcessEntry != &CurIcon->ProcessList)
|
||||
LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
|
||||
{
|
||||
ProcessData = CONTAINING_RECORD(ProcessEntry, CURICON_PROCESS, ListEntry);
|
||||
if (Win32Process == ProcessData->Process)
|
||||
{
|
||||
RemoveEntryList(&CurIcon->ListEntry);
|
||||
IntDestroyCurIconObject(WinSta, CurIcon, TRUE);
|
||||
break;
|
||||
}
|
||||
ProcessEntry = ProcessEntry->Flink;
|
||||
}
|
||||
|
||||
// ObmDereferenceObject(Object);
|
||||
|
|
|
@ -96,18 +96,16 @@ IntDesktopObjectCreate(PVOID ObjectBody,
|
|||
|
||||
RtlInitUnicodeString(&UnicodeString, (RemainingPath + 1));
|
||||
|
||||
|
||||
|
||||
KeInitializeSpinLock(&Desktop->Lock);
|
||||
InitializeListHead(&Desktop->ShellHookWindows);
|
||||
|
||||
Desktop->WindowStation = (PWINSTATION_OBJECT)Parent;
|
||||
|
||||
/* Put the desktop on the window station's list of associcated desktops */
|
||||
ExInterlockedInsertTailList(
|
||||
// ExInterlocked
|
||||
InsertTailList(
|
||||
&Desktop->WindowStation->DesktopListHead,
|
||||
&Desktop->ListEntry,
|
||||
&Desktop->WindowStation->Lock);
|
||||
&Desktop->ListEntry);//,
|
||||
// &Desktop->WindowStation->Lock);
|
||||
|
||||
return RtlCreateUnicodeString(&Desktop->Name, UnicodeString.Buffer);
|
||||
}
|
||||
|
@ -116,20 +114,41 @@ VOID STDCALL
|
|||
IntDesktopObjectDelete(PVOID DeletedObject)
|
||||
{
|
||||
PDESKTOP_OBJECT Desktop = (PDESKTOP_OBJECT)DeletedObject;
|
||||
KIRQL OldIrql;
|
||||
|
||||
DPRINT("Deleting desktop (0x%X)\n", Desktop);
|
||||
|
||||
/* Remove the desktop from the window station's list of associcated desktops */
|
||||
KeAcquireSpinLock(&Desktop->WindowStation->Lock, &OldIrql);
|
||||
RemoveEntryList(&Desktop->ListEntry);
|
||||
KeReleaseSpinLock(&Desktop->WindowStation->Lock, OldIrql);
|
||||
|
||||
RtlFreeUnicodeString(&Desktop->Name);
|
||||
}
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static int GetSystemVersionString(LPWSTR buffer)
|
||||
{
|
||||
RTL_OSVERSIONINFOEXW versionInfo;
|
||||
int len;
|
||||
|
||||
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
||||
|
||||
if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
|
||||
return 0;
|
||||
|
||||
if (versionInfo.dwMajorVersion <= 4)
|
||||
len = swprintf(buffer,
|
||||
L"ReactOS Version %d.%d %s Build %d",
|
||||
versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
|
||||
versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
|
||||
else
|
||||
len = swprintf(buffer,
|
||||
L"ReactOS %s (Build %d)",
|
||||
versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS FASTCALL
|
||||
IntParseDesktopPath(PEPROCESS Process,
|
||||
PUNICODE_STRING DesktopPath,
|
||||
|
@ -562,6 +581,37 @@ IntHideDesktop(PDESKTOP_OBJECT Desktop)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static
|
||||
HWND* FASTCALL
|
||||
UserBuildShellHookHwndList(PDESKTOP_OBJECT Desktop)
|
||||
{
|
||||
ULONG entries=0;
|
||||
PSHELL_HOOK_WINDOW Current;
|
||||
HWND* list;
|
||||
|
||||
/* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
|
||||
LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
|
||||
entries++;
|
||||
|
||||
if (!entries) return NULL;
|
||||
|
||||
list = ExAllocatePool(PagedPool, sizeof(HWND) * (entries + 1)); /* alloc one extra for nullterm */
|
||||
if (list)
|
||||
{
|
||||
HWND* cursor = list;
|
||||
|
||||
LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
|
||||
*cursor++ = Current->hWnd;
|
||||
|
||||
*cursor = NULL; /* nullterm list */
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the Message to the windows registered for ShellHook
|
||||
* notifications. The lParam contents depend on the Message. See
|
||||
|
@ -570,9 +620,7 @@ IntHideDesktop(PDESKTOP_OBJECT Desktop)
|
|||
VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
|
||||
{
|
||||
PDESKTOP_OBJECT Desktop = IntGetActiveDesktop();
|
||||
PLIST_ENTRY Entry, Entry2;
|
||||
PSHELL_HOOK_WINDOW Current;
|
||||
KIRQL OldLevel;
|
||||
HWND* HwndList;
|
||||
|
||||
static UINT MsgType = 0;
|
||||
|
||||
|
@ -599,43 +647,23 @@ VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
|
|||
return;
|
||||
}
|
||||
|
||||
/* We have to do some tricks because the list could change
|
||||
* between calls, and we can't keep the lock during the call
|
||||
*/
|
||||
|
||||
KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
|
||||
Entry = Desktop->ShellHookWindows.Flink;
|
||||
while (Entry != &Desktop->ShellHookWindows)
|
||||
HwndList = UserBuildShellHookHwndList(Desktop);
|
||||
if (HwndList)
|
||||
{
|
||||
Current = CONTAINING_RECORD(Entry, SHELL_HOOK_WINDOW, ListEntry);
|
||||
KeReleaseSpinLock(&Desktop->Lock, OldLevel);
|
||||
|
||||
DPRINT("Sending notify\n");
|
||||
co_IntPostOrSendMessage(Current->hWnd,
|
||||
MsgType,
|
||||
Message,
|
||||
lParam);
|
||||
|
||||
/* Loop again to find the window we were sending to. If it doesn't
|
||||
* exist anymore, we just stop. This could leave an infinite loop
|
||||
* if a window is removed and readded to the list. That's quite
|
||||
* unlikely though.
|
||||
*/
|
||||
|
||||
KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
|
||||
Entry2 = Desktop->ShellHookWindows.Flink;
|
||||
while (Entry2 != Entry &&
|
||||
Entry2 != &Desktop->ShellHookWindows)
|
||||
HWND* cursor = HwndList;
|
||||
|
||||
for (; *cursor; cursor++)
|
||||
{
|
||||
Entry2 = Entry2->Flink;
|
||||
DPRINT("Sending notify\n");
|
||||
co_IntPostOrSendMessage(*cursor,
|
||||
MsgType,
|
||||
Message,
|
||||
lParam);
|
||||
}
|
||||
|
||||
if (Entry2 == Entry)
|
||||
Entry = Entry->Flink;
|
||||
else
|
||||
break;
|
||||
ExFreePool(HwndList);
|
||||
}
|
||||
KeReleaseSpinLock(&Desktop->Lock, OldLevel);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -650,7 +678,6 @@ BOOL IntRegisterShellHookWindow(HWND hWnd)
|
|||
{
|
||||
PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
|
||||
PSHELL_HOOK_WINDOW Entry;
|
||||
KIRQL OldLevel;
|
||||
|
||||
DPRINT("IntRegisterShellHookWindow\n");
|
||||
|
||||
|
@ -659,20 +686,16 @@ BOOL IntRegisterShellHookWindow(HWND hWnd)
|
|||
*/
|
||||
IntDeRegisterShellHookWindow(hWnd);
|
||||
|
||||
Entry = ExAllocatePoolWithTag(NonPagedPool,
|
||||
Entry = ExAllocatePoolWithTag(PagedPool,
|
||||
sizeof(SHELL_HOOK_WINDOW),
|
||||
TAG_WINSTA);
|
||||
/* We have to walk this structure with while holding a spinlock, so we
|
||||
* need NonPagedPool */
|
||||
|
||||
if (!Entry)
|
||||
return FALSE;
|
||||
|
||||
Entry->hWnd = hWnd;
|
||||
|
||||
KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
|
||||
InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
|
||||
KeReleaseSpinLock(&Desktop->Lock, OldLevel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -685,31 +708,27 @@ BOOL IntRegisterShellHookWindow(HWND hWnd)
|
|||
BOOL IntDeRegisterShellHookWindow(HWND hWnd)
|
||||
{
|
||||
PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
|
||||
PLIST_ENTRY Entry;
|
||||
PSHELL_HOOK_WINDOW Current;
|
||||
KIRQL OldLevel;
|
||||
|
||||
KeAcquireSpinLock(&Desktop->Lock, &OldLevel);
|
||||
|
||||
Entry = Desktop->ShellHookWindows.Flink;
|
||||
while (Entry != &Desktop->ShellHookWindows)
|
||||
LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
|
||||
{
|
||||
Current = CONTAINING_RECORD(Entry, SHELL_HOOK_WINDOW, ListEntry);
|
||||
if (Current->hWnd == hWnd)
|
||||
{
|
||||
RemoveEntryList(Entry);
|
||||
KeReleaseSpinLock(&Desktop->Lock, OldLevel);
|
||||
ExFreePool(Entry);
|
||||
RemoveEntryList(&Current->ListEntry);
|
||||
ExFreePool(Current);
|
||||
return TRUE;
|
||||
}
|
||||
Entry = Entry->Flink;
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&Desktop->Lock, OldLevel);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* SYSCALLS *******************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* NtUserCreateDesktop
|
||||
*
|
||||
|
@ -759,7 +778,7 @@ NtUserCreateDesktop(
|
|||
CSR_API_MESSAGE Request;
|
||||
DECLARE_RETURN(HDESK);
|
||||
|
||||
DPRINT("Enter CreateDesktop: %wZ\n", lpszDesktopName);
|
||||
DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
|
||||
UserEnterExclusive();
|
||||
|
||||
Status = IntValidateWindowStationHandle(
|
||||
|
@ -1035,6 +1054,10 @@ NtUserOpenInputDesktop(
|
|||
PDESKTOP_OBJECT Object;
|
||||
NTSTATUS Status;
|
||||
HDESK Desktop;
|
||||
DECLARE_RETURN(HDESK);
|
||||
|
||||
DPRINT("Enter NtUserOpenInputDesktop\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
DPRINT("About to open input desktop\n");
|
||||
|
||||
|
@ -1049,7 +1072,7 @@ NtUserOpenInputDesktop(
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
|
||||
return (HDESK)0;
|
||||
RETURN((HDESK)0);
|
||||
}
|
||||
|
||||
/* Create a new handle to the object */
|
||||
|
@ -1068,11 +1091,16 @@ NtUserOpenInputDesktop(
|
|||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Successfully opened input desktop\n");
|
||||
return (HDESK)Desktop;
|
||||
RETURN((HDESK)Desktop);
|
||||
}
|
||||
|
||||
SetLastNtError(Status);
|
||||
return (HDESK)0;
|
||||
RETURN((HDESK)0);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1102,6 +1130,10 @@ NtUserCloseDesktop(HDESK hDesktop)
|
|||
{
|
||||
PDESKTOP_OBJECT Object;
|
||||
NTSTATUS Status;
|
||||
DECLARE_RETURN(BOOL);
|
||||
|
||||
DPRINT("Enter NtUserCloseDesktop\n");
|
||||
UserEnterExclusive();
|
||||
|
||||
DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
|
||||
|
||||
|
@ -1114,7 +1146,7 @@ NtUserCloseDesktop(HDESK hDesktop)
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
|
||||
return FALSE;
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
ObDereferenceObject(Object);
|
||||
|
@ -1125,35 +1157,19 @@ NtUserCloseDesktop(HDESK hDesktop)
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastNtError(Status);
|
||||
return FALSE;
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
RETURN(TRUE);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
||||
static int GetSystemVersionString(LPWSTR buffer)
|
||||
{
|
||||
RTL_OSVERSIONINFOEXW versionInfo;
|
||||
int len;
|
||||
|
||||
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
||||
|
||||
if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
|
||||
return 0;
|
||||
|
||||
if (versionInfo.dwMajorVersion <= 4)
|
||||
len = swprintf(buffer,
|
||||
L"ReactOS Version %d.%d %s Build %d",
|
||||
versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
|
||||
versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
|
||||
else
|
||||
len = swprintf(buffer,
|
||||
L"ReactOS %s (Build %d)",
|
||||
versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserPaintDesktop
|
||||
|
@ -1179,6 +1195,10 @@ NtUserPaintDesktop(HDC hDC)
|
|||
BOOL doPatBlt = TRUE;
|
||||
PWINDOW_OBJECT WndDesktop;
|
||||
int len;
|
||||
DECLARE_RETURN(BOOL);
|
||||
|
||||
UserEnterExclusive();
|
||||
DPRINT("Enter NtUserPaintDesktop\n");
|
||||
|
||||
PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
|
@ -1186,7 +1206,7 @@ NtUserPaintDesktop(HDC hDC)
|
|||
|
||||
hWndDesktop = IntGetDesktopWindow();
|
||||
if (!(WndDesktop = UserGetWindowObject(hWndDesktop)))
|
||||
return FALSE;
|
||||
RETURN(FALSE);
|
||||
|
||||
DesktopBrush = (HBRUSH)IntGetClassLong(WndDesktop, GCL_HBRBACKGROUND, FALSE); //fixme: verify retval
|
||||
|
||||
|
@ -1277,7 +1297,12 @@ NtUserPaintDesktop(HDC hDC)
|
|||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
RETURN(TRUE);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1302,6 +1327,10 @@ NtUserSwitchDesktop(HDESK hDesktop)
|
|||
{
|
||||
PDESKTOP_OBJECT DesktopObject;
|
||||
NTSTATUS Status;
|
||||
DECLARE_RETURN(BOOL);
|
||||
|
||||
UserEnterExclusive();
|
||||
DPRINT("Enter NtUserSwitchDesktop\n");
|
||||
|
||||
DPRINT("About to switch desktop (0x%X)\n", hDesktop);
|
||||
|
||||
|
@ -1314,7 +1343,7 @@ NtUserSwitchDesktop(HDESK hDesktop)
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
|
||||
return FALSE;
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1326,7 +1355,7 @@ NtUserSwitchDesktop(HDESK hDesktop)
|
|||
{
|
||||
ObDereferenceObject(DesktopObject);
|
||||
DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
|
||||
return FALSE;
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
/* FIXME: Fail if the desktop belong to an invisible window station */
|
||||
|
@ -1344,7 +1373,12 @@ NtUserSwitchDesktop(HDESK hDesktop)
|
|||
|
||||
ObDereferenceObject(DesktopObject);
|
||||
|
||||
return TRUE;
|
||||
RETURN(TRUE);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1376,18 +1410,22 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
|
|||
PDESKTOP_OBJECT DesktopObject;
|
||||
HDESK Ret, hThreadDesktop;
|
||||
OBJECT_HANDLE_INFORMATION HandleInformation;
|
||||
DECLARE_RETURN(HDESK);
|
||||
|
||||
UserEnterExclusive();
|
||||
DPRINT("Enter NtUserGetThreadDesktop\n");
|
||||
|
||||
if(!dwThreadId)
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
if(Thread->ThreadsProcess == PsGetCurrentProcess())
|
||||
|
@ -1396,7 +1434,7 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
|
|||
in the same context */
|
||||
Ret = Thread->Tcb.Win32Thread->hDesktop;
|
||||
ObDereferenceObject(Thread);
|
||||
return Ret;
|
||||
RETURN(Ret);
|
||||
}
|
||||
|
||||
/* get the desktop handle and the desktop of the thread */
|
||||
|
@ -1405,7 +1443,7 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
|
|||
{
|
||||
ObDereferenceObject(Thread);
|
||||
DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
|
||||
return NULL;
|
||||
RETURN(NULL);
|
||||
}
|
||||
|
||||
/* we could just use DesktopObject instead of looking up the handle, but latter
|
||||
|
@ -1425,7 +1463,7 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
|
|||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
ObDereferenceObject(Thread);
|
||||
return NULL;
|
||||
RETURN(NULL);
|
||||
}
|
||||
|
||||
/* lookup our handle table if we can find a handle to the desktop object,
|
||||
|
@ -1435,7 +1473,12 @@ NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
|
|||
/* all done, we got a valid handle to the desktop */
|
||||
ObDereferenceObject(DesktopObject);
|
||||
ObDereferenceObject(Thread);
|
||||
return Ret;
|
||||
RETURN(Ret);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1451,7 +1494,11 @@ NtUserSetThreadDesktop(HDESK hDesktop)
|
|||
PW32THREAD W32Thread;
|
||||
PDESKTOP_OBJECT DesktopObject;
|
||||
NTSTATUS Status;
|
||||
|
||||
DECLARE_RETURN(BOOL);
|
||||
|
||||
UserEnterExclusive();
|
||||
DPRINT("Enter NtUserSetThreadDesktop\n");
|
||||
|
||||
/* Validate the new desktop. */
|
||||
Status = IntValidateDesktopHandle(
|
||||
hDesktop,
|
||||
|
@ -1462,7 +1509,7 @@ NtUserSetThreadDesktop(HDESK hDesktop)
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
|
||||
return FALSE;
|
||||
RETURN(FALSE);
|
||||
}
|
||||
|
||||
W32Thread = PsGetWin32Thread();
|
||||
|
@ -1477,7 +1524,12 @@ NtUserSetThreadDesktop(HDESK hDesktop)
|
|||
W32Thread->Desktop = DesktopObject;
|
||||
W32Thread->hDesktop = hDesktop;
|
||||
|
||||
return TRUE;
|
||||
RETURN(TRUE);
|
||||
|
||||
CLEANUP:
|
||||
DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
|
||||
UserLeave();
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -510,21 +510,6 @@ NtUserCallTwoParam(
|
|||
UNIMPLEMENTED
|
||||
RETURN( 0);
|
||||
|
||||
case TWOPARAM_ROUTINE_VALIDATERGN:
|
||||
{
|
||||
PWINDOW_OBJECT Window = UserGetWindowObject((HWND) Param1);
|
||||
BOOL ret;
|
||||
|
||||
if (!Window)
|
||||
RETURN(FALSE);
|
||||
|
||||
UserRefObjectCo(Window);
|
||||
ret = co_UserValidateRgn(Window, (HRGN) Param2);
|
||||
UserDerefObjectCo(Window);
|
||||
|
||||
RETURN((DWORD) ret);
|
||||
}
|
||||
|
||||
case TWOPARAM_ROUTINE_SETWNDCONTEXTHLPID:
|
||||
|
||||
if(!(Window = UserGetWindowObject((HWND)Param1)))
|
||||
|
|
|
@ -292,11 +292,12 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
|
|||
{
|
||||
for (phWnd = List; *phWnd; ++phWnd)
|
||||
{
|
||||
Window = IntGetWindowObject(*phWnd);
|
||||
Window = UserGetWindowObject(*phWnd);
|
||||
if (Window && (Window->Style & WS_VISIBLE))
|
||||
{
|
||||
UserRefObjectCo(Window);
|
||||
co_IntPaintWindows(Window, Flags);
|
||||
ObmDereferenceObject(Window);
|
||||
UserDerefObjectCo(Window);
|
||||
}
|
||||
}
|
||||
ExFreePool(List);
|
||||
|
@ -414,31 +415,21 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
|
|||
if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
|
||||
((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
|
||||
{
|
||||
HWND *List, *phWnd;
|
||||
PWINDOW_OBJECT Child;
|
||||
|
||||
if ((List = IntWinListChildren(Window)))
|
||||
for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
|
||||
{
|
||||
for (phWnd = List; *phWnd; ++phWnd)
|
||||
if (Child->Style & WS_VISIBLE)
|
||||
{
|
||||
if(!(Child = UserGetWindowObject(*phWnd)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Child->Style & WS_VISIBLE)
|
||||
{
|
||||
/*
|
||||
* Recursive call to update children UpdateRegion
|
||||
*/
|
||||
HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
|
||||
NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
|
||||
IntInvalidateWindows(Child, hRgnTemp, Flags);
|
||||
NtGdiDeleteObject(hRgnTemp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursive call to update children UpdateRegion
|
||||
*/
|
||||
HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
|
||||
NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
|
||||
IntInvalidateWindows(Child, hRgnTemp, Flags);
|
||||
NtGdiDeleteObject(hRgnTemp);
|
||||
}
|
||||
ExFreePool(List);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -859,69 +850,6 @@ CLEANUP:
|
|||
END_CLEANUP;
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserInvalidateRect
|
||||
*
|
||||
* Status
|
||||
* @implemented
|
||||
*/
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserInvalidateRect(HWND hWnd, CONST RECT *Rect, BOOL Erase)
|
||||
{
|
||||
return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserInvalidateRgn
|
||||
*
|
||||
* Status
|
||||
* @implemented
|
||||
*/
|
||||
|
||||
DWORD STDCALL
|
||||
NtUserInvalidateRgn(HWND hWnd, HRGN Rgn, BOOL Erase)
|
||||
{
|
||||
return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL FASTCALL
|
||||
co_UserValidateRgn(PWINDOW_OBJECT Window, HRGN hRgn)
|
||||
{
|
||||
return co_UserRedrawWindow(Window, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserValidateRgn
|
||||
*
|
||||
* Status
|
||||
* @implemented
|
||||
*/
|
||||
|
||||
BOOL STDCALL
|
||||
NtUserValidateRgn(HWND hWnd, HRGN hRgn)
|
||||
{
|
||||
return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
|
||||
}
|
||||
|
||||
/*
|
||||
* NtUserUpdateWindow
|
||||
*
|
||||
* Status
|
||||
* @implemented
|
||||
*/
|
||||
|
||||
BOOL STDCALL
|
||||
NtUserUpdateWindow(HWND hWnd)
|
||||
{
|
||||
return NtUserRedrawWindow(hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
INT FASTCALL
|
||||
co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
|
||||
|
|
|
@ -293,8 +293,12 @@ static void IntSendDestroyMsg(HWND hWnd)
|
|||
* IntDestroyWindow
|
||||
*
|
||||
* Destroy storage associated to a window. "Internals" p.358
|
||||
*
|
||||
* This is the "functional" DestroyWindows function ei. all stuff
|
||||
* done in CreateWindow is undone here and not in DestroyWindow:-P
|
||||
|
||||
*/
|
||||
static LRESULT co_IntDestroyWindow(PWINDOW_OBJECT Window,
|
||||
static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
|
||||
PW32PROCESS ProcessData,
|
||||
PW32THREAD ThreadData,
|
||||
BOOLEAN SendMessages)
|
||||
|
@ -343,7 +347,7 @@ static LRESULT co_IntDestroyWindow(PWINDOW_OBJECT Window,
|
|||
IntSendDestroyMsg(Child->hSelf);
|
||||
}
|
||||
else
|
||||
co_IntDestroyWindow(Child, ProcessData, ThreadData, SendMessages);
|
||||
co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
|
||||
|
||||
UserDerefObject(Child);
|
||||
}
|
||||
|
@ -427,11 +431,8 @@ static LRESULT co_IntDestroyWindow(PWINDOW_OBJECT Window,
|
|||
|
||||
IntDestroyScrollBars(Window);
|
||||
|
||||
/* remove the window from the class object */
|
||||
RemoveEntryList(&Window->ClassListEntry);
|
||||
|
||||
/* dereference the class */
|
||||
ClassDereferenceObject(Window->Class);
|
||||
ClassDerefObject(Window->Class);
|
||||
Window->Class = NULL;
|
||||
|
||||
if(Window->WindowRegion)
|
||||
|
@ -1331,13 +1332,13 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
BOOL bUnicodeWindow)
|
||||
{
|
||||
PWINSTATION_OBJECT WinSta;
|
||||
PWNDCLASS_OBJECT Class;
|
||||
PWNDCLASS_OBJECT Class = NULL;
|
||||
PWINDOW_OBJECT Window = NULL;
|
||||
PWINDOW_OBJECT ParentWindow = NULL, OwnerWindow;
|
||||
HWND ParentWindowHandle;
|
||||
HWND OwnerWindowHandle;
|
||||
PMENU_OBJECT SystemMenu;
|
||||
HANDLE Handle;
|
||||
HWND hWnd;
|
||||
POINT Pos;
|
||||
SIZE Size;
|
||||
#if 0
|
||||
|
@ -1352,7 +1353,6 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
CBT_CREATEWNDW CbtCreate;
|
||||
LRESULT Result;
|
||||
BOOL MenuChanged;
|
||||
BOOL ClassFound;
|
||||
DECLARE_RETURN(HWND);
|
||||
BOOL HasOwner;
|
||||
|
||||
|
@ -1398,8 +1398,8 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
/* FIXME: parent must belong to the current process */
|
||||
|
||||
/* Check the class. */
|
||||
ClassFound = ClassReferenceClassByNameOrAtom(&Class, ClassName->Buffer, hInstance);
|
||||
if (!ClassFound)
|
||||
Class = ClassGetClassByNameOrAtom(ClassName->Buffer, hInstance);
|
||||
if (!Class)
|
||||
{
|
||||
if (IS_ATOM(ClassName->Buffer))
|
||||
{
|
||||
|
@ -1414,55 +1414,52 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
RETURN((HWND)0);
|
||||
}
|
||||
|
||||
ClassRefObject(Class);
|
||||
|
||||
/* Check the window station. */
|
||||
if (PsGetWin32Thread()->Desktop == NULL)
|
||||
{
|
||||
ClassDereferenceObject(Class);
|
||||
|
||||
DPRINT("Thread is not attached to a desktop! Cannot create window!\n");
|
||||
RETURN( (HWND)0);
|
||||
}
|
||||
WinSta = PsGetWin32Thread()->Desktop->WindowStation;
|
||||
|
||||
//FIXME: Reference thread/desktop instead
|
||||
ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
|
||||
|
||||
/* Create the window object. */
|
||||
Window = (PWINDOW_OBJECT)
|
||||
ObmCreateObject(&gHandleTable, &Handle,
|
||||
ObmCreateObject(&gHandleTable, (PHANDLE)&hWnd,
|
||||
otWindow, sizeof(WINDOW_OBJECT) + Class->cbWndExtra
|
||||
);
|
||||
|
||||
DPRINT("Created object with handle %X\n", Handle);
|
||||
DPRINT("Created object with handle %X\n", hWnd);
|
||||
if (!Window)
|
||||
{
|
||||
ObDereferenceObject(WinSta);
|
||||
ClassDereferenceObject(Class);
|
||||
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
|
||||
RETURN( (HWND)0);
|
||||
}
|
||||
|
||||
UserRefObjectCo(Window);
|
||||
|
||||
|
||||
ObDereferenceObject(WinSta);
|
||||
|
||||
if (NULL == PsGetWin32Thread()->Desktop->DesktopWindow)
|
||||
{
|
||||
/* If there is no desktop window yet, we must be creating it */
|
||||
PsGetWin32Thread()->Desktop->DesktopWindow = Handle;
|
||||
PsGetWin32Thread()->Desktop->DesktopWindow = hWnd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill out the structure describing it.
|
||||
*/
|
||||
Window->Class = Class;
|
||||
|
||||
InsertTailList(&Class->ClassWindowsListHead, &Window->ClassListEntry);
|
||||
|
||||
Window->SystemMenu = (HMENU)0;
|
||||
Window->ContextHelpId = 0;
|
||||
Window->IDMenu = 0;
|
||||
Window->Instance = hInstance;
|
||||
Window->hSelf = Handle;
|
||||
Window->hSelf = hWnd;
|
||||
if (0 != (dwStyle & WS_CHILD))
|
||||
{
|
||||
Window->IDMenu = (UINT) hMenu;
|
||||
|
@ -1505,19 +1502,11 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
Window->LastChild = NULL;
|
||||
Window->PrevSibling = NULL;
|
||||
Window->NextSibling = NULL;
|
||||
Window->ExtraDataSize = Class->cbWndExtra;
|
||||
|
||||
/* extra window data */
|
||||
if (Class->cbWndExtra != 0)
|
||||
{
|
||||
if (Class->cbWndExtra)
|
||||
Window->ExtraData = (PCHAR)(Window + 1);
|
||||
Window->ExtraDataSize = Class->cbWndExtra;
|
||||
RtlZeroMemory(Window->ExtraData, Window->ExtraDataSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
Window->ExtraData = NULL;
|
||||
Window->ExtraDataSize = 0;
|
||||
}
|
||||
|
||||
InitializeListHead(&Window->PropListHead);
|
||||
InitializeListHead(&Window->WndObjListHead);
|
||||
|
@ -1530,7 +1519,6 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
TAG_STRING);
|
||||
if (NULL == Window->WindowName.Buffer)
|
||||
{
|
||||
ClassDereferenceObject(Class);
|
||||
DPRINT1("Failed to allocate mem for window name\n");
|
||||
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
|
||||
RETURN( NULL);
|
||||
|
@ -1612,13 +1600,10 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
Cs.dwExStyle = dwExStyle;
|
||||
CbtCreate.lpcs = &Cs;
|
||||
CbtCreate.hwndInsertAfter = HWND_TOP;
|
||||
if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) Handle, (LPARAM) &CbtCreate))
|
||||
if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
|
||||
{
|
||||
|
||||
/* FIXME - Delete window object and remove it from the thread windows list */
|
||||
/* FIXME - delete allocated DCE */
|
||||
|
||||
ClassDereferenceObject(Class);
|
||||
DPRINT1("CBT-hook returned !0\n");
|
||||
RETURN( (HWND) NULL);
|
||||
}
|
||||
|
@ -1827,7 +1812,6 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
if (Result == (LRESULT)-1)
|
||||
{
|
||||
/* FIXME: Cleanup. */
|
||||
ClassDereferenceObject(Class);
|
||||
DPRINT("IntCreateWindowEx(): send CREATE message failed.\n");
|
||||
RETURN((HWND)0);
|
||||
}
|
||||
|
@ -1911,7 +1895,7 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
if ((!hWndParent) && (!HasOwner))
|
||||
{
|
||||
DPRINT("Sending CREATED notify\n");
|
||||
co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Handle);
|
||||
co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1934,14 +1918,14 @@ co_IntCreateWindowEx(DWORD dwExStyle,
|
|||
co_WinPosShowWindow(Window, dwShowMode);
|
||||
}
|
||||
|
||||
DPRINT("IntCreateWindow(): = %X\n", Handle);
|
||||
DPRINT("IntCreateWindow(): = %X\n", hWnd);
|
||||
DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
|
||||
RETURN((HWND)Handle);
|
||||
RETURN(hWnd);
|
||||
|
||||
CLEANUP:
|
||||
if (Window) UserDerefObjectCo(Window);
|
||||
if (ParentWindow) UserDerefObjectCo(ParentWindow);
|
||||
|
||||
if (!_ret_ && Class) ClassDerefObject(Class); /* only deref if failure (return 0) */
|
||||
END_CLEANUP;
|
||||
}
|
||||
|
||||
|
@ -2164,7 +2148,7 @@ BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
|
|||
}
|
||||
|
||||
/* Destroy the window storage */
|
||||
co_IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
|
||||
co_UserFreeWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -4208,14 +4192,6 @@ NtUserUpdateLayeredWindow(DWORD Unknown0,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID STDCALL
|
||||
NtUserValidateRect(HWND hWnd, const RECT* Rect)
|
||||
{
|
||||
return (VOID)NtUserRedrawWindow(hWnd, Rect, 0, RDW_VALIDATE | RDW_NOCHILDREN);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -107,6 +107,8 @@ IntWinStaObjectOpen(OB_OPEN_REASON Reason,
|
|||
PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)ObjectBody;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT1("IntWinStaObjectOpen\n");
|
||||
|
||||
if (Reason == ObCreateHandle)
|
||||
{
|
||||
DPRINT("Creating window station (0x%X)\n", WinSta);
|
||||
|
@ -115,10 +117,10 @@ IntWinStaObjectOpen(OB_OPEN_REASON Reason,
|
|||
|
||||
InitializeListHead(&WinSta->DesktopListHead);
|
||||
|
||||
DPRINT1("Create winsta atomtable\n");
|
||||
WinSta->AtomTable = NULL;
|
||||
|
||||
Status = RtlCreateAtomTable(37, &WinSta->AtomTable);
|
||||
|
||||
if (!NT_SUCCESS(Status)) DPRINT1("Error creating atom table\n");
|
||||
WinSta->SystemMenuTemplate = (HANDLE)0;
|
||||
|
||||
DPRINT("Window station successfully created.\n");
|
||||
|
|
|
@ -417,15 +417,12 @@ NtUserGetWindowPlacement 2
|
|||
NtUserGetWindowLong 3
|
||||
NtUserGetWindowRect 2
|
||||
NtUserGetWOWClass 2
|
||||
NtUserHideCaret 1
|
||||
NtUserHiliteMenuItem 4
|
||||
NtUserImpersonateDdeClientWindow 2
|
||||
NtUserInitializeClientPfnArrays 4
|
||||
NtUserInitTask 11
|
||||
NtUserInsertMenuItem 4
|
||||
NtUserInternalGetWindowText 3
|
||||
NtUserInvalidateRect 3
|
||||
NtUserInvalidateRgn 3
|
||||
NtUserIsClipboardFormatAvailable 1
|
||||
NtUserKillSystemTimer 2
|
||||
NtUserKillTimer 2
|
||||
|
@ -523,7 +520,7 @@ NtUserSetWindowsHookEx 6
|
|||
NtUserSetWindowStationUser 4
|
||||
NtUserSetWindowWord 3
|
||||
NtUserSetWinEventHook 8
|
||||
NtUserShowCaret 1
|
||||
NtUserShowCaret 2
|
||||
NtUserShowScrollBar 3
|
||||
NtUserShowWindow 2
|
||||
NtUserShowWindowAsync 2
|
||||
|
@ -544,12 +541,10 @@ NtUserUnregisterClass 3
|
|||
NtUserUnregisterHotKey 2
|
||||
NtUserUpdateInputContext 3
|
||||
NtUserUpdateInstance 3
|
||||
NtUserUpdateWindow 1
|
||||
NtUserUpdateLayeredWindow 9
|
||||
NtUserUpdatePerUserSystemParameters 2
|
||||
NtUserUserHandleGrantAccess 3
|
||||
NtUserValidateHandleSecure 1
|
||||
NtUserValidateRect 2
|
||||
NtUserVkKeyScanEx 3
|
||||
NtUserWaitForInputIdle 3
|
||||
NtUserWaitForMsgAndEvent 1
|
||||
|
|
Loading…
Reference in a new issue