--- /dev/null
--- /dev/null
- //#include <csr/csrss.h> // FIXME: data header.
++/*
++ * COPYRIGHT: See COPYING in the top level directory
++ * PROJECT: ReactOS System Libraries
++ * FILE: lib/kernel32/k32.h
++ * PURPOSE: Win32 Kernel Libary Header
++ * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
++ */
++
++#ifndef __K32_H
++#define __K32_H
++
++/* INCLUDES ******************************************************************/
++
++/* PSDK/NDK Headers */
++#define WIN32_NO_STATUS
++#include <windows.h>
++#include <tlhelp32.h>
++
++/* Redefine NTDDI_VERSION to 2K3 SP1 to get correct NDK definitions */
++#undef NTDDI_VERSION
++#define NTDDI_VERSION NTDDI_WS03SP1
++
++#include <ndk/cmfuncs.h>
++#include <ndk/dbgkfuncs.h>
++#include <ndk/exfuncs.h>
++#include <ndk/iofuncs.h>
++#include <ndk/kdtypes.h>
++#include <ndk/kefuncs.h>
++#include <ndk/ldrfuncs.h>
++#include <ndk/mmfuncs.h>
++#include <ndk/obfuncs.h>
++#include <ndk/pofuncs.h>
++#include <ndk/psfuncs.h>
++#include <ndk/rtlfuncs.h>
++#include <ndk/setypes.h>
++#include <ndk/umfuncs.h>
++
++/* CSRSS Header */
++#include <csr/csr.h>
++#include <win/base.h>
++#include <win/basemsg.h>
++#include <win/conmsg.h>
++#include <win/winmsg.h>
++
++/* C Headers */
++#include <ctype.h>
++#include <limits.h>
++#include <stdio.h>
++#include <wchar.h>
++
++/* DDK Driver Headers */
++#include <ntddbeep.h>
++#include <mountmgr.h>
++#include <mountdev.h>
++
++/* Internal Kernel32 Header */
++#include "include/kernel32.h"
++
++/* PSEH for SEH Support */
++#include <pseh/pseh2.h>
++
++/* Base Macros */
++#include "include/base_x.h"
++
++#endif
--- /dev/null
--- /dev/null
- user/ntuser/cursoricon.c
++
++set(USE_DIBLIB FALSE)
+++set(USE_NEW_CURSORICON FALSE)
++
++# Give WIN32 subsystem its own project.
++PROJECT(WIN32SS)
++
++add_subdirectory(drivers)
++
++if(USE_DIBLIB)
++ add_subdirectory(gdi/diblib)
++endif()
++
++add_subdirectory(gdi/gdi32)
++add_subdirectory(reactx)
++add_subdirectory(user/consrv)
++add_subdirectory(user/user32)
++add_subdirectory(user/winsrv)
++
++spec2def(win32k.sys win32k.spec ADD_IMPORTLIB)
++
++include_directories(
++ .
++ include
++ ${REACTOS_SOURCE_DIR}/ntoskrnl/include
++ ${REACTOS_SOURCE_DIR}/lib/3rdparty/freetype/include
++ ${REACTOS_SOURCE_DIR}/include/reactos/subsys
++ ${REACTOS_SOURCE_DIR}/include/reactos/drivers)
++
++add_definitions(
++ -DLANGPACK
++ -D_WIN32K_)
++
++file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gdi/dib)
++
++list(APPEND GENDIB_FILES
++ ${CMAKE_CURRENT_BINARY_DIR}/gdi/dib/dib8gen.c
++ ${CMAKE_CURRENT_BINARY_DIR}/gdi/dib/dib16gen.c
++ ${CMAKE_CURRENT_BINARY_DIR}/gdi/dib/dib32gen.c)
++
++add_custom_command(
++ OUTPUT ${GENDIB_FILES}
++ COMMAND native-gendib ${CMAKE_CURRENT_BINARY_DIR}/gdi/dib
++ DEPENDS native-gendib)
++
++list(APPEND SOURCE
++ gdi/dib/alphablend.c
++ gdi/dib/dib1bpp.c
++ gdi/dib/dib4bpp.c
++ gdi/dib/dib8bpp.c
++ gdi/dib/dib16bpp.c
++ gdi/dib/dib24bpp.c
++ gdi/dib/dib32bpp.c
++ gdi/dib/floodfill.c
++ gdi/dib/stretchblt.c
++ gdi/eng/alphablend.c
++ gdi/eng/bitblt.c
++ gdi/eng/engbrush.c
++ gdi/eng/engevent.c
++ gdi/eng/clip.c
++ gdi/eng/debug.c
++ gdi/eng/device.c
++ gdi/eng/driverobj.c
++ gdi/eng/error.c
++ gdi/eng/float.c
++ gdi/eng/gradient.c
++ gdi/eng/lineto.c
++ gdi/eng/ldevobj.c
++ gdi/eng/mapping.c
++ gdi/eng/mem.c
++ gdi/eng/engmisc.c
++ gdi/eng/mouse.c
++ gdi/eng/paint.c
++ gdi/eng/pdevobj.c
++ gdi/eng/perfcnt.c
++ gdi/eng/rlecomp.c
++ gdi/eng/semaphor.c
++ gdi/eng/sort.c
++ gdi/eng/string.c
++ gdi/eng/stretchblt.c
++ gdi/eng/surface.c
++ gdi/eng/transblt.c
++ gdi/eng/engwindow.c
++ gdi/eng/xlateobj.c
++ user/ntuser/main.c
++ user/ntuser/misc/file.c
++ user/ntuser/misc/math.c
++ user/ntuser/misc/rtlstr.c
++ user/ntuser/misc/copy.c
++ user/ntuser/misc/registry.c
++ user/ntuser/misc/usrheap.c
++ reactx/ntddraw/ddraw.c
++ reactx/ntddraw/dd.c
++ reactx/ntddraw/ddsurf.c
++ reactx/ntddraw/d3d.c
++ reactx/ntddraw/dvp.c
++ reactx/ntddraw/mocomp.c
++ reactx/ntddraw/eng.c
++ reactx/ntddraw/dxeng.c
++ user/ntuser/accelerator.c
++ user/ntuser/callback.c
++ user/ntuser/callproc.c
++ user/ntuser/caret.c
++ user/ntuser/class.c
++ user/ntuser/clipboard.c
++ user/ntuser/csr.c
++ user/ntuser/defwnd.c
++ user/ntuser/desktop.c
++ user/ntuser/display.c
++ user/ntuser/event.c
++ user/ntuser/focus.c
++ user/ntuser/guicheck.c
++ user/ntuser/hook.c
++ user/ntuser/hotkey.c
++ user/ntuser/input.c
++ user/ntuser/keyboard.c
++ user/ntuser/kbdlayout.c
++ user/ntuser/menu.c
++ user/ntuser/message.c
++ user/ntuser/metric.c
++ user/ntuser/misc.c
++ user/ntuser/monitor.c
++ user/ntuser/mouse.c
++ user/ntuser/msgqueue.c
++ user/ntuser/ntstubs.c
++ user/ntuser/ntuser.c
++ user/ntuser/painting.c
++ user/ntuser/prop.c
++ user/ntuser/scrollbar.c
++ user/ntuser/session.c
++ user/ntuser/simplecall.c
++ user/ntuser/sysparams.c
++ user/ntuser/timer.c
++ user/ntuser/useratom.c
++ user/ntuser/vis.c
++ user/ntuser/windc.c
++ user/ntuser/window.c
++ user/ntuser/winpos.c
++ user/ntuser/winsta.c
++ user/ntuser/object.c
++ gdi/ntgdi/arc.c
++ gdi/ntgdi/bezier.c
++ gdi/ntgdi/bitblt.c
++ gdi/ntgdi/bitmaps.c
++ gdi/ntgdi/brush.c
++ gdi/ntgdi/cliprgn.c
++ gdi/ntgdi/coord.c
++ gdi/ntgdi/dcattr.c
++ gdi/ntgdi/dclife.c
++ gdi/ntgdi/dcobjs.c
++ gdi/ntgdi/dcstate.c
++ gdi/ntgdi/dcutil.c
++ gdi/ntgdi/device.c
++ gdi/ntgdi/dibobj.c
++ gdi/ntgdi/drawing.c
++ gdi/ntgdi/fillshap.c
++ gdi/ntgdi/font.c
++ gdi/ntgdi/freetype.c
++ gdi/ntgdi/gdibatch.c
++ gdi/ntgdi/gdidbg.c
++ gdi/ntgdi/gdiobj.c
++ gdi/ntgdi/gdipool.c
++ gdi/ntgdi/icm.c
++ gdi/ntgdi/line.c
++ gdi/ntgdi/metafile.c
++ gdi/ntgdi/palette.c
++ gdi/ntgdi/path.c
++ gdi/ntgdi/pen.c
++ gdi/ntgdi/polyfill.c
++ gdi/ntgdi/print.c
++ gdi/ntgdi/rect.c
++ gdi/ntgdi/region.c
++ gdi/ntgdi/stockobj.c
++ gdi/ntgdi/text.c
++ gdi/ntgdi/wingl.c
++ gdi/ntgdi/xformobj.c
++ gdi/eng/stubs.c
++ gdi/eng/umpdstubs.c
++ win32k.rc)
++
++if(USE_DIBLIB)
++ add_definitions(-D_USE_DIBLIB_)
++ list(APPEND SOURCE
++ gdi/dib/dib_new.c
++ gdi/eng/bitblt_new.c)
++else()
++ list(APPEND SOURCE
++ gdi/dib/dib.c
++ gdi/eng/copybits.c
++ ${GENDIB_FILES})
++endif()
++
+++if(USE_NEW_CURSORICON)
+++ add_definitions(-DNEW_CURSORICON)
+++ list(APPEND SOURCE user/ntuser/cursoricon_new.c)
+++else()
+++ list(APPEND SOURCE user/ntuser/cursoricon.c)
+++endif()
+++
++if(ARCH STREQUAL "i386")
++list(APPEND SOURCE
++ gdi/dib/i386/dib24bpp_hline.s
++ gdi/dib/i386/dib32bpp_hline.s
++ gdi/dib/i386/dib32bpp_colorfill.s
++ gdi/eng/i386/floatobj.S)
++else()
++list(APPEND SOURCE
++ gdi/dib/dib24bppc.c
++ gdi/dib/dib32bppc.c)
++endif()
++
++if(KDBG)
++ list(APPEND SOURCE
++ gdi/ntgdi/gdikdbgext.c)
++endif()
++
++add_library(win32k SHARED
++ ${CMAKE_CURRENT_BINARY_DIR}/win32k.def
++ ${SOURCE})
++
++set_module_type(win32k kernelmodedriver)
++
++target_link_libraries(win32k
++ ${PSEH_LIB}
++ dxguid
++ libcntpr)
++
++if(USE_DIBLIB)
++ target_link_libraries(win32k diblib)
++endif()
++
++add_importlibs(win32k ntoskrnl hal ftfd)
++add_pch(win32k pch.h)
++add_cd_file(TARGET win32k DESTINATION reactos/system32 FOR all)
++
++add_library(win32ksys sys-stubs.S)
++set_source_files_properties(sys-stubs.S PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/w32ksvc.h)
--- /dev/null
- &(cursor)->field != (list) && ((&((cursor)->field)) != NULL); \
+ #pragma once
+
+ typedef struct INTENG_ENTER_LEAVE_TAG
+ {
+ /* Contents is private to EngEnter/EngLeave */
+ SURFOBJ *DestObj;
+ SURFOBJ *OutputObj;
+ HBITMAP OutputBitmap;
+ CLIPOBJ *TrivialClipObj;
+ RECTL DestRect;
+ BOOL ReadOnly;
+ } INTENG_ENTER_LEAVE, *PINTENG_ENTER_LEAVE;
+
+ extern BOOL APIENTRY IntEngEnter(PINTENG_ENTER_LEAVE EnterLeave,
+ SURFOBJ *DestObj,
+ RECTL *DestRect,
+ BOOL ReadOnly,
+ POINTL *Translate,
+ SURFOBJ **OutputObj);
+
+ extern BOOL APIENTRY IntEngLeave(PINTENG_ENTER_LEAVE EnterLeave);
+
+ extern HGDIOBJ StockObjects[];
+ extern SHORT gusLanguageID;
+
+ SHORT FASTCALL UserGetLanguageID(VOID);
+ VOID FASTCALL IntUserManualGuiCheck(LONG Check);
+ PVOID APIENTRY HackSecureVirtualMemory(IN PVOID,IN SIZE_T,IN ULONG,OUT PVOID *);
+ VOID APIENTRY HackUnsecureVirtualMemory(IN PVOID);
+
+ NTSTATUS
+ NTAPI
+ RegOpenKey(
+ LPCWSTR pwszKeyName,
+ PHKEY phkey);
+
+ NTSTATUS
+ NTAPI
+ RegQueryValue(
+ IN HKEY hkey,
+ IN PCWSTR pwszValueName,
+ IN ULONG ulType,
+ OUT PVOID pvData,
+ IN OUT PULONG pcbValue);
+
+ VOID
+ NTAPI
+ RegWriteSZ(HKEY hkey, PWSTR pwszValue, PWSTR pwszData);
+
+ VOID
+ NTAPI
+ RegWriteDWORD(HKEY hkey, PWSTR pwszValue, DWORD dwData);
+
+ BOOL
+ NTAPI
+ RegReadDWORD(HKEY hkey, PWSTR pwszValue, PDWORD pdwData);
+
+ BOOL
+ NTAPI
+ RegReadUserSetting(
+ IN PCWSTR pwszKeyName,
+ IN PCWSTR pwszValueName,
+ IN ULONG ulType,
+ OUT PVOID pvData,
+ IN ULONG cbDataSize);
+
+ BOOL
+ NTAPI
+ RegWriteUserSetting(
+ IN PCWSTR pwszKeyName,
+ IN PCWSTR pwszValueName,
+ IN ULONG ulType,
+ OUT PVOID pvData,
+ IN ULONG cbDataSize);
+
+ VOID FASTCALL
+ SetLastNtError(
+ NTSTATUS Status);
+
+ typedef struct _GDI_POOL *PGDI_POOL;
+
+ PGDI_POOL
+ NTAPI
+ GdiPoolCreate(
+ ULONG cjAllocSize,
+ ULONG ulTag);
+
+ VOID
+ NTAPI
+ GdiPoolDestroy(PGDI_POOL pPool);
+
+ PVOID
+ NTAPI
+ GdiPoolAllocate(
+ PGDI_POOL pPool);
+
+ VOID
+ NTAPI
+ GdiPoolFree(
+ PGDI_POOL pPool,
+ PVOID pvAlloc);
+
+ FORCEINLINE
+ VOID
+ ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
+ {
+ /* Try acquiring the lock */
+ if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
+ {
+ /* Someone changed it, use the slow path */
+ ExfAcquirePushLockExclusive(PushLock);
+ }
+ }
+
+ FORCEINLINE
+ VOID
+ ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
+ {
+ EX_PUSH_LOCK OldValue;
+
+ /* Unlock the pushlock */
+ OldValue.Value = InterlockedExchangeAddSizeT((PSIZE_T)PushLock,
+ -(SSIZE_T)EX_PUSH_LOCK_LOCK);
+ /* Check if anyone is waiting on it and it's not already waking */
+ if ((OldValue.Waiting) && !(OldValue.Waking))
+ {
+ /* Wake it up */
+ ExfTryToWakePushLock(PushLock);
+ }
+ }
+
+ FORCEINLINE
+ VOID
+ _ExInitializePushLock(PEX_PUSH_LOCK Lock)
+ {
+ *(PULONG_PTR)Lock = 0;
+ }
+ #define ExInitializePushLock _ExInitializePushLock
+
+ NTSTATUS FASTCALL
+ IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
+ PUNICODE_STRING Source);
+
+ NTSTATUS FASTCALL
+ IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
+ PUNICODE_STRING Source);
+
+ HBITMAP NTAPI UserLoadImage(PCWSTR);
+
+ BOOL NTAPI W32kDosPathNameToNtPathName(PCWSTR, PUNICODE_STRING);
+
+ #define ROUND_DOWN(n, align) \
+ (((ULONG)n) & ~((align) - 1l))
+
+ #define ROUND_UP(n, align) \
+ ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
+
+ #define LIST_FOR_EACH(elem, list, type, field) \
+ for ((elem) = CONTAINING_RECORD((list)->Flink, type, field); \
+ &(elem)->field != (list) && ((&((elem)->field)) != NULL); \
+ (elem) = CONTAINING_RECORD((elem)->field.Flink, type, field))
+
+ #define LIST_FOR_EACH_SAFE(cursor, cursor2, list, type, field) \
+ for ((cursor) = CONTAINING_RECORD((list)->Flink, type, field), \
+ (cursor2) = CONTAINING_RECORD((cursor)->field.Flink, type, field); \
++ &(cursor)->field != (list); \
+ (cursor) = (cursor2), \
+ (cursor2) = CONTAINING_RECORD((cursor)->field.Flink, type, field))
--- /dev/null
- struct _ETHREAD* Thread; /* Thread owning the hook */
+ #ifndef __WIN32K_NTUSER_H
+ #define __WIN32K_NTUSER_H
+
+ typedef struct _PROCESSINFO *PPROCESSINFO;
+ typedef struct _THREADINFO *PTHREADINFO;
+ struct _DESKTOP;
+ struct _WND;
+
+ #define FIRST_USER_HANDLE 0x0020 /* first possible value for low word of user handle */
+ #define LAST_USER_HANDLE 0xffef /* last possible value for low word of user handle */
+
+ #define HANDLEENTRY_INDESTROY 1
+
+ typedef struct _USER_HANDLE_ENTRY
+ {
+ void *ptr; /* pointer to object */
+ union
+ {
+ PVOID pi;
+ PTHREADINFO pti; // pointer to Win32ThreadInfo
+ PPROCESSINFO ppi; // pointer to W32ProcessInfo
+ };
+ unsigned char type; /* object type (0 if free) */
+ unsigned char flags;
+ unsigned short generation; /* generation counter */
+ } USER_HANDLE_ENTRY, * PUSER_HANDLE_ENTRY;
+
+ typedef struct _USER_HANDLE_TABLE
+ {
+ PUSER_HANDLE_ENTRY handles;
+ PUSER_HANDLE_ENTRY freelist;
+ int nb_handles;
+ int allocated_handles;
+ } USER_HANDLE_TABLE, * PUSER_HANDLE_TABLE;
+
+ typedef enum _USER_OBJECT_TYPE
+ {
+ otFree = 0,
+ otWindow,
+ otMenu,
+ otCursorIcon,
+ otSMWP,
+ otHook,
+ otClipBoardData,
+ otCallProc,
+ otAccel,
+ otDDEaccess,
+ otDDEconv,
+ otDDExact,
+ otMonitor,
+ otKBDlayout,
+ otKBDfile,
+ otEvent,
+ otTimer,
+ otInputContext,
+ otHidData,
+ otDeviceInfo,
+ otTouchInput,
+ otGestureInfo,
+ USER_HANDLE_TYPE_COUNT
+ } USER_OBJECT_TYPE;
+
+ typedef enum _USERTHREADINFOCLASS
+ {
+ UserThreadShutdownInformation,
+ UserThreadFlags,
+ UserThreadTaskName,
+ UserThreadWOWInformation,
+ UserThreadHungStatus,
+ UserThreadInitiateShutdown,
+ UserThreadEndShutdown,
+ UserThreadUseActiveDesktop,
+ UserThreadUseDesktop,
+ UserThreadRestoreDesktop,
+ UserThreadCsrApiPort,
+ } USERTHREADINFOCLASS;
+
+ typedef struct _LARGE_UNICODE_STRING
+ {
+ ULONG Length;
+ ULONG MaximumLength:31;
+ ULONG bAnsi:1;
+ PWSTR Buffer;
+ } LARGE_UNICODE_STRING, *PLARGE_UNICODE_STRING;
+
+ typedef struct _LARGE_STRING
+ {
+ ULONG Length;
+ ULONG MaximumLength:31;
+ ULONG bAnsi:1;
+ PVOID Buffer;
+ } LARGE_STRING, *PLARGE_STRING;
+ //
+ // Based on ANSI_STRING
+ //
+ typedef struct _LARGE_ANSI_STRING
+ {
+ ULONG Length;
+ ULONG MaximumLength:31;
+ ULONG bAnsi:1;
+ PCHAR Buffer;
+ } LARGE_ANSI_STRING, *PLARGE_ANSI_STRING;
+
+ VOID NTAPI RtlInitLargeAnsiString(IN OUT PLARGE_ANSI_STRING,IN PCSZ,IN INT);
+ VOID NTAPI RtlInitLargeUnicodeString(IN OUT PLARGE_UNICODE_STRING,IN PCWSTR,IN INT);
+ BOOL NTAPI RtlLargeStringToUnicodeString( PUNICODE_STRING, PLARGE_STRING);
+
+ #define NB_HOOKS (WH_MAXHOOK-WH_MINHOOK+1)
+
+ typedef struct _DESKTOPINFO
+ {
+ PVOID pvDesktopBase;
+ PVOID pvDesktopLimit;
+ struct _WND *spwnd;
+ DWORD fsHooks;
+ LIST_ENTRY aphkStart[NB_HOOKS];
+
+ HWND hTaskManWindow;
+ HWND hProgmanWindow;
+ HWND hShellWindow;
+
+ PPROCESSINFO ppiShellProcess;
+
+ union
+ {
+ UINT Dummy;
+ struct
+ {
+ UINT LastInputWasKbd : 1;
+ };
+ };
+
+ WCHAR szDesktopName[1];
+ } DESKTOPINFO, *PDESKTOPINFO;
+
+ #define CTI_THREADSYSLOCK 0x0001
+ #define CTI_INSENDMESSAGE 0x0002
+
+ typedef struct _CLIENTTHREADINFO
+ {
+ DWORD CTI_flags;
+ WORD fsChangeBits;
+ WORD fsWakeBits;
+ WORD fsWakeBitsJournal;
+ WORD fsWakeMask;
+ ULONG tickLastMsgChecked;
+ DWORD dwcPumpHook;
+ } CLIENTTHREADINFO, *PCLIENTTHREADINFO;
+
+ typedef struct _HEAD
+ {
+ HANDLE h;
+ DWORD cLockObj;
+ } HEAD, *PHEAD;
+
+ typedef struct _THROBJHEAD
+ {
+ HEAD;
+ PTHREADINFO pti;
+ } THROBJHEAD, *PTHROBJHEAD;
+
+ typedef struct _THRDESKHEAD
+ {
+ THROBJHEAD;
+ struct _DESKTOP *rpdesk;
+ PVOID pSelf;
+ } THRDESKHEAD, *PTHRDESKHEAD;
+
+ typedef struct _PROCDESKHEAD
+ {
+ HEAD;
+ DWORD hTaskWow;
+ struct _DESKTOP *rpdesk;
+ PVOID pSelf;
+ } PROCDESKHEAD, *PPROCDESKHEAD;
+
+ typedef struct _PROCMARKHEAD
+ {
+ HEAD;
+ ULONG hTaskWow;
+ PPROCESSINFO ppi;
+ } PROCMARKHEAD, *PPROCMARKHEAD;
+
+ #define UserHMGetHandle(obj) ((obj)->head.h)
+
+ /* Window Client Information structure */
+ struct _ETHREAD;
+
+ #define WEF_SETBYWNDPTI 0x0001
+
+ typedef struct tagHOOK
+ {
+ THRDESKHEAD head;
+ struct tagHOOK *phkNext; /* This is for user space. */
+ int HookId; /* Hook table index */
+ ULONG_PTR offPfn;
+ ULONG flags; /* Some internal flags */
+ INT ihmod;
+ PTHREADINFO ptiHooked;
+ struct _DESKTOP *rpdesk;
+ /* ReactOS */
+ LIST_ENTRY Chain; /* Hook chain entry */
- #if 0 // Correct type.
+ HOOKPROC Proc; /* Hook function */
+ BOOLEAN Ansi; /* Is it an Ansi hook? */
+ UNICODE_STRING ModuleName; /* Module name for global hooks */
+ } HOOK, *PHOOK;
+
+ typedef struct tagCLIPBOARDDATA
+ {
+ HEAD head;
+ DWORD cbData;
+ BYTE Data[0];
+ } CLIPBOARDDATA, *PCLIPBOARDDATA;
+
+ /* THREADINFO Flags */
+ #define TIF_INCLEANUP 0x00000001
+ #define TIF_16BIT 0x00000002
+ #define TIF_SYSTEMTHREAD 0x00000004
+ #define TIF_CSRSSTHREAD 0x00000008
+ #define TIF_TRACKRECTVISIBLE 0x00000010
+ #define TIF_ALLOWFOREGROUNDACTIVATE 0x00000020
+ #define TIF_DONTATTACHQUEUE 0x00000040
+ #define TIF_DONTJOURNALATTACH 0x00000080
+ #define TIF_WOW64 0x00000100
+ #define TIF_INACTIVATEAPPMSG 0x00000200
+ #define TIF_SPINNING 0x00000400
+ #define TIF_PALETTEAWARE 0x00000800
+ #define TIF_SHAREDWOW 0x00001000
+ #define TIF_FIRSTIDLE 0x00002000
+ #define TIF_WAITFORINPUTIDLE 0x00004000
+ #define TIF_MOVESIZETRACKING 0x00008000
+ #define TIF_VDMAPP 0x00010000
+ #define TIF_DOSEMULATOR 0x00020000
+ #define TIF_GLOBALHOOKER 0x00040000
+ #define TIF_DELAYEDEVENT 0x00080000
+ #define TIF_MSGPOSCHANGED 0x00100000
+ #define TIF_SHUTDOWNCOMPLETE 0x00200000
+ #define TIF_IGNOREPLAYBACKDELAY 0x00400000
+ #define TIF_ALLOWOTHERACCOUNTHOOK 0x00800000
+ #define TIF_GUITHREADINITIALIZED 0x02000000
+ #define TIF_DISABLEIME 0x04000000
+ #define TIF_INGETTEXTLENGTH 0x08000000
+ #define TIF_ANSILENGTH 0x10000000
+ #define TIF_DISABLEHOOKS 0x20000000
+
+ typedef struct _CALLBACKWND
+ {
+ HWND hWnd;
+ struct _WND *pWnd;
+ PVOID pActCtx;
+ } CALLBACKWND, *PCALLBACKWND;
+
+ #define CI_TRANSACTION 0x00000001
+ #define CI_QUEUEMSG 0x00000002
+ #define CI_WOW 0x00000004
+ #define CI_INITTHREAD 0x00000008
+ #define CI_CURTHPRHOOK 0x00000010
+ #define CI_CLASSESREGISTERED 0x00000020
+ #define CI_IMMACTIVATE 0x00000040
+
+ typedef struct _CLIENTINFO
+ {
+ ULONG_PTR CI_flags;
+ ULONG_PTR cSpins;
+ DWORD dwExpWinVer;
+ DWORD dwCompatFlags;
+ DWORD dwCompatFlags2;
+ DWORD dwTIFlags; // ThreadInfo TIF_Xxx flags for User space.
+ PDESKTOPINFO pDeskInfo;
+ ULONG_PTR ulClientDelta;
+ PHOOK phkCurrent;
+ ULONG fsHooks;
+ CALLBACKWND CallbackWnd;
+ DWORD dwHookCurrent;
+ INT cInDDEMLCallback;
+ PCLIENTTHREADINFO pClientThreadInfo;
+ ULONG_PTR dwHookData;
+ DWORD dwKeyCache;
+ BYTE afKeyState[8];
+ DWORD dwAsyncKeyCache;
+ BYTE afAsyncKeyState[8];
+ BYTE afAsyncKeyStateRecentDow[8];
+ HKL hKL;
+ USHORT CodePage;
+ UCHAR achDbcsCF[2];
+ MSG msgDbcsCB;
+ LPDWORD lpdwRegisteredClasses;
+ ULONG Win32ClientInfo3[26];
+ /* It's just a pointer reference not to be used w the structure in user space. */
+ PPROCESSINFO ppi;
+ } CLIENTINFO, *PCLIENTINFO;
+
+ /* Make sure it fits into the TEB */
+ C_ASSERT(sizeof(CLIENTINFO) <= sizeof(((PTEB)0)->Win32ClientInfo));
+
+ #define GetWin32ClientInfo() ((PCLIENTINFO)(NtCurrentTeb()->Win32ClientInfo))
+
+ #define HRGN_NULL ( (HRGN) 0) // NULL empty region
+ #define HRGN_WINDOW ( (HRGN) 1) // region from window rcWindow
+ #define HRGN_MONITOR ( (HRGN) 2) // region from monitor region.
+
+ /* Menu Item fType. */
+ #define MFT_RTOL 0x6000
+
+ typedef struct tagITEM
+ {
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ struct tagMENU* spSubMenu; /* Pop-up menu. */
+ HANDLE hbmpChecked;
+ HANDLE hbmpUnchecked;
+ USHORT* lpstr; /* Item text pointer. */
+ ULONG cch;
+ DWORD_PTR dwItemData;
+ ULONG xItem; /* Item position. left */
+ ULONG yItem; /* " top */
+ ULONG cxItem; /* Item Size Width */
+ ULONG cyItem; /* " Height */
+ ULONG dxTab; /* X position of text after Tab */
+ ULONG ulX; /* underline.. start position */
+ ULONG ulWidth; /* underline.. width */
+ HBITMAP hbmp; /* bitmap */
+ INT cxBmp; /* Width Maximum size of the bitmap items in MIIM_BITMAP state */
+ INT cyBmp; /* Height " */
+ } ITEM, *PITEM;
+
+ typedef struct tagMENULIST
+ {
+ struct tagMENULIST* pNext;
+ struct tagMENU* pMenu;
+ } MENULIST, *PMENULIST;
+
+ /* Menu fFlags, upper byte is MNS_X style flags. */
+ #define MNF_POPUP 0x0001
+ #define MNF_UNDERLINE 0x0004
+ #define MNF_INACTIVE 0x0010
+ #define MNF_RTOL 0x0020
+ #define MNF_DESKTOPMN 0x0040
+ #define MNF_SYSDESKMN 0x0080
+ #define MNF_SYSSUBMENU 0x0100
+
+ typedef struct tagMENU
+ {
+ PROCDESKHEAD head;
+ ULONG fFlags; /* [Style flags | Menu flags] */
+ INT iItem; /* nPos of selected item, if -1 not selected. */
+ UINT cAlloced; /* Number of allocated items. Inc's of 8 */
+ UINT cItems; /* Number of items in the menu */
+ ULONG cxMenu; /* Width of the whole menu */
+ ULONG cyMenu; /* Height of the whole menu */
+ ULONG cxTextAlign; /* Offset of text when items have both bitmaps and text */
+ struct _WND *spwndNotify; /* window receiving the messages for ownerdraw */
+ PITEM rgItems; /* Array of menu items */
+ struct tagMENULIST* pParentMenus; /* If this is SubMenu, list of parents. */
+ DWORD dwContextHelpId;
+ ULONG cyMax; /* max height of the whole menu, 0 is screen height */
+ DWORD_PTR dwMenuData; /* application defined value */
+ HBRUSH hbrBack; /* brush for menu background */
+ INT iTop; /* Current scroll position Top */
+ INT iMaxTop; /* Current scroll position Max Top */
+ DWORD dwArrowsOn:2; /* Arrows: 0 off, 1 on, 2 to the top, 3 to the bottom. */
+ } MENU, *PMENU;
+
+ typedef struct _REGISTER_SYSCLASS
+ {
+ /* This is a reactos specific class used to initialize the
+ system window classes during user32 initialization */
+ PWSTR ClassName;
+ UINT Style;
+ WNDPROC ProcW;
+ UINT ExtraBytes;
+ HICON hCursor;
+ HBRUSH hBrush;
+ WORD fiId;
+ WORD iCls;
+ } REGISTER_SYSCLASS, *PREGISTER_SYSCLASS;
+
+ typedef struct _CLSMENUNAME
+ {
+ LPSTR pszClientAnsiMenuName;
+ LPWSTR pwszClientUnicodeMenuName;
+ PUNICODE_STRING pusMenuName;
+ } CLSMENUNAME, *PCLSMENUNAME;
+
+ typedef struct tagSBDATA
+ {
+ INT posMin;
+ INT posMax;
+ INT page;
+ INT pos;
+ } SBDATA, *PSBDATA;
+
+ typedef struct tagSBINFO
+ {
+ INT WSBflags;
+ SBDATA Horz;
+ SBDATA Vert;
+ } SBINFO, *PSBINFO;
+
+ typedef struct tagSBCALC
+ {
+ INT posMin;
+ INT posMax;
+ INT page;
+ INT pos;
+ INT pxTop;
+ INT pxBottom;
+ INT pxLeft;
+ INT pxRight;
+ INT cpxThumb;
+ INT pxUpArrow;
+ INT pxDownArrow;
+ INT pxStart;
+ INT pxThumbBottom;
+ INT pxThumbTop;
+ INT cpx;
+ INT pxMin;
+ } SBCALC, *PSBCALC;
+
+ typedef enum _GETCPD
+ {
+ UserGetCPDA2U = 0x01, // " Unicode "
+ UserGetCPDU2A = 0X02, // " Ansi "
+ UserGetCPDClass = 0X10,
+ UserGetCPDWindow = 0X20,
+ UserGetCPDDialog = 0X40,
+ UserGetCPDWndtoCls = 0X80
+ } GETCPD, *PGETCPD;
+
+ typedef struct _CALLPROCDATA
+ {
+ PROCDESKHEAD head;
+ struct _CALLPROCDATA *spcpdNext;
+ WNDPROC pfnClientPrevious;
+ GETCPD wType;
+ } CALLPROCDATA, *PCALLPROCDATA;
+
+ #define CSF_SERVERSIDEPROC 0x0001
+ #define CSF_ANSIPROC 0x0002
+ #define CSF_WOWDEFERDESTROY 0x0004
+ #define CSF_SYSTEMCLASS 0x0008
+ #define CSF_WOWCLASS 0x0010
+ #define CSF_WOWEXTRA 0x0020
+ #define CSF_CACHEDSMICON 0x0040
+ #define CSF_WIN40COMPAT 0x0080
+
+ typedef struct _CLS
+ {
+ struct _CLS *pclsNext;
+ RTL_ATOM atomClassName;
+ ATOM atomNVClassName;
+ DWORD fnid;
+ struct _DESKTOP *rpdeskParent;
+ PVOID pdce;
+ DWORD CSF_flags;
+ PSTR lpszClientAnsiMenuName; // For client use
+ PWSTR lpszClientUnicodeMenuName; // " " "
+ PCALLPROCDATA spcpdFirst;
+ struct _CLS *pclsBase;
+ struct _CLS *pclsClone;
+ ULONG cWndReferenceCount;
+ UINT style;
+ WNDPROC lpfnWndProc;
+ INT cbclsExtra;
+ INT cbwndExtra;
+ HINSTANCE hModule;
+ HANDLE hIcon; /* FIXME - Use pointer! */
+ //PCURSOR spicn;
+ HANDLE hCursor; /* FIXME - Use pointer! */
+ //PCURSOR spcur;
+ HBRUSH hbrBackground;
+ PWSTR lpszMenuName; // kernel use
+ PSTR lpszAnsiClassName; // "
+ HANDLE hIconSm; /* FIXME - Use pointer! */
+ //PCURSOR spicnSm;
+
+ UINT Unicode : 1; // !CSF_ANSIPROC
+ UINT Global : 1; // CS_GLOBALCLASS or CSF_SERVERSIDEPROC
+ UINT MenuNameIsString : 1;
+ UINT NotUsed : 29;
+ } CLS, *PCLS;
+
+
+ typedef struct _SBINFOEX
+ {
+ SCROLLBARINFO ScrollBarInfo;
+ SCROLLINFO ScrollInfo;
+ } SBINFOEX, *PSBINFOEX;
+
+ // State Flags !Not Implemented!
+ #define WNDS_HASMENU 0X00000001
+ #define WNDS_HASVERTICALSCROOLLBAR 0X00000002
+ #define WNDS_HASHORIZONTALSCROLLBAR 0X00000004
+ #define WNDS_HASCAPTION 0X00000008
+ #define WNDS_SENDSIZEMOVEMSGS 0X00000010
+ #define WNDS_MSGBOX 0X00000020
+ #define WNDS_ACTIVEFRAME 0X00000040
+ #define WNDS_HASSPB 0X00000080
+ #define WNDS_NONCPAINT 0X00000100
+ #define WNDS_SENDERASEBACKGROUND 0X00000200
+ #define WNDS_ERASEBACKGROUND 0X00000400
+ #define WNDS_SENDNCPAINT 0X00000800
+ #define WNDS_INTERNALPAINT 0X00001000
+ #define WNDS_UPDATEDIRTY 0X00002000
+ #define WNDS_HIDDENPOPUP 0X00004000
+ #define WNDS_FORCEMENUDRAW 0X00008000
+ #define WNDS_DIALOGWINDOW 0X00010000
+ #define WNDS_HASCREATESTRUCTNAME 0X00020000
+ #define WNDS_SERVERSIDEWINDOWPROC 0x00040000 // Call proc inside win32k.
+ #define WNDS_ANSIWINDOWPROC 0x00080000
+ #define WNDS_BEINGACTIVATED 0x00100000
+ #define WNDS_HASPALETTE 0x00200000
+ #define WNDS_PAINTNOTPROCESSED 0x00400000
+ #define WNDS_SYNCPAINTPENDING 0x00800000
+ #define WNDS_RECIEVEDQUERYSUSPENDMSG 0x01000000
+ #define WNDS_RECIEVEDSUSPENDMSG 0x02000000
+ #define WNDS_TOGGLETOPMOST 0x04000000
+ #define WNDS_REDRAWIFHUNG 0x08000000
+ #define WNDS_REDRAWFRAMEIFHUNG 0x10000000
+ #define WNDS_ANSICREATOR 0x20000000
+ #define WNDS_MAXIMIZESTOMONITOR 0x40000000
+ #define WNDS_DESTROYED 0x80000000
+
+ #define WNDSACTIVEFRAME 0x00000006
+
+ // State2 Flags !Not Implemented!
+ #define WNDS2_WMPAINTSENT 0X00000001
+ #define WNDS2_ENDPAINTINVALIDATE 0X00000002
+ #define WNDS2_STARTPAINT 0X00000004
+ #define WNDS2_OLDUI 0X00000008
+ #define WNDS2_HASCLIENTEDGE 0X00000010
+ #define WNDS2_BOTTOMMOST 0X00000020
+ #define WNDS2_FULLSCREEN 0X00000040
+ #define WNDS2_INDESTROY 0X00000080
+ #define WNDS2_WIN31COMPAT 0X00000100
+ #define WNDS2_WIN40COMPAT 0X00000200
+ #define WNDS2_WIN50COMPAT 0X00000400
+ #define WNDS2_MAXIMIZEDMONITORREGION 0X00000800
+ #define WNDS2_CLOSEBUTTONDOWN 0X00001000
+ #define WNDS2_MAXIMIZEBUTTONDOWN 0X00002000
+ #define WNDS2_MINIMIZEBUTTONDOWN 0X00004000
+ #define WNDS2_HELPBUTTONDOWN 0X00008000
+ #define WNDS2_SCROLLBARLINEUPBTNDOWN 0X00010000
+ #define WNDS2_SCROLLBARPAGEUPBTNDOWN 0X00020000
+ #define WNDS2_SCROLLBARPAGEDOWNBTNDOWN 0X00040000
+ #define WNDS2_SCROLLBARLINEDOWNBTNDOWN 0X00080000
+ #define WNDS2_ANYSCROLLBUTTONDOWN 0X00100000
+ #define WNDS2_SCROLLBARVERTICALTRACKING 0X00200000
+ #define WNDS2_FORCENCPAINT 0X00400000
+ #define WNDS2_FORCEFULLNCPAINTCLIPRGN 0X00800000
+ #define WNDS2_FULLSCREENMODE 0X01000000
+ #define WNDS2_CAPTIONTEXTTRUNCATED 0X08000000
+ #define WNDS2_NOMINMAXANIMATERECTS 0X10000000
+ #define WNDS2_SMALLICONFROMWMQUERYDRAG 0X20000000
+ #define WNDS2_SHELLHOOKREGISTERED 0X40000000
+ #define WNDS2_WMCREATEMSGPROCESSED 0X80000000
+
+ /* ExStyles2 */
+ #define WS_EX2_CLIPBOARDLISTENER 0X00000001
+ #define WS_EX2_LAYEREDINVALIDATE 0X00000002
+ #define WS_EX2_REDIRECTEDFORPRINT 0X00000004
+ #define WS_EX2_LINKED 0X00000008
+ #define WS_EX2_LAYEREDFORDWM 0X00000010
+ #define WS_EX2_LAYEREDLIMBO 0X00000020
+ #define WS_EX2_HIGHTDPI_UNAWAR 0X00000040
+ #define WS_EX2_VERTICALLYMAXIMIZEDLEFT 0X00000080
+ #define WS_EX2_VERTICALLYMAXIMIZEDRIGHT 0X00000100
+ #define WS_EX2_HASOVERLAY 0X00000200
+ #define WS_EX2_CONSOLEWINDOW 0X00000400
+ #define WS_EX2_CHILDNOACTIVATE 0X00000800
+
+ #define WPF_MININIT 0x0008
+ #define WPF_MAXINIT 0x0010
+
+ typedef struct _WND
+ {
+ THRDESKHEAD head;
+ DWORD state;
+ DWORD state2;
+ /* Extended style. */
+ DWORD ExStyle;
+ /* Style. */
+ DWORD style;
+ /* Handle of the module that created the window. */
+ HINSTANCE hModule;
+ DWORD fnid;
+ struct _WND *spwndNext;
+ struct _WND *spwndPrev;
+ struct _WND *spwndParent;
+ struct _WND *spwndChild;
+ struct _WND *spwndOwner;
+ RECT rcWindow;
+ RECT rcClient;
+ WNDPROC lpfnWndProc;
+ /* Pointer to the window class. */
+ PCLS pcls;
+ HRGN hrgnUpdate;
+ /* Property list head.*/
+ LIST_ENTRY PropListHead;
+ ULONG PropListItems;
+ /* Scrollbar info */
+ PSBINFO pSBInfo;
+ /* system menu handle. */
+ HMENU SystemMenu;
+ //PMENU spmenuSys;
+ /* Window menu handle or window id */
+ UINT IDMenu; // Use spmenu
+ //PMENU spmenu;
+ HRGN hrgnClip;
+ HRGN hrgnNewFrame;
+ /* Window name. */
+ LARGE_UNICODE_STRING strName;
+ /* Size of the extra data associated with the window. */
+ ULONG cbwndExtra;
+ struct _WND *spwndLastActive;
+ //HIMC hImc; // Input context associated with this window.
+ LONG dwUserData;
+ PVOID pActCtx;
+ //PD3DMATRIX pTransForm;
+ struct _WND *spwndClipboardListener;
+ DWORD ExStyle2;
+
+ /* ReactOS */
+ struct
+ {
+ RECT NormalRect;
+ POINT IconPos;
+ POINT MaxPos;
+ UINT flags; // WPF_ flags.
+ } InternalPos;
+
+ UINT Unicode : 1; // !(WNDS_ANSICREATOR|WNDS_ANSIWINDOWPROC) ?
+ UINT InternalPosInitialized : 1;
+ UINT HideFocus : 1; // WS_EX_UISTATEFOCUSRECTHIDDEN ?
+ UINT HideAccel : 1; // WS_EX_UISTATEKBACCELHIDDEN ?
+
+ /* Scrollbar info */
+ PSBINFOEX pSBInfoex; // convert to PSBINFO
+ /* Entry in the list of thread windows. */
+ LIST_ENTRY ThreadListEntry;
+ } WND, *PWND;
+
+ #define PWND_BOTTOM ((PWND)1)
+
+ typedef struct _SBWND
+ {
+ WND wnd;
+ BOOL fVert;
+ UINT wDisableFlags;
+ SBCALC SBCalc;
+ } SBWND, *PSBWND;
+
+ typedef struct _PFNCLIENT
+ {
+ WNDPROC pfnScrollBarWndProc;
+ WNDPROC pfnTitleWndProc;
+ WNDPROC pfnMenuWndProc;
+ WNDPROC pfnDesktopWndProc;
+ WNDPROC pfnDefWindowProc;
+ WNDPROC pfnMessageWindowProc;
+ WNDPROC pfnSwitchWindowProc;
+ WNDPROC pfnButtonWndProc;
+ WNDPROC pfnComboBoxWndProc;
+ WNDPROC pfnComboListBoxProc;
+ WNDPROC pfnDialogWndProc;
+ WNDPROC pfnEditWndProc;
+ WNDPROC pfnListBoxWndProc;
+ WNDPROC pfnMDIClientWndProc;
+ WNDPROC pfnStaticWndProc;
+ WNDPROC pfnImeWndProc;
+ WNDPROC pfnGhostWndProc;
+ WNDPROC pfnHkINLPCWPSTRUCT;
+ WNDPROC pfnHkINLPCWPRETSTRUCT;
+ WNDPROC pfnDispatchHook;
+ WNDPROC pfnDispatchDefWindowProc;
+ WNDPROC pfnDispatchMessage;
+ WNDPROC pfnMDIActivateDlgProc;
+ } PFNCLIENT, *PPFNCLIENT;
+
+ /*
+ Wine Common proc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL Unicode );
+ Windows uses Ansi == TRUE, Wine uses Unicode == TRUE.
+ */
+
+ typedef LRESULT(CALLBACK *WNDPROC_EX)(HWND,UINT,WPARAM,LPARAM,BOOL);
+
+ typedef struct _PFNCLIENTWORKER
+ {
+ WNDPROC_EX pfnButtonWndProc;
+ WNDPROC_EX pfnComboBoxWndProc;
+ WNDPROC_EX pfnComboListBoxProc;
+ WNDPROC_EX pfnDialogWndProc;
+ WNDPROC_EX pfnEditWndProc;
+ WNDPROC_EX pfnListBoxWndProc;
+ WNDPROC_EX pfnMDIClientWndProc;
+ WNDPROC_EX pfnStaticWndProc;
+ WNDPROC_EX pfnImeWndProc;
+ WNDPROC_EX pfnGhostWndProc;
+ WNDPROC_EX pfnCtfHookProc;
+ } PFNCLIENTWORKER, *PPFNCLIENTWORKER;
+
+ typedef LONG_PTR (NTAPI *PFN_FNID)(PWND, UINT, WPARAM, LPARAM, ULONG_PTR);
+
+ // FNID's for NtUserSetWindowFNID, NtUserMessageCall
+ #define FNID_FIRST 0x029A
+ #define FNID_SCROLLBAR 0x029A
+ #define FNID_ICONTITLE 0x029B
+ #define FNID_MENU 0x029C
+ #define FNID_DESKTOP 0x029D
+ #define FNID_DEFWINDOWPROC 0x029E
+ #define FNID_MESSAGEWND 0x029F
+ #define FNID_SWITCH 0x02A0
+ #define FNID_BUTTON 0x02A1
+ #define FNID_COMBOBOX 0x02A2
+ #define FNID_COMBOLBOX 0x02A3
+ #define FNID_DIALOG 0x02A4
+ #define FNID_EDIT 0x02A5
+ #define FNID_LISTBOX 0x02A6
+ #define FNID_MDICLIENT 0x02A7
+ #define FNID_STATIC 0x02A8
+ #define FNID_IME 0x02A9
+ #define FNID_GHOST 0x02AA
+ #define FNID_CALLWNDPROC 0x02AB
+ #define FNID_CALLWNDPROCRET 0x02AC
+ #define FNID_HKINLPCWPEXSTRUCT 0x02AD
+ #define FNID_HKINLPCWPRETEXSTRUCT 0x02AE
+ #define FNID_MB_DLGPROC 0x02AF
+ #define FNID_MDIACTIVATEDLGPROC 0x02B0
+ #define FNID_SENDMESSAGE 0x02B1
+ #define FNID_SENDMESSAGEFF 0x02B2
+ // Kernel has option to use TimeOut or normal msg send, based on type of msg.
+ #define FNID_SENDMESSAGEWTOOPTION 0x02B3
+ #define FNID_SENDMESSAGECALLPROC 0x02B4
+ #define FNID_BROADCASTSYSTEMMESSAGE 0x02B5
+ #define FNID_TOOLTIPS 0x02B6
+ #define FNID_SENDNOTIFYMESSAGE 0x02B7
+ #define FNID_SENDMESSAGECALLBACK 0x02B8
+ #define FNID_LAST 0x02B9
+
+ #define FNID_NUM FNID_LAST - FNID_FIRST + 1
+ #define FNID_NUMSERVERPROC FNID_SWITCH - FNID_FIRST + 1
+
+ #define FNID_DDEML 0x2000 // Registers DDEML
+ #define FNID_DESTROY 0x4000 // This is sent when WM_NCDESTROY or in the support routine.
+ // Seen during WM_CREATE on error exit too.
+ #define FNID_FREED 0x8000 // Window being Freed...
+
+ #define ICLASS_TO_MASK(iCls) (1 << ((iCls)))
+
+ #define GETPFNCLIENTA(fnid)\
+ (WNDPROC)(*(((ULONG_PTR *)&gpsi->apfnClientA) + (fnid - FNID_FIRST)))
+ #define GETPFNCLIENTW(fnid)\
+ (WNDPROC)(*(((ULONG_PTR *)&gpsi->apfnClientW) + (fnid - FNID_FIRST)))
+
+ #define GETPFNSERVER(fnid) gpsi->aStoCidPfn[fnid - FNID_FIRST]
+
+ // ICLS's for NtUserGetClassName FNID to ICLS, NtUserInitializeClientPfnArrays
+ #define ICLS_BUTTON 0
+ #define ICLS_EDIT 1
+ #define ICLS_STATIC 2
+ #define ICLS_LISTBOX 3
+ #define ICLS_SCROLLBAR 4
+ #define ICLS_COMBOBOX 5
+ #define ICLS_MDICLIENT 6
+ #define ICLS_COMBOLBOX 7
+ #define ICLS_DDEMLEVENT 8
+ #define ICLS_DDEMLMOTHER 9
+ #define ICLS_DDEML16BIT 10
+ #define ICLS_DDEMLCLIENTA 11
+ #define ICLS_DDEMLCLIENTW 12
+ #define ICLS_DDEMLSERVERA 13
+ #define ICLS_DDEMLSERVERW 14
+ #define ICLS_IME 15
+ #define ICLS_GHOST 16
+ #define ICLS_DESKTOP 17
+ #define ICLS_DIALOG 18
+ #define ICLS_MENU 19
+ #define ICLS_SWITCH 20
+ #define ICLS_ICONTITLE 21
+ #define ICLS_TOOLTIPS 22
+ #if (_WIN32_WINNT <= 0x0501)
+ #define ICLS_UNKNOWN 22
+ #define ICLS_NOTUSED 23
+ #else
+ #define ICLS_SYSSHADOW 23
+ #define ICLS_HWNDMESSAGE 24
+ #define ICLS_NOTUSED 25
+ #endif
+ #define ICLS_END 31
+
+ #define COLOR_LAST COLOR_MENUBAR
+ #define MAX_MB_STRINGS 11
+
+ #define SRVINFO_APIHOOK 0x0010
+ #define SRVINFO_METRICS 0x0020
+ #define SRVINFO_KBDPREF 0x0080
+
+ #define NUM_SYSCOLORS 31
+
+ typedef struct tagOEMBITMAPINFO
+ {
+ INT x;
+ INT y;
+ INT cx;
+ INT cy;
+ } OEMBITMAPINFO, *POEMBITMAPINFO;
+
+ typedef struct tagMBSTRING
+ {
+ WCHAR szName[16];
+ UINT uID;
+ UINT uStr;
+ } MBSTRING, *PMBSTRING;
+
+ typedef struct tagDPISERVERINFO
+ {
+ INT gclBorder; /* 000 */
+ HFONT hCaptionFont; /* 004 */
+ HFONT hMsgFont; /* 008 */
+ INT cxMsgFontChar; /* 00C */
+ INT cyMsgFontChar; /* 010 */
+ UINT wMaxBtnSize; /* 014 */
+ } DPISERVERINFO, *PDPISERVERINFO;
+
+ // PUSIFlags:
+ #define PUSIF_PALETTEDISPLAY 0x01
+ #define PUSIF_SNAPTO 0x02
+ #define PUSIF_COMBOBOXANIMATION 0x04
+ #define PUSIF_LISTBOXSMOOTHSCROLLING 0x08
+ #define PUSIF_KEYBOARDCUES 0x20
+
+ typedef struct _PERUSERSERVERINFO
+ {
+ INT aiSysMet[SM_CMETRICS];
+ ULONG argbSystemUnmatched[NUM_SYSCOLORS];
+ COLORREF argbSystem[NUM_SYSCOLORS];
+ HBRUSH ahbrSystem[NUM_SYSCOLORS];
+ HBRUSH hbrGray;
+ POINT ptCursor;
+ POINT ptCursorReal;
+ DWORD dwLastRITEventTickCount;
+ INT nEvents;
+ UINT dtScroll;
+ UINT dtLBSearch;
+ UINT dtCaretBlink;
+ UINT ucWheelScrollLines;
+ UINT ucWheelScrollChars;
+ INT wMaxLeftOverlapChars;
+ INT wMaxRightOverlapChars;
+ INT cxSysFontChar;
+ INT cySysFontChar;
+ TEXTMETRICW tmSysFont;
+ DPISERVERINFO dpiSystem;
+ HICON hIconSmWindows;
+ HICON hIcoWindows;
+ DWORD dwKeyCache;
+ DWORD dwAsyncKeyCache;
+ ULONG cCaptures;
+ OEMBITMAPINFO oembmi[93];
+ RECT rcScreenReal;
+ USHORT BitCount;
+ USHORT dmLogPixels;
+ BYTE Planes;
+ BYTE BitsPixel;
+ ULONG PUSIFlags;
+ UINT uCaretWidth;
+ USHORT UILangID;
+ DWORD dwLastSystemRITEventTickCountUpdate;
+ ULONG adwDBGTAGFlags[35];
+ DWORD dwTagCount;
+ DWORD dwRIPFlags;
+ } PERUSERSERVERINFO, *PPERUSERSERVERINFO;
+
+ typedef struct tagSERVERINFO
+ {
+ DWORD dwSRVIFlags;
+ ULONG_PTR cHandleEntries;
+ PFN_FNID mpFnidPfn[FNID_NUM];
+ WNDPROC aStoCidPfn[FNID_NUMSERVERPROC];
+ USHORT mpFnid_serverCBWndProc[FNID_NUM];
+ PFNCLIENT apfnClientA;
+ PFNCLIENT apfnClientW;
+ PFNCLIENTWORKER apfnClientWorker;
+ ULONG cbHandleTable;
+ ATOM atomSysClass[ICLS_NOTUSED+1];
+ DWORD dwDefaultHeapBase;
+ DWORD dwDefaultHeapSize;
+ UINT uiShellMsg;
+ MBSTRING MBStrings[MAX_MB_STRINGS];
+ ATOM atomIconSmProp;
+ ATOM atomIconProp;
+ ATOM atomContextHelpIdProp;
+ ATOM atomFrostedWindowProp;
+ CHAR acOemToAnsi[256];
+ CHAR acAnsiToOem[256];
+ DWORD dwInstalledEventHooks;
+ PERUSERSERVERINFO;
+ } SERVERINFO, *PSERVERINFO;
+
+
+ // Server event activity bits.
+ #define SRV_EVENT_MENU 0x0001
+ #define SRV_EVENT_END_APPLICATION 0x0002
+ #define SRV_EVENT_RUNNING 0x0004
+ #define SRV_EVENT_NAMECHANGE 0x0008
+ #define SRV_EVENT_VALUECHANGE 0x0010
+ #define SRV_EVENT_STATECHANGE 0x0020
+ #define SRV_EVENT_LOCATIONCHANGE 0x0040
+ #define SRV_EVENT_CREATE 0x8000
+
+ typedef struct _PROPLISTITEM
+ {
+ ATOM Atom;
+ HANDLE Data;
+ } PROPLISTITEM, *PPROPLISTITEM;
+
+ typedef struct _PROPERTY
+ {
+ LIST_ENTRY PropListEntry;
+ HANDLE Data;
+ ATOM Atom;
+ } PROPERTY, *PPROPERTY;
+
+ typedef struct _BROADCASTPARM
+ {
+ DWORD flags;
+ DWORD recipients;
+ HDESK hDesk;
+ HWND hWnd;
+ LUID luid;
+ } BROADCASTPARM, *PBROADCASTPARM;
+
+ PTHREADINFO GetW32ThreadInfo(VOID);
+ PPROCESSINFO GetW32ProcessInfo(VOID);
+
+ typedef struct _WNDMSG
+ {
+ DWORD maxMsgs;
+ PINT abMsgs;
+ } WNDMSG, *PWNDMSG;
+
+ typedef struct _SHAREDINFO
+ {
+ PSERVERINFO psi; // global Server Info
+ PVOID aheList; // Handle Entry List
+ PVOID pDispInfo; // global PDISPLAYINFO pointer
+ ULONG_PTR ulSharedDelta; // Heap delta
+ WNDMSG awmControl[FNID_LAST - FNID_FIRST];
+ WNDMSG DefWindowMsgs;
+ WNDMSG DefWindowSpecMsgs;
+ } SHAREDINFO, *PSHAREDINFO;
+
+ typedef struct _USERCONNECT
+ {
+ ULONG ulVersion;
+ ULONG ulCurrentVersion;
+ DWORD dwDispatchCount;
+ SHAREDINFO siClient;
+ } USERCONNECT, *PUSERCONNECT;
+
+ typedef struct tagGETCLIPBDATA
+ {
+ UINT uFmtRet;
+ BOOL fGlobalHandle;
+ union
+ {
+ HANDLE hLocale;
+ HANDLE hPalette;
+ };
+ } GETCLIPBDATA, *PGETCLIPBDATA;
+
+ typedef struct tagSETCLIPBDATA
+ {
+ BOOL fGlobalHandle;
+ BOOL fIncSerialNumber;
+ } SETCLIPBDATA, *PSETCLIPBDATA;
+
+ DWORD
+ NTAPI
+ NtUserAssociateInputContext(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3);
+
+ DWORD
+ NTAPI
+ NtUserBuildHimcList(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4);
+
+ DWORD
+ NTAPI
+ NtUserCalcMenuBar(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4,
+ DWORD dwUnknown5);
+
+ DWORD
+ NTAPI
+ NtUserCheckMenuItem(
+ HMENU hmenu,
+ UINT uIDCheckItem,
+ UINT uCheck);
+
+ DWORD
+ NTAPI
+ NtUserCtxDisplayIOCtl(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3);
+
+ BOOL
+ NTAPI
+ NtUserDeleteMenu(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags);
+
+ BOOL
+ NTAPI
+ NtUserDestroyMenu(
+ HMENU hMenu);
+
+ DWORD
+ NTAPI
+ NtUserDrawMenuBarTemp(
+ HWND hWnd,
+ HDC hDC,
+ PRECT hRect,
+ HMENU hMenu,
+ HFONT hFont);
+
+ UINT
+ NTAPI
+ NtUserEnableMenuItem(
+ HMENU hMenu,
+ UINT uIDEnableItem,
+ UINT uEnable);
+
+ BOOL
+ NTAPI
+ NtUserEndMenu(VOID);
+
+ BOOL
+ NTAPI
+ NtUserGetMenuBarInfo(
+ HWND hwnd,
+ LONG idObject,
+ LONG idItem,
+ PMENUBARINFO pmbi);
+
+ UINT
+ NTAPI
+ NtUserGetMenuIndex(
+ HMENU hMenu,
+ HMENU hSubMenu);
+
+ BOOL
+ NTAPI
+ NtUserGetMenuItemRect(
+ HWND hWnd,
+ HMENU hMenu,
+ UINT uItem,
+ LPRECT lprcItem);
+
+ HMENU
+ NTAPI
+ NtUserGetSystemMenu(
+ HWND hWnd,
+ BOOL bRevert);
+
+ BOOL
+ NTAPI
+ NtUserHiliteMenuItem(
+ HWND hWnd,
+ HMENU hMenu,
+ UINT uItemHilite,
+ UINT uHilite);
+
+ int
+ NTAPI
+ NtUserMenuItemFromPoint(
+ HWND hWnd,
+ HMENU hMenu,
+ DWORD X,
+ DWORD Y);
+
+ BOOL
+ NTAPI
+ NtUserRemoveMenu(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags);
+
+ BOOL
+ NTAPI
+ NtUserSetMenu(
+ HWND hWnd,
+ HMENU hMenu,
+ BOOL bRepaint);
+
+ BOOL
+ NTAPI
+ NtUserSetMenuContextHelpId(
+ HMENU hmenu,
+ DWORD dwContextHelpId);
+
+ BOOL
+ NTAPI
+ NtUserSetMenuDefaultItem(
+ HMENU hMenu,
+ UINT uItem,
+ UINT fByPos);
+
+ BOOL
+ NTAPI
+ NtUserSetMenuFlagRtoL(
+ HMENU hMenu);
+
+ BOOL
+ NTAPI
+ NtUserSetSystemMenu(
+ HWND hWnd,
+ HMENU hMenu);
+
+ BOOL
+ NTAPI
+ NtUserThunkedMenuInfo(
+ HMENU hMenu,
+ LPCMENUINFO lpcmi);
+
+ BOOL
+ NTAPI
+ NtUserThunkedMenuItemInfo(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ BOOL bInsert,
+ LPMENUITEMINFOW lpmii,
+ PUNICODE_STRING lpszCaption);
+
+ BOOL
+ NTAPI
+ NtUserTrackPopupMenuEx(
+ HMENU hmenu,
+ UINT fuFlags,
+ int x,
+ int y,
+ HWND hwnd,
+ LPTPMPARAMS lptpm);
+
+ HKL
+ NTAPI
+ NtUserActivateKeyboardLayout(
+ HKL hKl,
+ ULONG Flags);
+
+ DWORD
+ NTAPI
+ NtUserAlterWindowStyle(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2);
+
+ BOOL
+ NTAPI
+ NtUserAttachThreadInput(
+ IN DWORD idAttach,
+ IN DWORD idAttachTo,
+ IN BOOL fAttach);
+
+ HDC NTAPI
+ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs);
+
+ BOOL
+ NTAPI
+ NtUserBitBltSysBmp(
+ HDC hdc,
+ INT nXDest,
+ INT nYDest,
+ INT nWidth,
+ INT nHeight,
+ INT nXSrc,
+ INT nYSrc,
+ DWORD dwRop );
+
+ BOOL
+ NTAPI
+ NtUserBlockInput(
+ BOOL BlockIt);
+
+ NTSTATUS
+ NTAPI
+ NtUserBuildHwndList(
+ HDESK hDesktop,
+ HWND hwndParent,
+ BOOLEAN bChildren,
+ ULONG dwThreadId,
+ ULONG lParam,
+ HWND* pWnd,
+ ULONG* pBufSize);
+
+ NTSTATUS NTAPI
+ NtUserBuildNameList(
+ HWINSTA hWinSta,
+ ULONG dwSize,
+ PVOID lpBuffer,
+ PULONG pRequiredSize);
+
+ NTSTATUS
+ NTAPI
+ NtUserBuildPropList(
+ HWND hWnd,
+ LPVOID Buffer,
+ DWORD BufferSize,
+ DWORD *Count);
+
+ /* apfnSimpleCall indices from Windows XP SP 2 */
+ /* TODO: Check for differences in Windows 2000, 2003 and 2008 */
+ #define WIN32K_VERSION NTDDI_WINXPSP2 // FIXME: this should go somewhere else
+
+ enum SimpleCallRoutines
+ {
+ NOPARAM_ROUTINE_CREATEMENU,
+ NOPARAM_ROUTINE_CREATEMENUPOPUP,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ NOPARAM_ROUTINE_ALLOWFOREGNDACTIVATION,
+ NOPARAM_ROUTINE_MSQCLEARWAKEMASK,
+ NOPARAM_ROUTINE_CREATESYSTEMTHREADS,
+ NOPARAM_ROUTINE_DESTROY_CARET,
+ #endif
+ NOPARAM_ROUTINE_ENABLEPROCWNDGHSTING,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ NOPARAM_ROUTINE_MSQCLEARWAKEMASK,
+ NOPARAM_ROUTINE_ALLOWFOREGNDACTIVATION,
+ NOPARAM_ROUTINE_DESTROY_CARET,
+ #endif
+ NOPARAM_ROUTINE_GETDEVICECHANGEINFO,
+ NOPARAM_ROUTINE_GETIMESHOWSTATUS,
+ NOPARAM_ROUTINE_GETINPUTDESKTOP,
+ NOPARAM_ROUTINE_GETMSESSAGEPOS,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ NOPARAM_ROUTINE_HANDLESYSTHRDCREATFAIL,
+ #else
+ NOPARAM_ROUTINE_GETREMOTEPROCID,
+ #endif
+ NOPARAM_ROUTINE_HIDECURSORNOCAPTURE,
+ NOPARAM_ROUTINE_LOADCURSANDICOS,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ NOPARAM_ROUTINE_LOADUSERAPIHOOK,
+ NOPARAM_ROUTINE_PREPAREFORLOGOFF, /* 0x0f */
+ #endif
+ NOPARAM_ROUTINE_RELEASECAPTURE,
+ NOPARAM_ROUTINE_RESETDBLCLICK,
+ NOPARAM_ROUTINE_ZAPACTIVEANDFOUS,
+ NOPARAM_ROUTINE_REMOTECONSHDWSTOP,
+ NOPARAM_ROUTINE_REMOTEDISCONNECT,
+ NOPARAM_ROUTINE_REMOTELOGOFF,
+ NOPARAM_ROUTINE_REMOTENTSECURITY,
+ NOPARAM_ROUTINE_REMOTESHDWSETUP,
+ NOPARAM_ROUTINE_REMOTESHDWSTOP,
+ NOPARAM_ROUTINE_REMOTEPASSTHRUENABLE,
+ NOPARAM_ROUTINE_REMOTEPASSTHRUDISABLE,
+ NOPARAM_ROUTINE_REMOTECONNECTSTATE,
+ NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING,
+ NOPARAM_ROUTINE_USERPWRCALLOUTWORKER,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ NOPARAM_ROUTINE_WAKERITFORSHTDWN,
+ #endif
+ NOPARAM_ROUTINE_INIT_MESSAGE_PUMP,
+ NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ NOPARAM_ROUTINE_LOADUSERAPIHOOK,
+ #endif
+ ONEPARAM_ROUTINE_BEGINDEFERWNDPOS,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ ONEPARAM_ROUTINE_GETSENDMSGRECVR,
+ #endif
+ ONEPARAM_ROUTINE_WINDOWFROMDC,
+ ONEPARAM_ROUTINE_ALLOWSETFOREGND,
+ ONEPARAM_ROUTINE_CREATEEMPTYCUROBJECT,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ ONEPARAM_ROUTINE_CREATESYSTEMTHREADS,
+ #endif
+ ONEPARAM_ROUTINE_CSDDEUNINITIALIZE,
+ ONEPARAM_ROUTINE_DIRECTEDYIELD,
+ ONEPARAM_ROUTINE_ENUMCLIPBOARDFORMATS,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ ONEPARAM_ROUTINE_GETCURSORPOS,
+ #endif
+ ONEPARAM_ROUTINE_GETINPUTEVENT,
+ ONEPARAM_ROUTINE_GETKEYBOARDLAYOUT,
+ ONEPARAM_ROUTINE_GETKEYBOARDTYPE,
+ ONEPARAM_ROUTINE_GETPROCDEFLAYOUT,
+ ONEPARAM_ROUTINE_GETQUEUESTATUS,
+ ONEPARAM_ROUTINE_GETWINSTAINFO,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ ONEPARAM_ROUTINE_HANDLESYSTHRDCREATFAIL,
+ #endif
+ ONEPARAM_ROUTINE_LOCKFOREGNDWINDOW,
+ ONEPARAM_ROUTINE_LOADFONTS,
+ ONEPARAM_ROUTINE_MAPDEKTOPOBJECT,
+ ONEPARAM_ROUTINE_MESSAGEBEEP,
+ ONEPARAM_ROUTINE_PLAYEVENTSOUND,
+ ONEPARAM_ROUTINE_POSTQUITMESSAGE,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ ONEPARAM_ROUTINE_PREPAREFORLOGOFF,
+ #endif
+ ONEPARAM_ROUTINE_REALIZEPALETTE,
+ ONEPARAM_ROUTINE_REGISTERLPK,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ ONEPARAM_ROUTINE_REGISTERSYSTEMTHREAD,
+ #endif
+ ONEPARAM_ROUTINE_REMOTERECONNECT,
+ ONEPARAM_ROUTINE_REMOTETHINWIRESTATUS,
+ ONEPARAM_ROUTINE_RELEASEDC,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ ONEPARAM_ROUTINE_REMOTENOTIFY,
+ #endif
+ ONEPARAM_ROUTINE_REPLYMESSAGE,
+ ONEPARAM_ROUTINE_SETCARETBLINKTIME,
+ ONEPARAM_ROUTINE_SETDBLCLICKTIME,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ ONEPARAM_ROUTINE_SETIMESHOWSTATUS,
+ #endif
+ ONEPARAM_ROUTINE_SETMESSAGEEXTRAINFO,
+ ONEPARAM_ROUTINE_SETPROCDEFLAYOUT,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ ONEPARAM_ROUTINE_SETWATERMARKSTRINGS,
+ #endif
+ ONEPARAM_ROUTINE_SHOWCURSOR,
+ ONEPARAM_ROUTINE_SHOWSTARTGLASS,
+ ONEPARAM_ROUTINE_SWAPMOUSEBUTTON,
+ X_ROUTINE_WOWMODULEUNLOAD,
+ #if (WIN32K_VERSION < NTDDI_VISTA)
+ X_ROUTINE_REMOTENOTIFY,
+ #endif
+ HWND_ROUTINE_DEREGISTERSHELLHOOKWINDOW,
+ HWND_ROUTINE_DWP_GETENABLEDPOPUP,
+ HWND_ROUTINE_GETWNDCONTEXTHLPID,
+ HWND_ROUTINE_REGISTERSHELLHOOKWINDOW,
+ HWND_ROUTINE_SETMSGBOX,
+ HWNDOPT_ROUTINE_SETPROGMANWINDOW,
+ HWNDOPT_ROUTINE_SETTASKMANWINDOW,
+ HWNDPARAM_ROUTINE_GETCLASSICOCUR,
+ HWNDPARAM_ROUTINE_CLEARWINDOWSTATE,
+ HWNDPARAM_ROUTINE_KILLSYSTEMTIMER,
+ HWNDPARAM_ROUTINE_SETDIALOGPOINTER,
+ HWNDPARAM_ROUTINE_SETVISIBLE,
+ HWNDPARAM_ROUTINE_SETWNDCONTEXTHLPID,
+ HWNDPARAM_ROUTINE_SETWINDOWSTATE,
+ HWNDLOCK_ROUTINE_WINDOWHASSHADOW, /* correct prefix ? */
+ HWNDLOCK_ROUTINE_ARRANGEICONICWINDOWS,
+ HWNDLOCK_ROUTINE_DRAWMENUBAR,
+ HWNDLOCK_ROUTINE_CHECKIMESHOWSTATUSINTHRD,
+ HWNDLOCK_ROUTINE_GETSYSMENUHANDLE,
+ HWNDLOCK_ROUTINE_REDRAWFRAME,
+ HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK,
+ HWNDLOCK_ROUTINE_SETDLGSYSMENU,
+ HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOW,
+ HWNDLOCK_ROUTINE_SETSYSMENU,
+ HWNDLOCK_ROUTINE_UPDATECKIENTRECT,
+ HWNDLOCK_ROUTINE_UPDATEWINDOW,
+ X_ROUTINE_IMESHOWSTATUSCHANGE,
+ TWOPARAM_ROUTINE_ENABLEWINDOW,
+ TWOPARAM_ROUTINE_REDRAWTITLE,
+ TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS,
+ TWOPARAM_ROUTINE_SWITCHTOTHISWINDOW,
+ TWOPARAM_ROUTINE_UPDATEWINDOWS,
+ TWOPARAM_ROUTINE_VALIDATERGN,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ TWOPARAM_ROUTINE_CHANGEWNDMSGFILTER,
+ TWOPARAM_ROUTINE_GETCURSORPOS,
+ #endif
+ TWOPARAM_ROUTINE_GETHDEVNAME,
+ TWOPARAM_ROUTINE_INITANSIOEM,
+ TWOPARAM_ROUTINE_NLSSENDIMENOTIFY,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ TWOPARAM_ROUTINE_REGISTERGHSTWND,
+ #endif
+ TWOPARAM_ROUTINE_REGISTERLOGONPROCESS,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ TWOPARAM_ROUTINE_REGISTERSBLFROSTWND,
+ #else
+ TWOPARAM_ROUTINE_REGISTERSYSTEMTHREAD,
+ #endif
+ TWOPARAM_ROUTINE_REGISTERUSERHUNGAPPHANDLERS,
+ TWOPARAM_ROUTINE_SHADOWCLEANUP,
+ TWOPARAM_ROUTINE_REMOTESHADOWSTART,
+ TWOPARAM_ROUTINE_SETCARETPOS,
+ TWOPARAM_ROUTINE_SETCURSORPOS,
+ #if (WIN32K_VERSION >= NTDDI_VISTA)
+ TWOPARAM_ROUTINE_SETPHYSCURSORPOS,
+ #endif
+ TWOPARAM_ROUTINE_UNHOOKWINDOWSHOOK,
+ TWOPARAM_ROUTINE_WOWCLEANUP
+ };
+
+ DWORD
+ NTAPI
+ NtUserCallHwnd(
+ HWND hWnd,
+ DWORD Routine);
+
+ BOOL
+ NTAPI
+ NtUserCallHwndLock(
+ HWND hWnd,
+ DWORD Routine);
+
+ HWND
+ NTAPI
+ NtUserCallHwndOpt(
+ HWND hWnd,
+ DWORD Routine);
+
+ DWORD
+ NTAPI
+ NtUserCallHwndParam(
+ HWND hWnd,
+ DWORD Param,
+ DWORD Routine);
+
+ DWORD
+ NTAPI
+ NtUserCallHwndParamLock(
+ HWND hWnd,
+ DWORD Param,
+ DWORD Routine);
+
+ BOOL
+ NTAPI
+ NtUserCallMsgFilter(
+ LPMSG msg,
+ INT code);
+
+ LRESULT
+ NTAPI
+ NtUserCallNextHookEx(
+ int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi);
+
+ DWORD_PTR
+ NTAPI
+ NtUserCallNoParam(
+ DWORD Routine);
+
+ DWORD_PTR
+ NTAPI
+ NtUserCallOneParam(
+ DWORD_PTR Param,
+ DWORD Routine);
+
+ DWORD_PTR
+ NTAPI
+ NtUserCallTwoParam(
+ DWORD_PTR Param1,
+ DWORD_PTR Param2,
+ DWORD Routine);
+
+ BOOL
+ NTAPI
+ NtUserChangeClipboardChain(
+ HWND hWndRemove,
+ HWND hWndNewNext);
+
+ LONG
+ NTAPI
+ NtUserChangeDisplaySettings(
+ PUNICODE_STRING lpszDeviceName,
+ LPDEVMODEW lpDevMode,
+ HWND hwnd,
+ DWORD dwflags,
+ LPVOID lParam);
+
+ BOOL
+ NTAPI
+ NtUserCheckDesktopByThreadId(
+ DWORD dwThreadId);
+
+ BOOL
+ NTAPI
+ NtUserCheckWindowThreadDesktop(
+ HWND hwnd,
+ DWORD dwThreadId,
+ ULONG ReturnValue);
+
+ DWORD
+ NTAPI
+ NtUserCheckImeHotKey(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2);
+
+ HWND NTAPI
+ NtUserChildWindowFromPointEx(
+ HWND Parent,
+ LONG x,
+ LONG y,
+ UINT Flags);
+
+ BOOL
+ NTAPI
+ NtUserClipCursor(
+ RECT *lpRect);
+
+ BOOL
+ NTAPI
+ NtUserCloseClipboard(VOID);
+
+ BOOL
+ NTAPI
+ NtUserCloseDesktop(
+ HDESK hDesktop);
+
+ BOOL
+ NTAPI
+ NtUserCloseWindowStation(
+ HWINSTA hWinSta);
+
+ DWORD
+ NTAPI
+ NtUserConsoleControl(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3);
+
+ HANDLE
+ NTAPI
+ NtUserConvertMemHandle(
+ PVOID pData,
+ DWORD cbData);
+
+ ULONG
+ NTAPI
+ NtUserCopyAcceleratorTable(
+ HACCEL Table,
+ LPACCEL Entries,
+ ULONG EntriesCount);
+
+ DWORD
+ NTAPI
+ NtUserCountClipboardFormats(VOID);
+
+ HACCEL
+ NTAPI
+ NtUserCreateAcceleratorTable(
+ LPACCEL Entries,
+ ULONG EntriesCount);
+
+ BOOL
+ NTAPI
+ NtUserCreateCaret(
+ HWND hWnd,
+ HBITMAP hBitmap,
+ int nWidth,
+ int nHeight);
+
+ HDESK
+ NTAPI
+ NtUserCreateDesktop(
+ POBJECT_ATTRIBUTES poa,
+ PUNICODE_STRING lpszDesktopDevice,
+ LPDEVMODEW lpdmw,
+ DWORD dwFlags,
+ ACCESS_MASK dwDesiredAccess);
+
+ DWORD
+ NTAPI
+ NtUserCreateInputContext(
+ DWORD dwUnknown1);
+
+ NTSTATUS
+ NTAPI
+ NtUserCreateLocalMemHandle(
+ HANDLE hMem,
+ PVOID pData,
+ DWORD cbData,
+ DWORD *pcbData);
+
+ HWND
+ NTAPI
+ NtUserCreateWindowEx(
+ DWORD dwExStyle,
+ PLARGE_STRING plstrClassName,
+ PLARGE_STRING plstrClsVersion,
+ PLARGE_STRING plstrWindowName,
+ DWORD dwStyle,
+ int x,
+ int y,
+ int nWidth,
+ int nHeight,
+ HWND hWndParent,
+ HMENU hMenu,
+ HINSTANCE hInstance,
+ LPVOID lpParam,
+ DWORD dwFlags,
+ PVOID acbiBuffer);
+
+ HWINSTA
+ NTAPI
+ NtUserCreateWindowStation(
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ ACCESS_MASK dwDesiredAccess,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4,
+ DWORD Unknown5,
+ DWORD Unknown6);
+
+ BOOL
+ NTAPI
+ NtUserDdeGetQualityOfService(
+ IN HWND hwndClient,
+ IN HWND hWndServer,
+ OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev);
+
+ DWORD
+ NTAPI
+ NtUserDdeInitialize(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4);
+
+ BOOL
+ NTAPI
+ NtUserDdeSetQualityOfService(
+ IN HWND hwndClient,
+ IN PSECURITY_QUALITY_OF_SERVICE pqosNew,
+ OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev);
+
+ HDWP NTAPI
+ NtUserDeferWindowPos(
+ HDWP WinPosInfo,
+ HWND Wnd,
+ HWND WndInsertAfter,
+ int x,
+ int y,
+ int cx,
+ int cy,
+ UINT Flags);
+
+ BOOL NTAPI
+ NtUserDefSetText(HWND WindowHandle, PLARGE_STRING WindowText);
+
+ BOOLEAN
+ NTAPI
+ NtUserDestroyAcceleratorTable(
+ HACCEL Table);
+
+ BOOL
+ NTAPI
+ NtUserDestroyCursor(
+ HANDLE Handle,
+ DWORD Unknown);
+
+ DWORD
+ NTAPI
+ NtUserDestroyInputContext(
+ DWORD dwUnknown1);
+
+ BOOLEAN NTAPI
+ NtUserDestroyWindow(HWND Wnd);
+
+ DWORD
+ NTAPI
+ NtUserDisableThreadIme(
+ DWORD dwUnknown1);
+
+ LRESULT
+ NTAPI
+ NtUserDispatchMessage(PMSG pMsg);
+
+ BOOL
+ NTAPI
+ NtUserDragDetect(
+ HWND hWnd,
+ POINT pt);
+
+ DWORD
+ NTAPI
+ NtUserDragObject(
+ HWND hwnd1,
+ HWND hwnd2,
+ UINT u1,
+ DWORD dw1,
+ HCURSOR hc1);
+
+ BOOL
+ NTAPI
+ NtUserDrawAnimatedRects(
+ HWND hwnd,
+ INT idAni,
+ RECT *lprcFrom,
+ RECT *lprcTo);
+
+ BOOL
+ NTAPI
+ NtUserDrawCaption(
+ HWND hWnd,
+ HDC hDc,
+ LPCRECT lpRc,
+ UINT uFlags);
+
+ BOOL
+ NTAPI
+ NtUserDrawCaptionTemp(
+ HWND hWnd,
+ HDC hDC,
+ LPCRECT lpRc,
+ HFONT hFont,
+ HICON hIcon,
+ const PUNICODE_STRING str,
+ UINT uFlags);
+
+ // Used with NtUserDrawIconEx, last parameter.
+ typedef struct _DRAWICONEXDATA
+ {
+ HBITMAP hbmMask;
+ HBITMAP hbmColor;
+ int cx;
+ int cy;
+ } DRAWICONEXDATA, *PDRAWICONEXDATA;
+
+ BOOL
+ NTAPI
+ NtUserDrawIconEx(
+ HDC hdc,
+ int xLeft,
+ int yTop,
+ HICON hIcon,
+ int cxWidth,
+ int cyWidth,
+ UINT istepIfAniCur,
+ HBRUSH hbrFlickerFreeDraw,
+ UINT diFlags,
+ BOOL bMetaHDC,
+ PVOID pDIXData);
+
+ BOOL
+ NTAPI
+ NtUserEmptyClipboard(VOID);
+
+ BOOL
+ NTAPI
+ NtUserEnableScrollBar(
+ HWND hWnd,
+ UINT wSBflags,
+ UINT wArrows);
+
+ BOOL
+ NTAPI
+ NtUserEndDeferWindowPosEx(
+ HDWP WinPosInfo,
+ DWORD Unknown1);
+
+ BOOL NTAPI
+ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs);
+
+ BOOL
+ NTAPI
+ NtUserEnumDisplayDevices (
+ PUNICODE_STRING lpDevice, /* device name */
+ DWORD iDevNum, /* display device */
+ PDISPLAY_DEVICEW lpDisplayDevice, /* device information */
+ DWORD dwFlags ); /* reserved */
+
+ /*BOOL
+ NTAPI
+ NtUserEnumDisplayMonitors (
+ HDC hdc,
+ LPCRECT lprcClip,
+ MONITORENUMPROC lpfnEnum,
+ LPARAM dwData );*/
+ /* FIXME: The call below is ros-specific and should be rewritten to use the same params as the correct call above. */
+ INT
+ NTAPI
+ NtUserEnumDisplayMonitors(
+ OPTIONAL IN HDC hDC,
+ OPTIONAL IN LPCRECT pRect,
+ OPTIONAL OUT HMONITOR *hMonitorList,
+ OPTIONAL OUT LPRECT monitorRectList,
+ OPTIONAL IN DWORD listSize );
+
+
+ NTSTATUS
+ NTAPI
+ NtUserEnumDisplaySettings(
+ PUNICODE_STRING lpszDeviceName,
+ DWORD iModeNum,
+ LPDEVMODEW lpDevMode, /* FIXME is this correct? */
+ DWORD dwFlags );
+
+ DWORD
+ NTAPI
+ NtUserEvent(
+ DWORD Unknown0);
+
+ DWORD
+ NTAPI
+ NtUserExcludeUpdateRgn(
+ HDC hDC,
+ HWND hWnd);
+
+ BOOL
+ NTAPI
+ NtUserFillWindow(
+ HWND hWndPaint,
+ HWND hWndPaint1,
+ HDC hDC,
+ HBRUSH hBrush);
+
+ HICON
+ NTAPI
+ NtUserFindExistingCursorIcon(
+ HMODULE hModule,
+ HRSRC hRsrc,
+ LONG cx,
+ LONG cy);
+
+ HWND
+ NTAPI
+ NtUserFindWindowEx(
+ HWND hwndParent,
+ HWND hwndChildAfter,
+ PUNICODE_STRING ucClassName,
+ PUNICODE_STRING ucWindowName,
+ DWORD dwUnknown
+ );
+
+ BOOL
+ NTAPI
+ NtUserFlashWindowEx(
+ IN PFLASHWINFO pfwi);
+
+ BOOL
+ NTAPI
+ NtUserGetAltTabInfo(
+ HWND hwnd,
+ INT iItem,
+ PALTTABINFO pati,
+ LPWSTR pszItemText,
+ UINT cchItemText,
+ BOOL Ansi);
+
+ HWND NTAPI
+ NtUserGetAncestor(HWND hWnd, UINT Flags);
+
+ DWORD
+ NTAPI
+ NtUserGetAppImeLevel(
+ DWORD dwUnknown1);
+
+ SHORT
+ NTAPI
+ NtUserGetAsyncKeyState(
+ INT Key);
+
+ DWORD
+ NTAPI
+ NtUserGetAtomName(
+ ATOM nAtom,
+ PUNICODE_STRING pBuffer);
+
+ UINT
+ NTAPI
+ NtUserGetCaretBlinkTime(VOID);
+
+ BOOL
+ NTAPI
+ NtUserGetCaretPos(
+ LPPOINT lpPoint);
+
+ BOOL NTAPI
+ NtUserGetClassInfo(HINSTANCE hInstance,
+ PUNICODE_STRING ClassName,
+ LPWNDCLASSEXW wcex,
+ LPWSTR *ppszMenuName,
+ BOOL Ansi);
+
+ INT
+ NTAPI
+ NtUserGetClassName(HWND hWnd,
+ BOOL Real, // 0 GetClassNameW, 1 RealGetWindowClassA/W
+ PUNICODE_STRING ClassName);
+
+ HANDLE
+ NTAPI
+ NtUserGetClipboardData(
+ UINT fmt,
+ PGETCLIPBDATA pgcd);
+
+ INT
+ NTAPI
+ NtUserGetClipboardFormatName(
+ UINT uFormat,
+ LPWSTR lpszFormatName,
+ INT cchMaxCount);
+
+ HWND
+ NTAPI
+ NtUserGetClipboardOwner(VOID);
+
+ DWORD
+ NTAPI
+ NtUserGetClipboardSequenceNumber(VOID);
+
+ HWND
+ NTAPI
+ NtUserGetClipboardViewer(VOID);
+
+ BOOL
+ NTAPI
+ NtUserGetClipCursor(
+ RECT *lpRect);
+
+ BOOL
+ NTAPI
+ NtUserGetComboBoxInfo(
+ HWND hWnd,
+ PCOMBOBOXINFO pcbi);
+
+ HBRUSH
+ NTAPI
+ NtUserGetControlBrush(
+ HWND hwnd,
+ HDC hdc,
+ UINT ctlType);
+
+ HBRUSH
+ NTAPI
+ NtUserGetControlColor(
+ HWND hwndParent,
+ HWND hwnd,
+ HDC hdc,
+ UINT CtlMsg);
+
+ ULONG_PTR
+ NTAPI
+ NtUserGetCPD(
+ HWND hWnd,
+ GETCPD Flags,
+ ULONG_PTR Proc);
+
+ HCURSOR
+ NTAPI
+ NtUserGetCursorFrameInfo(
+ HCURSOR hCursor,
+ DWORD istep,
+ PDWORD rate_jiffies,
+ INT *num_steps);
+
+ BOOL
+ NTAPI
+ NtUserGetCursorInfo(
+ PCURSORINFO pci);
+
+ HDC
+ NTAPI
+ NtUserGetDC(
+ HWND hWnd);
+
+ HDC
+ NTAPI
+ NtUserGetDCEx(
+ HWND hWnd,
+ HANDLE hRegion,
+ ULONG Flags);
+
+ UINT
+ NTAPI
+ NtUserGetDoubleClickTime(VOID);
+
+ HWND
+ NTAPI
+ NtUserGetForegroundWindow(VOID);
+
+ DWORD
+ NTAPI
+ NtUserGetGuiResources(
+ HANDLE hProcess,
+ DWORD uiFlags);
+
+ BOOL
+ NTAPI
+ NtUserGetGUIThreadInfo(
+ DWORD idThread,
+ LPGUITHREADINFO lpgui);
+
+ BOOL
+ NTAPI
+ NtUserGetIconInfo(
+ HANDLE hCurIcon,
+ PICONINFO IconInfo,
+ PUNICODE_STRING lpInstName,
+ PUNICODE_STRING lpResName,
+ LPDWORD pbpp,
+ BOOL bInternal);
+
+ BOOL
+ NTAPI
+ NtUserGetIconSize(
+ HANDLE Handle,
+ UINT istepIfAniCur,
+ LONG *plcx,
+ LONG *plcy);
+
+ DWORD
+ NTAPI
+ NtUserGetImeHotKey(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3);
+
+ DWORD
+ NTAPI
+ NtUserGetImeInfoEx(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2);
+
+ DWORD
+ NTAPI
+ NtUserGetInternalWindowPos(
+ HWND hwnd,
+ LPRECT rectWnd,
+ LPPOINT ptIcon);
+
+ HKL
+ NTAPI
+ NtUserGetKeyboardLayout(
+ DWORD dwThreadid);
+
+ UINT
+ NTAPI
+ NtUserGetKeyboardLayoutList(
+ ULONG nItems,
+ HKL *pHklBuff);
+
+ BOOL
+ NTAPI
+ NtUserGetKeyboardLayoutName(
+ LPWSTR lpszName);
+
+ DWORD
+ NTAPI
+ NtUserGetKeyboardState(
+ LPBYTE Unknown0);
+
+ DWORD
+ NTAPI
+ NtUserGetKeyboardType(
+ DWORD TypeFlag);
+
+ DWORD
+ NTAPI
+ NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize );
+
+ SHORT
+ NTAPI
+ NtUserGetKeyState(
+ INT VirtKey);
+
+ BOOL
+ NTAPI
+ NtUserGetLayeredWindowAttributes(
+ HWND hwnd,
+ COLORREF *pcrKey,
+ BYTE *pbAlpha,
+ DWORD *pdwFlags);
+
+ DWORD
+ NTAPI
+ NtUserGetListBoxInfo(
+ HWND hWnd);
+
+ BOOL APIENTRY
+ NtUserGetMessage(PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax);
+
+ DWORD
+ NTAPI
+ NtUserGetMouseMovePointsEx(
+ UINT cbSize,
+ LPMOUSEMOVEPOINT lppt,
+ LPMOUSEMOVEPOINT lpptBuf,
+ int nBufPoints,
+ DWORD resolution);
+
+ BOOL
+ NTAPI
+ NtUserGetObjectInformation(
+ HANDLE hObject,
+ DWORD nIndex,
+ PVOID pvInformation,
+ DWORD nLength,
+ PDWORD nLengthNeeded);
+
+ HWND
+ NTAPI
+ NtUserGetOpenClipboardWindow(VOID);
+
+ INT
+ NTAPI
+ NtUserGetPriorityClipboardFormat(
+ UINT *paFormatPriorityList,
+ INT cFormats);
+
+ HWINSTA
+ NTAPI
+ NtUserGetProcessWindowStation(VOID);
+
+ DWORD
+ NTAPI
+ NtUserGetRawInputBuffer(
+ PRAWINPUT pData,
+ PUINT pcbSize,
+ UINT cbSizeHeader);
+
+ DWORD
+ NTAPI
+ NtUserGetRawInputData(
+ HRAWINPUT hRawInput,
+ UINT uiCommand,
+ LPVOID pData,
+ PUINT pcbSize,
+ UINT cbSizeHeader);
+
+ DWORD
+ NTAPI
+ NtUserGetRawInputDeviceInfo(
+ HANDLE hDevice,
+ UINT uiCommand,
+ LPVOID pData,
+ PUINT pcbSize);
+
+ DWORD
+ NTAPI
+ NtUserGetRawInputDeviceList(
+ PRAWINPUTDEVICELIST pRawInputDeviceList,
+ PUINT puiNumDevices,
+ UINT cbSize);
+
+ DWORD
+ NTAPI
+ NtUserGetRegisteredRawInputDevices(
+ PRAWINPUTDEVICE pRawInputDevices,
+ PUINT puiNumDevices,
+ UINT cbSize);
+
+ BOOL
+ NTAPI
+ NtUserGetScrollBarInfo(
+ HWND hWnd,
+ LONG idObject,
+ PSCROLLBARINFO psbi);
+
+ HDESK
+ NTAPI
+ NtUserGetThreadDesktop(
+ DWORD dwThreadId,
+ DWORD Unknown1);
+
+
+ enum ThreadStateRoutines
+ {
+ THREADSTATE_GETTHREADINFO,
+ THREADSTATE_INSENDMESSAGE,
+ THREADSTATE_FOCUSWINDOW,
+ THREADSTATE_ACTIVEWINDOW,
+ THREADSTATE_CAPTUREWINDOW,
+ THREADSTATE_PROGMANWINDOW,
+ THREADSTATE_TASKMANWINDOW,
+ THREADSTATE_GETMESSAGETIME,
+ THREADSTATE_GETINPUTSTATE,
+ THREADSTATE_UPTIMELASTREAD,
+ THREADSTATE_FOREGROUNDTHREAD,
+ THREADSTATE_GETCURSOR
+ };
+
+ DWORD_PTR
+ NTAPI
+ NtUserGetThreadState(
+ DWORD Routine);
+
+ BOOLEAN
+ NTAPI
+ NtUserGetTitleBarInfo(
+ HWND hwnd,
+ PTITLEBARINFO pti);
+
+ BOOL NTAPI
+ NtUserGetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL fErase);
+
+ int
+ NTAPI
+ NtUserGetUpdateRgn(
+ HWND hWnd,
+ HRGN hRgn,
+ BOOL bErase);
+
+ HDC
+ NTAPI
+ NtUserGetWindowDC(
+ HWND hWnd);
+
+ BOOL
+ NTAPI
+ NtUserGetWindowPlacement(
+ HWND hWnd,
+ WINDOWPLACEMENT *lpwndpl);
+
+ PCLS
+ NTAPI
+ NtUserGetWOWClass(
+ HINSTANCE hInstance,
+ PUNICODE_STRING ClassName);
+
+ DWORD
+ NTAPI
+ NtUserHardErrorControl(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3);
+
+ BOOL
+ NTAPI
+ NtUserImpersonateDdeClientWindow(
+ HWND hWndClient,
+ HWND hWndServer);
+
+ NTSTATUS
+ NTAPI
+ NtUserInitialize(
+ DWORD dwWinVersion,
+ HANDLE hPowerRequestEvent,
+ HANDLE hMediaRequestEvent);
+
+ NTSTATUS
+ NTAPI
+ NtUserInitializeClientPfnArrays(
+ PPFNCLIENT pfnClientA,
+ PPFNCLIENT pfnClientW,
+ PPFNCLIENTWORKER pfnClientWorker,
+ HINSTANCE hmodUser);
+
+ DWORD
+ NTAPI
+ NtUserInitTask(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4,
+ DWORD Unknown5,
+ DWORD Unknown6,
+ DWORD Unknown7,
+ DWORD Unknown8,
+ DWORD Unknown9,
+ DWORD Unknown10,
+ DWORD Unknown11);
+
+ INT
+ NTAPI
+ NtUserInternalGetWindowText(
+ HWND hWnd,
+ LPWSTR lpString,
+ INT nMaxCount);
+
+ BOOL
+ NTAPI
+ NtUserInvalidateRect(
+ HWND hWnd,
+ CONST RECT *lpRect,
+ BOOL bErase);
+
+ BOOL
+ NTAPI
+ NtUserInvalidateRgn(
+ HWND hWnd,
+ HRGN hRgn,
+ BOOL bErase);
+
+ BOOL
+ NTAPI
+ NtUserIsClipboardFormatAvailable(
+ UINT format);
+
+ BOOL
+ NTAPI
+ NtUserKillTimer
+ (
+ HWND hWnd,
+ UINT_PTR uIDEvent
+ );
+
+ HKL
+ NTAPI
+ NtUserLoadKeyboardLayoutEx(
+ IN HANDLE Handle,
+ IN DWORD offTable,
+ IN PUNICODE_STRING puszKeyboardName,
+ IN HKL hKL,
+ IN PUNICODE_STRING puszKLID,
+ IN DWORD dwKLID,
+ IN UINT Flags);
+
+ BOOL
+ NTAPI
+ NtUserLockWindowStation(
+ HWINSTA hWindowStation);
+
+ BOOL
+ NTAPI
+ NtUserLockWindowUpdate(
+ HWND hWnd);
+
+ BOOL
+ NTAPI
+ NtUserLockWorkStation(VOID);
+
+ UINT
+ NTAPI
+ NtUserMapVirtualKeyEx( UINT keyCode,
+ UINT transType,
+ DWORD keyboardId,
+ HKL dwhkl );
+
+ typedef struct tagDOSENDMESSAGE
+ {
+ UINT uFlags;
+ UINT uTimeout;
+ ULONG_PTR Result;
+ }
+ DOSENDMESSAGE, *PDOSENDMESSAGE;
+
+ BOOL
+ NTAPI
+ NtUserMessageCall(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ ULONG_PTR ResultInfo,
+ DWORD dwType, // FNID_XX types
+ BOOL Ansi);
+
+ DWORD
+ NTAPI
+ NtUserMinMaximize(
+ HWND hWnd,
+ UINT cmd, // Wine SW_ commands
+ BOOL Hide);
+
+ DWORD
+ NTAPI
+ NtUserMNDragLeave(VOID);
+
+ DWORD
+ NTAPI
+ NtUserMNDragOver(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ DWORD
+ NTAPI
+ NtUserModifyUserStartupInfoFlags(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ BOOL
+ NTAPI
+ NtUserMoveWindow(
+ HWND hWnd,
+ int X,
+ int Y,
+ int nWidth,
+ int nHeight,
+ BOOL bRepaint
+ );
+
+ DWORD
+ NTAPI
+ NtUserNotifyIMEStatus(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2);
+
+ DWORD
+ NTAPI
+ NtUserNotifyProcessCreate(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4);
+
+ VOID
+ NTAPI
+ NtUserNotifyWinEvent(
+ DWORD Event,
+ HWND hWnd,
+ LONG idObject,
+ LONG idChild);
+
+ BOOL
+ NTAPI
+ NtUserOpenClipboard(
+ HWND hWnd,
+ DWORD Unknown1);
+
+ HDESK
+ NTAPI
+ NtUserOpenDesktop(
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ DWORD dwFlags,
+ ACCESS_MASK dwDesiredAccess);
+
+ HDESK
+ NTAPI
+ NtUserOpenInputDesktop(
+ DWORD dwFlags,
+ BOOL fInherit,
+ ACCESS_MASK dwDesiredAccess);
+
+ HWINSTA
+ NTAPI
+ NtUserOpenWindowStation(
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ ACCESS_MASK dwDesiredAccess);
+
+ BOOL
+ NTAPI
+ NtUserPaintDesktop(
+ HDC hDC);
+
+ DWORD
+ NTAPI
+ NtUserPaintMenuBar(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4,
+ DWORD dwUnknown5,
+ DWORD dwUnknown6);
+
+ BOOL APIENTRY
+ NtUserPeekMessage( PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg);
+
+ BOOL
+ NTAPI
+ NtUserPostMessage(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ BOOL
+ NTAPI
+ NtUserPostThreadMessage(
+ DWORD idThread,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ BOOL
+ NTAPI
+ NtUserPrintWindow(
+ HWND hwnd,
+ HDC hdcBlt,
+ UINT nFlags);
+
+ NTSTATUS
+ NTAPI
+ NtUserProcessConnect(
+ IN HANDLE Process,
+ OUT PUSERCONNECT pUserConnect,
+ IN DWORD dwSize); // sizeof(USERCONNECT)
+
+ DWORD
+ NTAPI
+ NtUserQueryInformationThread(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4,
+ DWORD dwUnknown5);
+
+ DWORD
+ NTAPI
+ NtUserQueryInputContext(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2);
+
+ DWORD
+ NTAPI
+ NtUserQuerySendMessage(
+ DWORD Unknown0);
+
+ DWORD
+ NTAPI
+ NtUserQueryUserCounters(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4);
+
+ #define QUERY_WINDOW_UNIQUE_PROCESS_ID 0x00
+ #define QUERY_WINDOW_UNIQUE_THREAD_ID 0x01
+ #define QUERY_WINDOW_ACTIVE 0x02
+ #define QUERY_WINDOW_FOCUS 0x03
+ #define QUERY_WINDOW_ISHUNG 0x04
+ #define QUERY_WINDOW_REAL_ID 0x05
+ #define QUERY_WINDOW_FOREGROUND 0x06
+ DWORD
+ NTAPI
+ NtUserQueryWindow(
+ HWND hWnd,
+ DWORD Index);
+
+ BOOL
+ NTAPI
+ NtUserRealInternalGetMessage(
+ LPMSG lpMsg,
+ HWND hWnd,
+ UINT wMsgFilterMin,
+ UINT wMsgFilterMax,
+ UINT wRemoveMsg,
+ BOOL bGMSG);
+
+ HWND
+ NTAPI
+ NtUserRealChildWindowFromPoint(
+ HWND Parent,
+ LONG x,
+ LONG y);
+
+ BOOL
+ NTAPI
+ NtUserRealWaitMessageEx(
+ DWORD dwWakeMask,
+ UINT uTimeout);
+
+ BOOL
+ NTAPI
+ NtUserRedrawWindow
+ (
+ HWND hWnd,
+ CONST RECT *lprcUpdate,
+ HRGN hrgnUpdate,
+ UINT flags
+ );
+
+ RTL_ATOM
+ NTAPI
+ NtUserRegisterClassExWOW(
+ WNDCLASSEXW* lpwcx,
+ PUNICODE_STRING pustrClassName,
+ PUNICODE_STRING pustrCNVersion,
+ PCLSMENUNAME pClassMenuName,
+ DWORD fnID,
+ DWORD Flags,
+ LPDWORD pWow);
+
+ BOOL
+ NTAPI
+ NtUserRegisterRawInputDevices(
+ IN PCRAWINPUTDEVICE pRawInputDevices,
+ IN UINT uiNumDevices,
+ IN UINT cbSize);
+
+ BOOL
+ NTAPI
+ NtUserRegisterUserApiHook(
+ PUNICODE_STRING m_dllname1,
+ PUNICODE_STRING m_funname1,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4);
+
+ BOOL
+ NTAPI
+ NtUserRegisterHotKey(HWND hWnd,
+ int id,
+ UINT fsModifiers,
+ UINT vk);
+
+ DWORD
+ NTAPI
+ NtUserRegisterTasklist(
+ DWORD Unknown0);
+
+ UINT NTAPI
+ NtUserRegisterWindowMessage(PUNICODE_STRING MessageName);
+
+ DWORD
+ NTAPI
+ NtUserRemoteConnect(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3);
+
+ DWORD
+ NTAPI
+ NtUserRemoteRedrawRectangle(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4);
+
+ DWORD
+ NTAPI
+ NtUserRemoteRedrawScreen(VOID);
+
+ DWORD
+ NTAPI
+ NtUserRemoteStopScreenUpdates(VOID);
+
+ HANDLE NTAPI
+ NtUserRemoveProp(HWND hWnd, ATOM Atom);
+
+ DWORD
+ NTAPI
+ NtUserResolveDesktop(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4);
+
+ DWORD
+ NTAPI
+ NtUserResolveDesktopForWOW(
+ DWORD Unknown0);
+
+ BOOL
+ NTAPI
+ NtUserSBGetParms(
+ HWND hwnd,
+ int fnBar,
+ PSBDATA pSBData,
+ LPSCROLLINFO lpsi);
+
+ BOOL
+ NTAPI
+ NtUserScrollDC(
+ HDC hDC,
+ int dx,
+ int dy,
+ CONST RECT *lprcScroll,
+ CONST RECT *lprcClip ,
+ HRGN hrgnUpdate,
+ LPRECT lprcUpdate);
+
+ DWORD NTAPI
+ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *rect,
+ const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags);
+
+ UINT
+ NTAPI
+ NtUserSendInput(
+ UINT nInputs,
+ LPINPUT pInput,
+ INT cbSize);
+
+ HWND NTAPI
+ NtUserSetActiveWindow(HWND Wnd);
+
+ DWORD
+ NTAPI
+ NtUserSetAppImeLevel(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2);
+
+ HWND NTAPI
+ NtUserSetCapture(HWND Wnd);
+
+ ULONG_PTR NTAPI
+ NtUserSetClassLong(
+ HWND hWnd,
+ INT Offset,
+ ULONG_PTR dwNewLong,
+ BOOL Ansi );
+
+ WORD
+ NTAPI
+ NtUserSetClassWord(
+ HWND hWnd,
+ INT nIndex,
+ WORD wNewWord);
+
+ HANDLE
+ NTAPI
+ NtUserSetClipboardData(
+ UINT fmt,
+ HANDLE hMem,
+ PSETCLIPBDATA scd);
+
+ HWND
+ NTAPI
+ NtUserSetClipboardViewer(
+ HWND hWndNewViewer);
+
+ HPALETTE
+ NTAPI
+ NtUserSelectPalette(
+ HDC hDC,
+ HPALETTE hpal,
+ BOOL ForceBackground
+ );
+
+ DWORD
+ NTAPI
+ NtUserSetConsoleReserveKeys(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ HCURSOR
+ NTAPI
+ NtUserSetCursor(
+ HCURSOR hCursor);
+
+ BOOL
+ NTAPI
+ NtUserSetCursorContents(
+ HANDLE Handle,
+ PICONINFO IconInfo);
+
- HCURSOR hCursor,
- PUNICODE_STRING ModuleName,
- PUNICODE_STRING ResourceName,
- PCURSORDATA pCursorData);
++ #ifdef NEW_CURSORICON
+ BOOL
+ NTAPI
+ NtUserSetCursorIconData(
- BOOL
- NTAPI
- NtUserSetCursorIconData(
- HANDLE Handle,
- PBOOL fIcon,
- POINT *Hotspot,
- HMODULE hModule,
- HRSRC hRsrc,
- HRSRC hGroupRsrc);
-
++ _In_ HCURSOR hCursor,
++ _In_ HINSTANCE hinst,
++ _In_ HRSRC hrsrc,
++ _In_ PICONINFO pii);
++ #else
++ BOOL
++ NTAPI
++ NtUserSetCursorIconData(
++ HANDLE Handle,
++ PBOOL fIcon,
++ POINT *Hotspot,
++ HMODULE hModule,
++ HRSRC hRsrc,
++ HRSRC hGroupRsrc);
+ #endif
+
+ DWORD
+ NTAPI
+ NtUserSetDbgTag(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ HWND
+ NTAPI
+ NtUserSetFocus(
+ HWND hWnd);
+
+ DWORD
+ NTAPI
+ NtUserSetImeHotKey(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4);
+
+ DWORD
+ NTAPI
+ NtUserSetImeInfoEx(
+ DWORD dwUnknown1);
+
+ DWORD
+ NTAPI
+ NtUserSetImeOwnerWindow(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ DWORD
+ NTAPI
+ NtUserSetInformationProcess(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4);
+
+ NTSTATUS
+ NTAPI
+ NtUserSetInformationThread(
+ IN HANDLE ThreadHandle,
+ IN USERTHREADINFOCLASS ThreadInformationClass,
+ IN PVOID ThreadInformation,
+ IN ULONG ThreadInformationLength
+ );
+
+ DWORD
+ NTAPI
+ NtUserSetInternalWindowPos(
+ HWND hwnd,
+ UINT showCmd,
+ LPRECT rect,
+ LPPOINT pt);
+
+ BOOL
+ NTAPI
+ NtUserSetKeyboardState(
+ LPBYTE lpKeyState);
+
+ BOOL
+ NTAPI
+ NtUserSetLayeredWindowAttributes(
+ HWND hwnd,
+ COLORREF crKey,
+ BYTE bAlpha,
+ DWORD dwFlags);
+
+ BOOL
+ NTAPI
+ NtUserSetLogonNotifyWindow(
+ HWND hWnd);
+
+ BOOL
+ NTAPI
+ NtUserSetObjectInformation(
+ HANDLE hObject,
+ DWORD nIndex,
+ PVOID pvInformation,
+ DWORD nLength);
+
+ HWND
+ NTAPI
+ NtUserSetParent(
+ HWND hWndChild,
+ HWND hWndNewParent);
+
+ BOOL
+ NTAPI
+ NtUserSetProcessWindowStation(
+ HWINSTA hWindowStation);
+
+ BOOL NTAPI
+ NtUserSetProp(HWND hWnd, ATOM Atom, HANDLE Data);
+
+ DWORD
+ NTAPI
+ NtUserSetRipFlags(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ DWORD
+ NTAPI
+ NtUserSetScrollInfo(
+ HWND hwnd,
+ int fnBar,
+ LPCSCROLLINFO lpsi,
+ BOOL bRedraw);
+
+ BOOL
+ NTAPI
+ NtUserSetShellWindowEx(
+ HWND hwndShell,
+ HWND hwndShellListView);
+
+ BOOL
+ NTAPI
+ NtUserSetSysColors(
+ int cElements,
+ IN CONST INT *lpaElements,
+ IN CONST COLORREF *lpaRgbValues,
+ FLONG Flags);
+
+ BOOL
+ NTAPI
+ NtUserSetSystemCursor(
+ HCURSOR hcur,
+ DWORD id);
+
+ BOOL
+ NTAPI
+ NtUserSetThreadDesktop(
+ HDESK hDesktop);
+
+ DWORD
+ NTAPI
+ NtUserSetThreadState(
+ DWORD Unknown0,
+ DWORD Unknown1);
+
+ UINT_PTR
+ NTAPI
+ NtUserSetSystemTimer
+ (
+ HWND hWnd,
+ UINT_PTR nIDEvent,
+ UINT uElapse,
+ TIMERPROC lpTimerFunc
+ );
+
+ DWORD
+ NTAPI
+ NtUserSetThreadLayoutHandles(
+ DWORD dwUnknown1,
+ DWORD dwUnknown2);
+
+ UINT_PTR
+ NTAPI
+ NtUserSetTimer
+ (
+ HWND hWnd,
+ UINT_PTR nIDEvent,
+ UINT uElapse,
+ TIMERPROC lpTimerFunc
+ );
+
+ BOOL
+ NTAPI
+ NtUserSetWindowFNID(
+ HWND hWnd,
+ WORD fnID);
+
+ LONG
+ NTAPI
+ NtUserSetWindowLong(
+ HWND hWnd,
+ DWORD Index,
+ LONG NewValue,
+ BOOL Ansi);
+
+ BOOL
+ NTAPI
+ NtUserSetWindowPlacement(
+ HWND hWnd,
+ WINDOWPLACEMENT *lpwndpl);
+
+ BOOL
+ NTAPI NtUserSetWindowPos(
+ HWND hWnd,
+ HWND hWndInsertAfter,
+ int X,
+ int Y,
+ int cx,
+ int cy,
+ UINT uFlags
+ );
+
+ INT
+ NTAPI
+ NtUserSetWindowRgn(
+ HWND hWnd,
+ HRGN hRgn,
+ BOOL bRedraw);
+
+ HHOOK
+ NTAPI
+ NtUserSetWindowsHookAW(
+ int idHook,
+ HOOKPROC lpfn,
+ BOOL Ansi);
+
+ HHOOK
+ NTAPI
+ NtUserSetWindowsHookEx(
+ HINSTANCE Mod,
+ PUNICODE_STRING ModuleName,
+ DWORD ThreadId,
+ int HookId,
+ HOOKPROC HookProc,
+ BOOL Ansi);
+
+ DWORD
+ NTAPI
+ NtUserSetWindowStationUser(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3);
+
+ WORD NTAPI
+ NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewVal);
+
+ HWINEVENTHOOK
+ NTAPI
+ NtUserSetWinEventHook(
+ UINT eventMin,
+ UINT eventMax,
+ HMODULE hmodWinEventProc,
+ PUNICODE_STRING puString,
+ WINEVENTPROC lpfnWinEventProc,
+ DWORD idProcess,
+ DWORD idThread,
+ UINT dwflags);
+
+ BOOL
+ NTAPI
+ NtUserShowCaret(
+ HWND hWnd);
+
+ BOOL
+ NTAPI
+ NtUserHideCaret(
+ HWND hWnd);
+
+ DWORD
+ NTAPI
+ NtUserShowScrollBar(HWND hWnd, int wBar, DWORD bShow);
+
+ BOOL
+ NTAPI
+ NtUserShowWindow(
+ HWND hWnd,
+ LONG nCmdShow);
+
+ BOOL
+ NTAPI
+ NtUserShowWindowAsync(
+ HWND hWnd,
+ LONG nCmdShow);
+
+ BOOL
+ NTAPI
+ NtUserSoundSentry(VOID);
+
+ BOOL
+ NTAPI
+ NtUserSwitchDesktop(
+ HDESK hDesktop);
+
+ BOOL
+ NTAPI
+ NtUserSystemParametersInfo(
+ UINT uiAction,
+ UINT uiParam,
+ PVOID pvParam,
+ UINT fWinIni);
+
+ DWORD
+ NTAPI
+ NtUserTestForInteractiveUser(
+ DWORD dwUnknown1);
+
+ INT
+ NTAPI
+ NtUserToUnicodeEx(
+ UINT wVirtKey,
+ UINT wScanCode,
+ PBYTE lpKeyState,
+ LPWSTR pwszBuff,
+ int cchBuff,
+ UINT wFlags,
+ HKL dwhkl );
+
+ BOOL
+ NTAPI
+ NtUserTrackMouseEvent(
+ LPTRACKMOUSEEVENT lpEventTrack);
+
+ int
+ NTAPI
+ NtUserTranslateAccelerator(
+ HWND Window,
+ HACCEL Table,
+ LPMSG Message);
+
+ BOOL
+ NTAPI
+ NtUserTranslateMessage(
+ LPMSG lpMsg,
+ UINT flags );
+
+ BOOL
+ NTAPI
+ NtUserUnhookWindowsHookEx(
+ HHOOK Hook);
+
+ BOOL
+ NTAPI
+ NtUserUnhookWinEvent(
+ HWINEVENTHOOK hWinEventHook);
+
+ BOOL
+ NTAPI
+ NtUserUnloadKeyboardLayout(
+ HKL hKl);
+
+ BOOL
+ NTAPI
+ NtUserUnlockWindowStation(
+ HWINSTA hWindowStation);
+
+ BOOL
+ NTAPI
+ NtUserUnregisterClass(
+ PUNICODE_STRING ClassNameOrAtom,
+ HINSTANCE hInstance,
+ PCLSMENUNAME pClassMenuName);
+
+ BOOL
+ NTAPI
+ NtUserUnregisterHotKey(HWND hWnd,
+ int id);
+
+ BOOL
+ NTAPI
+ NtUserUnregisterUserApiHook(VOID);
+
+ DWORD
+ NTAPI
+ NtUserUpdateInputContext(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2);
+
+ DWORD
+ NTAPI
+ NtUserUpdateInstance(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2);
+
+ BOOL
+ NTAPI
+ NtUserUpdateLayeredWindow(
+ HWND hwnd,
+ HDC hdcDst,
+ POINT *pptDst,
+ SIZE *psize,
+ HDC hdcSrc,
+ POINT *pptSrc,
+ COLORREF crKey,
+ BLENDFUNCTION *pblend,
+ DWORD dwFlags,
+ RECT *prcDirty);
+
+ BOOL
+ NTAPI
+ NtUserUpdatePerUserSystemParameters(
+ DWORD dwReserved,
+ BOOL bEnable);
+
+ BOOL
+ NTAPI
+ NtUserUserHandleGrantAccess(
+ IN HANDLE hUserHandle,
+ IN HANDLE hJob,
+ IN BOOL bGrant);
+
+ BOOL
+ NTAPI
+ NtUserValidateHandleSecure(
+ HANDLE hHdl,
+ BOOL Restricted);
+
+ BOOL
+ NTAPI
+ NtUserValidateRect(
+ HWND hWnd,
+ CONST RECT *lpRect);
+
+ BOOL
+ APIENTRY
+ NtUserValidateTimerCallback(
+ HWND hWnd,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ DWORD
+ NTAPI
+ NtUserVkKeyScanEx(
+ WCHAR wChar,
+ HKL KeyboardLayout,
+ BOOL bUsehHK);
+
+ DWORD
+ NTAPI
+ NtUserWaitForInputIdle(
+ IN HANDLE hProcess,
+ IN DWORD dwMilliseconds,
+ IN BOOL Unknown2); // Always FALSE
+
+ DWORD
+ NTAPI
+ NtUserWaitForMsgAndEvent(
+ DWORD Unknown0);
+
+ BOOL
+ NTAPI
+ NtUserWaitMessage(VOID);
+
+ DWORD
+ NTAPI
+ NtUserWin32PoolAllocationStats(
+ DWORD Unknown0,
+ DWORD Unknown1,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4,
+ DWORD Unknown5);
+
+ HWND
+ NTAPI
+ NtUserWindowFromPhysicalPoint(
+ POINT Point);
+
+ HWND
+ NTAPI
+ NtUserWindowFromPoint(
+ LONG X,
+ LONG Y);
+
+ DWORD
+ NTAPI
+ NtUserYieldTask(VOID);
+
+ /* lParam of DDE messages */
+ typedef struct tagKMDDEEXECUTEDATA
+ {
+ HWND Sender;
+ HGLOBAL ClientMem;
+ /* BYTE Data[DataSize] */
+ } KMDDEEXECUTEDATA, *PKMDDEEXECUTEDATA;
+
+ typedef struct tagKMDDELPARAM
+ {
+ UINT_PTR uiLo;
+ UINT_PTR uiHi;
+ } KMDDELPARAM, *PKMDDELPARAM;
+
+
+
+
+
+ /* NtUserBad
+ * ReactOS-specific NtUser calls and their related structures, both which shouldn't exist.
+ */
+
+ #define NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO 0xffff0005
+ #define ONEPARAM_ROUTINE_CSRSS_GUICHECK 0xffff0008
+ #define ONEPARAM_ROUTINE_SWITCHCARETSHOWING 0xfffe0008
+ #define ONEPARAM_ROUTINE_ENABLEPROCWNDGHSTING 0xfffe000d
+ #define ONEPARAM_ROUTINE_GETDESKTOPMAPPING 0xfffe000e
+ #define ONEPARAM_ROUTINE_GETCURSORPOSITION 0xfffe0048 // use ONEPARAM_ or TWOPARAM routine ?
+ #define TWOPARAM_ROUTINE_SETMENUBARHEIGHT 0xfffd0050
+ #define TWOPARAM_ROUTINE_SETGUITHRDHANDLE 0xfffd0052
+ #define MSQ_STATE_CAPTURE 0x1
+ #define MSQ_STATE_ACTIVE 0x2
+ #define MSQ_STATE_FOCUS 0x3
+ #define MSQ_STATE_MENUOWNER 0x4
+ #define MSQ_STATE_MOVESIZE 0x5
+ #define MSQ_STATE_CARET 0x6
+ #define TWOPARAM_ROUTINE_SETCARETPOS 0xfffd0060
+ #define TWOPARAM_ROUTINE_ROS_UPDATEUISTATE 0x1004
+ #define HWNDPARAM_ROUTINE_ROS_NOTIFYWINEVENT 0x1005
+
+ DWORD
+ NTAPI
+ NtUserBuildMenuItemList(
+ HMENU hMenu,
+ PVOID Buffer,
+ ULONG nBufSize,
+ DWORD Reserved);
+
+ UINT
+ NTAPI
+ NtUserGetMenuDefaultItem(
+ HMENU hMenu,
+ UINT fByPos,
+ UINT gmdiFlags);
+
+ BOOL
+ NTAPI
+ NtUserGetMonitorInfo(
+ IN HMONITOR hMonitor,
+ OUT LPMONITORINFO pMonitorInfo);
+
+ /* Should be done in usermode */
+
+ /* (other FocusedItem values give the position of the focused item) */
+ #define NO_SELECTED_ITEM 0xffff
+
+ typedef struct tagROSMENUINFO
+ {
+ /* ----------- MENUINFO ----------- */
+ DWORD cbSize;
+ DWORD fMask;
+ DWORD dwStyle;
+ UINT cyMax;
+ HBRUSH hbrBack;
+ DWORD dwContextHelpID;
+ ULONG_PTR dwMenuData;
+ /* ----------- Extra ----------- */
+ HMENU Self; /* Handle of this menu */
+ WORD Flags; /* Menu flags (MF_POPUP, MF_SYSMENU) */
+ UINT FocusedItem; /* Currently focused item */
+ UINT MenuItemCount; /* Number of items in the menu */
+ HWND Wnd; /* Window containing the menu */
+ WORD Width; /* Width of the whole menu */
+ WORD Height; /* Height of the whole menu */
+ HWND WndOwner; /* window receiving the messages for ownerdraw */
+ BOOL TimeToHide; /* Request hiding when receiving a second click in the top-level menu item */
+ SIZE maxBmpSize; /* Maximum size of the bitmap items in MIIM_BITMAP state */
+ } ROSMENUINFO, *PROSMENUINFO;
+
+ BOOL
+ NTAPI
+ NtUserMenuInfo(
+ HMENU hmenu,
+ PROSMENUINFO lpmi,
+ BOOL fsog
+ );
+
+ typedef struct tagROSMENUITEMINFO
+ {
+ /* ----------- MENUITEMINFOW ----------- */
+ UINT cbSize;
+ UINT fMask;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HMENU hSubMenu;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ DWORD dwItemData;
+ LPWSTR dwTypeData;
+ UINT cch;
+ HBITMAP hbmpItem;
+ /* ----------- Extra ----------- */
+ RECT Rect; /* Item area (relative to menu window) */
+ UINT dxTab; /* X position of text after Tab */
+ LPWSTR lpstr; /* Copy of the text pointer in MenuItem->Text */
+ } ROSMENUITEMINFO, *PROSMENUITEMINFO;
+
+ BOOL
+ NTAPI
+ NtUserMenuItemInfo(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ PROSMENUITEMINFO lpmii,
+ BOOL fsog
+ );
+
+ HMONITOR
+ NTAPI
+ NtUserMonitorFromPoint(
+ IN POINT point,
+ IN DWORD dwFlags);
+
+ HMONITOR
+ NTAPI
+ NtUserMonitorFromRect(
+ IN LPCRECT pRect,
+ IN DWORD dwFlags);
+
+ HMONITOR
+ NTAPI
+ NtUserMonitorFromWindow(
+ IN HWND hWnd,
+ IN DWORD dwFlags);
+
+ typedef struct _SETSCROLLBARINFO
+ {
+ int nTrackPos;
+ int reserved;
+ DWORD rgstate[CCHILDREN_SCROLLBAR+1];
+ } SETSCROLLBARINFO, *PSETSCROLLBARINFO;
+
+ BOOL
+ NTAPI
+ NtUserSetScrollBarInfo(
+ HWND hwnd,
+ LONG idObject,
+ SETSCROLLBARINFO *info);
+
+
+
+ #endif /* __WIN32K_NTUSER_H */
+
+ /* EOF */
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Callproc support
+ * FILE: subsystems/win32/win32k/ntuser/callproc.c
+ * PROGRAMER: Thomas Weidenmueller <w3seek@reactos.com>
+ */
+
+ #include <win32k.h>
+
+ /* CALLPROC ******************************************************************/
+
+ WNDPROC
+ GetCallProcHandle(IN PCALLPROCDATA CallProc)
+ {
+ /* FIXME: Check for 64 bit architectures... */
+ return (WNDPROC)((ULONG_PTR)UserHMGetHandle(CallProc) | 0xFFFF0000);
+ }
+
+ VOID
+ DestroyCallProc(IN PDESKTOPINFO Desktop,
+ IN OUT PCALLPROCDATA CallProc)
+ {
+ UserDeleteObject(UserHMGetHandle(CallProc), otCallProc);
+ }
+
+ PCALLPROCDATA
+ CreateCallProc(IN PDESKTOP Desktop,
+ IN WNDPROC WndProc,
+ IN BOOL Unicode,
+ IN PPROCESSINFO pi)
+ {
+ PCALLPROCDATA NewCallProc;
+ HANDLE Handle;
+
+ NewCallProc = (PCALLPROCDATA)UserCreateObject(gHandleTable,
+ Desktop,
+ NULL,
+ &Handle,
+ otCallProc,
+ sizeof(CALLPROCDATA));
+ if (NewCallProc != NULL)
+ {
+ NewCallProc->pfnClientPrevious = WndProc;
+ NewCallProc->wType |= Unicode ? UserGetCPDA2U : UserGetCPDU2A ;
+ NewCallProc->spcpdNext = NULL;
+ }
+
++ /* Release the extra reference (UserCreateObject added 2 references) */
++ UserDereferenceObject(NewCallProc);
++
+ return NewCallProc;
+ }
+
+ BOOL
+ UserGetCallProcInfo(IN HANDLE hCallProc,
+ OUT PWNDPROC_INFO wpInfo)
+ {
+ PCALLPROCDATA CallProc;
+
+ CallProc = UserGetObject(gHandleTable,
+ hCallProc,
+ otCallProc);
+ if (CallProc == NULL)
+ {
+ return FALSE;
+ }
+
+ /* Use Handle pEntry->ppi!
+ if (CallProc->pi != GetW32ProcessInfo())
+ {
+ return FALSE;
+ }*/
+
+ wpInfo->WindowProc = CallProc->pfnClientPrevious;
+ wpInfo->IsUnicode = !!(CallProc->wType & UserGetCPDA2U);
+
+ return TRUE;
+ }
+
+ /*
+ Based on UserFindCallProc.
+ */
+ PCALLPROCDATA
+ FASTCALL
+ UserSearchForCallProc(
+ PCALLPROCDATA pcpd,
+ WNDPROC WndProc,
+ GETCPD Type)
+ {
+ while ( pcpd && (pcpd->pfnClientPrevious != WndProc || pcpd->wType != Type) )
+ {
+ pcpd = pcpd->spcpdNext;
+ }
+ return pcpd;
+ }
+
+ /*
+ Get Call Proc Data handle for the window proc being requested or create a
+ new Call Proc Data handle to be return for the requested window proc.
+ */
+ ULONG_PTR
+ FASTCALL
+ UserGetCPD(
+ PVOID pvClsWnd,
+ GETCPD Flags,
+ ULONG_PTR ProcIn)
+ {
+ PCLS pCls;
+ PWND pWnd;
+ PCALLPROCDATA CallProc = NULL;
+ PTHREADINFO pti;
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if ( Flags & (UserGetCPDWindow|UserGetCPDDialog) ||
+ Flags & UserGetCPDWndtoCls)
+ {
+ pWnd = pvClsWnd;
+ pCls = pWnd->pcls;
+ }
+ else
+ pCls = pvClsWnd;
+
+ // Search Class call proc data list.
+ if (pCls->spcpdFirst)
+ CallProc = UserSearchForCallProc( pCls->spcpdFirst, (WNDPROC)ProcIn, Flags);
+
+ // No luck, create a new one for the requested proc.
+ if (!CallProc)
+ {
+ CallProc = CreateCallProc( NULL,
+ (WNDPROC)ProcIn,
+ !!(Flags & UserGetCPDA2U),
+ pti->ppi);
+ if (CallProc)
+ {
+ CallProc->spcpdNext = pCls->spcpdFirst;
+ (void)InterlockedExchangePointer((PVOID*)&pCls->spcpdFirst,
+ CallProc);
+ CallProc->wType = Flags;
+ }
+ }
+ return (ULONG_PTR)(CallProc ? GetCallProcHandle(CallProc) : NULL);
+ }
+
+ /* SYSCALLS *****************************************************************/
+
+ /*
+ Retrieve the WinProcA/W or CallProcData handle for Class, Dialog or Window.
+ This Function called from user space uses Window handle for class, window
+ and dialog procs only.
+
+ Note:
+ ProcIn is the default proc from pCls/pDlg/pWnd->lpfnXxyz, caller is
+ looking for another type of proc if the original lpfnXxyz proc is preset
+ to Ansi or Unicode.
+
+ Example:
+ If pWnd is created from Ansi and lpfnXxyz is assumed to be Ansi, caller
+ will ask for Unicode Proc return Proc or CallProcData handle.
+ */
+ ULONG_PTR
+ APIENTRY
+ NtUserGetCPD(
+ HWND hWnd,
+ GETCPD Flags,
+ ULONG_PTR ProcIn)
+ {
+ PWND Wnd;
+ ULONG_PTR Result = 0;
+
+ UserEnterExclusive();
+ if (!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ goto Cleanup;
+ }
+
+ // Processing Window only from User space.
+ if ((Flags & ~(UserGetCPDU2A|UserGetCPDA2U)) != UserGetCPDClass)
+ Result = UserGetCPD(Wnd, Flags, ProcIn);
+
+ Cleanup:
+ UserLeave();
+ return Result;
+ }
+
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Clipboard routines
+ * FILE: subsys/win32k/ntuser/clipboard.c
+ * PROGRAMER: Filip Navara <xnavara@volny.cz>
+ * Pablo Borobia <pborobia@gmail.com>
+ * Rafal Harabien <rafalh@reactos.org>
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserClipbrd);
+
+ #define DATA_DELAYED (HANDLE)0
+ #define DATA_SYNTH_USER (HANDLE)1
+ #define DATA_SYNTH_KRNL (HANDLE)2
+ #define IS_DATA_DELAYED(ce) ((ce)->hData == DATA_DELAYED)
+ #define IS_DATA_SYNTHESIZED(ce) ((ce)->hData == DATA_SYNTH_USER || (ce)->hData == DATA_SYNTH_KRNL)
+
+ PWINSTATION_OBJECT static FASTCALL
+ IntGetWinStaForCbAccess(VOID)
+ {
+ HWINSTA hWinSta;
+ PWINSTATION_OBJECT pWinStaObj;
+ NTSTATUS Status;
+
+ hWinSta = UserGetProcessWindowStation();
+ Status = IntValidateWindowStationHandle(hWinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &pWinStaObj);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Cannot open winsta\n");
+ SetLastNtError(Status);
+ return NULL;
+ }
+
+ return pWinStaObj;
+ }
+
+ /* If format exists, returns a non zero value (pointing to formated object) */
+ PCLIP static FASTCALL
+ IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj, UINT fmt)
+ {
+ unsigned i = 0;
+
+ for (i = 0; i < pWinStaObj->cNumClipFormats; ++i)
+ {
+ if (pWinStaObj->pClipBase[i].fmt == fmt)
+ return &pWinStaObj->pClipBase[i];
+ }
+
+ return NULL;
+ }
+
+ VOID static FASTCALL
+ IntFreeElementData(PCLIP pElement)
+ {
+ if (!IS_DATA_DELAYED(pElement) &&
+ !IS_DATA_SYNTHESIZED(pElement))
+ {
+ if (pElement->fGlobalHandle)
+ UserDeleteObject(pElement->hData, otClipBoardData);
+ else if (pElement->fmt == CF_BITMAP || pElement->fmt == CF_PALETTE ||
+ pElement->fmt == CF_DSPBITMAP)
+ {
+ GreSetObjectOwner(pElement->hData, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(pElement->hData);
+ }
+ }
+ }
+
+ /* Adds a new format and data to the clipboard */
+ PCLIP static NTAPI
+ IntAddFormatedData(PWINSTATION_OBJECT pWinStaObj, UINT fmt, HANDLE hData, BOOLEAN fGlobalHandle, BOOL bEnd)
+ {
+ PCLIP pElement = NULL;
+
+ /* Use exisiting entry with specified format */
+ if (!bEnd)
+ pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+
+ /* Put new entry at the end if nothing was found */
+ if (!pElement)
+ {
+ /* Allocate bigger clipboard if needed. We could use lists but Windows uses array */
+ if (pWinStaObj->cNumClipFormats % 4 == 0)
+ {
+ PCLIP pNewClip;
+
+ /* Allocate new clipboard */
+ pNewClip = ExAllocatePoolWithTag(PagedPool,
+ (pWinStaObj->cNumClipFormats + 4) * sizeof(CLIP),
+ USERTAG_CLIPBOARD);
+ if (!pNewClip)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ /* Copy data */
+ memcpy(pNewClip, pWinStaObj->pClipBase, pWinStaObj->cNumClipFormats * sizeof(CLIP));
+
+ /* Free old clipboard */
+ if (pWinStaObj->pClipBase)
+ ExFreePoolWithTag(pWinStaObj->pClipBase, USERTAG_CLIPBOARD);
+
+ /* Update WinSta */
+ pWinStaObj->pClipBase = pNewClip;
+ }
+
+ /* New element is at the end */
+ pElement = &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats];
+ pElement->fmt = fmt;
+ pWinStaObj->cNumClipFormats++;
+ }
+ else
+ IntFreeElementData(pElement);
+
+ pElement->hData = hData;
+ pElement->fGlobalHandle = fGlobalHandle;
+
+ return pElement;
+ }
+
+ BOOL static FASTCALL
+ IntIsClipboardOpenByMe(PWINSTATION_OBJECT pWinSta)
+ {
+ /* Check if current thread has opened the clipboard */
+ if (pWinSta->ptiClipLock &&
+ pWinSta->ptiClipLock == PsGetCurrentThreadWin32Thread())
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ VOID static NTAPI
+ IntSynthesizeDib(
+ PWINSTATION_OBJECT pWinStaObj,
+ HBITMAP hbm)
+ {
+ HDC hdc;
+ ULONG cjInfoSize, cjDataSize;
+ PCLIPBOARDDATA pClipboardData;
+ HANDLE hMem;
+ INT iResult;
+ struct
+ {
+ BITMAPINFOHEADER bmih;
+ RGBQUAD rgbColors[256];
+ } bmiBuffer;
+ PBITMAPINFO pbmi = (PBITMAPINFO)&bmiBuffer;
+
+ /* Get the display DC */
+ hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+ if (!hdc)
+ {
+ return;
+ }
+
+ /* Get information about the bitmap format */
+ iResult = GreGetDIBitsInternal(hdc,
+ hbm,
+ 0,
+ 0,
+ NULL,
+ pbmi,
+ DIB_RGB_COLORS,
+ 0,
+ sizeof(bmiBuffer));
+ if (iResult == 0)
+ {
+ goto cleanup;
+ }
+
+ /* Get the size for a full BITMAPINFO */
+ cjInfoSize = DIB_BitmapInfoSize(pbmi, DIB_RGB_COLORS);
+
+ /* Calculate the size of the clipboard data, which is a packed DIB */
+ cjDataSize = cjInfoSize + pbmi->bmiHeader.biSizeImage;
+
+ /* Create the clipboard data */
+ pClipboardData = (PCLIPBOARDDATA)UserCreateObject(gHandleTable,
+ NULL,
+ NULL,
+ &hMem,
+ otClipBoardData,
+ cjDataSize);
+ if (!pClipboardData)
+ {
+ goto cleanup;
+ }
+
+ /* Set the data size */
+ pClipboardData->cbData = cjDataSize;
+
+ /* Copy the BITMAPINFOHEADER */
+ memcpy(pClipboardData->Data, pbmi, sizeof(BITMAPINFOHEADER));
+
+ /* Get the bitmap bits and the color table */
+ iResult = GreGetDIBitsInternal(hdc,
+ hbm,
+ 0,
+ abs(pbmi->bmiHeader.biHeight),
+ (LPBYTE)pClipboardData->Data + cjInfoSize,
+ (LPBITMAPINFO)pClipboardData->Data,
+ DIB_RGB_COLORS,
+ pbmi->bmiHeader.biSizeImage,
+ cjInfoSize);
+
+ /* Add the clipboard data */
+ IntAddFormatedData(pWinStaObj, CF_DIB, hMem, TRUE, TRUE);
+
++ /* Release the extra reference (UserCreateObject added 2 references) */
++ UserDereferenceObject(pClipboardData);
++
+ cleanup:
+ UserReleaseDC(NULL, hdc, FALSE);
+ }
+
+ VOID static WINAPI
+ IntSynthesizeBitmap(PWINSTATION_OBJECT pWinStaObj, PCLIP pBmEl)
+ {
+ HDC hdc = NULL;
+ PBITMAPINFO pBmi, pConvertedBmi = NULL;
+ HBITMAP hBm = NULL;
+ PCLIPBOARDDATA pMemObj;
+ PCLIP pDibEl;
+ ULONG Offset;
+
+ TRACE("IntSynthesizeBitmap(%p, %p)\n", pWinStaObj, pBmEl);
+
+ pDibEl = IntIsFormatAvailable(pWinStaObj, CF_DIB);
+ ASSERT(pDibEl && !IS_DATA_SYNTHESIZED(pDibEl));
+ if(!pDibEl->fGlobalHandle)
+ return;
+
+ pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, pDibEl->hData, otClipBoardData);
+ if (!pMemObj)
+ return;
+
+ pBmi = (BITMAPINFO*)pMemObj->Data;
+
+ if (pMemObj->cbData < sizeof(DWORD) && pMemObj->cbData < pBmi->bmiHeader.biSize)
+ goto cleanup;
+
+ pConvertedBmi = DIB_ConvertBitmapInfo(pBmi, DIB_RGB_COLORS);
+ if (!pConvertedBmi)
+ goto cleanup;
+
+ Offset = DIB_BitmapInfoSize(pBmi, DIB_RGB_COLORS);
+
+ hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
+ if (!hdc)
+ goto cleanup;
+
+ hBm = GreCreateDIBitmapInternal(hdc,
+ pConvertedBmi->bmiHeader.biWidth,
+ pConvertedBmi->bmiHeader.biHeight,
+ CBM_INIT,
+ pMemObj->Data + Offset,
+ pConvertedBmi,
+ DIB_RGB_COLORS,
+ 0,
+ pMemObj->cbData - Offset,
+ 0);
+
+ if (hBm)
+ {
+ GreSetObjectOwner(hBm, GDI_OBJ_HMGR_PUBLIC);
+ pBmEl->hData = hBm;
+ }
+
+ cleanup:
+ if (hdc)
+ UserReleaseDC(NULL, hdc, FALSE);
+
+ if (pConvertedBmi)
+ DIB_FreeConvertedBitmapInfo(pConvertedBmi, pBmi);
+ }
+
+ VOID static NTAPI
+ IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj)
+ {
+ PCLIP pTextEl, pUniTextEl, pOemTextEl, pLocaleEl, pBmEl, pDibEl;
+
+ pTextEl = IntIsFormatAvailable(pWinStaObj, CF_TEXT);
+ pOemTextEl = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT);
+ pUniTextEl = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT);
+ pLocaleEl = IntIsFormatAvailable(pWinStaObj, CF_LOCALE);
+ pBmEl = IntIsFormatAvailable(pWinStaObj, CF_BITMAP);
+ pDibEl = IntIsFormatAvailable(pWinStaObj, CF_DIB);
+
+ /* Add CF_LOCALE format if we have CF_TEXT */
+ if (!pLocaleEl && pTextEl)
+ {
+ PCLIPBOARDDATA pMemObj;
+ HANDLE hMem;
+
+ pMemObj = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, NULL, &hMem, otClipBoardData,
+ sizeof(CLIPBOARDDATA) + sizeof(LCID));
+ if (pMemObj)
+ {
+ pMemObj->cbData = sizeof(LCID);
+ *((LCID*)pMemObj->Data) = NtCurrentTeb()->CurrentLocale;
+ IntAddFormatedData(pWinStaObj, CF_LOCALE, hMem, TRUE, TRUE);
+ }
++
++ /* Release the extra reference (UserCreateObject added 2 references) */
++ UserDereferenceObject(pMemObj);
+ }
+
+ /* Add CF_TEXT. Note: it is synthesized in user32.dll */
+ if (!pTextEl && (pUniTextEl || pOemTextEl))
+ IntAddFormatedData(pWinStaObj, CF_TEXT, DATA_SYNTH_USER, FALSE, TRUE);
+
+ /* Add CF_OEMTEXT. Note: it is synthesized in user32.dll */
+ if (!pOemTextEl && (pUniTextEl || pTextEl))
+ IntAddFormatedData(pWinStaObj, CF_OEMTEXT, DATA_SYNTH_USER, FALSE, TRUE);
+
+ /* Add CF_UNICODETEXT. Note: it is synthesized in user32.dll */
+ if (!pUniTextEl && (pTextEl || pOemTextEl))
+ IntAddFormatedData(pWinStaObj, CF_UNICODETEXT, DATA_SYNTH_USER, FALSE, TRUE);
+
+ /* Add CF_BITMAP. Note: it is synthesized on demand */
+ if (!pBmEl && pDibEl)
+ IntAddFormatedData(pWinStaObj, CF_BITMAP, DATA_SYNTH_KRNL, FALSE, TRUE);
+
+ /* Note: We need to render the DIB or DIBV5 format as soon as possible
+ because pallette information may change */
+ if (!pDibEl && pBmEl)
+ IntSynthesizeDib(pWinStaObj, pBmEl->hData);
+ }
+
+ VOID NTAPI
+ UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta)
+ {
+ unsigned i;
+ PCLIP pElement;
+
+ for (i = 0; i < pWinSta->cNumClipFormats; ++i)
+ {
+ pElement = &pWinSta->pClipBase[i];
+ IntFreeElementData(pElement);
+ }
+
+ if(pWinSta->pClipBase)
+ ExFreePoolWithTag(pWinSta->pClipBase, USERTAG_CLIPBOARD);
+ pWinSta->pClipBase = NULL;
+ pWinSta->cNumClipFormats = 0;
+ }
+
+ /* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */
+ VOID FASTCALL
+ UserClipboardFreeWindow(PWND pWindow)
+ {
+ PWINSTATION_OBJECT pWinStaObj;
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ return;
+
+ /* Check if clipboard is not locked by this window, if yes, unlock it */
+ if (pWindow == pWinStaObj->spwndClipOpen)
+ {
+ /* The window that opens the clipboard was destroyed */
+ pWinStaObj->spwndClipOpen = NULL;
+ pWinStaObj->ptiClipLock = NULL;
+ }
+ if (pWindow == pWinStaObj->spwndClipOwner)
+ {
+ /* The owner window was destroyed */
+ pWinStaObj->spwndClipOwner = NULL;
+ }
+ /* Remove window from window chain */
+ if (pWindow == pWinStaObj->spwndClipViewer)
+ pWinStaObj->spwndClipViewer = NULL;
+
+ ObDereferenceObject(pWinStaObj);
+ }
+
+ UINT APIENTRY
+ UserEnumClipboardFormats(UINT fmt)
+ {
+ UINT Ret = 0;
+ PCLIP pElement;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ /* Check if clipboard has been opened */
+ if (!IntIsClipboardOpenByMe(pWinStaObj))
+ {
+ EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+ goto cleanup;
+ }
+
+ if (fmt == 0)
+ {
+ /* Return first format */
+ if (pWinStaObj->pClipBase)
+ Ret = pWinStaObj->pClipBase[0].fmt;
+ }
+ else
+ {
+ /* Return next format */
+ pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+ ++pElement;
+ if (pElement < &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats])
+ Ret = pElement->fmt;
+ }
+
+ cleanup:
+ if(pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
+
+ return Ret;
+ }
+
+ BOOL NTAPI
+ UserOpenClipboard(HWND hWnd)
+ {
+ PWND pWindow = NULL;
+ BOOL bRet = FALSE;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+
+ if (hWnd)
+ {
+ pWindow = UserGetWindowObject(hWnd);
+ if (!pWindow)
+ goto cleanup;
+ }
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (pWinStaObj->ptiClipLock)
+ {
+ /* Clipboard is already open */
+ if (pWinStaObj->spwndClipOpen != pWindow)
+ {
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ ERR("Access denied!\n");
+ goto cleanup;
+ }
+ }
+
+ /* Open clipboard */
+ pWinStaObj->spwndClipOpen = pWindow;
+ pWinStaObj->ptiClipLock = PsGetCurrentThreadWin32Thread();
+ bRet = TRUE;
+
+ cleanup:
+ if (pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
+
+ return bRet;
+ }
+
+ BOOL APIENTRY
+ NtUserOpenClipboard(HWND hWnd, DWORD Unknown1)
+ {
+ BOOL bRet;
+
+ UserEnterExclusive();
+ bRet = UserOpenClipboard(hWnd);
+ UserLeave();
+
+ return bRet;
+ }
+
+ BOOL NTAPI
+ UserCloseClipboard(VOID)
+ {
+ BOOL bRet = FALSE;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (!IntIsClipboardOpenByMe(pWinStaObj))
+ {
+ EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+ goto cleanup;
+ }
+
+ /* Clipboard is no longer open */
+ pWinStaObj->spwndClipOpen = NULL;
+ pWinStaObj->ptiClipLock = NULL;
+ bRet = TRUE;
+
+ if (pWinStaObj->fClipboardChanged)
+ {
+ /* Add synthesized formats - they are rendered later */
+ IntAddSynthesizedFormats(pWinStaObj);
+
+ /* Notify viewer windows in chain */
+ if (pWinStaObj->spwndClipViewer)
+ {
+ TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h);
+ co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0);
+ }
+
+ pWinStaObj->fClipboardChanged = FALSE;
+ }
+
+ cleanup:
+ if (pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
+
+ return bRet;
+ }
+
+ BOOL APIENTRY
+ NtUserCloseClipboard(VOID)
+ {
+ BOOL bRet;
+
+ UserEnterExclusive();
+ bRet = UserCloseClipboard();
+ UserLeave();
+
+ return bRet;
+ }
+
+ HWND APIENTRY
+ NtUserGetOpenClipboardWindow(VOID)
+ {
+ HWND hWnd = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (pWinStaObj->spwndClipOpen)
+ hWnd = pWinStaObj->spwndClipOpen->head.h;
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return hWnd;
+ }
+
+ BOOL APIENTRY
+ NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext)
+ {
+ BOOL bRet = FALSE;
+ PWND pWindowRemove;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ TRACE("NtUserChangeClipboardChain(%p, %p)\n", hWndRemove, hWndNewNext);
+
+ UserEnterExclusive();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ pWindowRemove = UserGetWindowObject(hWndRemove);
+
+ if (pWindowRemove && pWinStaObj->spwndClipViewer)
+ {
+ if(pWindowRemove == pWinStaObj->spwndClipViewer)
+ pWinStaObj->spwndClipViewer = UserGetWindowObject(hWndNewNext);
+
+ if(pWinStaObj->spwndClipViewer)
+ bRet = (BOOL)co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, (LPARAM)hWndNewNext);
+ }
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return bRet;
+ }
+
+ DWORD APIENTRY
+ NtUserCountClipboardFormats(VOID)
+ {
+ DWORD cFormats = 0;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ cFormats = pWinStaObj->cNumClipFormats;
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return cFormats;
+ }
+
+ BOOL NTAPI
+ UserEmptyClipboard(VOID)
+ {
+ BOOL bRet = FALSE;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ return FALSE;
+
+ if (IntIsClipboardOpenByMe(pWinStaObj))
+ {
+ UserEmptyClipboardData(pWinStaObj);
+
+ if (pWinStaObj->spwndClipOwner)
+ {
+ TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p", pWinStaObj->spwndClipOwner->head.h);
+ co_IntSendMessageNoWait(pWinStaObj->spwndClipOwner->head.h, WM_DESTROYCLIPBOARD, 0, 0);
+ }
+
+ pWinStaObj->spwndClipOwner = pWinStaObj->spwndClipOpen;
+
+ pWinStaObj->iClipSequenceNumber++;
+
+ bRet = TRUE;
+ }
+ else
+ {
+ EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+ ERR("Access denied!\n");
+ }
+
+ ObDereferenceObject(pWinStaObj);
+
+ return bRet;
+ }
+
+ BOOL APIENTRY
+ NtUserEmptyClipboard(VOID)
+ {
+ BOOL bRet;
+
+ TRACE("NtUserEmptyClipboard()\n");
+
+ UserEnterExclusive();
+ bRet = UserEmptyClipboard();
+ UserLeave();
+
+ return bRet;
+ }
+
+ INT APIENTRY
+ NtUserGetClipboardFormatName(UINT fmt, LPWSTR lpszFormatName, INT cchMaxCount)
+ {
+ INT iRet = 0;
+
+ UserEnterShared();
+
+ /* If the format is built-in we fail */
+ if (fmt < 0xc000)
+ {
+ /* Registetrated formats are >= 0xc000 */
+ goto cleanup;
+ }
+
+ if (cchMaxCount < 1 || !lpszFormatName)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto cleanup;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(lpszFormatName, cchMaxCount * sizeof(WCHAR), 1);
+
+ iRet = IntGetAtomName((RTL_ATOM)fmt,
+ lpszFormatName,
+ cchMaxCount * sizeof(WCHAR));
+ iRet /= sizeof(WCHAR);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ cleanup:
+ UserLeave();
+
+ return iRet;
+ }
+
+ HWND APIENTRY
+ NtUserGetClipboardOwner(VOID)
+ {
+ HWND hWnd = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (pWinStaObj->spwndClipOwner)
+ hWnd = pWinStaObj->spwndClipOwner->head.h;
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return hWnd;
+ }
+
+ HWND APIENTRY
+ NtUserGetClipboardViewer(VOID)
+ {
+ HWND hWnd = NULL;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if(!pWinStaObj)
+ goto cleanup;
+
+ if (pWinStaObj->spwndClipViewer)
+ hWnd = pWinStaObj->spwndClipViewer->head.h;
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return hWnd;
+ }
+
+ INT APIENTRY
+ NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
+ {
+ INT i, iRet = 0;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (pWinStaObj->pClipBase == NULL)
+ {
+ iRet = 0;
+ }
+ else
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(paFormatPriorityList, cFormats * sizeof(UINT), sizeof(UINT));
+
+ iRet = -1;
+
+ for (i = 0; i < cFormats; ++i)
+ {
+ if (IntIsFormatAvailable(pWinStaObj, paFormatPriorityList[i]))
+ {
+ iRet = paFormatPriorityList[i];
+ break;
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ }
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return iRet;
+
+ }
+
+ BOOL APIENTRY
+ NtUserIsClipboardFormatAvailable(UINT fmt)
+ {
+ BOOL bRet = FALSE;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ TRACE("NtUserIsClipboardFormatAvailable(%x)\n", fmt);
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (IntIsFormatAvailable(pWinStaObj, fmt))
+ bRet = TRUE;
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return bRet;
+ }
+
+ HANDLE APIENTRY
+ NtUserGetClipboardData(UINT fmt, PGETCLIPBDATA pgcd)
+ {
+ HANDLE hRet = NULL;
+ PCLIP pElement;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+
+ TRACE("NtUserGetClipboardData(%x, %p)\n", fmt, pgcd);
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ if (!IntIsClipboardOpenByMe(pWinStaObj))
+ {
+ EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+ goto cleanup;
+ }
+
+ pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+ if (pElement && IS_DATA_DELAYED(pElement) && pWinStaObj->spwndClipOwner)
+ {
+ /* Send WM_RENDERFORMAT message */
+ pWinStaObj->fInDelayedRendering = TRUE;
+ co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_RENDERFORMAT, (WPARAM)fmt, 0);
+ pWinStaObj->fInDelayedRendering = FALSE;
+
+ /* Data should be in clipboard now */
+ pElement = IntIsFormatAvailable(pWinStaObj, fmt);
+ }
+
+ if (!pElement || IS_DATA_DELAYED(pElement))
+ goto cleanup;
+
+
+ if (IS_DATA_SYNTHESIZED(pElement))
+ {
+ /* Note: Data is synthesized in usermode */
+ /* TODO: Add more formats */
+ switch (fmt)
+ {
+ case CF_UNICODETEXT:
+ case CF_TEXT:
+ case CF_OEMTEXT:
+ pElement = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT);
+ if (IS_DATA_SYNTHESIZED(pElement))
+ pElement = IntIsFormatAvailable(pWinStaObj, CF_TEXT);
+ if (IS_DATA_SYNTHESIZED(pElement))
+ pElement = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT);
+ break;
+ case CF_BITMAP:
+ IntSynthesizeBitmap(pWinStaObj, pElement);
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(pgcd, sizeof(*pgcd), 1);
+ pgcd->uFmtRet = pElement->fmt;
+ pgcd->fGlobalHandle = pElement->fGlobalHandle;
+
+ /* Text and bitmap needs more data */
+ if (fmt == CF_TEXT)
+ {
+ PCLIP pLocaleEl;
+
+ pLocaleEl = IntIsFormatAvailable(pWinStaObj, CF_LOCALE);
+ if (pLocaleEl && !IS_DATA_DELAYED(pLocaleEl))
+ pgcd->hLocale = pLocaleEl->hData;
+ }
+ else if (fmt == CF_BITMAP)
+ {
+ PCLIP pPaletteEl;
+
+ pPaletteEl = IntIsFormatAvailable(pWinStaObj, CF_PALETTE);
+ if (pPaletteEl && !IS_DATA_DELAYED(pPaletteEl))
+ pgcd->hPalette = pPaletteEl->hData;
+ }
+
+ hRet = pElement->hData;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ cleanup:
+ if(pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
+
+ UserLeave();
+
+ TRACE("NtUserGetClipboardData returns %p\n", hRet);
+
+ return hRet;
+ }
+
+ HANDLE NTAPI
+ UserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA scd)
+ {
+ HANDLE hRet = NULL;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ /* If it's delayed rendering we don't have to open clipboard */
+ if ((pWinStaObj->fInDelayedRendering &&
+ pWinStaObj->spwndClipOwner->head.pti != PsGetCurrentThreadWin32Thread()) ||
+ !IntIsClipboardOpenByMe(pWinStaObj))
+ {
+ ERR("Access denied!\n");
+ EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
+ goto cleanup;
+ }
+
+ if (scd->fIncSerialNumber)
+ pWinStaObj->iClipSerialNumber++;
+
+ /* Is it a delayed render? */
+ if (hData)
+ {
+ /* Is it a bitmap? */
+ if (fmt == CF_BITMAP)
+ {
+ /* Make bitmap public */
+ GreSetObjectOwner(hData, GDI_OBJ_HMGR_PUBLIC);
+ }
+
+ /* Save data in the clipboard */
+ IntAddFormatedData(pWinStaObj, fmt, hData, scd->fGlobalHandle, FALSE);
+ TRACE("hData stored\n");
+
+ pWinStaObj->iClipSequenceNumber++;
+ pWinStaObj->fClipboardChanged = TRUE;
+
+ /* Note: Synthesized formats are added in NtUserCloseClipboard */
+ }
+ else
+ {
+ /* This is a delayed render */
+ IntAddFormatedData(pWinStaObj, fmt, DATA_DELAYED, FALSE, FALSE);
+ TRACE("SetClipboardData delayed format: %u\n", fmt);
+ }
+
+ /* Return hData on success */
+ hRet = hData;
+
+ cleanup:
+ TRACE("NtUserSetClipboardData returns: %p\n", hRet);
+
+ if(pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
+
+ return hRet;
+ }
+
+ HANDLE APIENTRY
+ NtUserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA pUnsafeScd)
+ {
+ SETCLIPBDATA scd;
+ HANDLE hRet;
+
+ TRACE("NtUserSetClipboardData(%x %p %p)\n", fmt, hData, pUnsafeScd);
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pUnsafeScd, sizeof(*pUnsafeScd), 1);
+ RtlCopyMemory(&scd, pUnsafeScd, sizeof(scd));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(return NULL;)
+ }
+ _SEH2_END
+
+ UserEnterExclusive();
+
+ /* Call internal function */
+ hRet = UserSetClipboardData(fmt, hData, &scd);
+
+ UserLeave();
+
+ return hRet;
+ }
+
+ HWND APIENTRY
+ NtUserSetClipboardViewer(HWND hWndNewViewer)
+ {
+ HWND hWndNext = NULL;
+ PWINSTATION_OBJECT pWinStaObj = NULL;
+ PWND pWindow;
+
+ UserEnterExclusive();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ pWindow = UserGetWindowObject(hWndNewViewer);
+ if (!pWindow)
+ {
+ EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ goto cleanup;
+ }
+
+ /* Return previous viewer. New viever window should
+ send messages to rest of the chain */
+ if (pWinStaObj->spwndClipViewer)
+ hWndNext = pWinStaObj->spwndClipViewer->head.h;
+
+ /* Set new viewer window */
+ pWinStaObj->spwndClipViewer = pWindow;
+
+ cleanup:
+ if(pWinStaObj)
+ ObDereferenceObject(pWinStaObj);
+
+ UserLeave();
+
+ return hWndNext;
+ }
+
+ // Sequence number is incremented whenever the contents of the clipboard change
+ // or the clipboard is emptied. If clipboard rendering is delayed,
+ // the sequence number is not incremented until the changes are rendered.
+
+ DWORD APIENTRY
+ NtUserGetClipboardSequenceNumber(VOID)
+ {
+ DWORD dwRet = 0;
+ PWINSTATION_OBJECT pWinStaObj;
+
+ UserEnterShared();
+
+ pWinStaObj = IntGetWinStaForCbAccess();
+ if (!pWinStaObj)
+ goto cleanup;
+
+ /* Get windowstation sequence number */
+ dwRet = (DWORD)pWinStaObj->iClipSequenceNumber;
+
+ ObDereferenceObject(pWinStaObj);
+
+ cleanup:
+ UserLeave();
+
+ return dwRet;
+ }
+
+ HANDLE APIENTRY
+ NtUserConvertMemHandle(
+ PVOID pData,
+ DWORD cbData)
+ {
+ HANDLE hMem = NULL;
+ PCLIPBOARDDATA pMemObj;
+
+ UserEnterExclusive();
+
+ /* Create Clipboard data object */
+ pMemObj = UserCreateObject(gHandleTable, NULL, NULL, &hMem, otClipBoardData, sizeof(CLIPBOARDDATA) + cbData);
+ if (!pMemObj)
+ goto cleanup;
+
+ pMemObj->cbData = cbData;
+
+ /* Copy data */
+ _SEH2_TRY
+ {
+ ProbeForRead(pData, cbData, 1);
+ memcpy(pMemObj->Data, pData, cbData);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ pMemObj = NULL;
+ }
+ _SEH2_END;
+
++ /* Release the extra reference (UserCreateObject added 2 references) */
++ UserDereferenceObject(pMemObj);
++
+ /* If we failed to copy data, remove handle */
+ if (!pMemObj)
+ {
+ UserDeleteObject(hMem, otClipBoardData);
+ hMem = NULL;
+ }
+
+ cleanup:
+ UserLeave();
+
+ return hMem;
+ }
+
+ NTSTATUS APIENTRY
+ NtUserCreateLocalMemHandle(
+ HANDLE hMem,
+ PVOID pData,
+ DWORD cbData,
+ DWORD *pcbData)
+ {
+ PCLIPBOARDDATA pMemObj;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UserEnterShared();
+
+ /* Get Clipboard data object */
+ pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, hMem, otClipBoardData);
+ if (!pMemObj)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ goto cleanup;
+ }
+
+ /* Don't overrun */
+ if (cbData > pMemObj->cbData)
+ cbData = pMemObj->cbData;
+
+ /* Copy data to usermode */
+ _SEH2_TRY
+ {
+ if (pcbData)
+ {
+ ProbeForWrite(pcbData, sizeof(*pcbData), 1);
+ *pcbData = pMemObj->cbData;
+ }
+
+ ProbeForWrite(pData, cbData, 1);
+ memcpy(pData, pMemObj->Data, cbData);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ cleanup:
+ UserLeave();
+
+ return Status;
+ }
+
+ /* EOF */
--- /dev/null
- IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, BOOL ProcessCleanup)
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Cursor and icon functions
+ * FILE: subsystems/win32/win32k/ntuser/cursoricon.c
+ * PROGRAMER: ReactOS Team
+ */
+ /*
+ * We handle two types of cursors/icons:
+ * - Private
+ * Loaded without LR_SHARED flag
+ * Private to a process
+ * Can be deleted by calling NtDestroyCursorIcon()
+ * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc set to NULL
+ * - Shared
+ * Loaded with LR_SHARED flag
+ * Possibly shared by multiple processes
+ * Immune to NtDestroyCursorIcon()
+ * CurIcon->hModule, CurIcon->hRsrc and CurIcon->hGroupRsrc are valid
+ * There's a M:N relationship between processes and (shared) cursor/icons.
+ * A process can have multiple cursor/icons and a cursor/icon can be used
+ * by multiple processes. To keep track of this we keep a list of all
+ * cursor/icons (CurIconList) and per cursor/icon we keep a list of
+ * CURICON_PROCESS structs starting at CurIcon->ProcessList.
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserIcon);
+
+ static PPAGED_LOOKASIDE_LIST pgProcessLookasideList;
+ static LIST_ENTRY gCurIconList;
+
+ SYSTEM_CURSORINFO gSysCursorInfo;
+
+ BOOL
+ InitCursorImpl()
+ {
+ pgProcessLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
+ if(!pgProcessLookasideList)
+ return FALSE;
+
+ ExInitializePagedLookasideList(pgProcessLookasideList,
+ NULL,
+ NULL,
+ 0,
+ sizeof(CURICON_PROCESS),
+ TAG_DIB,
+ 128);
+ InitializeListHead(&gCurIconList);
+
+ gSysCursorInfo.Enabled = FALSE;
+ gSysCursorInfo.ButtonsDown = 0;
+ gSysCursorInfo.bClipped = FALSE;
+ gSysCursorInfo.LastBtnDown = 0;
+ gSysCursorInfo.CurrentCursorObject = NULL;
+ gSysCursorInfo.ShowingCursor = -1;
+ gSysCursorInfo.ClickLockActive = FALSE;
+ gSysCursorInfo.ClickLockTime = 0;
+
+ return TRUE;
+ }
+
+ PSYSTEM_CURSORINFO
+ IntGetSysCursorInfo()
+ {
+ return &gSysCursorInfo;
+ }
+
+ /* This function creates a reference for the object! */
+ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon)
+ {
+ PCURICON_OBJECT CurIcon;
+
+ if (!hCurIcon)
+ {
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
+ CurIcon = (PCURICON_OBJECT)UserReferenceObjectByHandle(hCurIcon, otCursorIcon);
+ if (!CurIcon)
+ {
+ /* We never set ERROR_INVALID_ICON_HANDLE. lets hope noone ever checks for it */
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ return NULL;
+ }
+
+ ASSERT(CurIcon->head.cLockObj >= 1);
+ return CurIcon;
+ }
+
+ BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
+ {
+ PWND DesktopWindow;
+ PSYSTEM_CURSORINFO CurInfo;
+ MSG Msg;
+ RECTL rcClip;
+ POINT pt;
+
+ if(!(DesktopWindow = UserGetDesktopWindow()))
+ {
+ return FALSE;
+ }
+
+ CurInfo = IntGetSysCursorInfo();
+
+ /* Clip cursor position */
+ if (!CurInfo->bClipped)
+ rcClip = DesktopWindow->rcClient;
+ else
+ rcClip = CurInfo->rcClip;
+
+ if(x >= rcClip.right) x = rcClip.right - 1;
+ if(x < rcClip.left) x = rcClip.left;
+ if(y >= rcClip.bottom) y = rcClip.bottom - 1;
+ if(y < rcClip.top) y = rcClip.top;
+
+ pt.x = x;
+ pt.y = y;
+
+ /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */
+ Msg.message = WM_MOUSEMOVE;
+ Msg.wParam = UserGetMouseButtonsState();
+ Msg.lParam = MAKELPARAM(x, y);
+ Msg.pt = pt;
+ co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook);
+
+ /* 2. Store the new cursor position */
+ gpsi->ptCursor = pt;
+
+ return TRUE;
+ }
+
+ /*
+ * We have to register that this object is in use by the current
+ * process. The only way to do that seems to be to walk the list
+ * of cursor/icon objects starting at W32Process->CursorIconListHead.
+ * If the object is already present in the list, we don't have to do
+ * anything, if it's not present we add it and inc the ProcessCount
+ * in the object. Having to walk the list kind of sucks, but that's
+ * life...
+ */
+ static BOOLEAN FASTCALL
+ ReferenceCurIconByProcess(PCURICON_OBJECT CurIcon)
+ {
+ PPROCESSINFO Win32Process;
+ PCURICON_PROCESS Current;
+
+ Win32Process = PsGetCurrentProcessWin32Process();
+
+ LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
+ {
+ if (Current->Process == Win32Process)
+ {
+ /* Already registered for this process */
+ return TRUE;
+ }
+ }
+
+ /* Not registered yet */
+ Current = ExAllocateFromPagedLookasideList(pgProcessLookasideList);
+ if (NULL == Current)
+ {
+ return FALSE;
+ }
+ InsertHeadList(&CurIcon->ProcessList, &Current->ListEntry);
+ Current->Process = Win32Process;
+
+ return TRUE;
+ }
+
+ PCURICON_OBJECT FASTCALL
+ IntFindExistingCurIconObject(HMODULE hModule,
+ HRSRC hRsrc, LONG cx, LONG cy)
+ {
+ PCURICON_OBJECT CurIcon;
+
+ LIST_FOR_EACH(CurIcon, &gCurIconList, CURICON_OBJECT, ListEntry)
+ {
+
+ // if (NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon))) // <- huh????
+ // UserReferenceObject( CurIcon);
+ // {
+ if ((CurIcon->hModule == hModule) && (CurIcon->hRsrc == hRsrc))
+ {
+ if (cx && ((cx != CurIcon->Size.cx) || (cy != CurIcon->Size.cy)))
+ {
+ // UserDereferenceObject(CurIcon);
+ continue;
+ }
+ if (! ReferenceCurIconByProcess(CurIcon))
+ {
+ return NULL;
+ }
+
+ return CurIcon;
+ }
+ // }
+ // UserDereferenceObject(CurIcon);
+
+ }
+
+ return NULL;
+ }
+
+ PCURICON_OBJECT
+ IntCreateCurIconHandle()
+ {
+ PCURICON_OBJECT CurIcon;
+ HANDLE hCurIcon;
+
+ CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, otCursorIcon, sizeof(CURICON_OBJECT));
+
+ if (!CurIcon)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ CurIcon->Self = hCurIcon;
+ InitializeListHead(&CurIcon->ProcessList);
+
+ if (! ReferenceCurIconByProcess(CurIcon))
+ {
+ ERR("Failed to add process\n");
+ UserDeleteObject(hCurIcon, otCursorIcon);
+ UserDereferenceObject(CurIcon);
+ return NULL;
+ }
+
+ InsertHeadList(&gCurIconList, &CurIcon->ListEntry);
+
+ return CurIcon;
+ }
+
+ BOOLEAN FASTCALL
- BOOLEAN Ret;
++ IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi)
+ {
+ PSYSTEM_CURSORINFO CurInfo;
+ HBITMAP bmpMask, bmpColor;
- PPROCESSINFO W32Process = PsGetCurrentProcessWin32Process();
-
- /* Private objects can only be destroyed by their own process */
- if (NULL == CurIcon->hModule)
- {
- ASSERT(CurIcon->ProcessList.Flink->Flink == &CurIcon->ProcessList);
- Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
- if (Current->Process != W32Process)
- {
- ERR("Trying to destroy private icon/cursor of another process\n");
- return FALSE;
- }
- }
- else if (! ProcessCleanup)
- {
- TRACE("Trying to destroy shared icon/cursor\n");
- return FALSE;
- }
++ BOOLEAN Ret, bListEmpty, bFound = FALSE;
+ PCURICON_PROCESS Current = NULL;
- if (Current->Process == W32Process)
++
++ /* For handles created without any data (error handling) */
++ if(IsListEmpty(&CurIcon->ProcessList))
++ goto emptyList;
+
+ /* Now find this process in the list of processes referencing this object and
+ remove it from that list */
+ LIST_FOR_EACH(Current, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
+ {
- RemoveEntryList(&Current->ListEntry);
++ if (Current->Process == ppi)
+ {
- if (! IsListEmpty(&CurIcon->ProcessList))
++ bFound = TRUE;
++ bListEmpty = RemoveEntryList(&Current->ListEntry);
+ break;
+ }
+ }
++
++ if(!bFound)
++ {
++ /* This object doesn't belong to this process */
++ EngSetLastError(ERROR_INVALID_HANDLE);
++ return FALSE;
++ }
+
+ ExFreeToPagedLookasideList(pgProcessLookasideList, Current);
+
+ /* If there are still processes referencing this object we can't destroy it yet */
-
- if (! ProcessCleanup)
- {
- RemoveEntryList(&CurIcon->ListEntry);
- }
++ if (!bListEmpty)
+ {
++ if(CurIcon->head.ppi == ppi)
++ {
++ /* Set the first process of the list as owner */
++ Current = CONTAINING_RECORD(CurIcon->ProcessList.Flink, CURICON_PROCESS, ListEntry);
++ UserSetObjectOwner(CurIcon, otCursorIcon, Current->Process);
++ }
++ UserDereferenceObject(CurIcon);
+ return TRUE;
+ }
+
- PCURICON_PROCESS ProcessData;
++ emptyList:
++ /* Remove it from the list */
++ RemoveEntryList(&CurIcon->ListEntry);
+
+ CurInfo = IntGetSysCursorInfo();
+
+ if (CurInfo->CurrentCursorObject == CurIcon)
+ {
+ /* Hide the cursor if we're destroying the current cursor */
+ UserSetCursor(NULL, TRUE);
+ }
+
+ bmpMask = CurIcon->IconInfo.hbmMask;
+ bmpColor = CurIcon->IconInfo.hbmColor;
+
+ /* Delete bitmaps */
+ if (bmpMask)
+ {
+ GreSetObjectOwner(bmpMask, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpMask);
+ CurIcon->IconInfo.hbmMask = NULL;
+ }
+ if (bmpColor)
+ {
+ GreSetObjectOwner(bmpColor, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(bmpColor);
+ CurIcon->IconInfo.hbmColor = NULL;
+ }
+
+ /* We were given a pointer, no need to keep the reference anylonger! */
+ UserDereferenceObject(CurIcon);
+ Ret = UserDeleteObject(CurIcon->Self, otCursorIcon);
+
+ return Ret;
+ }
+
+ VOID FASTCALL
+ IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
+ {
+ PCURICON_OBJECT CurIcon, tmp;
- // if(NT_SUCCESS(UserReferenceObjectByPointer(Object, otCursorIcon)))
- {
- LIST_FOR_EACH(ProcessData, &CurIcon->ProcessList, CURICON_PROCESS, ListEntry)
- {
- if (Win32Process == ProcessData->Process)
- {
- RemoveEntryList(&CurIcon->ListEntry);
- IntDestroyCurIconObject(CurIcon, TRUE);
- CurIcon = NULL;
- break;
- }
- }
-
- // UserDereferenceObject(Object);
- }
-
- if (CurIcon)
- {
- UserDereferenceObject(CurIcon);
- }
+
++ /* Run through the list of icon objects */
+ LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
+ {
+ UserReferenceObject(CurIcon);
-
++ IntDestroyCurIconObject(CurIcon, Win32Process);
+ }
- ret = IntDestroyCurIconObject(CurIcon, FALSE);
+ }
+
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserGetIconInfo(
+ HANDLE hCurIcon,
+ PICONINFO IconInfo,
+ PUNICODE_STRING lpInstName, // Optional
+ PUNICODE_STRING lpResName, // Optional
+ LPDWORD pbpp, // Optional
+ BOOL bInternal)
+ {
+ ICONINFO ii;
+ PCURICON_OBJECT CurIcon;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Ret = FALSE;
+ DWORD colorBpp = 0;
+
+ TRACE("Enter NtUserGetIconInfo\n");
+ UserEnterExclusive();
+
+ if (!IconInfo)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto leave;
+ }
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ goto leave;
+ }
+
+ RtlCopyMemory(&ii, &CurIcon->IconInfo, sizeof(ICONINFO));
+
+ /* Copy bitmaps */
+ ii.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
+ ii.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
+
+ if (pbpp)
+ {
+ PSURFACE psurfBmp;
+
+ psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor);
+ if (psurfBmp)
+ {
+ colorBpp = BitsPerFormat(psurfBmp->SurfObj.iBitmapFormat);
+ SURFACE_ShareUnlockSurface(psurfBmp);
+ }
+ }
+
+ /* Copy fields */
+ _SEH2_TRY
+ {
+ ProbeForWrite(IconInfo, sizeof(ICONINFO), 1);
+ RtlCopyMemory(IconInfo, &ii, sizeof(ICONINFO));
+
+ if (pbpp)
+ {
+ ProbeForWrite(pbpp, sizeof(DWORD), 1);
+ *pbpp = colorBpp;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (NT_SUCCESS(Status))
+ Ret = TRUE;
+ else
+ SetLastNtError(Status);
+
+ UserDereferenceObject(CurIcon);
+
+ leave:
+ TRACE("Leave NtUserGetIconInfo, ret=%i\n", Ret);
+ UserLeave();
+
+ return Ret;
+ }
+
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserGetIconSize(
+ HANDLE hCurIcon,
+ UINT istepIfAniCur,
+ PLONG plcx, // &size.cx
+ PLONG plcy) // &size.cy
+ {
+ PCURICON_OBJECT CurIcon;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL bRet = FALSE;
+
+ TRACE("Enter NtUserGetIconSize\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ goto cleanup;
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(plcx, sizeof(LONG), 1);
+ RtlCopyMemory(plcx, &CurIcon->Size.cx, sizeof(LONG));
+ ProbeForWrite(plcy, sizeof(LONG), 1);
+ RtlCopyMemory(plcy, &CurIcon->Size.cy, sizeof(LONG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (NT_SUCCESS(Status))
+ bRet = TRUE;
+ else
+ SetLastNtError(Status); // Maybe not, test this
+
+ UserDereferenceObject(CurIcon);
+
+ cleanup:
+ TRACE("Leave NtUserGetIconSize, ret=%i\n", bRet);
+ UserLeave();
+ return bRet;
+ }
+
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserGetCursorInfo(
+ PCURSORINFO pci)
+ {
+ CURSORINFO SafeCi;
+ PSYSTEM_CURSORINFO CurInfo;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCURICON_OBJECT CurIcon;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserGetCursorInfo\n");
+ UserEnterExclusive();
+
+ CurInfo = IntGetSysCursorInfo();
+ CurIcon = (PCURICON_OBJECT)CurInfo->CurrentCursorObject;
+
+ SafeCi.cbSize = sizeof(CURSORINFO);
+ SafeCi.flags = ((CurIcon && CurInfo->ShowingCursor >= 0) ? CURSOR_SHOWING : 0);
+ SafeCi.hCursor = (CurIcon ? (HCURSOR)CurIcon->Self : (HCURSOR)0);
+
+ SafeCi.ptScreenPos = gpsi->ptCursor;
+
+ _SEH2_TRY
+ {
+ if (pci->cbSize == sizeof(CURSORINFO))
+ {
+ ProbeForWrite(pci, sizeof(CURSORINFO), 1);
+ RtlCopyMemory(pci, &SafeCi, sizeof(CURSORINFO));
+ Ret = TRUE;
+ }
+ else
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ }
+
+ RETURN(Ret);
+
+ CLEANUP:
+ TRACE("Leave NtUserGetCursorInfo, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ BOOL
+ APIENTRY
+ UserClipCursor(
+ RECTL *prcl)
+ {
+ /* FIXME: Check if process has WINSTA_WRITEATTRIBUTES */
+ PSYSTEM_CURSORINFO CurInfo;
+ PWND DesktopWindow = NULL;
+
+ CurInfo = IntGetSysCursorInfo();
+
+ DesktopWindow = UserGetDesktopWindow();
+
+ if (prcl != NULL && DesktopWindow != NULL)
+ {
+ if (prcl->right < prcl->left || prcl->bottom < prcl->top)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ CurInfo->bClipped = TRUE;
+
+ /* Set nw cliping region. Note: we can't use RECTL_bIntersectRect because
+ it sets rect to 0 0 0 0 when it's empty. For more info see monitor winetest */
+ CurInfo->rcClip.left = max(prcl->left, DesktopWindow->rcWindow.left);
+ CurInfo->rcClip.right = min(prcl->right, DesktopWindow->rcWindow.right);
+ if (CurInfo->rcClip.right < CurInfo->rcClip.left)
+ CurInfo->rcClip.right = CurInfo->rcClip.left;
+
+ CurInfo->rcClip.top = max(prcl->top, DesktopWindow->rcWindow.top);
+ CurInfo->rcClip.bottom = min(prcl->bottom, DesktopWindow->rcWindow.bottom);
+ if (CurInfo->rcClip.bottom < CurInfo->rcClip.top)
+ CurInfo->rcClip.bottom = CurInfo->rcClip.top;
+
+ /* Make sure cursor is in clipping region */
+ UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, 0, 0, FALSE);
+ }
+ else
+ {
+ CurInfo->bClipped = FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserClipCursor(
+ RECTL *prcl)
+ {
+ RECTL rclLocal;
+ BOOL bResult;
+
+ if (prcl)
+ {
+ _SEH2_TRY
+ {
+ /* Probe and copy rect */
+ ProbeForRead(prcl, sizeof(RECTL), 1);
+ rclLocal = *prcl;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ _SEH2_YIELD(return FALSE;)
+ }
+ _SEH2_END
+
+ prcl = &rclLocal;
+ }
+
+ UserEnterExclusive();
+
+ /* Call the internal function */
+ bResult = UserClipCursor(prcl);
+
+ UserLeave();
+
+ return bResult;
+ }
+
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserDestroyCursor(
+ HANDLE hCurIcon,
+ DWORD Unknown)
+ {
+ PCURICON_OBJECT CurIcon;
+ BOOL ret;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserDestroyCursorIcon\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ RETURN(FALSE);
+ }
+
++ ret = IntDestroyCurIconObject(CurIcon, PsGetCurrentProcessWin32Process());
+ /* Note: IntDestroyCurIconObject will remove our reference for us! */
+
+ RETURN(ret);
+
+ CLEANUP:
+ TRACE("Leave NtUserDestroyCursorIcon, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+
+ /*
+ * @implemented
+ */
+ HICON
+ APIENTRY
+ NtUserFindExistingCursorIcon(
+ HMODULE hModule,
+ HRSRC hRsrc,
+ LONG cx,
+ LONG cy)
+ {
+ PCURICON_OBJECT CurIcon;
+ HANDLE Ret = (HANDLE)0;
+ DECLARE_RETURN(HICON);
+
+ TRACE("Enter NtUserFindExistingCursorIcon\n");
+ UserEnterExclusive();
+
+ CurIcon = IntFindExistingCurIconObject(hModule, hRsrc, cx, cy);
+ if (CurIcon)
+ {
+ Ret = CurIcon->Self;
+
+ // IntReleaseCurIconObject(CurIcon); // FIXME: Is this correct? Does IntFindExistingCurIconObject add a ref?
+ RETURN(Ret);
+ }
+
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ RETURN((HANDLE)0);
+
+ CLEANUP:
+ TRACE("Leave NtUserFindExistingCursorIcon, ret=%p\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserGetClipCursor(
+ RECTL *lpRect)
+ {
+ /* FIXME: Check if process has WINSTA_READATTRIBUTES */
+ PSYSTEM_CURSORINFO CurInfo;
+ RECTL Rect;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserGetClipCursor\n");
+ UserEnterExclusive();
+
+ if (!lpRect)
+ RETURN(FALSE);
+
+ CurInfo = IntGetSysCursorInfo();
+ if (CurInfo->bClipped)
+ {
+ Rect = CurInfo->rcClip;
+ }
+ else
+ {
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = UserGetSystemMetrics(SM_CXSCREEN);
+ Rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
+ }
+
+ Status = MmCopyToCaller(lpRect, &Rect, sizeof(RECT));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(FALSE);
+ }
+
+ RETURN(TRUE);
+
+ CLEANUP:
+ TRACE("Leave NtUserGetClipCursor, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+
+ /*
+ * @implemented
+ */
+ HCURSOR
+ APIENTRY
+ NtUserSetCursor(
+ HCURSOR hCursor)
+ {
+ PCURICON_OBJECT pcurOld, pcurNew;
+ HCURSOR hOldCursor = NULL;
+
+ TRACE("Enter NtUserSetCursor\n");
+ UserEnterExclusive();
+
+ if (hCursor)
+ {
+ pcurNew = UserGetCurIconObject(hCursor);
+ if (!pcurNew)
+ {
+ EngSetLastError(ERROR_INVALID_CURSOR_HANDLE);
+ goto leave;
+ }
+ }
+ else
+ {
+ pcurNew = NULL;
+ }
+
+ pcurOld = UserSetCursor(pcurNew, FALSE);
+ if (pcurOld)
+ {
+ hOldCursor = (HCURSOR)pcurOld->Self;
+ UserDereferenceObject(pcurOld);
+ }
+
+ leave:
+ UserLeave();
+ return hOldCursor;
+ }
+
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserSetCursorContents(
+ HANDLE hCurIcon,
+ PICONINFO UnsafeIconInfo)
+ {
+ PCURICON_OBJECT CurIcon;
+ ICONINFO IconInfo;
+ PSURFACE psurfBmp;
+ NTSTATUS Status;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserSetCursorContents\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ RETURN(FALSE);
+ }
+
+ /* Copy fields */
+ Status = MmCopyFromCaller(&IconInfo, UnsafeIconInfo, sizeof(ICONINFO));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ goto done;
+ }
+
+ /* Delete old bitmaps */
+ if ((CurIcon->IconInfo.hbmColor)
+ && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
+ {
+ GreDeleteObject(CurIcon->IconInfo.hbmColor);
+ }
+ if ((CurIcon->IconInfo.hbmMask)
+ && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
+ {
+ GreDeleteObject(CurIcon->IconInfo.hbmMask);
+ }
+
+ /* Copy new IconInfo field */
+ CurIcon->IconInfo = IconInfo;
+
+ if (CurIcon->IconInfo.hbmColor)
+ {
+ psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmColor);
+ if (!psurfBmp)
+ goto done;
+
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
+ SURFACE_ShareUnlockSurface(psurfBmp);
+ GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
+ }
+ else
+ {
+ psurfBmp = SURFACE_ShareLockSurface(CurIcon->IconInfo.hbmMask);
+ if (!psurfBmp)
+ goto done;
+
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy / 2;
+
+ SURFACE_ShareUnlockSurface(psurfBmp);
+ }
+ GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
+
+ Ret = TRUE;
+
+ done:
+
+ if (CurIcon)
+ {
+ UserDereferenceObject(CurIcon);
+ }
+ RETURN(Ret);
+
+ CLEANUP:
+ TRACE("Leave NtUserSetCursorContents, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+
+ /*
+ * @implemented
+ */
+ #if 0
+ BOOL
+ APIENTRY
+ NtUserSetCursorIconData(
+ HANDLE Handle,
+ HMODULE hModule,
+ PUNICODE_STRING pstrResName,
+ PICONINFO pIconInfo)
+ {
+ PCURICON_OBJECT CurIcon;
+ PSURFACE psurfBmp;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserSetCursorIconData\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(Handle)))
+ {
+ RETURN(FALSE);
+ }
+
+ CurIcon->hModule = hModule;
+ CurIcon->hRsrc = NULL; //hRsrc;
+ CurIcon->hGroupRsrc = NULL; //hGroupRsrc;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pIconInfo, sizeof(ICONINFO), 1);
+ RtlCopyMemory(&CurIcon->IconInfo, pIconInfo, sizeof(ICONINFO));
+
+ CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(pIconInfo->hbmMask);
+ CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(pIconInfo->hbmColor);
+
+ if (CurIcon->IconInfo.hbmColor)
+ {
+ if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
+ {
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
+ SURFACE_UnlockSurface(psurfBmp);
+ GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
+ }
+ }
+ if (CurIcon->IconInfo.hbmMask)
+ {
+ if (CurIcon->IconInfo.hbmColor == NULL)
+ {
+ if ((psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
+ {
+ CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
+ CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
+ SURFACE_UnlockSurface(psurfBmp);
+ }
+ }
+ GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ SetLastNtError(Status);
+ else
+ Ret = TRUE;
+
+ UserDereferenceObject(CurIcon);
+ RETURN(Ret);
+
+ CLEANUP:
+ TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+ #else
+ BOOL
+ APIENTRY
+ NtUserSetCursorIconData(
+ HANDLE hCurIcon,
+ PBOOL fIcon,
+ POINT *Hotspot,
+ HMODULE hModule,
+ HRSRC hRsrc,
+ HRSRC hGroupRsrc)
+ {
+ PCURICON_OBJECT CurIcon;
+ NTSTATUS Status;
+ POINT SafeHotspot;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserSetCursorIconData\n");
+ UserEnterExclusive();
+
+ if (!(CurIcon = UserGetCurIconObject(hCurIcon)))
+ {
+ RETURN(FALSE);
+ }
+
+ CurIcon->hModule = hModule;
+ CurIcon->hRsrc = hRsrc;
+ CurIcon->hGroupRsrc = hGroupRsrc;
+
+ /* Copy fields */
+ if (fIcon)
+ {
+ Status = MmCopyFromCaller(&CurIcon->IconInfo.fIcon, fIcon, sizeof(BOOL));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ goto done;
+ }
+ }
+ else
+ {
+ if (!Hotspot)
+ Ret = TRUE;
+ }
+
+ if (Hotspot)
+ {
+ Status = MmCopyFromCaller(&SafeHotspot, Hotspot, sizeof(POINT));
+ if (NT_SUCCESS(Status))
+ {
+ CurIcon->IconInfo.xHotspot = SafeHotspot.x;
+ CurIcon->IconInfo.yHotspot = SafeHotspot.y;
+
+ Ret = TRUE;
+ }
+ else
+ SetLastNtError(Status);
+ }
+
+ if (!fIcon && !Hotspot)
+ {
+ Ret = TRUE;
+ }
+
+ done:
+ if(Ret)
+ {
+ /* This icon is shared now */
+ GreSetObjectOwner(CurIcon->IconInfo.hbmMask, GDI_OBJ_HMGR_PUBLIC);
+ if(CurIcon->IconInfo.hbmColor)
+ {
+ GreSetObjectOwner(CurIcon->IconInfo.hbmColor, GDI_OBJ_HMGR_PUBLIC);
+ }
+ }
+ UserDereferenceObject(CurIcon);
+ RETURN(Ret);
+
+
+ CLEANUP:
+ TRACE("Leave NtUserSetCursorIconData, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+ #endif
+
+ /* Mostly inspired from wine code.
+ * We use low level functions because:
+ * - at this point, the icon bitmap could have a different bit depth than the DC,
+ * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
+ * This happens after a mode setting change.
+ * - it avoids massive GDI objects locking when only the destination surface needs it.
+ * - It makes (small) performance gains.
+ */
+ BOOL
+ UserDrawIconEx(
+ HDC hDc,
+ INT xLeft,
+ INT yTop,
+ PCURICON_OBJECT pIcon,
+ INT cxWidth,
+ INT cyHeight,
+ UINT istepIfAniCur,
+ HBRUSH hbrFlickerFreeDraw,
+ UINT diFlags)
+ {
+ PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen;
+ PDC pdc = NULL;
+ BOOL Ret = FALSE;
+ HBITMAP hbmMask, hbmColor;
+ BOOL bOffScreen, bAlpha = FALSE;
+ RECTL rcDest, rcSrc;
+ CLIPOBJ* pdcClipObj = NULL;
+ EXLATEOBJ exlo;
+
+ /* Stupid case */
+ if((diFlags & DI_NORMAL) == 0)
+ {
+ ERR("DrawIconEx called without mask or color bitmap to draw.\n");
+ return FALSE;
+ }
+
+ hbmMask = pIcon->IconInfo.hbmMask;
+ hbmColor = pIcon->IconInfo.hbmColor;
+
+ if (istepIfAniCur)
+ ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
+
+ /*
+ * Get our objects.
+ * Shared locks are enough, we are only reading those bitmaps
+ */
+ psurfMask = SURFACE_ShareLockSurface(hbmMask);
+ if(psurfMask == NULL)
+ {
+ ERR("Unable to lock the mask surface.\n");
+ return FALSE;
+ }
+
+ /* Color bitmap is not mandatory */
+ if(hbmColor == NULL)
+ {
+ /* But then the mask bitmap must have the information in it's bottom half */
+ ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy);
+ psurfColor = NULL;
+ }
+ else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
+ {
+ ERR("Unable to lock the color bitmap.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ return FALSE;
+ }
+
+ /* Set source rect */
+ RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
+
+ /* Check for alpha */
+ if (psurfColor &&
+ (psurfColor->SurfObj.iBitmapFormat == BMF_32BPP) &&
+ (diFlags & DI_IMAGE))
+ {
+ PFN_DIB_GetPixel fnSource_GetPixel = NULL;
+ INT i, j;
+
+ /* In order to correctly display 32 bit icons Windows first scans the image,
+ because information about transparency is not stored in any image's headers */
+ fnSource_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
+ for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++)
+ {
+ for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++)
+ {
+ bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j) >> 24) & 0xff);
+ if (bAlpha)
+ break;
+ }
+ if (bAlpha)
+ break;
+ }
+ }
+
+ /* Fix width parameter, if needed */
+ if (!cxWidth)
+ {
+ if(diFlags & DI_DEFAULTSIZE)
+ cxWidth = pIcon->IconInfo.fIcon ?
+ UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
+ else
+ cxWidth = pIcon->Size.cx;
+ }
+
+ /* Fix height parameter, if needed */
+ if (!cyHeight)
+ {
+ if(diFlags & DI_DEFAULTSIZE)
+ cyHeight = pIcon->IconInfo.fIcon ?
+ UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
+ else
+ cyHeight = pIcon->Size.cy;
+ }
+
+ /* Should we render off-screen? */
+ bOffScreen = hbrFlickerFreeDraw && (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH);
+
+ if (bOffScreen)
+ {
+ /* Yes: Allocate and paint the offscreen surface */
+ EBRUSHOBJ eboFill;
+ PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw);
+
+ TRACE("Performing off-screen rendering.\n");
+
+ if(!pbrush)
+ {
+ ERR("Failed to get brush object.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+
+ psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
+ cxWidth, cyHeight, psurfColor->SurfObj.iBitmapFormat,
+ 0, 0, NULL);
+ if(!psurfOffScreen)
+ {
+ ERR("Failed to allocate the off-screen surface.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ BRUSH_ShareUnlockBrush(pbrush);
+ return FALSE;
+ }
+
+ /* Paint the brush */
+ EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL);
+ RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight);
+
+ Ret = IntEngBitBlt(&psurfOffScreen->SurfObj,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &rcDest,
+ NULL,
+ NULL,
+ &eboFill.BrushObject,
+ &pbrush->ptOrigin,
+ ROP4_PATCOPY);
+
+ /* Clean up everything */
+ EBRUSHOBJ_vCleanup(&eboFill);
+ BRUSH_ShareUnlockBrush(pbrush);
+
+ if(!Ret)
+ {
+ ERR("Failed to paint the off-screen surface.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
+ return FALSE;
+ }
+
+ /* We now have our destination surface */
+ psurfDest = psurfOffScreen;
+ }
+ else
+ {
+ /* We directly draw to the DC */
+ TRACE("Performing on screen rendering.\n");
+
+ psurfOffScreen = NULL;
+ pdc = DC_LockDc(hDc);
+ if(!pdc)
+ {
+ ERR("Could not lock the destination DC.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+ /* Calculate destination rectangle */
+ RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+ IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
+ RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+
+ /* Prepare the underlying surface */
+ DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
+
+ /* Get the clip object */
+ pdcClipObj = pdc->rosdc.CombinedClip;
+
+ /* We now have our destination surface and rectangle */
+ psurfDest = pdc->dclevel.pSurface;
+
+ if(psurfDest == NULL)
+ {
+ /* Empty DC */
+ DC_vFinishBlit(pdc, NULL);
+ DC_UnlockDc(pdc);
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+ }
+
+ /* Now do the rendering */
+ if(bAlpha && (diFlags & DI_IMAGE))
+ {
+ BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
+ BYTE Alpha;
+ INT i, j;
+ PSURFACE psurf = NULL;
+ PBYTE ptr ;
+ HBITMAP hsurfCopy = NULL;
+
+ hsurfCopy = BITMAP_CopyBitmap(hbmColor);
+ if(!hsurfCopy)
+ {
+ ERR("BITMAP_CopyBitmap failed!");
+ goto CleanupAlpha;
+ }
+
+ psurf = SURFACE_ShareLockSurface(hsurfCopy);
+ if(!psurf)
+ {
+ ERR("SURFACE_LockSurface failed!\n");
+ goto CleanupAlpha;
+ }
+
+ /* Premultiply with the alpha channel value */
+ for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
+ {
+ ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
+ for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
+ {
+ Alpha = ptr[3];
+ ptr[0] = (ptr[0] * Alpha) / 0xff;
+ ptr[1] = (ptr[1] * Alpha) / 0xff;
+ ptr[2] = (ptr[2] * Alpha) / 0xff;
+
+ ptr += 4;
+ }
+ }
+
+ /* Initialize color translation object */
+ EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+
+ /* Now do it */
+ Ret = IntEngAlphaBlend(&psurfDest->SurfObj,
+ &psurf->SurfObj,
+ pdcClipObj,
+ &exlo.xlo,
+ &rcDest,
+ &rcSrc,
+ &blendobj);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ CleanupAlpha:
+ if(psurf) SURFACE_ShareUnlockSurface(psurf);
+ if(hsurfCopy) NtGdiDeleteObjectApp(hsurfCopy);
+ if(Ret) goto done;
+ ERR("NtGdiAlphaBlend failed!\n");
+ }
+
+ if (diFlags & DI_MASK)
+ {
+ DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY;
+
+ EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
+
+ Ret = IntEngStretchBlt(&psurfDest->SurfObj,
+ &psurfMask->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ NULL,
+ &rcDest,
+ &rcSrc,
+ NULL,
+ NULL,
+ NULL,
+ rop4);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ if(!Ret)
+ {
+ ERR("Failed to mask the bitmap data.\n");
+ goto Cleanup;
+ }
+ }
+
+ if(diFlags & DI_IMAGE)
+ {
+ if (psurfColor)
+ {
+ DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
+
+ EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
+
+ Ret = IntEngStretchBlt(&psurfDest->SurfObj,
+ &psurfColor->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ NULL,
+ &rcDest,
+ &rcSrc,
+ NULL,
+ NULL,
+ NULL,
+ rop4);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ if(!Ret)
+ {
+ ERR("Failed to render the icon bitmap.\n");
+ goto Cleanup;
+ }
+ }
+ else
+ {
+ /* Mask bitmap holds the information in its bottom half */
+ DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
+ RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy);
+
+ EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
+
+ Ret = IntEngStretchBlt(&psurfDest->SurfObj,
+ &psurfMask->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ NULL,
+ &rcDest,
+ &rcSrc,
+ NULL,
+ NULL,
+ NULL,
+ rop4);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ if(!Ret)
+ {
+ ERR("Failed to render the icon bitmap.\n");
+ goto Cleanup;
+ }
+ }
+ }
+
+ done:
+ /* We're done. Was it a double buffered draw ? */
+ if(bOffScreen)
+ {
+ /* Yes. Draw it back to our DC */
+ POINTL ptSrc = {0, 0};
+ pdc = DC_LockDc(hDc);
+ if(!pdc)
+ {
+ ERR("Could not lock the destination DC.\n");
+ return FALSE;
+ }
+ /* Calculate destination rectangle */
+ RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+ IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
+ RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+
+ /* Prepare the underlying surface */
+ DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
+
+ /* Get the clip object */
+ pdcClipObj = pdc->rosdc.CombinedClip;
+
+ /* We now have our destination surface and rectangle */
+ psurfDest = pdc->dclevel.pSurface;
+ if(!psurfDest)
+ {
+ /* So, you did all of this for an empty DC. */
+ DC_UnlockDc(pdc);
+ goto Cleanup2;
+ }
+
+ /* Color translation */
+ EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal, 0x00FFFFFF, 0x00FFFFFF, 0);
+
+ /* Blt it! */
+ Ret = IntEngBitBlt(&psurfDest->SurfObj,
+ &psurfOffScreen->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ &rcDest,
+ &ptSrc,
+ NULL,
+ NULL,
+ NULL,
+ ROP4_SRCCOPY);
+
+ EXLATEOBJ_vCleanup(&exlo);
+ }
+ Cleanup:
+ if(pdc)
+ {
+ DC_vFinishBlit(pdc, NULL);
+ DC_UnlockDc(pdc);
+ }
+
+ Cleanup2:
+ /* Delete off screen rendering surface */
+ if(psurfOffScreen)
+ GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
+
+ /* Unlock other surfaces */
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+
+ return Ret;
+ }
+
+ /*
+ * @implemented
+ */
+ BOOL
+ APIENTRY
+ NtUserDrawIconEx(
+ HDC hdc,
+ int xLeft,
+ int yTop,
+ HICON hIcon,
+ int cxWidth,
+ int cyHeight,
+ UINT istepIfAniCur,
+ HBRUSH hbrFlickerFreeDraw,
+ UINT diFlags,
+ BOOL bMetaHDC, // When TRUE, GDI functions need to be handled in User32!
+ PVOID pDIXData)
+ {
+ PCURICON_OBJECT pIcon;
+ BOOL Ret;
+
+ TRACE("Enter NtUserDrawIconEx\n");
+ UserEnterExclusive();
+
+ if (!(pIcon = UserGetCurIconObject(hIcon)))
+ {
+ ERR("UserGetCurIconObject() failed!\n");
+ UserLeave();
+ return FALSE;
+ }
+
+ Ret = UserDrawIconEx(hdc,
+ xLeft,
+ yTop,
+ pIcon,
+ cxWidth,
+ cyHeight,
+ istepIfAniCur,
+ hbrFlickerFreeDraw,
+ diFlags);
+
+ UserDereferenceObject(pIcon);
+
+ UserLeave();
+ return Ret;
+ }
+
+ /* EOF */
--- /dev/null
+ #pragma once
+
+ #define MAXCURICONHANDLES 4096
+
+ typedef struct tagCURICON_PROCESS
+ {
+ LIST_ENTRY ListEntry;
+ PPROCESSINFO Process;
+ } CURICON_PROCESS, *PCURICON_PROCESS;
+
++ #ifdef NEW_CURSORICON
++ typedef struct _CURICON_FRAME
++ {
++ HBITMAP hbmMask;
++ HBITMAP hbmColor;
++ HBITMAP hbmAlpha;
++ } CURICON_FRAME, *PCURICON_FRAME;
++
++ typedef struct _CURICON_OBJECT
++ {
++ PROCMARKHEAD head;
++ LIST_ENTRY ListEntry;
++ HANDLE Self;
++ LIST_ENTRY ProcessList;
++ HMODULE hModule;
++ HRSRC hRsrc;
++ SIZE Size;
++ BYTE Shadow;
++ BOOL bIcon;
++ POINTL ptlHotspot;
++ CURICON_FRAME aFrame[1];
++ } CURICON_OBJECT, *PCURICON_OBJECT;
++
++ #else
++
+ typedef struct _CURICON_OBJECT
+ {
+ PROCMARKHEAD head;
+ LIST_ENTRY ListEntry;
+ HANDLE Self;
+ LIST_ENTRY ProcessList;
+ HMODULE hModule;
+ HRSRC hRsrc;
+ HRSRC hGroupRsrc;
+ SIZE Size;
+ BYTE Shadow;
+ ICONINFO IconInfo;
+ } CURICON_OBJECT, *PCURICON_OBJECT;
++ #endif
+
+ typedef struct _CURSORACCELERATION_INFO
+ {
+ UINT FirstThreshold;
+ UINT SecondThreshold;
+ UINT Acceleration;
+ } CURSORACCELERATION_INFO, *PCURSORACCELERATION_INFO;
+
+ typedef struct _SYSTEM_CURSORINFO
+ {
+ BOOL Enabled;
+ BOOL ClickLockActive;
+ DWORD ClickLockTime;
+ // BOOL SwapButtons;
+ UINT ButtonsDown;
+ RECTL rcClip;
+ BOOL bClipped;
+ PCURICON_OBJECT CurrentCursorObject;
+ INT ShowingCursor;
+ /*
+ UINT WheelScroLines;
+ UINT WheelScroChars;
+ UINT DblClickSpeed;
+ UINT DblClickWidth;
+ UINT DblClickHeight;
+
+ UINT MouseHoverTime;
+ UINT MouseHoverWidth;
+ UINT MouseHoverHeight;
+
+ UINT MouseSpeed;
+ CURSORACCELERATION_INFO CursorAccelerationInfo;
+ */
+ DWORD LastBtnDown;
+ LONG LastBtnDownX;
+ LONG LastBtnDownY;
+ HANDLE LastClkWnd;
+ BOOL ScreenSaverRunning;
+ } SYSTEM_CURSORINFO, *PSYSTEM_CURSORINFO;
+
+ BOOL InitCursorImpl(VOID);
+ PCURICON_OBJECT IntCreateCurIconHandle(VOID);
+ VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process);
+
+ BOOL UserDrawIconEx(HDC hDc, INT xLeft, INT yTop, PCURICON_OBJECT pIcon, INT cxWidth,
+ INT cyHeight, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags);
+ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon);
+ BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook);
+ BOOL APIENTRY UserClipCursor(RECTL *prcl);
+ PSYSTEM_CURSORINFO IntGetSysCursorInfo(VOID);
+
+ #define IntReleaseCurIconObject(CurIconObj) \
+ UserDereferenceObject(CurIconObj)
+
+ /* EOF */
--- /dev/null
--- /dev/null
--- /dev/null
- if (Hook->Thread)
- pti = Hook->Thread->Tcb.Win32Thread;
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Window hooks
+ * FILE: subsystems/win32/win32k/ntuser/hook.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * James Tabor (james.tabor@rectos.org)
+ * Rafal Harabien (rafalh@reactos.org)
+ * NOTE: Most of this code was adapted from Wine,
+ * Copyright (C) 2002 Alexandre Julliard
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserHook);
+
+ typedef struct _HOOKPACK
+ {
+ PHOOK pHk;
+ LPARAM lParam;
+ PVOID pHookStructs;
+ } HOOKPACK, *PHOOKPACK;
+
+ UNICODE_STRING strUahModule;
+ UNICODE_STRING strUahInitFunc;
+ PPROCESSINFO ppiUahServer;
+
+ /* PRIVATE FUNCTIONS *********************************************************/
+
+ /* Calls ClientLoadLibrary in user32 in order to load or unload a module */
+ BOOL
+ IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload)
+ {
+ PPROCESSINFO ppi;
+ BOOL bResult;
+
+ ppi = PsGetCurrentProcessWin32Process();
+
+ ERR("IntLoadHookModule. Client PID: %d\n", PsGetProcessId(ppi->peProcess));
+
+ /* Check if this is the api hook */
+ if(iHookID == WH_APIHOOK)
+ {
+ if(!Unload && !(ppi->W32PF_flags & W32PF_APIHOOKLOADED))
+ {
+ /* A callback in user mode can trigger UserLoadApiHook to be called and
+ as a result IntLoadHookModule will be called recursively.
+ To solve this we set the flag that means that the appliaction has
+ loaded the api hook before the callback and in case of error we remove it */
+ ppi->W32PF_flags |= W32PF_APIHOOKLOADED;
+
+ /* Call ClientLoadLibrary in user32 */
+ bResult = co_IntClientLoadLibrary(&strUahModule, &strUahInitFunc, Unload, TRUE);
+ TRACE("co_IntClientLoadLibrary returned %d\n", bResult );
+ if (!bResult)
+ {
+ /* Remove the flag we set before */
+ ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED;
+ }
+ return bResult;
+ }
+ else if(Unload && (ppi->W32PF_flags & W32PF_APIHOOKLOADED))
+ {
+ /* Call ClientLoadLibrary in user32 */
+ bResult = co_IntClientLoadLibrary(NULL, NULL, Unload, TRUE);
+ if (bResult)
+ {
+ ppi->W32PF_flags &= ~W32PF_APIHOOKLOADED;
+ }
+ return bResult;
+ }
+
+ return TRUE;
+ }
+
+ STUB;
+
+ return FALSE;
+ }
+
+ /*
+ IntHookModuleUnloaded:
+ Sends a internal message to all threads of the requested desktop
+ and notifies them that a global hook was destroyed
+ and an injected module must be unloaded.
+ As a result, IntLoadHookModule will be called for all the threads that
+ will receive the special purpose internal message.
+ */
+ BOOL
+ IntHookModuleUnloaded(PDESKTOP pdesk, int iHookID, HHOOK hHook)
+ {
+ PTHREADINFO ptiCurrent;
+ PLIST_ENTRY ListEntry;
+ PPROCESSINFO ppiCsr;
+
+ ERR("IntHookModuleUnloaded: iHookID=%d\n", iHookID);
+
+ ppiCsr = PsGetProcessWin32Process(CsrProcess);
+
+ ListEntry = pdesk->PtiList.Flink;
+ while(ListEntry != &pdesk->PtiList)
+ {
+ ptiCurrent = CONTAINING_RECORD(ListEntry, THREADINFO, PtiLink);
+
+ /* FIXME: Do some more security checks here */
+
+ /* FIXME: The first check is a reactos specific hack for system threads */
+ if(!PsIsSystemProcess(ptiCurrent->ppi->peProcess) &&
+ ptiCurrent->ppi != ppiCsr)
+ {
+ if(ptiCurrent->ppi->W32PF_flags & W32PF_APIHOOKLOADED)
+ {
+ TRACE("IntHookModuleUnloaded: sending message to PID %d, ppi=0x%x\n", PsGetProcessId(ptiCurrent->ppi->peProcess), ptiCurrent->ppi);
+ co_MsqSendMessageAsync( ptiCurrent,
+ 0,
+ iHookID,
+ TRUE,
+ (LPARAM)hHook,
+ NULL,
+ 0,
+ FALSE,
+ MSQ_INJECTMODULE);
+ }
+ }
+ ListEntry = ListEntry->Flink;
+ }
+
+ return TRUE;
+ }
+
+ BOOL
+ FASTCALL
+ UserLoadApiHook(VOID)
+ {
+ return IntLoadHookModule(WH_APIHOOK, 0, FALSE);
+ }
+
+ BOOL
+ FASTCALL
+ UserRegisterUserApiHook(
+ PUNICODE_STRING pstrDllName,
+ PUNICODE_STRING pstrFuncName)
+ {
+ PTHREADINFO pti, ptiCurrent;
+ HWND *List;
+ PWND DesktopWindow, pwndCurrent;
+ ULONG i;
+ PPROCESSINFO ppiCsr;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ ppiCsr = PsGetProcessWin32Process(CsrProcess);
+
+ /* Fail if the api hook is already registered */
+ if(gpsi->dwSRVIFlags & SRVINFO_APIHOOK)
+ {
+ return FALSE;
+ }
+
+ ERR("UserRegisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
+
+ /* Register the api hook */
+ gpsi->dwSRVIFlags |= SRVINFO_APIHOOK;
+
+ strUahModule = *pstrDllName;
+ strUahInitFunc = *pstrFuncName;
+ ppiUahServer = pti->ppi;
+
+ /* Broadcast an internal message to every top level window */
+ DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
+ List = IntWinListChildren(DesktopWindow);
+
+ if (List != NULL)
+ {
+ for (i = 0; List[i]; i++)
+ {
+ pwndCurrent = UserGetWindowObject(List[i]);
+ if(pwndCurrent == NULL)
+ {
+ continue;
+ }
+ ptiCurrent = pwndCurrent->head.pti;
+
+ /* FIXME: The first check is a reactos specific hack for system threads */
+ if(PsIsSystemProcess(ptiCurrent->ppi->peProcess) ||
+ ptiCurrent->ppi == ppiCsr)
+ {
+ continue;
+ }
+
+ co_MsqSendMessageAsync( ptiCurrent,
+ 0,
+ WH_APIHOOK,
+ FALSE, /* Load the module */
+ 0,
+ NULL,
+ 0,
+ FALSE,
+ MSQ_INJECTMODULE);
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+
+ return TRUE;
+ }
+
+ BOOL
+ FASTCALL
+ UserUnregisterUserApiHook(VOID)
+ {
+ PTHREADINFO pti;
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ /* Fail if the api hook is not registered */
+ if(!(gpsi->dwSRVIFlags & SRVINFO_APIHOOK))
+ {
+ return FALSE;
+ }
+
+ /* Only the process that registered the api hook can uregister it */
+ if(ppiUahServer != PsGetCurrentProcessWin32Process())
+ {
+ return FALSE;
+ }
+
+ ERR("UserUnregisterUserApiHook. Server PID: %d\n", PsGetProcessId(pti->ppi->peProcess));
+
+ /* Unregister the api hook */
+ gpsi->dwSRVIFlags &= ~SRVINFO_APIHOOK;
+ ppiUahServer = NULL;
+ ReleaseCapturedUnicodeString(&strUahModule, UserMode);
+ ReleaseCapturedUnicodeString(&strUahInitFunc, UserMode);
+
+ /* Notify all applications that the api hook module must be unloaded */
+ return IntHookModuleUnloaded(pti->rpdesk, WH_APIHOOK, 0);
+ }
+
+ static
+ LRESULT
+ FASTCALL
+ co_IntCallLowLevelHook(PHOOK Hook,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
+ {
+ NTSTATUS Status;
+ PTHREADINFO pti;
+ PHOOKPACK pHP;
+ INT Size = 0;
+ UINT uTimeout = 300;
+ BOOL Block = FALSE;
+ ULONG_PTR uResult = 0;
+
- if (Hook->Thread)
++ if (Hook->ptiHooked)
++ pti = Hook->ptiHooked;
+ else
+ pti = Hook->head.pti;
+
+ pHP = ExAllocatePoolWithTag(NonPagedPool, sizeof(HOOKPACK), TAG_HOOK);
+ if (!pHP) return 0;
+
+ pHP->pHk = Hook;
+ pHP->lParam = lParam;
+ pHP->pHookStructs = NULL;
+
+ // This prevents stack corruption from the caller.
+ switch(Hook->HookId)
+ {
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ uTimeout = 0;
+ Size = sizeof(EVENTMSG);
+ break;
+ case WH_KEYBOARD_LL:
+ Size = sizeof(KBDLLHOOKSTRUCT);
+ break;
+ case WH_MOUSE_LL:
+ Size = sizeof(MSLLHOOKSTRUCT);
+ break;
+ case WH_MOUSE:
+ uTimeout = 200;
+ Block = TRUE;
+ Size = sizeof(MOUSEHOOKSTRUCT);
+ break;
+ case WH_KEYBOARD:
+ uTimeout = 200;
+ Block = TRUE;
+ break;
+ }
+
+ if (Size)
+ {
+ pHP->pHookStructs = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK);
+ if (pHP->pHookStructs) RtlCopyMemory(pHP->pHookStructs, (PVOID)lParam, Size);
+ }
+
+ /* FIXME: Should get timeout from
+ * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
+ Status = co_MsqSendMessage( pti->MessageQueue,
+ IntToPtr(Code), // hWnd
+ Hook->HookId, // Msg
+ wParam,
+ (LPARAM)pHP,
+ uTimeout,
+ Block,
+ MSQ_ISHOOK,
+ &uResult);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook->HookId, Status);
+ if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK);
+ ExFreePoolWithTag(pHP, TAG_HOOK);
+ }
+ return NT_SUCCESS(Status) ? uResult : 0;
+ }
+
+
+ //
+ // Dispatch MsgQueue Hook Call processor!
+ //
+ LRESULT
+ FASTCALL
+ co_CallHook( INT HookId,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
+ {
+ LRESULT Result;
+ PHOOK phk;
+ PHOOKPACK pHP = (PHOOKPACK)lParam;
+
+ phk = pHP->pHk;
+ lParam = pHP->lParam;
+
+ switch(HookId)
+ {
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ case WH_KEYBOARD:
+ case WH_KEYBOARD_LL:
+ case WH_MOUSE_LL:
+ case WH_MOUSE:
+ lParam = (LPARAM)pHP->pHookStructs;
+ break;
+ }
+
+ /* The odds are high for this to be a Global call. */
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ phk->Proc,
+ phk->Ansi,
+ &phk->ModuleName);
+
+ /* The odds so high, no one is waiting for the results. */
+ if (pHP->pHookStructs) ExFreePoolWithTag(pHP->pHookStructs, TAG_HOOK);
+ ExFreePoolWithTag(pHP, TAG_HOOK);
+ return Result;
+ }
+
+ static
+ LRESULT
+ FASTCALL
+ co_HOOK_CallHookNext( PHOOK Hook,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
+ {
+ TRACE("Calling Next HOOK %d\n", Hook->HookId);
+
+ return co_IntCallHookProc( Hook->HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+
+ static
+ LRESULT
+ FASTCALL
+ co_IntCallDebugHook(PHOOK Hook,
+ int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi)
+ {
+ LRESULT lResult = 0;
+ ULONG Size;
+ DEBUGHOOKINFO Debug;
+ PVOID HooklParam = NULL;
+ BOOL BadChk = FALSE;
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(DEBUGHOOKINFO),
+ 1);
+
+ RtlCopyMemory(&Debug,
+ (PVOID)lParam,
+ sizeof(DEBUGHOOKINFO));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_DEBUG read from lParam ERROR!\n");
+ return lResult;
+ }
+ }
+ else
+ return lResult; /* Need lParam! */
+
+ switch (wParam)
+ {
+ case WH_CBT:
+ {
+ switch (Debug.code)
+ {
+ case HCBT_CLICKSKIPPED:
+ Size = sizeof(MOUSEHOOKSTRUCTEX);
+ break;
+
+ case HCBT_MOVESIZE:
+ Size = sizeof(RECT);
+ break;
+
+ case HCBT_ACTIVATE:
+ Size = sizeof(CBTACTIVATESTRUCT);
+ break;
+
+ case HCBT_CREATEWND: /* Handle ANSI? */
+ Size = sizeof(CBT_CREATEWND);
+ /* What shall we do? Size += sizeof(HOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS); same as CREATESTRUCTEX */
+ break;
+
+ default:
+ Size = sizeof(LPARAM);
+ }
+ }
+ break;
+
+ case WH_MOUSE_LL:
+ Size = sizeof(MSLLHOOKSTRUCT);
+ break;
+
+ case WH_KEYBOARD_LL:
+ Size = sizeof(KBDLLHOOKSTRUCT);
+ break;
+
+ case WH_MSGFILTER:
+ case WH_SYSMSGFILTER:
+ case WH_GETMESSAGE:
+ Size = sizeof(MSG);
+ break;
+
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ Size = sizeof(EVENTMSG);
+ break;
+
+ case WH_FOREGROUNDIDLE:
+ case WH_KEYBOARD:
+ case WH_SHELL:
+ default:
+ Size = sizeof(LPARAM);
+ }
+
+ if (Size > sizeof(LPARAM))
+ HooklParam = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HOOK);
+
+ if (HooklParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)Debug.lParam,
+ Size,
+ 1);
+
+ RtlCopyMemory(HooklParam,
+ (PVOID)Debug.lParam,
+ Size);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_DEBUG read from Debug.lParam ERROR!\n");
+ ExFreePoolWithTag(HooklParam, TAG_HOOK);
+ return lResult;
+ }
+ }
+
+ if (HooklParam) Debug.lParam = (LPARAM)HooklParam;
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Debug);
+ if (HooklParam) ExFreePoolWithTag(HooklParam, TAG_HOOK);
+
+ return lResult;
+ }
+
+ static
+ LRESULT
+ FASTCALL
+ co_UserCallNextHookEx(PHOOK Hook,
+ int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi)
+ {
+ LRESULT lResult = 0;
+ BOOL BadChk = FALSE;
+
+ /* Handle this one first. */
+ if ((Hook->HookId == WH_MOUSE) ||
+ (Hook->HookId == WH_CBT && Code == HCBT_CLICKSKIPPED))
+ {
+ MOUSEHOOKSTRUCTEX Mouse;
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(MOUSEHOOKSTRUCTEX),
+ 1);
+
+ RtlCopyMemory(&Mouse,
+ (PVOID)lParam,
+ sizeof(MOUSEHOOKSTRUCTEX));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_MOUSE read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse);
+ }
+
+ return lResult;
+ }
+
+ switch(Hook->HookId)
+ {
+ case WH_MOUSE_LL:
+ {
+ MSLLHOOKSTRUCT Mouse;
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(MSLLHOOKSTRUCT),
+ 1);
+
+ RtlCopyMemory(&Mouse,
+ (PVOID)lParam,
+ sizeof(MSLLHOOKSTRUCT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_MOUSE_LL read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Mouse);
+ }
+ break;
+ }
+
+ case WH_KEYBOARD_LL:
+ {
+ KBDLLHOOKSTRUCT Keyboard;
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(KBDLLHOOKSTRUCT),
+ 1);
+
+ RtlCopyMemory(&Keyboard,
+ (PVOID)lParam,
+ sizeof(KBDLLHOOKSTRUCT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_KEYBORD_LL read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Keyboard);
+ }
+ break;
+ }
+
+ case WH_MSGFILTER:
+ case WH_SYSMSGFILTER:
+ case WH_GETMESSAGE:
+ {
+ MSG Msg;
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(MSG),
+ 1);
+
+ RtlCopyMemory(&Msg,
+ (PVOID)lParam,
+ sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_XMESSAGEX read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&Msg);
+
+ if (lParam && (Hook->HookId == WH_GETMESSAGE))
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)lParam,
+ sizeof(MSG),
+ 1);
+
+ RtlCopyMemory((PVOID)lParam,
+ &Msg,
+ sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_GETMESSAGE write to lParam ERROR!\n");
+ }
+ }
+ }
+ break;
+ }
+
+ case WH_CBT:
+ TRACE("HOOK WH_CBT!\n");
+ switch (Code)
+ {
+ case HCBT_CREATEWND:
+ {
+ LPCBT_CREATEWNDW pcbtcww = (LPCBT_CREATEWNDW)lParam;
+
+ TRACE("HOOK HCBT_CREATEWND\n");
+ _SEH2_TRY
+ {
+ if (Ansi)
+ {
+ ProbeForRead( pcbtcww,
+ sizeof(CBT_CREATEWNDA),
+ 1);
+ ProbeForWrite(pcbtcww->lpcs,
+ sizeof(CREATESTRUCTA),
+ 1);
+ ProbeForRead( pcbtcww->lpcs->lpszName,
+ sizeof(CHAR),
+ 1);
+
+ if (!IS_ATOM(pcbtcww->lpcs->lpszClass))
+ {
+ ProbeForRead( pcbtcww->lpcs->lpszClass,
+ sizeof(CHAR),
+ 1);
+ }
+ }
+ else
+ {
+ ProbeForRead( pcbtcww,
+ sizeof(CBT_CREATEWNDW),
+ 1);
+ ProbeForWrite(pcbtcww->lpcs,
+ sizeof(CREATESTRUCTW),
+ 1);
+ ProbeForRead( pcbtcww->lpcs->lpszName,
+ sizeof(WCHAR),
+ 1);
+
+ if (!IS_ATOM(pcbtcww->lpcs->lpszClass))
+ {
+ ProbeForRead( pcbtcww->lpcs->lpszClass,
+ sizeof(WCHAR),
+ 1);
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK HCBT_CREATEWND write ERROR!\n");
+ }
+ /* The next call handles the structures. */
+ if (!BadChk && Hook->Proc)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
+ }
+ break;
+ }
+
+ case HCBT_MOVESIZE:
+ {
+ RECTL rt;
+
+ TRACE("HOOK HCBT_MOVESIZE\n");
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(RECT),
+ 1);
+
+ RtlCopyMemory(&rt,
+ (PVOID)lParam,
+ sizeof(RECT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK HCBT_MOVESIZE read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&rt);
+ }
+ break;
+ }
+
+ case HCBT_ACTIVATE:
+ {
+ CBTACTIVATESTRUCT CbAs;
+
+ TRACE("HOOK HCBT_ACTIVATE\n");
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(CBTACTIVATESTRUCT),
+ 1);
+
+ RtlCopyMemory(&CbAs,
+ (PVOID)lParam,
+ sizeof(CBTACTIVATESTRUCT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK HCBT_ACTIVATE read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)&CbAs);
+ }
+ break;
+ }
+
+ /* The rest just use default. */
+ default:
+ TRACE("HOOK HCBT_ %d\n",Code);
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
+ break;
+ }
+ break;
+ /*
+ Note WH_JOURNALPLAYBACK,
+ "To have the system wait before processing the message, the return value
+ must be the amount of time, in clock ticks, that the system should wait."
+ */
+ case WH_JOURNALPLAYBACK:
+ case WH_JOURNALRECORD:
+ {
+ EVENTMSG EventMsg;
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lParam,
+ sizeof(EVENTMSG),
+ 1);
+
+ RtlCopyMemory(&EventMsg,
+ (PVOID)lParam,
+ sizeof(EVENTMSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_JOURNAL read from lParam ERROR!\n");
+ }
+ }
+
+ if (!BadChk)
+ {
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, (LPARAM)(lParam ? &EventMsg : NULL));
+
+ if (lParam)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)lParam,
+ sizeof(EVENTMSG),
+ 1);
+
+ RtlCopyMemory((PVOID)lParam,
+ &EventMsg,
+ sizeof(EVENTMSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+
+ if (BadChk)
+ {
+ ERR("HOOK WH_JOURNAL write to lParam ERROR!\n");
+ }
+ }
+ }
+ break;
+ }
+
+ case WH_DEBUG:
+ lResult = co_IntCallDebugHook(Hook, Code, wParam, lParam, Ansi);
+ break;
+
+ /*
+ * Default the rest like, WH_FOREGROUNDIDLE, WH_KEYBOARD and WH_SHELL.
+ */
+ case WH_FOREGROUNDIDLE:
+ case WH_KEYBOARD:
+ case WH_SHELL:
+ lResult = co_HOOK_CallHookNext(Hook, Code, wParam, lParam);
+ break;
+
+ default:
+ ERR("Unsupported HOOK Id -> %d\n",Hook->HookId);
+ break;
+ }
+ return lResult;
+ }
+
+ PHOOK
+ FASTCALL
+ IntGetHookObject(HHOOK hHook)
+ {
+ PHOOK Hook;
+
+ if (!hHook)
+ {
+ EngSetLastError(ERROR_INVALID_HOOK_HANDLE);
+ return NULL;
+ }
+
+ Hook = (PHOOK)UserGetObject(gHandleTable, hHook, otHook);
+ if (!Hook)
+ {
+ EngSetLastError(ERROR_INVALID_HOOK_HANDLE);
+ return NULL;
+ }
+
+ UserReferenceObject(Hook);
+
+ return Hook;
+ }
+
+ static
+ HHOOK*
+ FASTCALL
+ IntGetGlobalHookHandles(PDESKTOP pdo, int HookId)
+ {
+ PLIST_ENTRY pLastHead, pElem;
+ unsigned i = 0;
+ unsigned cHooks = 0;
+ HHOOK *pList;
+ PHOOK pHook;
+
+ pLastHead = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
+ for (pElem = pLastHead->Flink; pElem != pLastHead; pElem = pElem->Flink)
+ ++cHooks;
+
+ pList = ExAllocatePoolWithTag(PagedPool, (cHooks + 1) * sizeof(HHOOK), TAG_HOOK);
+ if(!pList)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ for (pElem = pLastHead->Flink; pElem != pLastHead; pElem = pElem->Flink)
+ {
+ pHook = CONTAINING_RECORD(pElem, HOOK, Chain);
+ pList[i++] = pHook->head.h;
+ }
+ pList[i] = NULL;
+
+ return pList;
+ }
+
+ /* Find the next hook in the chain */
+ PHOOK
+ FASTCALL
+ IntGetNextHook(PHOOK Hook)
+ {
+ int HookId = Hook->HookId;
+ PLIST_ENTRY pLastHead, pElem;
+ PTHREADINFO pti;
+
- pti = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
++ if (Hook->ptiHooked)
+ {
- if (Hook->Thread) // Local
++ pti = Hook->ptiHooked;
+ pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+ }
+ else
+ {
+ pti = PsGetCurrentThreadWin32Thread();
+ pLastHead = &pti->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
+ }
+
+ pElem = Hook->Chain.Flink;
+ if (pElem != pLastHead)
+ return CONTAINING_RECORD(pElem, HOOK, Chain);
+ return NULL;
+ }
+
+ /* Free a hook, removing it from its chain */
+ static
+ VOID
+ FASTCALL
+ IntFreeHook(PHOOK Hook)
+ {
+ RemoveEntryList(&Hook->Chain);
+ if (Hook->ModuleName.Buffer)
+ {
+ ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK);
+ Hook->ModuleName.Buffer = NULL;
+ }
+ /* Close handle */
+ UserDeleteObject(UserHMGetHandle(Hook), otHook);
+ }
+
+ /* Remove a hook, freeing it from the chain */
+ static
+ VOID
+ FASTCALL
+ IntRemoveHook(PHOOK Hook)
+ {
+ INT HookId;
+ PTHREADINFO pti;
+ PDESKTOP pdo;
+
+ HookId = Hook->HookId;
+
- pti = ((PTHREADINFO)Hook->Thread->Tcb.Win32Thread);
++ if (Hook->ptiHooked) // Local
+ {
- ObDereferenceObject(Thread);
-
++ pti = Hook->ptiHooked;
+
+ IntFreeHook( Hook);
+
+ if ( IsListEmpty(&pti->aphkStart[HOOKID_TO_INDEX(HookId)]) )
+ {
+ pti->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+ _SEH2_TRY
+ {
+ pti->pClientInfo->fsHooks = pti->fsHooks;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+ }
+ }
+ else // Global
+ {
+ IntFreeHook( Hook);
+
+ pdo = IntGetActiveDesktop();
+
+ if ( pdo &&
+ pdo->pDeskInfo &&
+ IsListEmpty(&pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)]) )
+ {
+ pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
+ }
+ }
+ }
+
+ VOID
+ FASTCALL
+ HOOK_DestroyThreadHooks(PETHREAD Thread)
+ {
+ PTHREADINFO pti;
+ PDESKTOP pdo;
+ int HookId;
+ PHOOK HookObj;
+ PLIST_ENTRY pElem;
+
+ pti = Thread->Tcb.Win32Thread;
+ pdo = IntGetActiveDesktop();
+
+ if (!pti || !pdo)
+ {
+ ERR("Kill Thread Hooks pti 0x%x pdo 0x%x\n",pti,pdo);
+ return;
+ }
+
+ // Local Thread cleanup.
+ if (pti->fsHooks)
+ {
+ for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
+ {
+ PLIST_ENTRY pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+
+ pElem = pLastHead->Flink;
+ while (pElem != pLastHead)
+ {
+ HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
+ pElem = HookObj->Chain.Flink; // get next element before hook is destroyed
+ IntRemoveHook(HookObj);
+ }
+ }
+ pti->fsHooks = 0;
+ pti->pClientInfo->fsHooks = 0;
+ }
+ // Global search based on Thread and cleanup.
+ if (pdo->pDeskInfo->fsHooks)
+ {
+ for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
+ {
+ PLIST_ENTRY pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
+
+ pElem = pGLE->Flink;
+ while (pElem != pGLE)
+ {
+ HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
+ pElem = HookObj->Chain.Flink; // Get next element before hook is destroyed
+ if (HookObj->head.pti == pti)
+ {
+ IntRemoveHook(HookObj);
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ /*
+ Win32k Kernel Space Hook Caller.
+ */
+ LRESULT
+ FASTCALL
+ co_HOOK_CallHooks( INT HookId,
+ INT Code,
+ WPARAM wParam,
+ LPARAM lParam)
+ {
+ PHOOK Hook, SaveHook;
+ PTHREADINFO pti;
+ PCLIENTINFO ClientInfo;
+ PLIST_ENTRY pLastHead;
+ PDESKTOP pdo;
+ BOOL Local = FALSE, Global = FALSE;
+ LRESULT Result = 0;
+ USER_REFERENCE_ENTRY Ref;
+
+ ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
+
+ pti = PsGetCurrentThreadWin32Thread();
+ if (!pti || !pti->rpdesk || !pti->rpdesk->pDeskInfo)
+ {
+ pdo = IntGetActiveDesktop();
+ /* If KeyboardThread|MouseThread|(RawInputThread or RIT) aka system threads,
+ pti->fsHooks most likely, is zero. So process KbT & MsT to "send" the message.
+ */
+ if ( !pti || !pdo || (!(HookId == WH_KEYBOARD_LL) && !(HookId == WH_MOUSE_LL)) )
+ {
+ TRACE("No PDO %d\n", HookId);
+ goto Exit;
+ }
+ }
+ else
+ {
+ pdo = pti->rpdesk;
+ }
+
+ if ( pti->TIF_flags & (TIF_INCLEANUP|TIF_DISABLEHOOKS))
+ {
+ TRACE("Hook Thread dead %d\n", HookId);
+ goto Exit;
+ }
+
+ if ( ISITHOOKED(HookId) )
+ {
+ TRACE("Local Hooker %d\n", HookId);
+ Local = TRUE;
+ }
+
+ if ( pdo->pDeskInfo->fsHooks & HOOKID_TO_FLAG(HookId) )
+ {
+ TRACE("Global Hooker %d\n", HookId);
+ Global = TRUE;
+ }
+
+ if ( !Local && !Global ) goto Exit; // No work!
+
+ Hook = NULL;
+
+ /* SetWindowHookEx sorts out the Thread issue by placing the Hook to
+ the correct Thread if not NULL.
+ */
+ if ( Local )
+ {
+ pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+ if (IsListEmpty(pLastHead))
+ {
+ ERR("No Local Hook Found!\n");
+ goto Exit;
+ }
+
+ Hook = CONTAINING_RECORD(pLastHead->Flink, HOOK, Chain);
+ UserRefObjectCo(Hook, &Ref);
+
+ ClientInfo = pti->pClientInfo;
+ SaveHook = pti->sphkCurrent;
+ /* Note: Setting pti->sphkCurrent will also lock the next hook to this
+ * hook ID. So, the CallNextHookEx will only call to that hook ID
+ * chain anyway. For Thread Hooks....
+ */
+
+ /* Load it for the next call. */
+ pti->sphkCurrent = Hook;
+ Hook->phkNext = IntGetNextHook(Hook);
+ if (ClientInfo)
+ {
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = Hook;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ClientInfo = NULL; // Don't bother next run.
+ }
+ _SEH2_END;
+ }
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ if (ClientInfo)
+ {
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = SaveHook;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
+ }
+ pti->sphkCurrent = SaveHook;
+ Hook->phkNext = NULL;
+ UserDerefObjectCo(Hook);
+ }
+
+ if ( Global )
+ {
+ PTHREADINFO ptiHook;
+ HHOOK *pHookHandles;
+ unsigned i;
+
+ /* Keep hooks in array because hooks can be destroyed in user world */
+ pHookHandles = IntGetGlobalHookHandles(pdo, HookId);
+ if(!pHookHandles)
+ goto Exit;
+
+ /* Performance goes down the drain. If more hooks are associated to this
+ * hook ID, this will have to post to each of the thread message queues
+ * or make a direct call.
+ */
+ for(i = 0; pHookHandles[i]; ++i)
+ {
+ Hook = (PHOOK)UserGetObject(gHandleTable, pHookHandles[i], otHook);
+ if(!Hook)
+ {
+ ERR("Invalid hook!\n");
+ continue;
+ }
+ UserRefObjectCo(Hook, &Ref);
+
+ /* Hook->Thread is null, we hax around this with Hook->head.pti. */
+ ptiHook = Hook->head.pti;
+
+ if ( (pti->TIF_flags & TIF_DISABLEHOOKS) || (ptiHook->TIF_flags & TIF_INCLEANUP))
+ {
+ TRACE("Next Hook 0x%x, 0x%x\n",ptiHook->rpdesk,pdo);
+ continue;
+ }
+
+ if (ptiHook != pti )
+ {
+ // Block | TimeOut
+ if ( HookId == WH_JOURNALPLAYBACK || // 1 | 0
+ HookId == WH_JOURNALRECORD || // 1 | 0
+ HookId == WH_KEYBOARD || // 1 | 200
+ HookId == WH_MOUSE || // 1 | 200
+ HookId == WH_KEYBOARD_LL || // 0 | 300
+ HookId == WH_MOUSE_LL ) // 0 | 300
+ {
+ TRACE("\nGlobal Hook posting to another Thread! %d\n",HookId );
+ Result = co_IntCallLowLevelHook(Hook, Code, wParam, lParam);
+ }
+ }
+ else
+ { /* Make the direct call. */
+ TRACE("Local Hook calling to Thread! %d\n",HookId );
+ Result = co_IntCallHookProc( HookId,
+ Code,
+ wParam,
+ lParam,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+ UserDerefObjectCo(Hook);
+ }
+ ExFreePoolWithTag(pHookHandles, TAG_HOOK);
+ TRACE("Ret: Global HookId %d Result 0x%x\n", HookId,Result);
+ }
+ Exit:
+ return Result;
+ }
+
+ BOOL
+ FASTCALL
+ IntUnhookWindowsHook(int HookId, HOOKPROC pfnFilterProc)
+ {
+ PHOOK Hook;
+ PLIST_ENTRY pLastHead, pElement;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId )
+ {
+ EngSetLastError(ERROR_INVALID_HOOK_FILTER);
+ return FALSE;
+ }
+
+ if (pti->fsHooks)
+ {
+ pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
+
+ pElement = pLastHead->Flink;
+ while (pElement != pLastHead)
+ {
+ Hook = CONTAINING_RECORD(pElement, HOOK, Chain);
+
+ if (Hook->Proc == pfnFilterProc)
+ {
+ if (Hook->head.pti == pti)
+ {
+ IntRemoveHook(Hook);
+ UserDereferenceObject(Hook);
+ return TRUE;
+ }
+ else
+ {
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+ }
+
+ pElement = Hook->Chain.Flink;
+ }
+ }
+ return FALSE;
+ }
+
+ /*
+ * Support for compatibility only? Global hooks are processed in kernel space.
+ * This is very thread specific! Never seeing applications with more than one
+ * hook per thread installed. Most of the applications are Global hookers and
+ * associated with just one hook Id. Maybe it's for diagnostic testing or a
+ * throw back to 3.11?
+ */
+ LRESULT
+ APIENTRY
+ NtUserCallNextHookEx( int Code,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL Ansi)
+ {
+ PTHREADINFO pti;
+ PHOOK HookObj, NextObj;
+ PCLIENTINFO ClientInfo;
+ LRESULT lResult = 0;
+ DECLARE_RETURN(LRESULT);
+
+ TRACE("Enter NtUserCallNextHookEx\n");
+ UserEnterExclusive();
+
+ pti = GetW32ThreadInfo();
+
+ HookObj = pti->sphkCurrent;
+
+ if (!HookObj) RETURN( 0);
+
+ NextObj = HookObj->phkNext;
+
+ pti->sphkCurrent = NextObj;
+ ClientInfo = pti->pClientInfo;
+ _SEH2_TRY
+ {
+ ClientInfo->phkCurrent = NextObj;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ClientInfo = NULL;
+ }
+ _SEH2_END;
+
+ /* Now in List run down. */
+ if (ClientInfo && NextObj)
+ {
+ NextObj->phkNext = IntGetNextHook(NextObj);
+ lResult = co_UserCallNextHookEx( NextObj, Code, wParam, lParam, NextObj->Ansi);
+ }
+ RETURN( lResult);
+
+ CLEANUP:
+ TRACE("Leave NtUserCallNextHookEx, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ HHOOK
+ APIENTRY
+ NtUserSetWindowsHookAW( int idHook,
+ HOOKPROC lpfn,
+ BOOL Ansi)
+ {
+ DWORD ThreadId;
+ UNICODE_STRING USModuleName;
+
+ RtlInitUnicodeString(&USModuleName, NULL);
+ ThreadId = PtrToUint(NtCurrentTeb()->ClientId.UniqueThread);
+
+ return NtUserSetWindowsHookEx( NULL,
+ &USModuleName,
+ ThreadId,
+ idHook,
+ lpfn,
+ Ansi);
+ }
+
+ HHOOK
+ APIENTRY
+ NtUserSetWindowsHookEx( HINSTANCE Mod,
+ PUNICODE_STRING UnsafeModuleName,
+ DWORD ThreadId,
+ int HookId,
+ HOOKPROC HookProc,
+ BOOL Ansi)
+ {
+ PWINSTATION_OBJECT WinStaObj;
+ PHOOK Hook;
+ UNICODE_STRING ModuleName;
+ NTSTATUS Status;
+ HHOOK Handle;
+ PETHREAD Thread = NULL;
+ PTHREADINFO pti, ptiHook = NULL;
+ DECLARE_RETURN(HHOOK);
+
+ TRACE("Enter NtUserSetWindowsHookEx\n");
+ UserEnterExclusive();
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if (HookId < WH_MINHOOK || WH_MAXHOOK < HookId )
+ {
+ EngSetLastError(ERROR_INVALID_HOOK_FILTER);
+ RETURN( NULL);
+ }
+
+ if (!HookProc)
+ {
+ EngSetLastError(ERROR_INVALID_FILTER_PROC);
+ RETURN( NULL);
+ }
+
+ if (ThreadId) /* thread-local hook */
+ {
+ if ( HookId == WH_JOURNALRECORD ||
+ HookId == WH_JOURNALPLAYBACK ||
+ HookId == WH_KEYBOARD_LL ||
+ HookId == WH_MOUSE_LL ||
+ HookId == WH_SYSMSGFILTER)
+ {
+ ERR("Local hook installing Global HookId: %d\n",HookId);
+ /* these can only be global */
+ EngSetLastError(ERROR_GLOBAL_ONLY_HOOK);
+ RETURN( NULL);
+ }
+
+ if (!NT_SUCCESS(PsLookupThreadByThreadId((HANDLE)(DWORD_PTR) ThreadId, &Thread)))
+ {
+ ERR("Invalid thread id 0x%x\n", ThreadId);
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN( NULL);
+ }
+
+ ptiHook = Thread->Tcb.Win32Thread;
+
- Hook->Thread = Thread; /* Set Thread, Null is Global. */
+ if ( ptiHook->rpdesk != pti->rpdesk) // gptiCurrent->rpdesk)
+ {
+ ERR("Local hook wrong desktop HookId: %d\n",HookId);
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ RETURN( NULL);
+ }
+
+ if (Thread->ThreadsProcess != PsGetCurrentProcess())
+ {
+ if ( !Mod &&
+ (HookId == WH_GETMESSAGE ||
+ HookId == WH_CALLWNDPROC ||
+ HookId == WH_CBT ||
+ HookId == WH_HARDWARE ||
+ HookId == WH_DEBUG ||
+ HookId == WH_SHELL ||
+ HookId == WH_FOREGROUNDIDLE ||
+ HookId == WH_CALLWNDPROCRET) )
+ {
+ ERR("Local hook needs hMod HookId: %d\n",HookId);
+ EngSetLastError(ERROR_HOOK_NEEDS_HMOD);
+ RETURN( NULL);
+ }
+
+ if ( (ptiHook->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD)) &&
+ (HookId == WH_GETMESSAGE ||
+ HookId == WH_CALLWNDPROC ||
+ HookId == WH_CBT ||
+ HookId == WH_HARDWARE ||
+ HookId == WH_DEBUG ||
+ HookId == WH_SHELL ||
+ HookId == WH_FOREGROUNDIDLE ||
+ HookId == WH_CALLWNDPROCRET) )
+ {
+ EngSetLastError(ERROR_HOOK_TYPE_NOT_ALLOWED);
+ RETURN( NULL);
+ }
+ }
+ }
+ else /* System-global hook */
+ {
+ ptiHook = pti; // gptiCurrent;
+ if ( !Mod &&
+ (HookId == WH_GETMESSAGE ||
+ HookId == WH_CALLWNDPROC ||
+ HookId == WH_CBT ||
+ HookId == WH_SYSMSGFILTER ||
+ HookId == WH_HARDWARE ||
+ HookId == WH_DEBUG ||
+ HookId == WH_SHELL ||
+ HookId == WH_FOREGROUNDIDLE ||
+ HookId == WH_CALLWNDPROCRET) )
+ {
+ ERR("Global hook needs hMod HookId: %d\n",HookId);
+ EngSetLastError(ERROR_HOOK_NEEDS_HMOD);
+ RETURN( NULL);
+ }
+ }
+
+ Status = IntValidateWindowStationHandle( PsGetCurrentProcess()->Win32WindowStation,
+ KernelMode,
+ 0,
+ &WinStaObj);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+ ObDereferenceObject(WinStaObj);
+
+ Hook = UserCreateObject(gHandleTable, NULL, NULL, (PHANDLE)&Handle, otHook, sizeof(HOOK));
+
+ if (!Hook)
+ {
+ RETURN( NULL);
+ }
+
+ Hook->ihmod = (INT)Mod; // Module Index from atom table, Do this for now.
+ Hook->HookId = HookId;
+ Hook->rpdesk = ptiHook->rpdesk;
+ Hook->phkNext = NULL; /* Dont use as a chain! Use link lists for chaining. */
+ Hook->Proc = HookProc;
+ Hook->Ansi = Ansi;
+
+ TRACE("Set Hook Desk 0x%x DeskInfo 0x%x Handle Desk 0x%x\n",pti->rpdesk, pti->pDeskInfo,Hook->head.rpdesk);
+
+ if (ThreadId) /* Thread-local hook */
+ {
+ InsertHeadList(&ptiHook->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
+ ptiHook->sphkCurrent = NULL;
+ Hook->ptiHooked = ptiHook;
+ ptiHook->fsHooks |= HOOKID_TO_FLAG(HookId);
+
+ if (ptiHook->pClientInfo)
+ {
+ if ( ptiHook->ppi == pti->ppi) /* gptiCurrent->ppi) */
+ {
+ _SEH2_TRY
+ {
+ ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks;
+ ptiHook->pClientInfo->phkCurrent = NULL;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ERR("Problem writing to Local ClientInfo!\n");
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ KeAttachProcess(&ptiHook->ppi->peProcess->Pcb);
+ _SEH2_TRY
+ {
+ ptiHook->pClientInfo->fsHooks = ptiHook->fsHooks;
+ ptiHook->pClientInfo->phkCurrent = NULL;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ERR("Problem writing to Remote ClientInfo!\n");
+ }
+ _SEH2_END;
+ KeDetachProcess();
+ }
+ }
+ }
+ else
+ {
+ InsertHeadList(&ptiHook->rpdesk->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)], &Hook->Chain);
+ Hook->ptiHooked = NULL;
+ //gptiCurrent->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
+ ptiHook->rpdesk->pDeskInfo->fsHooks |= HOOKID_TO_FLAG(HookId);
+ ptiHook->sphkCurrent = NULL;
+ ptiHook->pClientInfo->phkCurrent = NULL;
+ }
+
+ RtlInitUnicodeString(&Hook->ModuleName, NULL);
+
+ if (Mod)
+ {
+ Status = MmCopyFromCaller(&ModuleName,
+ UnsafeModuleName,
+ sizeof(UNICODE_STRING));
+ if (!NT_SUCCESS(Status))
+ {
+ IntRemoveHook(Hook);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ Hook->ModuleName.Buffer = ExAllocatePoolWithTag( PagedPool,
+ ModuleName.MaximumLength,
+ TAG_HOOK);
+ if (NULL == Hook->ModuleName.Buffer)
+ {
+ IntRemoveHook(Hook);
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ RETURN( NULL);
+ }
+
+ Hook->ModuleName.MaximumLength = ModuleName.MaximumLength;
+ Status = MmCopyFromCaller( Hook->ModuleName.Buffer,
+ ModuleName.Buffer,
+ ModuleName.MaximumLength);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Hook->ModuleName.Buffer, TAG_HOOK);
+ Hook->ModuleName.Buffer = NULL;
+ IntRemoveHook(Hook);
+ SetLastNtError(Status);
+ RETURN( NULL);
+ }
+
+ Hook->ModuleName.Length = ModuleName.Length;
+ /* Make proc relative to the module base */
+ Hook->offPfn = (ULONG_PTR)((char *)HookProc - (char *)Mod);
+ }
+ else
+ Hook->offPfn = 0;
+
+ TRACE("Installing: HookId %d Global %s\n", HookId, !ThreadId ? "TRUE" : "FALSE");
+ RETURN( Handle);
+
+ CLEANUP:
+ TRACE("Leave NtUserSetWindowsHookEx, ret=%i\n",_ret_);
++ if (Thread) ObDereferenceObject(Thread);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ BOOL
+ APIENTRY
+ NtUserUnhookWindowsHookEx(HHOOK Hook)
+ {
+ PHOOK HookObj;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserUnhookWindowsHookEx\n");
+ UserEnterExclusive();
+
+ if (!(HookObj = IntGetHookObject(Hook)))
+ {
+ ERR("Invalid handle passed to NtUserUnhookWindowsHookEx\n");
+ /* SetLastNtError(Status); */
+ RETURN( FALSE);
+ }
+
+ ASSERT(Hook == UserHMGetHandle(HookObj));
+
+ IntRemoveHook(HookObj);
+
+ UserDereferenceObject(HookObj);
+
+ RETURN( TRUE);
+
+ CLEANUP:
+ TRACE("Leave NtUserUnhookWindowsHookEx, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ BOOL
+ APIENTRY
+ NtUserRegisterUserApiHook(
+ PUNICODE_STRING m_dllname1,
+ PUNICODE_STRING m_funname1,
+ DWORD dwUnknown3,
+ DWORD dwUnknown4)
+ {
+ BOOL ret;
+ UNICODE_STRING strDllNameSafe;
+ UNICODE_STRING strFuncNameSafe;
+ NTSTATUS Status;
+
+ /* Probe and capture parameters */
+ Status = ProbeAndCaptureUnicodeString(&strDllNameSafe, UserMode, m_dllname1);
+ if(!NT_SUCCESS(Status))
+ {
+ EngSetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ Status = ProbeAndCaptureUnicodeString(&strFuncNameSafe, UserMode, m_funname1);
+ if(!NT_SUCCESS(Status))
+ {
+ ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode);
+ EngSetLastError(RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+
+ UserEnterExclusive();
+
+ /* Call internal function */
+ ret = UserRegisterUserApiHook(&strDllNameSafe, &strFuncNameSafe);
+
+ UserLeave();
+
+ /* Cleanup only in case of failure */
+ if(ret == FALSE)
+ {
+ ReleaseCapturedUnicodeString(&strDllNameSafe, UserMode);
+ ReleaseCapturedUnicodeString(&strFuncNameSafe, UserMode);
+ }
+
+ return ret;
+ }
+
+ BOOL
+ APIENTRY
+ NtUserUnregisterUserApiHook(VOID)
+ {
+ BOOL ret;
+
+ UserEnterExclusive();
+ ret = UserUnregisterUserApiHook();
+ UserLeave();
+
+ return ret;
+ }
+
+ /* EOF */
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Message queues
+ * FILE: subsystems/win32/win32k/ntuser/msgqueue.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ Alexandre Julliard
+ Maarten Lankhorst
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserMsgQ);
+
+ /* GLOBALS *******************************************************************/
+
+ static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
+ PUSER_MESSAGE_QUEUE gpqCursor;
+
+ /* FUNCTIONS *****************************************************************/
+
+ INIT_FUNCTION
+ NTSTATUS
+ NTAPI
+ MsqInitializeImpl(VOID)
+ {
+ pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
+ if(!pgMessageLookasideList)
+ return STATUS_NO_MEMORY;
+ ExInitializePagedLookasideList(pgMessageLookasideList,
+ NULL,
+ NULL,
+ 0,
+ sizeof(USER_MESSAGE),
+ TAG_USRMSG,
+ 256);
+
+ return(STATUS_SUCCESS);
+ }
+
+ PWND FASTCALL
+ IntChildrenWindowFromPoint(PWND pWndTop, INT x, INT y)
+ {
+ PWND pWnd, pWndChild;
+
+ if ( !pWndTop )
+ {
+ pWndTop = UserGetDesktopWindow();
+ if ( !pWndTop ) return NULL;
+ }
+
+ if (!(pWndTop->style & WS_VISIBLE)) return NULL;
+ if ((pWndTop->style & WS_DISABLED)) return NULL;
+ if (!IntPtInWindow(pWndTop, x, y)) return NULL;
+
+ if (RECTL_bPointInRect(&pWndTop->rcClient, x, y))
+ {
+ for (pWnd = pWndTop->spwndChild;
+ pWnd != NULL;
+ pWnd = pWnd->spwndNext)
+ {
+ if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED )
+ {
+ TRACE("The Window is in DESTROY!\n");
+ continue;
+ }
+
+ pWndChild = IntChildrenWindowFromPoint(pWnd, x, y);
+
+ if (pWndChild)
+ {
+ return pWndChild;
+ }
+ }
+ }
+ return pWndTop;
+ }
+
+ PWND FASTCALL
+ IntTopLevelWindowFromPoint(INT x, INT y)
+ {
+ PWND pWnd, pwndDesktop;
+
+ /* Get the desktop window */
+ pwndDesktop = UserGetDesktopWindow();
+ if (!pwndDesktop)
+ return NULL;
+
+ /* Loop all top level windows */
+ for (pWnd = pwndDesktop->spwndChild;
+ pWnd != NULL;
+ pWnd = pWnd->spwndNext)
+ {
+ if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED)
+ {
+ TRACE("The Window is in DESTROY!\n");
+ continue;
+ }
+
+ if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y))
+ return pWnd;
+ }
+
+ /* Window has not been found */
+ return pwndDesktop;
+ }
+
+ PCURICON_OBJECT
+ FASTCALL
+ UserSetCursor(
+ PCURICON_OBJECT NewCursor,
+ BOOL ForceChange)
+ {
+ PCURICON_OBJECT OldCursor;
+ HDC hdcScreen;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PWND pWnd;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ /* Get the screen DC */
+ if(!(hdcScreen = IntGetScreenDC()))
+ {
+ return NULL;
+ }
+
+ OldCursor = MessageQueue->CursorObject;
+
+ /* Check if cursors are different */
+ if (OldCursor == NewCursor)
+ return OldCursor;
+
+ /* Update cursor for this message queue */
+ MessageQueue->CursorObject = NewCursor;
+
+ /* If cursor is not visible we have nothing to do */
+ if (MessageQueue->iCursorLevel < 0)
+ return OldCursor;
+
+ /* Update cursor if this message queue controls it */
+ pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
+ if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
+ {
+ if (NewCursor)
+ {
+ /* Call GDI to set the new screen cursor */
++ #ifdef NEW_CURSORICON
++ GreSetPointerShape(hdcScreen,
++ NewCursor->aFrame[0].hbmMask,
++ NewCursor->aFrame[0].hbmColor,
++ NewCursor->ptlHotspot.x,
++ NewCursor->ptlHotspot.y,
++ gpsi->ptCursor.x,
++ gpsi->ptCursor.y);
++ #else
+ GreSetPointerShape(hdcScreen,
+ NewCursor->IconInfo.hbmMask,
+ NewCursor->IconInfo.hbmColor,
+ NewCursor->IconInfo.xHotspot,
+ NewCursor->IconInfo.yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y);
++ #endif
+ }
+ else /* Note: OldCursor != NewCursor so we have to hide cursor */
+ {
+ /* Remove the cursor */
+ GreMovePointer(hdcScreen, -1, -1);
+ TRACE("Removing pointer!\n");
+ }
+ IntGetSysCursorInfo()->CurrentCursorObject = NewCursor;
+ }
+
+ /* Return the old cursor */
+ return OldCursor;
+ }
+
+ /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
+ * User32 macro NtUserShowCursor */
+ int UserShowCursor(BOOL bShow)
+ {
+ HDC hdcScreen;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PWND pWnd;
+
+ if (!(hdcScreen = IntGetScreenDC()))
+ {
+ return -1; /* No mouse */
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ /* Update counter */
+ MessageQueue->iCursorLevel += bShow ? 1 : -1;
+ pti->iCursorLevel += bShow ? 1 : -1;
+
+ /* Check for trivial cases */
+ if ((bShow && MessageQueue->iCursorLevel != 0) ||
+ (!bShow && MessageQueue->iCursorLevel != -1))
+ {
+ /* Note: w don't update global info here because it is used only
+ internally to check if cursor is visible */
+ return MessageQueue->iCursorLevel;
+ }
+
+ /* Check if cursor is above window owned by this MessageQueue */
+ pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
+ if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
+ {
+ if (bShow)
+ {
+ /* Show the pointer */
+ GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
+ TRACE("Showing pointer!\n");
+ }
+ else
+ {
+ /* Remove the pointer */
+ GreMovePointer(hdcScreen, -1, -1);
+ TRACE("Removing pointer!\n");
+ }
+
+ /* Update global info */
+ IntGetSysCursorInfo()->ShowingCursor = MessageQueue->iCursorLevel;
+ }
+
+ return MessageQueue->iCursorLevel;
+ }
+
+ DWORD FASTCALL
+ UserGetKeyState(DWORD dwKey)
+ {
+ DWORD dwRet = 0;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ if (dwKey < 0x100)
+ {
+ if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey))
+ dwRet |= 0xFF80; // If down, windows returns 0xFF80.
+ if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey))
+ dwRet |= 0x1;
+ }
+ else
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ }
+ return dwRet;
+ }
+
+ /* change the input key state for a given key */
+ static VOID
+ UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown)
+ {
+ TRACE("UpdateKeyState wVk: %d, bIsDown: %d\n", wVk, bIsDown);
+
+ if (bIsDown)
+ {
+ /* If it's first key down event, xor lock bit */
+ if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk))
+ SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk));
+
+ SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE);
+ MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8));
+ }
+ else
+ SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE);
+ }
+
+ /* update the input key state for a keyboard message */
+ static VOID
+ UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg)
+ {
+ UCHAR key;
+ BOOL down = FALSE;
+
+ TRACE("UpdateKeyStateFromMsg message:%d\n", msg->message);
+
+ switch (msg->message)
+ {
+ case WM_LBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_LBUTTONUP:
+ UpdateKeyState(MessageQueue, VK_LBUTTON, down);
+ break;
+ case WM_MBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_MBUTTONUP:
+ UpdateKeyState(MessageQueue, VK_MBUTTON, down);
+ break;
+ case WM_RBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_RBUTTONUP:
+ UpdateKeyState(MessageQueue, VK_RBUTTON, down);
+ break;
+ case WM_XBUTTONDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_XBUTTONUP:
+ if (msg->wParam == XBUTTON1)
+ UpdateKeyState(MessageQueue, VK_XBUTTON1, down);
+ else if (msg->wParam == XBUTTON2)
+ UpdateKeyState(MessageQueue, VK_XBUTTON2, down);
+ break;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ down = TRUE;
+ /* fall through */
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ key = (UCHAR)msg->wParam;
+ UpdateKeyState(MessageQueue, key, down);
+ switch(key)
+ {
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL);
+ UpdateKeyState(MessageQueue, VK_CONTROL, down);
+ break;
+ case VK_LMENU:
+ case VK_RMENU:
+ down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU);
+ UpdateKeyState(MessageQueue, VK_MENU, down);
+ break;
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT);
+ UpdateKeyState(MessageQueue, VK_SHIFT, down);
+ break;
+ }
+ break;
+ }
+ }
+
+ HANDLE FASTCALL
+ IntMsqSetWakeMask(DWORD WakeMask)
+ {
+ PTHREADINFO Win32Thread;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ HANDLE MessageEventHandle;
+ DWORD dwFlags = HIWORD(WakeMask);
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+ if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
+ return 0;
+
+ MessageQueue = Win32Thread->MessageQueue;
+ // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
+ MessageEventHandle = MessageQueue->NewMessagesHandle;
+
+ if (Win32Thread->pcti)
+ {
+ if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
+ ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
+ {
+ ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
+ KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up!
+ return MessageEventHandle;
+ }
+ }
+
+ IdlePing();
+
+ return MessageEventHandle;
+ }
+
+ BOOL FASTCALL
+ IntMsqClearWakeMask(VOID)
+ {
+ PTHREADINFO Win32Thread;
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+ if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
+ return FALSE;
+ // Very hacky, but that is what they do.
+ Win32Thread->pcti->fsWakeBits = 0;
+
+ IdlePong();
+
+ return TRUE;
+ }
+
+ /*
+ Due to the uncertainty of knowing what was set in our multilevel message queue,
+ and even if the bits are all cleared. The same as cTimers/cPaintsReady.
+ I think this is the best solution... (jt) */
+ VOID FASTCALL
+ MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent)
+ {
+ PTHREADINFO pti;
+
+ if (Queue->QF_flags & QF_INDESTROY)
+ {
+ ERR("This Message Queue is in Destroy!\n");
+ }
+ pti = Queue->Thread->Tcb.Win32Thread;
+ pti->pcti->fsWakeBits |= MessageBits;
+ pti->pcti->fsChangeBits |= MessageBits;
+
+ // Start bit accounting to help clear the main set of bits.
+ if (MessageBits & QS_KEY) Queue->nCntsQBits[QSRosKey]++;
+ if (MessageBits & QS_MOUSEMOVE) Queue->nCntsQBits[QSRosMouseMove]++;
+ if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++;
+ if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++;
+ if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++;
+ if (MessageBits & QS_HOTKEY) Queue->nCntsQBits[QSRosHotKey]++;
+
+ if (KeyEvent)
+ KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
+ }
+
+ VOID FASTCALL
+ ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits)
+ {
+ PTHREADINFO pti;
+ UINT ClrMask = 0;
+
+ pti = Queue->Thread->Tcb.Win32Thread;
+
+ if (MessageBits & QS_KEY)
+ {
+ if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
+ }
+ if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
+ { // Account for tracking mouse moves..
+ if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
+ // Handle mouse move bits here.
+ if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
+ }
+ if (MessageBits & QS_MOUSEBUTTON)
+ {
+ if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
+ }
+ if (MessageBits & QS_POSTMESSAGE)
+ {
+ if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
+ }
+ if (MessageBits & QS_TIMER) // ReactOS hard coded.
+ { // Handle timer bits here.
+ if ( pti->cTimersReady )
+ {
+ if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
+ }
+ }
+ if (MessageBits & QS_PAINT) // ReactOS hard coded.
+ { // Handle paint bits here.
+ if ( pti->cPaintsReady )
+ {
+ if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
+ }
+ }
+ if (MessageBits & QS_SENDMESSAGE)
+ {
+ if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
+ }
+ if (MessageBits & QS_HOTKEY)
+ {
+ if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
+ }
+
+ pti->pcti->fsWakeBits &= ~ClrMask;
+ pti->pcti->fsChangeBits &= ~ClrMask;
+ }
+
+ VOID FASTCALL
+ MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+ {
+ PTHREADINFO pti;
+ pti = Queue->Thread->Tcb.Win32Thread;
+ pti->cPaintsReady++;
+ MsqWakeQueue(Queue, QS_PAINT, TRUE);
+ }
+
+ VOID FASTCALL
+ MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+ {
+ ClearMsgBitsMask(Queue, QS_PAINT);
+ }
+
+ VOID FASTCALL
+ MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg)
+ {
+ MessageQueue->MouseMoveMsg = *Msg;
+ MessageQueue->MouseMoved = TRUE;
+ MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE);
+ }
+
+ VOID FASTCALL
+ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
+ {
+ LARGE_INTEGER LargeTickCount;
+ MSLLHOOKSTRUCT MouseHookData;
+ PDESKTOP pDesk;
+ PWND pwnd, pwndDesktop;
+ HDC hdcScreen;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PSYSTEM_CURSORINFO CurInfo;
+
+ KeQueryTickCount(&LargeTickCount);
+ Msg->time = MsqCalculateMessageTime(&LargeTickCount);
+
+ MouseHookData.pt.x = LOWORD(Msg->lParam);
+ MouseHookData.pt.y = HIWORD(Msg->lParam);
+ switch (Msg->message)
+ {
+ case WM_MOUSEWHEEL:
+ MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
+ break;
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_XBUTTONDBLCLK:
+ case WM_NCXBUTTONDOWN:
+ case WM_NCXBUTTONUP:
+ case WM_NCXBUTTONDBLCLK:
+ MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
+ break;
+ default:
+ MouseHookData.mouseData = 0;
+ break;
+ }
+
+ MouseHookData.flags = flags; // LLMHF_INJECTED
+ MouseHookData.time = Msg->time;
+ MouseHookData.dwExtraInfo = dwExtraInfo;
+
+ /* If the hook procedure returned non zero, dont send the message */
+ if (Hook)
+ {
+ if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
+ return;
+ }
+
+ /* Get the desktop window */
+ pwndDesktop = UserGetDesktopWindow();
+ if (!pwndDesktop) return;
+ pDesk = pwndDesktop->head.rpdesk;
+
+ /* Check if the mouse is captured */
+ Msg->hwnd = IntGetCaptureWindow();
+ if (Msg->hwnd != NULL)
+ {
+ pwnd = UserGetWindowObject(Msg->hwnd);
+ }
+ else
+ {
+ pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
+ if (pwnd) Msg->hwnd = pwnd->head.h;
+ }
+
+ hdcScreen = IntGetScreenDC();
+ CurInfo = IntGetSysCursorInfo();
+
+ /* Check if we found a window */
+ if (Msg->hwnd != NULL && pwnd != NULL)
+ {
+ MessageQueue = pwnd->head.pti->MessageQueue;
+
+ if ( pwnd->head.pti->TIF_flags & TIF_INCLEANUP || MessageQueue->QF_flags & QF_INDESTROY)
+ {
+ ERR("Mouse is over the Window Thread is Dead!\n");
+ return;
+ }
+
+ if (Msg->message == WM_MOUSEMOVE)
+ {
+ /* Check if cursor should be visible */
+ if(hdcScreen &&
+ MessageQueue->CursorObject &&
+ MessageQueue->iCursorLevel >= 0)
+ {
+ /* Check if shape has changed */
+ if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
+ {
+ /* Call GDI to set the new screen cursor */
++ #ifdef NEW_CURSORICON
+ GreSetPointerShape(hdcScreen,
++ MessageQueue->CursorObject->aFrame[0].hbmMask,
++ MessageQueue->CursorObject->aFrame[0].hbmColor,
++ MessageQueue->CursorObject->ptlHotspot.x,
++ MessageQueue->CursorObject->ptlHotspot.y,
++ gpsi->ptCursor.x,
++ gpsi->ptCursor.y);
++ #else
++ GreSetPointerShape(hdcScreen,
+ MessageQueue->CursorObject->IconInfo.hbmMask,
+ MessageQueue->CursorObject->IconInfo.hbmColor,
+ MessageQueue->CursorObject->IconInfo.xHotspot,
+ MessageQueue->CursorObject->IconInfo.yHotspot,
+ gpsi->ptCursor.x,
+ gpsi->ptCursor.y);
++ #endif
+ } else
+ GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
+ }
+ /* Check if w have to hide cursor */
+ else if (CurInfo->ShowingCursor >= 0)
+ GreMovePointer(hdcScreen, -1, -1);
+
+ /* Update global cursor info */
+ CurInfo->ShowingCursor = MessageQueue->iCursorLevel;
+ CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
+ gpqCursor = MessageQueue;
+
+ /* Mouse move is a special case */
+ MsqPostMouseMove(MessageQueue, Msg);
+ }
+ else
+ {
+ TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
+ MsqPostMessage(MessageQueue, Msg, TRUE, QS_MOUSEBUTTON);
+ }
+ }
+ else if (hdcScreen)
+ {
+ /* always show cursor on background; FIXME: set default pointer */
+ GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
+ CurInfo->ShowingCursor = 0;
+ }
+ }
+
+ VOID FASTCALL
+ MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
+ {
+ PWND Window;
+ PTHREADINFO Win32Thread;
+ MSG Mesg;
+ LARGE_INTEGER LargeTickCount;
+ NTSTATUS Status;
+ INT id;
+ DWORD Type;
+
+ Status = ObReferenceObjectByPointer (Thread,
+ THREAD_ALL_ACCESS,
+ PsThreadType,
+ KernelMode);
+ if (!NT_SUCCESS(Status))
+ return;
+
+ Win32Thread = ((PETHREAD)Thread)->Tcb.Win32Thread;
+ if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
+ {
+ ObDereferenceObject ((PETHREAD)Thread);
+ return;
+ }
+
+ Window = IntGetWindowObject(hWnd);
+ if (!Window)
+ {
+ ObDereferenceObject ((PETHREAD)Thread);
+ return;
+ }
+
+ id = wParam; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
+
+ Mesg.hwnd = hWnd;
+ Mesg.message = id != IDHK_REACTOS ? WM_HOTKEY : WM_SYSCOMMAND;
+ Mesg.wParam = id != IDHK_REACTOS ? wParam : SC_HOTKEY;
+ Mesg.lParam = id != IDHK_REACTOS ? lParam : (LPARAM)hWnd;
+ Type = id != IDHK_REACTOS ? QS_HOTKEY : QS_POSTMESSAGE;
+ KeQueryTickCount(&LargeTickCount);
+ Mesg.time = MsqCalculateMessageTime(&LargeTickCount);
+ Mesg.pt = gpsi->ptCursor;
+ MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, Type);
+ UserDereferenceObject(Window);
+ ObDereferenceObject (Thread);
+
+ }
+
+ PUSER_MESSAGE FASTCALL
+ MsqCreateMessage(LPMSG Msg)
+ {
+ PUSER_MESSAGE Message;
+
+ Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList);
+ if (!Message)
+ {
+ return NULL;
+ }
+
+ RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
+
+ return Message;
+ }
+
+ VOID FASTCALL
+ MsqDestroyMessage(PUSER_MESSAGE Message)
+ {
+ ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
+ }
+
+ BOOLEAN FASTCALL
+ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
+ {
+ PUSER_SENT_MESSAGE SaveMsg, Message;
+ PLIST_ENTRY Entry;
+ PTHREADINFO pti;
+ BOOL Ret;
+ LRESULT Result = 0;
+
+ if (IsListEmpty(&MessageQueue->SentMessagesListHead))
+ {
+ return(FALSE);
+ }
+
+ /* remove it from the list of pending messages */
+ Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
+ Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+
+ pti = MessageQueue->Thread->Tcb.Win32Thread;
+
+ SaveMsg = pti->pusmCurrent;
+ pti->pusmCurrent = Message;
+
+ // Processing a message sent to it from another thread.
+ if ( ( Message->SenderQueue && MessageQueue != Message->SenderQueue) ||
+ ( Message->CallBackSenderQueue && MessageQueue != Message->CallBackSenderQueue ))
+ { // most likely, but, to be sure.
+ pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
+ }
+
+ /* insert it to the list of messages that are currently dispatched by this
+ message queue */
+ InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
+ &Message->ListEntry);
+
+ ClearMsgBitsMask(MessageQueue, Message->QS_Flags);
+
+ if (Message->HookMessage == MSQ_ISHOOK)
+ { // Direct Hook Call processor
+ Result = co_CallHook( Message->Msg.message, // HookId
+ (INT)(INT_PTR)Message->Msg.hwnd, // Code
+ Message->Msg.wParam,
+ Message->Msg.lParam);
+ }
+ else if (Message->HookMessage == MSQ_ISEVENT)
+ { // Direct Event Call processor
+ Result = co_EVENT_CallEvents( Message->Msg.message,
+ Message->Msg.hwnd,
+ Message->Msg.wParam,
+ Message->Msg.lParam);
+ }
+ else if(Message->HookMessage == MSQ_INJECTMODULE)
+ {
+ Result = IntLoadHookModule(Message->Msg.message,
+ (HHOOK)Message->Msg.lParam,
+ Message->Msg.wParam);
+ }
+ else if ((Message->CompletionCallback) &&
+ (Message->CallBackSenderQueue == MessageQueue))
+ { /* Call the callback routine */
+ if (Message->QS_Flags & QS_SMRESULT)
+ {
+ co_IntCallSentMessageCallback(Message->CompletionCallback,
+ Message->Msg.hwnd,
+ Message->Msg.message,
+ Message->CompletionCallbackContext,
+ Message->lResult);
+ /* Set callback to NULL to prevent reentry */
+ Message->CompletionCallback = NULL;
+ }
+ else
+ {
+ /* The message has not been processed yet, reinsert it. */
+ RemoveEntryList(&Message->ListEntry);
+ InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
+ TRACE("Callback Message not processed yet. Requeuing the message\n");
+ Ret = FALSE;
+ goto Exit;
+ }
+ }
+ else
+ { /* Call the window procedure. */
+ Result = co_IntSendMessage( Message->Msg.hwnd,
+ Message->Msg.message,
+ Message->Msg.wParam,
+ Message->Msg.lParam);
+ }
+
+ /* remove the message from the local dispatching list, because it doesn't need
+ to be cleaned up on thread termination anymore */
+ RemoveEntryList(&Message->ListEntry);
+
+ /* If the message is a callback, insert it in the callback senders MessageQueue */
+ if (Message->CompletionCallback)
+ {
+ if (Message->CallBackSenderQueue)
+ {
+ Message->lResult = Result;
+ Message->QS_Flags |= QS_SMRESULT;
+
+ /* insert it in the callers message queue */
+ InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
+ MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE);
+ IntDereferenceMessageQueue(Message->CallBackSenderQueue);
+ }
+ Ret = TRUE;
+ goto Exit;
+ }
+
+ /* remove the message from the dispatching list if needed, so lock the sender's message queue */
+ if (Message->SenderQueue)
+ {
+ if (Message->DispatchingListEntry.Flink != NULL)
+ {
+ /* only remove it from the dispatching list if not already removed by a timeout */
+ RemoveEntryList(&Message->DispatchingListEntry);
+ }
+ }
+ /* still keep the sender's message queue locked, so the sender can't exit the
+ MsqSendMessage() function (if timed out) */
+
+ if (Message->QS_Flags & QS_SMRESULT)
+ {
+ Result = Message->lResult;
+ }
+
+ /* Let the sender know the result. */
+ if (Message->Result != NULL)
+ {
+ *Message->Result = Result;
+ }
+
+ if (Message->HasPackedLParam == TRUE)
+ {
+ if (Message->Msg.lParam)
+ ExFreePool((PVOID)Message->Msg.lParam);
+ }
+
+ /* Notify the sender. */
+ if (Message->CompletionEvent != NULL)
+ {
+ KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ /* if the message has a sender */
+ if (Message->SenderQueue)
+ {
+ /* dereference our and the sender's message queue */
+ IntDereferenceMessageQueue(Message->SenderQueue);
+ IntDereferenceMessageQueue(MessageQueue);
+ }
+
+ /* free the message */
+ ExFreePoolWithTag(Message, TAG_USRMSG);
+ Ret = TRUE;
+ Exit:
+ /* do not hangup on the user if this is reentering */
+ if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
+ pti->pusmCurrent = SaveMsg;
+
+ return Ret;
+ }
+
+ VOID APIENTRY
+ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
+ {
+ PUSER_SENT_MESSAGE SentMessage;
+ PUSER_MESSAGE PostedMessage;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PLIST_ENTRY CurrentEntry, ListHead;
+ PWND Window = pWindow;
+
+ ASSERT(Window);
+
+ MessageQueue = Window->head.pti->MessageQueue;
+ ASSERT(MessageQueue);
+
+ /* remove the posted messages for this window */
+ CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
+ ListHead = &MessageQueue->PostedMessagesListHead;
+ while (CurrentEntry != ListHead)
+ {
+ PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ if (PostedMessage->Msg.hwnd == Window->head.h)
+ {
+ RemoveEntryList(&PostedMessage->ListEntry);
+ ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags);
+ MsqDestroyMessage(PostedMessage);
+ CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
+ }
+ else
+ {
+ CurrentEntry = CurrentEntry->Flink;
+ }
+ }
+
+ /* Reference we message queue, so it won't get deleted */
+ IntReferenceMessageQueue(MessageQueue);
+
+ /* remove the sent messages for this window */
+ CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
+ ListHead = &MessageQueue->SentMessagesListHead;
+ while (CurrentEntry != ListHead)
+ {
+ SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+ if(SentMessage->Msg.hwnd == Window->head.h)
+ {
+ TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
+
+ RemoveEntryList(&SentMessage->ListEntry);
+ ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
+
+ /* if it is a callback and this queue is not the sender queue, dereference queue */
+ if ((SentMessage->CompletionCallback) && (SentMessage->CallBackSenderQueue != MessageQueue))
+ {
+ IntDereferenceMessageQueue(SentMessage->CallBackSenderQueue);
+ }
+ /* Only if the message has a sender was the queue referenced */
+ if ((SentMessage->SenderQueue)
+ && (SentMessage->DispatchingListEntry.Flink != NULL))
+ {
+ RemoveEntryList(&SentMessage->DispatchingListEntry);
+ }
+
+ /* wake the sender's thread */
+ if (SentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ if (SentMessage->HasPackedLParam == TRUE)
+ {
+ if (SentMessage->Msg.lParam)
+ ExFreePool((PVOID)SentMessage->Msg.lParam);
+ }
+
+ /* if the message has a sender */
+ if (SentMessage->SenderQueue)
+ {
+ /* dereference our and the sender's message queue */
+ IntDereferenceMessageQueue(MessageQueue);
+ IntDereferenceMessageQueue(SentMessage->SenderQueue);
+ }
+
+ /* free the message */
+ ExFreePoolWithTag(SentMessage, TAG_USRMSG);
+
+ CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
+ }
+ else
+ {
+ CurrentEntry = CurrentEntry->Flink;
+ }
+ }
+
+ /* Remove the reference we added */
+ IntDereferenceMessageQueue(MessageQueue);
+ }
+
+ BOOL FASTCALL
+ co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
+ HWND hwnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ SENDASYNCPROC CompletionCallback,
+ ULONG_PTR CompletionCallbackContext,
+ BOOL HasPackedLParam,
+ INT HookMessage)
+ {
+
+ PTHREADINFO ptiSender;
+ PUSER_SENT_MESSAGE Message;
+
+ if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+ {
+ ERR("MsqSendMessage(): Not enough memory to allocate a message");
+ return FALSE;
+ }
+
+ ptiSender = PsGetCurrentThreadWin32Thread();
+
+ IntReferenceMessageQueue(ptiReceiver->MessageQueue);
+ /* Take reference on this MessageQueue if its a callback. It will be released
+ when message is processed or removed from target hwnd MessageQueue */
+ if (CompletionCallback)
+ IntReferenceMessageQueue(ptiSender->MessageQueue);
+
+ Message->Msg.hwnd = hwnd;
+ Message->Msg.message = Msg;
+ Message->Msg.wParam = wParam;
+ Message->Msg.lParam = lParam;
+ Message->CompletionEvent = NULL;
+ Message->Result = 0;
+ Message->lResult = 0;
+ Message->SenderQueue = NULL;
+ Message->CallBackSenderQueue = ptiSender->MessageQueue;
+ Message->DispatchingListEntry.Flink = NULL;
+ Message->CompletionCallback = CompletionCallback;
+ Message->CompletionCallbackContext = CompletionCallbackContext;
+ Message->HookMessage = HookMessage;
+ Message->HasPackedLParam = HasPackedLParam;
+ Message->QS_Flags = QS_SENDMESSAGE;
+
+ InsertTailList(&ptiReceiver->MessageQueue->SentMessagesListHead, &Message->ListEntry);
+ MsqWakeQueue(ptiReceiver->MessageQueue, QS_SENDMESSAGE, TRUE);
+ IntDereferenceMessageQueue(ptiReceiver->MessageQueue);
+
+ return TRUE;
+ }
+
+ NTSTATUS FASTCALL
+ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
+ HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
+ UINT uTimeout, BOOL Block, INT HookMessage,
+ ULONG_PTR *uResult)
+ {
+ PTHREADINFO pti, ptirec;
+ PUSER_SENT_MESSAGE Message;
+ KEVENT CompletionEvent;
+ NTSTATUS WaitStatus;
+ PUSER_MESSAGE_QUEUE ThreadQueue;
+ LARGE_INTEGER Timeout;
+ PLIST_ENTRY Entry;
+ PWND pWnd;
+ LRESULT Result = 0; //// Result could be trashed. ////
+
+ pti = PsGetCurrentThreadWin32Thread();
+ ThreadQueue = pti->MessageQueue;
+ ptirec = MessageQueue->Thread->Tcb.Win32Thread;
+ ASSERT(ThreadQueue != MessageQueue);
+ ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
+
+ /* Don't send from or to a dying thread */
+ if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
+ {
+ if (uResult) *uResult = -1;
+ ERR("MsqSM: Current pti %d or Rec pti %d\n",pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if ( HookMessage == MSQ_NORMAL )
+ {
+ pWnd = ValidateHwndNoErr(Wnd);
+
+ // These can not cross International Border lines!
+ if ( pti->ppi != ptirec->ppi && pWnd )
+ {
+ switch(Msg)
+ {
+ // Handle the special case when working with password transfers across bordering processes.
+ case EM_GETLINE:
+ case EM_SETPASSWORDCHAR:
+ case WM_GETTEXT:
+ // Look for edit controls setup for passwords.
+ if ( gpsi->atomSysClass[ICLS_EDIT] == pWnd->pcls->atomClassName && // Use atomNVClassName.
+ pWnd->style & ES_PASSWORD )
+ {
+ if (uResult) *uResult = -1;
+ ERR("Running across the border without a passport!\n");
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return STATUS_UNSUCCESSFUL;
+ }
+ break;
+ case WM_NOTIFY:
+ if (uResult) *uResult = -1;
+ ERR("Running across the border without a passport!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ // These can not cross State lines!
+ if ( Msg == WM_CREATE || Msg == WM_NCCREATE )
+ {
+ if (uResult) *uResult = -1;
+ ERR("Can not tell the other State we have Create!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+ {
+ ERR("MsqSendMessage(): Not enough memory to allocate a message");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
+
+ Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
+
+ /* FIXME: Increase reference counter of sender's message queue here */
+
+ Message->Msg.hwnd = Wnd;
+ Message->Msg.message = Msg;
+ Message->Msg.wParam = wParam;
+ Message->Msg.lParam = lParam;
+ Message->CompletionEvent = &CompletionEvent;
+ Message->Result = &Result;
+ Message->lResult = 0;
+ Message->QS_Flags = 0;
+ Message->SenderQueue = ThreadQueue;
+ Message->CallBackSenderQueue = NULL;
+ IntReferenceMessageQueue(ThreadQueue);
+ Message->CompletionCallback = NULL;
+ Message->CompletionCallbackContext = 0;
+ Message->HookMessage = HookMessage;
+ Message->HasPackedLParam = FALSE;
+
+ IntReferenceMessageQueue(MessageQueue);
+
+ /* Add it to the list of pending messages */
+ InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
+
+ /* Queue it in the destination's message queue */
+ InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
+
+ Message->QS_Flags = QS_SENDMESSAGE;
+ MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
+
+ /* We can't access the Message anymore since it could have already been deleted! */
+
+ if(Block)
+ {
+ UserLeaveCo();
+
+ /* Don't process messages sent to the thread */
+ WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
+ FALSE, (uTimeout ? &Timeout : NULL));
+
+ UserEnterCo();
+
+ if(WaitStatus == STATUS_TIMEOUT)
+ {
+ /* Look up if the message has not yet dispatched, if so
+ make sure it can't pass a result and it must not set the completion event anymore */
+ Entry = MessageQueue->SentMessagesListHead.Flink;
+ while (Entry != &MessageQueue->SentMessagesListHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the message queue is locked
+ and the message is still hasn't been dispatched */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ /* Remove from the local dispatching list so the other thread knows,
+ it can't pass a result and it must not set the completion event anymore */
+ Entry = ThreadQueue->DispatchingMessagesHead.Flink;
+ while (Entry != &ThreadQueue->DispatchingMessagesHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the sender's message is locked
+ and the message has definitely not yet been destroyed, otherwise it would
+ have been removed from this list by the dispatching routine right after
+ dispatching the message */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ RemoveEntryList(&Message->DispatchingListEntry);
+ Message->DispatchingListEntry.Flink = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ TRACE("MsqSendMessage (blocked) timed out 1\n");
+ }
+ while (co_MsqDispatchOneSentMessage(ThreadQueue))
+ ;
+ }
+ else
+ {
+ PVOID WaitObjects[2];
+
+ WaitObjects[0] = &CompletionEvent;
+ WaitObjects[1] = ThreadQueue->NewMessages;
+ do
+ {
+ UserLeaveCo();
+
+ WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
+ UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
+
+ UserEnterCo();
+
+ if(WaitStatus == STATUS_TIMEOUT)
+ {
+ /* Look up if the message has not yet been dispatched, if so
+ make sure it can't pass a result and it must not set the completion event anymore */
+ Entry = MessageQueue->SentMessagesListHead.Flink;
+ while (Entry != &MessageQueue->SentMessagesListHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the message queue is locked
+ and the message is still hasn't been dispatched */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ /* Remove from the local dispatching list so the other thread knows,
+ it can't pass a result and it must not set the completion event anymore */
+ Entry = ThreadQueue->DispatchingMessagesHead.Flink;
+ while (Entry != &ThreadQueue->DispatchingMessagesHead)
+ {
+ if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
+ == Message)
+ {
+ /* We can access Message here, it's secure because the sender's message is locked
+ and the message has definitely not yet been destroyed, otherwise it would
+ have been removed from this list by the dispatching routine right after
+ dispatching the message */
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ RemoveEntryList(&Message->DispatchingListEntry);
+ Message->DispatchingListEntry.Flink = NULL;
+ break;
+ }
+ Entry = Entry->Flink;
+ }
+
+ TRACE("MsqSendMessage timed out 2\n");
+ break;
+ }
+ while (co_MsqDispatchOneSentMessage(ThreadQueue))
+ ;
+ }
+ while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
+ }
+
+ if(WaitStatus != STATUS_TIMEOUT)
+ *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
+
+ return WaitStatus;
+ }
+
+ VOID FASTCALL
+ MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessage,
+ DWORD MessageBits)
+ {
+ PUSER_MESSAGE Message;
+
+ if(!(Message = MsqCreateMessage(Msg)))
+ {
+ return;
+ }
+
+ if(!HardwareMessage)
+ {
+ InsertTailList(&MessageQueue->PostedMessagesListHead,
+ &Message->ListEntry);
+ }
+ else
+ {
+ InsertTailList(&MessageQueue->HardwareMessagesListHead,
+ &Message->ListEntry);
+ }
+
+ Message->QS_Flags = MessageBits;
+ MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
+ }
+
+ VOID FASTCALL
+ MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
+ {
+ MessageQueue->QuitPosted = TRUE;
+ MessageQueue->QuitExitCode = ExitCode;
+ MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
+ }
+
+ /***********************************************************************
+ * MsqSendParentNotify
+ *
+ * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
+ * the window has the WS_EX_NOPARENTNOTIFY style.
+ */
+ static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
+ {
+ PWND pwndDesktop = UserGetDesktopWindow();
+
+ /* pt has to be in the client coordinates of the parent window */
+ pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
+ pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
+
+ for (;;)
+ {
+ PWND pwndParent;
+
+ if (!(pwnd->style & WS_CHILD)) break;
+ if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
+ if (!(pwndParent = IntGetParent(pwnd))) break;
+ if (pwndParent == pwndDesktop) break;
+ pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
+ pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
+
+ pwnd = pwndParent;
+ co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
+ MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
+ }
+ }
+
+ VOID
+ FASTCALL
+ IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
+ {
+ // PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
+ hittest = GetNCHitEx(pwndTrack, msg->pt);
+
+ if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
+ msg->message != WM_MOUSEMOVE || // Mouse click changes or
+ pDesk->htEx != hittest) // Change in current hit test states.
+ {
+ TRACE("ITMM: Track Mouse Move!\n");
+
+ /* Handle only the changing window track and mouse move across a border. */
+ if ( pDesk->spwndTrack != pwndTrack ||
+ (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) )
+ {
+ TRACE("ITMM: Another Wnd %d or Across Border %d\n",
+ pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT));
+
+ if ( pDesk->dwDTFlags & DF_TME_LEAVE )
+ UserPostMessage( UserHMGetHandle(pDesk->spwndTrack),
+ (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
+ 0, 0);
+
+ if ( pDesk->dwDTFlags & DF_TME_HOVER )
+ IntKillTimer(UserHMGetHandle(pDesk->spwndTrack), ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
+
+ /* Clear the flags to sign a change. */
+ pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER);
+ }
+ /* Set the Track window and hit test. */
+ pDesk->spwndTrack = pwndTrack;
+ pDesk->htEx = hittest;
+ }
+
+ /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
+ if ( pDesk->spwndTrack == pwndTrack &&
+ ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) &&
+ pDesk->dwDTFlags & DF_TME_HOVER )
+ {
+ TRACE("ITMM: Reset Hover points!\n");
+ // Restart timer for the hover period.
+ IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
+ // Reset desktop mouse hover from the system default hover rectangle.
+ RECTL_vSetRect(&pDesk->rcMouseHover,
+ msg->pt.x - gspv.iMouseHoverWidth / 2,
+ msg->pt.y - gspv.iMouseHoverHeight / 2,
+ msg->pt.x + gspv.iMouseHoverWidth / 2,
+ msg->pt.y + gspv.iMouseHoverHeight / 2);
+ }
+ }
+
+ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last)
+ {
+ MSG clk_msg;
+ POINT pt;
+ UINT message;
+ USHORT hittest;
+ EVENTMSG event;
+ MOUSEHOOKSTRUCT hook;
+ BOOL eatMsg;
+
+ PWND pwndMsg, pwndDesktop;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PTHREADINFO pti;
+ PSYSTEM_CURSORINFO CurInfo;
+ PDESKTOP pDesk;
+ DECLARE_RETURN(BOOL);
+
+ pti = PsGetCurrentThreadWin32Thread();
+ pwndDesktop = UserGetDesktopWindow();
+ MessageQueue = pti->MessageQueue;
+ CurInfo = IntGetSysCursorInfo();
+ pwndMsg = ValidateHwndNoErr(msg->hwnd);
+ clk_msg = MessageQueue->msgDblClk;
+ pDesk = pwndDesktop->head.rpdesk;
+
+ /* find the window to dispatch this mouse message to */
+ if (MessageQueue->spwndCapture)
+ {
+ hittest = HTCLIENT;
+ pwndMsg = MessageQueue->spwndCapture;
+ if (pwndMsg) UserReferenceObject(pwndMsg);
+ }
+ else
+ { // Fix wine Msg test_HTTRANSPARENT. Start with a NULL window.
+ // http://www.winehq.org/pipermail/wine-patches/2012-August/116776.html
+ pwndMsg = co_WinPosWindowFromPoint(NULL, &msg->pt, &hittest);
+ }
+
+ TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest );
+
+ if (pwndMsg == NULL || pwndMsg->head.pti != pti)
+ {
+ /* Remove and ignore the message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+
+ if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
+ {
+ IntTrackMouseMove(pwndMsg, pDesk, msg, hittest);
+ }
+ else
+ {
+ ERR("Not the same cursor!\n");
+ }
+
+ msg->hwnd = UserHMGetHandle(pwndMsg);
+
+ #if 0
+ if (!check_hwnd_filter( msg, hwnd_filter )) RETURN(FALSE);
+ #endif
+
+ pt = msg->pt;
+ message = msg->message;
+ /* Note: windows has no concept of a non-client wheel message */
+ if (message != WM_MOUSEWHEEL)
+ {
+ if (hittest != HTCLIENT)
+ {
+ message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
+ msg->wParam = hittest;
+ }
+ else
+ {
+ /* coordinates don't get translated while tracking a menu */
+ /* FIXME: should differentiate popups and top-level menus */
+ if (!(MessageQueue->MenuOwner))
+ {
+ pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
+ pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
+ }
+ }
+ }
+ msg->lParam = MAKELONG( pt.x, pt.y );
+
+ /* translate double clicks */
+
+ if ((msg->message == WM_LBUTTONDOWN) ||
+ (msg->message == WM_RBUTTONDOWN) ||
+ (msg->message == WM_MBUTTONDOWN) ||
+ (msg->message == WM_XBUTTONDOWN))
+ {
+ BOOL update = *RemoveMessages;
+
+ /* translate double clicks -
+ * note that ...MOUSEMOVEs can slip in between
+ * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
+
+ if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
+ hittest != HTCLIENT ||
+ (pwndMsg->pcls->style & CS_DBLCLKS))
+ {
+ if ((msg->message == clk_msg.message) &&
+ (msg->hwnd == clk_msg.hwnd) &&
+ (msg->wParam == clk_msg.wParam) &&
+ ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
+ (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
+ (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
+ {
+ message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
+ if (update)
+ {
+ MessageQueue->msgDblClk.message = 0; /* clear the double click conditions */
+ update = FALSE;
+ }
+ }
+ }
+
+ if (!((first == 0 && last == 0) || (message >= first || message <= last)))
+ {
+ TRACE("Message out of range!!!\n");
+ RETURN(FALSE);
+ }
+
+ /* update static double click conditions */
+ if (update) MessageQueue->msgDblClk = *msg;
+ }
+ else
+ {
+ if (!((first == 0 && last == 0) || (message >= first || message <= last)))
+ {
+ TRACE("Message out of range!!!\n");
+ RETURN(FALSE);
+ }
+ }
+
+ if(gspv.bMouseClickLock)
+ {
+ BOOL IsClkLck = FALSE;
+
+ if(msg->message == WM_LBUTTONUP)
+ {
+ IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
+ if (IsClkLck && (!CurInfo->ClickLockActive))
+ {
+ CurInfo->ClickLockActive = TRUE;
+ }
+ }
+ else if (msg->message == WM_LBUTTONDOWN)
+ {
+ if (CurInfo->ClickLockActive)
+ {
+ IsClkLck = TRUE;
+ CurInfo->ClickLockActive = FALSE;
+ }
+
+ CurInfo->ClickLockTime = msg->time;
+ }
+
+ if(IsClkLck)
+ {
+ /* Remove and ignore the message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+ }
+
+ /* message is accepted now (but may still get dropped) */
+
+ event.message = msg->message;
+ event.time = msg->time;
+ event.hwnd = msg->hwnd;
+ event.paramL = msg->pt.x;
+ event.paramH = msg->pt.y;
+ co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+
+ hook.pt = msg->pt;
+ hook.hwnd = msg->hwnd;
+ hook.wHitTestCode = hittest;
+ hook.dwExtraInfo = 0 /* extra_info */ ;
+ if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+ message, (LPARAM)&hook ))
+ {
+ hook.pt = msg->pt;
+ hook.hwnd = msg->hwnd;
+ hook.wHitTestCode = hittest;
+ hook.dwExtraInfo = 0 /* extra_info */ ;
+ co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
+
+ ERR("WH_MOUSE dorpped mouse message!\n");
+
+ /* Remove and skip message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+
+ if ((hittest == HTERROR) || (hittest == HTNOWHERE))
+ {
+ co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
+ MAKELONG( hittest, msg->message ));
+
+ /* Remove and skip message */
+ *RemoveMessages = TRUE;
+ RETURN(FALSE);
+ }
+
+ if ((*RemoveMessages == FALSE) || MessageQueue->spwndCapture)
+ {
+ /* Accept the message */
+ msg->message = message;
+ RETURN(TRUE);
+ }
+
+ eatMsg = FALSE;
+
+ if ((msg->message == WM_LBUTTONDOWN) ||
+ (msg->message == WM_RBUTTONDOWN) ||
+ (msg->message == WM_MBUTTONDOWN) ||
+ (msg->message == WM_XBUTTONDOWN))
+ {
+ /* Send the WM_PARENTNOTIFY,
+ * note that even for double/nonclient clicks
+ * notification message is still WM_L/M/RBUTTONDOWN.
+ */
+ MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
+
+ /* Activate the window if needed */
+
+ if (pwndMsg != MessageQueue->spwndActive)
+ {
+ PWND pwndTop = pwndMsg;
+ while (pwndTop && ((pwndTop->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
+ {
+ pwndTop = pwndTop->spwndParent;
+ }
+
+ if (pwndTop && pwndTop != pwndDesktop)
+ {
+ LONG ret = co_IntSendMessage( msg->hwnd,
+ WM_MOUSEACTIVATE,
+ (WPARAM)UserHMGetHandle(pwndTop),
+ MAKELONG( hittest, msg->message));
+ switch(ret)
+ {
+ case MA_NOACTIVATEANDEAT:
+ eatMsg = TRUE;
+ /* fall through */
+ case MA_NOACTIVATE:
+ break;
+ case MA_ACTIVATEANDEAT:
+ eatMsg = TRUE;
+ /* fall through */
+ case MA_ACTIVATE:
+ case 0:
+ if (!co_IntMouseActivateWindow( pwndTop )) eatMsg = TRUE;
+ break;
+ default:
+ ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
+ break;
+ }
+ }
+ }
+ }
+
+ /* send the WM_SETCURSOR message */
+
+ /* Windows sends the normal mouse message as the message parameter
+ in the WM_SETCURSOR message even if it's non-client mouse message */
+ co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
+
+ msg->message = message;
+ RETURN(!eatMsg);
+
+ CLEANUP:
+ if(pwndMsg)
+ UserDereferenceObject(pwndMsg);
+
+ END_CLEANUP;
+ }
+
+ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
+ {
+ EVENTMSG Event;
+
+ if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
+ Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
+ {
+ switch (Msg->wParam)
+ {
+ case VK_LSHIFT: case VK_RSHIFT:
+ Msg->wParam = VK_SHIFT;
+ break;
+ case VK_LCONTROL: case VK_RCONTROL:
+ Msg->wParam = VK_CONTROL;
+ break;
+ case VK_LMENU: case VK_RMENU:
+ Msg->wParam = VK_MENU;
+ break;
+ }
+ }
+
+ Event.message = Msg->message;
+ Event.hwnd = Msg->hwnd;
+ Event.time = Msg->time;
+ Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
+ Event.paramH = Msg->lParam & 0x7FFF;
+ if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
+ co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+ if (co_HOOK_CallHooks( WH_KEYBOARD,
+ *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+ LOWORD(Msg->wParam),
+ Msg->lParam))
+ {
+ /* skip this message */
+ co_HOOK_CallHooks( WH_CBT,
+ HCBT_KEYSKIPPED,
+ LOWORD(Msg->wParam),
+ Msg->lParam );
+ ERR("KeyboardMessage WH_CBT Call Hook return!\n");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
+ {
+ if ( IS_MOUSE_MESSAGE(Msg->message))
+ {
+ return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
+ }
+ else if ( IS_KBD_MESSAGE(Msg->message))
+ {
+ return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
+ }
+
+ return TRUE;
+ }
+
+ BOOL APIENTRY
+ co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
+ IN BOOL Remove,
+ IN PWND Window,
+ IN UINT MsgFilterLow,
+ IN UINT MsgFilterHigh,
+ OUT MSG* pMsg)
+ {
+ BOOL AcceptMessage;
+ MSG msg;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ if(!(MessageQueue->MouseMoved))
+ return FALSE;
+
+ if (!MessageQueue->ptiSysLock)
+ {
+ MessageQueue->ptiSysLock = pti;
+ pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
+ }
+
+ if (MessageQueue->ptiSysLock != pti)
+ {
+ ERR("MsqPeekMouseMove: Thread Q is locked to another pti!\n");
+ return FALSE;
+ }
+
+ msg = MessageQueue->MouseMoveMsg;
+
+ AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+
+ if(AcceptMessage)
+ *pMsg = msg;
+
+ if(Remove)
+ {
+ ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE);
+ MessageQueue->MouseMoved = FALSE;
+ }
+
+ MessageQueue->ptiSysLock = NULL;
+ pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
+ return AcceptMessage;
+ }
+
+ /* check whether a message filter contains at least one potential hardware message */
+ static INT FASTCALL
+ filter_contains_hw_range( UINT first, UINT last )
+ {
+ /* hardware message ranges are (in numerical order):
+ * WM_NCMOUSEFIRST .. WM_NCMOUSELAST
+ * WM_KEYFIRST .. WM_KEYLAST
+ * WM_MOUSEFIRST .. WM_MOUSELAST
+ */
+ if (!last) --last;
+ if (last < WM_NCMOUSEFIRST) return 0;
+ if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
+ if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
+ if (first > WM_MOUSELAST) return 0;
+ return 1;
+ }
+
+ BOOL APIENTRY
+ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
+ IN BOOL Remove,
+ IN PWND Window,
+ IN UINT MsgFilterLow,
+ IN UINT MsgFilterHigh,
+ IN UINT QSflags,
+ OUT MSG* pMsg)
+ {
+
+ BOOL AcceptMessage;
+ PUSER_MESSAGE CurrentMessage;
+ PLIST_ENTRY ListHead, CurrentEntry = NULL;
+ MSG msg;
+ BOOL Ret = FALSE;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
+
+ ListHead = &MessageQueue->HardwareMessagesListHead;
+ CurrentEntry = ListHead->Flink;
+
+ if (IsListEmpty(CurrentEntry)) return FALSE;
+
+ if (!MessageQueue->ptiSysLock)
+ {
+ MessageQueue->ptiSysLock = pti;
+ pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
+ }
+
+ if (MessageQueue->ptiSysLock != pti)
+ {
+ ERR("MsqPeekHardwareMessage: Thread Q is locked to another pti!\n");
+ return FALSE;
+ }
+
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ do
+ {
+ if (IsListEmpty(CurrentEntry)) break;
+ if (!CurrentMessage) break;
+ CurrentEntry = CurrentMessage->ListEntry.Flink;
+ /*
+ MSDN:
+ 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
+ 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
+ 3: handle to the window whose messages are to be retrieved.
+ */
+ if ( ( !Window || // 1
+ ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
+ ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+ ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
+ ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
+ {
+ msg = CurrentMessage->Msg;
+
+ UpdateKeyStateFromMsg(MessageQueue, &msg);
+ AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+
+ if (Remove)
+ {
+ RemoveEntryList(&CurrentMessage->ListEntry);
+ ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
+ MsqDestroyMessage(CurrentMessage);
+ }
+
+ if (AcceptMessage)
+ {
+ *pMsg = msg;
+ Ret = TRUE;
+ break;
+ }
+ }
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ }
+ while(CurrentEntry != ListHead);
+
+ MessageQueue->ptiSysLock = NULL;
+ pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
+ return Ret;
+ }
+
+ BOOLEAN APIENTRY
+ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
+ IN BOOLEAN Remove,
+ IN PWND Window,
+ IN UINT MsgFilterLow,
+ IN UINT MsgFilterHigh,
+ IN UINT QSflags,
+ OUT PMSG Message)
+ {
+ PLIST_ENTRY CurrentEntry;
+ PUSER_MESSAGE CurrentMessage;
+ PLIST_ENTRY ListHead;
+ BOOL Ret = FALSE;
+ PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
+ CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
+ ListHead = &MessageQueue->PostedMessagesListHead;
+
+ if (IsListEmpty(CurrentEntry)) return FALSE;
+
+ if (!MessageQueue->ptiSysLock)
+ {
+ MessageQueue->ptiSysLock = pti;
+ pti->pcti->CTI_flags |= CTI_THREADSYSLOCK;
+ }
+
+ if (MessageQueue->ptiSysLock != pti)
+ {
+ ERR("MsqPeekMessage: Thread Q is locked to another pti!\n");
+ return FALSE;
+ }
+
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ do
+ {
+ if (IsListEmpty(CurrentEntry)) break;
+ if (!CurrentMessage) break;
+ CurrentEntry = CurrentEntry->Flink;
+ /*
+ MSDN:
+ 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
+ 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
+ 3: handle to the window whose messages are to be retrieved.
+ */
+ if ( ( !Window || // 1
+ ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
+ ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+ ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
+ ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
+ {
+ *Message = CurrentMessage->Msg;
+
+ if (Remove)
+ {
+ RemoveEntryList(&CurrentMessage->ListEntry);
+ ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
+ MsqDestroyMessage(CurrentMessage);
+ }
+ Ret = TRUE;
+ break;
+ }
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ }
+ while (CurrentEntry != ListHead);
+
+ MessageQueue->ptiSysLock = NULL;
+ pti->pcti->CTI_flags &= ~CTI_THREADSYSLOCK;
+ return Ret;
+ }
+
+ NTSTATUS FASTCALL
+ co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
+ UINT MsgFilterMin, UINT MsgFilterMax)
+ {
+ NTSTATUS ret;
+ UserLeaveCo();
+ ret = KeWaitForSingleObject( MessageQueue->NewMessages,
+ UserRequest,
+ UserMode,
+ FALSE,
+ NULL );
+ UserEnterCo();
+ return ret;
+ }
+
+ BOOL FASTCALL
+ MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
+ {
+ LARGE_INTEGER LargeTickCount;
+
+ KeQueryTickCount(&LargeTickCount);
+ return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
+ }
+
+ VOID
+ CALLBACK
+ HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+ {
+ DoTheScreenSaver();
+ TRACE("HungAppSysTimerProc\n");
+ // Process list of windows that are hung and waiting.
+ }
+
+ BOOLEAN FASTCALL
+ MsqInitializeMessageQueue(PTHREADINFO pti, PUSER_MESSAGE_QUEUE MessageQueue)
+ {
+ struct _ETHREAD *Thread;
+ LARGE_INTEGER LargeTickCount;
+ NTSTATUS Status;
+
+ Thread = pti->pEThread;
+ MessageQueue->Thread = Thread;
+ MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
+ InitializeListHead(&MessageQueue->PostedMessagesListHead);
+ InitializeListHead(&MessageQueue->SentMessagesListHead);
+ InitializeListHead(&MessageQueue->HardwareMessagesListHead);
+ InitializeListHead(&MessageQueue->DispatchingMessagesHead);
+ InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
+ MessageQueue->QuitPosted = FALSE;
+ MessageQueue->QuitExitCode = 0;
+ KeQueryTickCount(&LargeTickCount);
+ MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
+ MessageQueue->spwndFocus = NULL;
+ MessageQueue->NewMessagesHandle = NULL;
+ MessageQueue->iCursorLevel = 0;
+ MessageQueue->CursorObject = NULL;
+ RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
+
+ Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
+ NULL, SynchronizationEvent, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
+ ExEventObjectType, KernelMode,
+ (PVOID*)&MessageQueue->NewMessages, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ ZwClose(MessageQueue->NewMessagesHandle);
+ MessageQueue->NewMessagesHandle = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ VOID FASTCALL
+ MsqCleanupMessageQueue(PTHREADINFO pti)
+ {
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PLIST_ENTRY CurrentEntry;
+ PUSER_MESSAGE CurrentMessage;
+ PUSER_SENT_MESSAGE CurrentSentMessage;
+
+ MessageQueue = pti->MessageQueue;
+
+ /* cleanup posted messages */
+ while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
+ {
+ CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
+ CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+ ListEntry);
+ MsqDestroyMessage(CurrentMessage);
+ }
+
+ /* remove the messages that have not yet been dispatched */
+ while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
+ {
+ CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+
+ /* if it is a callback and this queue is not the sender queue, dereference queue */
+ if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
+ {
+ IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
+ }
+
+ TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
+ /* Only if the message has a sender was the message in the DispatchingList */
+ if ((CurrentSentMessage->SenderQueue)
+ && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
+ {
+ RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
+ }
+
+ /* wake the sender's thread */
+ if (CurrentSentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ if (CurrentSentMessage->HasPackedLParam == TRUE)
+ {
+ if (CurrentSentMessage->Msg.lParam)
+ ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+ }
+
+ /* if the message has a sender */
+ if (CurrentSentMessage->SenderQueue)
+ {
+ /* dereference our and the sender's message queue */
+ IntDereferenceMessageQueue(MessageQueue);
+ IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
+ }
+
+ /* free the message */
+ ExFreePool(CurrentSentMessage);
+ }
+
+ /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
+ ExitThread() was called in a SendMessage() umode callback */
+ while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
+ {
+ CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+
+ /* if it is a callback and this queue is not the sender queue, dereference queue */
+ if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
+ {
+ IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
+ }
+
+ /* remove the message from the dispatching list */
+ if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
+ {
+ RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
+ }
+
+ TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
+
+ /* wake the sender's thread */
+ if (CurrentSentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ if (CurrentSentMessage->HasPackedLParam == TRUE)
+ {
+ if (CurrentSentMessage->Msg.lParam)
+ ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+ }
+
+ /* if the message has a sender */
+ if (CurrentSentMessage->SenderQueue)
+ {
+ /* dereference our and the sender's message queue */
+ IntDereferenceMessageQueue(MessageQueue);
+ IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
+ }
+
+ /* free the message */
+ ExFreePool(CurrentSentMessage);
+ }
+
+ /* tell other threads not to bother returning any info to us */
+ while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
+ {
+ CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ DispatchingListEntry);
+ CurrentSentMessage->CompletionEvent = NULL;
+ CurrentSentMessage->Result = NULL;
+
+ /* do NOT dereference our message queue as it might get attempted to be
+ locked later */
+ }
+
+ // Clear it all out.
+ if (pti->pcti)
+ {
+ pti->pcti->fsWakeBits = 0;
+ pti->pcti->fsChangeBits = 0;
+ }
+
+ MessageQueue->nCntsQBits[QSRosKey] = 0;
+ MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
+ MessageQueue->nCntsQBits[QSRosMouseButton] = 0;
+ MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
+ MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
+ MessageQueue->nCntsQBits[QSRosHotKey] = 0;
+
+ if (MessageQueue->CursorObject)
+ {
+ PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
+
+ /* Change to another cursor if we going to dereference current one
+ Note: we can't use UserSetCursor because it uses current thread
+ message queue instead of queue given for cleanup */
+ if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
+ {
+ HDC hdcScreen;
+
+ /* Get the screen DC */
+ hdcScreen = IntGetScreenDC();
+ if (hdcScreen)
+ GreMovePointer(hdcScreen, -1, -1);
+ IntGetSysCursorInfo()->CurrentCursorObject = NULL;
+ }
+
+ UserDereferenceObject(pCursor);
+ }
+ }
+
+ PUSER_MESSAGE_QUEUE FASTCALL
+ MsqCreateMessageQueue(PTHREADINFO pti)
+ {
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
+ USERTAG_Q);
+
+ if (!MessageQueue)
+ {
+ return NULL;
+ }
+
+ RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
+ /* hold at least one reference until it'll be destroyed */
+ IntReferenceMessageQueue(MessageQueue);
+ /* initialize the queue */
+ if (!MsqInitializeMessageQueue(pti, MessageQueue))
+ {
+ IntDereferenceMessageQueue(MessageQueue);
+ return NULL;
+ }
+
+ return MessageQueue;
+ }
+
+ VOID FASTCALL
+ MsqDestroyMessageQueue(PTHREADINFO pti)
+ {
+ PDESKTOP desk;
+ PUSER_MESSAGE_QUEUE MessageQueue = pti->MessageQueue;
+
+ MessageQueue->QF_flags |= QF_INDESTROY;
+
+ /* remove the message queue from any desktops */
+ if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
+ {
+ (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
+ IntDereferenceMessageQueue(MessageQueue);
+ }
+
+ /* clean it up */
+ MsqCleanupMessageQueue(pti);
+
+ if (MessageQueue->NewMessagesHandle != NULL)
+ ZwClose(MessageQueue->NewMessagesHandle);
+ MessageQueue->NewMessagesHandle = NULL;
+ /* decrease the reference counter, if it hits zero, the queue will be freed */
+ IntDereferenceMessageQueue(MessageQueue);
+ }
+
+ LPARAM FASTCALL
+ MsqSetMessageExtraInfo(LPARAM lParam)
+ {
+ LPARAM Ret;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+ if(!MessageQueue)
+ {
+ return 0;
+ }
+
+ Ret = MessageQueue->ExtraInfo;
+ MessageQueue->ExtraInfo = lParam;
+
+ return Ret;
+ }
+
+ LPARAM FASTCALL
+ MsqGetMessageExtraInfo(VOID)
+ {
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+ if(!MessageQueue)
+ {
+ return 0;
+ }
+
+ return MessageQueue->ExtraInfo;
+ }
+
+ // ReplyMessage is called by the thread receiving the window message.
+ BOOL FASTCALL
+ co_MsqReplyMessage( LRESULT lResult )
+ {
+ PUSER_SENT_MESSAGE Message;
+ PTHREADINFO pti;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ Message = pti->pusmCurrent;
+
+ if (!Message) return FALSE;
+
+ if (Message->QS_Flags & QS_SMRESULT) return FALSE;
+
+ // SendMessageXxx || Callback msg and not a notify msg
+ if (Message->SenderQueue || Message->CompletionCallback)
+ {
+ Message->lResult = lResult;
+ Message->QS_Flags |= QS_SMRESULT;
+ // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
+ }
+ return TRUE;
+ }
+
+ HWND FASTCALL
+ MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
+ {
+ HWND Prev;
+
+ switch(Type)
+ {
+ case MSQ_STATE_CAPTURE:
+ Prev = MessageQueue->spwndCapture ? UserHMGetHandle(MessageQueue->spwndCapture) : 0;
+ MessageQueue->spwndCapture = ValidateHwndNoErr(hWnd);
+ return Prev;
+ case MSQ_STATE_ACTIVE:
+ Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0;
+ MessageQueue->spwndActive = ValidateHwndNoErr(hWnd);
+ return Prev;
+ case MSQ_STATE_FOCUS:
+ Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0;
+ MessageQueue->spwndFocus = ValidateHwndNoErr(hWnd);
+ return Prev;
+ case MSQ_STATE_MENUOWNER:
+ Prev = MessageQueue->MenuOwner;
+ MessageQueue->MenuOwner = hWnd;
+ return Prev;
+ case MSQ_STATE_MOVESIZE:
+ Prev = MessageQueue->MoveSize;
+ MessageQueue->MoveSize = hWnd;
+ return Prev;
+ case MSQ_STATE_CARET:
+ ASSERT(MessageQueue->CaretInfo);
+ Prev = MessageQueue->CaretInfo->hWnd;
+ MessageQueue->CaretInfo->hWnd = hWnd;
+ return Prev;
+ }
+
+ return NULL;
+ }
+
+ SHORT
+ APIENTRY
+ NtUserGetKeyState(INT key)
+ {
+ DWORD Ret;
+
+ UserEnterShared();
+
+ Ret = UserGetKeyState(key);
+
+ UserLeave();
+
+ return (SHORT)Ret;
+ }
+
+
+ DWORD
+ APIENTRY
+ NtUserGetKeyboardState(LPBYTE lpKeyState)
+ {
+ DWORD i, ret = TRUE;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ UserEnterShared();
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ _SEH2_TRY
+ {
+ /* Probe and copy key state to an array */
+ ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1);
+ for (i = 0; i < 256; ++i)
+ {
+ lpKeyState[i] = 0;
+ if (IS_KEY_DOWN(MessageQueue->afKeyState, i))
+ lpKeyState[i] |= KS_DOWN_BIT;
+ if (IS_KEY_LOCKED(MessageQueue->afKeyState, i))
+ lpKeyState[i] |= KS_LOCK_BIT;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ ret = FALSE;
+ }
+ _SEH2_END;
+
+ UserLeave();
+
+ return ret;
+ }
+
+ BOOL
+ APIENTRY
+ NtUserSetKeyboardState(LPBYTE pKeyState)
+ {
+ UINT i;
+ BOOL bRet = TRUE;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+
+ UserEnterExclusive();
+
+ pti = PsGetCurrentThreadWin32Thread();
+ MessageQueue = pti->MessageQueue;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1);
+ for (i = 0; i < 256; ++i)
+ {
+ SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT);
+ SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ bRet = FALSE;
+ }
+ _SEH2_END;
+
+ UserLeave();
+
+ return bRet;
+ }
+
+ /* EOF */
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: User handle manager
+ * FILE: subsystems/win32/win32k/ntuser/object.c
+ * PROGRAMER: Copyright (C) 2001 Alexandre Julliard
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserObj);
+
+ //int usedHandles=0;
+ PUSER_HANDLE_TABLE gHandleTable = NULL;
+
+ #if DBG
+
+ void DbgUserDumpHandleTable()
+ {
+ int HandleCounts[USER_HANDLE_TYPE_COUNT];
+ PPROCESSINFO ppiList;
+ int i;
+ PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc",
+ L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile",
+ L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"};
+
+ ERR("Total handles count: %d\n", gpsi->cHandleEntries);
+
+ memset(HandleCounts, 0, sizeof(HandleCounts));
+
+ /* First of all count the number of handles per tpe */
+ ppiList = gppiList;
+ while (ppiList)
+ {
+ ERR("Process %s (%d) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount);
+
+ for (i = 1 ;i < USER_HANDLE_TYPE_COUNT; i++)
+ {
+ HandleCounts[i] += ppiList->DbgHandleCount[i];
+
+ DbgPrint("%S: %d, ", TypeNames[i], ppiList->DbgHandleCount[i]);
+ if (i % 6 == 0)
+ DbgPrint("\n\t");
+ }
+ DbgPrint("\n");
+
+ ppiList = ppiList->ppiNext;
+ }
+
+ /* Print total type counts */
+ ERR("Total handles of the running processes: \n\t");
+ for (i = 1 ;i < USER_HANDLE_TYPE_COUNT; i++)
+ {
+ DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
+ if (i % 6 == 0)
+ DbgPrint("\n\t");
+ }
+ DbgPrint("\n");
+
+ /* Now count the handle counts that are allocated from the handle table */
+ memset(HandleCounts, 0, sizeof(HandleCounts));
+ for (i = 0; i < gHandleTable->nb_handles; i++)
+ HandleCounts[gHandleTable->handles[i].type]++;
+
+ ERR("Total handles count allocated: \n\t");
+ for (i = 1 ;i < USER_HANDLE_TYPE_COUNT; i++)
+ {
+ DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
+ if (i % 6 == 0)
+ DbgPrint("\n\t");
+ }
+ DbgPrint("\n");
+ }
+
+ #endif
+
+ PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
+ {
+ unsigned short generation;
+ int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
+ if (index < 0 || index >= ht->nb_handles)
+ return NULL;
+ if (!ht->handles[index].type)
+ return NULL;
+ generation = (unsigned int)handle >> 16;
+ if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
+ return &ht->handles[index];
+ return NULL;
+ }
+
+ __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
+ {
+ int index = ptr - ht->handles;
+ return (HANDLE)(((index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
+ }
+
+ __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
+ {
+ PUSER_HANDLE_ENTRY entry;
+ PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
+ TRACE("handles used %i\n",gpsi->cHandleEntries);
+
+ if (ht->freelist)
+ {
+ entry = ht->freelist;
+ ht->freelist = entry->ptr;
+
+ gpsi->cHandleEntries++;
+ ppi->UserHandleCount++;
+ return entry;
+ }
+
+ if (ht->nb_handles >= ht->allocated_handles) /* Need to grow the array */
+ {
+ ERR("Out of user handles! Used -> %i, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
+
+ #if DBG
+ DbgUserDumpHandleTable();
+ #endif
+
+ return NULL;
+ #if 0
+ PUSER_HANDLE_ENTRY new_handles;
+ /* Grow array by 50% (but at minimum 32 entries) */
+ int growth = max( 32, ht->allocated_handles / 2 );
+ int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
+ if (new_size <= ht->allocated_handles)
+ return NULL;
+ if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
+ return NULL;
+ ht->handles = new_handles;
+ ht->allocated_handles = new_size;
+ #endif
+ }
+
+ entry = &ht->handles[ht->nb_handles++];
+
+ entry->generation = 1;
+
+ gpsi->cHandleEntries++;
+ ppi->UserHandleCount++;
+
+ return entry;
+ }
+
+ VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
+ {
+ ht->freelist = NULL;
+ ht->handles = mem;
+
+ ht->nb_handles = 0;
+ ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
+ }
+
+ __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
+ {
+ PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
+ void *ret;
+
+ #if DBG
+ ppi->DbgHandleCount[entry->type]--;
+ #endif
+
+ ret = entry->ptr;
+ entry->ptr = ht->freelist;
+ entry->type = 0;
+ entry->flags = 0;
+ entry->pi = NULL;
+ ht->freelist = entry;
+
+ gpsi->cHandleEntries--;
+ ppi->UserHandleCount--;
+
+ return ret;
+ }
+
+ static __inline PVOID
+ UserHandleOwnerByType(USER_OBJECT_TYPE type)
+ {
+ PVOID pi;
+
+ switch (type)
+ {
+ case otWindow:
+ case otInputContext:
+ pi = GetW32ThreadInfo();
+ break;
+
+ case otMenu:
+ case otCursorIcon:
+ case otHook:
+ case otCallProc:
+ case otAccel:
+ case otSMWP:
+ pi = GetW32ProcessInfo();
+ break;
+
+ case otMonitor:
+ pi = NULL; /* System */
+ break;
+
+ default:
+ pi = NULL;
+ break;
+ }
+
+ return pi;
+ }
+
+ /* allocate a user handle for a given object */
+ HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
+ {
+ PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
+ if (!entry)
+ return 0;
+ entry->ptr = object;
+ entry->type = type;
+ entry->flags = 0;
+ entry->pi = UserHandleOwnerByType(type);
+ if (++entry->generation >= 0xffff)
+ entry->generation = 1;
+
+ /* We have created a handle, which is a reference! */
+ UserReferenceObject(object);
+
+ return entry_to_handle(ht, entry );
+ }
+
+ /* return a pointer to a user object from its handle without setting an error */
+ PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
+ {
+ PUSER_HANDLE_ENTRY entry;
+
+ ASSERT(ht);
+
+ if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
+ {
+ return NULL;
+ }
+ return entry->ptr;
+ }
+
+ /* return a pointer to a user object from its handle */
+ PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
+ {
+ PUSER_HANDLE_ENTRY entry;
+
+ ASSERT(ht);
+
+ if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
+ {
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return NULL;
+ }
+ return entry->ptr;
+ }
+
+
+ /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
+ HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle )
+ {
+ PUSER_HANDLE_ENTRY entry;
+
+ if ((unsigned int)handle >> 16)
+ return handle;
+ if (!(entry = handle_to_entry(ht, handle )))
+ return handle;
+ return entry_to_handle( ht, entry );
+ }
+
+
+ /* Same as get_user_object plus set the handle to the full 32-bit value */
+ void *get_user_object_handle(PUSER_HANDLE_TABLE ht, HANDLE* handle, USER_OBJECT_TYPE type )
+ {
+ PUSER_HANDLE_ENTRY entry;
+
+ if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
+ return NULL;
+ *handle = entry_to_handle( ht, entry );
+ return entry->ptr;
+ }
+
+
+
+ BOOL FASTCALL UserCreateHandleTable(VOID)
+ {
+ PVOID mem;
+ INT HandleCount = 1024 * 4;
+
+ // FIXME: Don't alloc all at once! Must be mapped into umode also...
+ mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount);
+ if (!mem)
+ {
+ ERR("Failed creating handle table\n");
+ return FALSE;
+ }
+
+ gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
+ if (gHandleTable == NULL)
+ {
+ UserHeapFree(mem);
+ ERR("Failed creating handle table\n");
+ return FALSE;
+ }
+
+ // FIXME: Make auto growable
+ UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount);
+
+ return TRUE;
+ }
+
+ //
+ // New
+ //
+ PVOID
+ FASTCALL
+ UserCreateObject( PUSER_HANDLE_TABLE ht,
+ PDESKTOP pDesktop,
+ PTHREADINFO pti,
+ HANDLE* h,
+ USER_OBJECT_TYPE type,
+ ULONG size)
+ {
+ HANDLE hi;
+ PVOID Object;
+ PPROCESSINFO ppi;
+ BOOL dt;
+ PDESKTOP rpdesk = pDesktop;
+
+ /* We could get the desktop for the new object from the pti however this is
+ * not always the case for example when creating a new desktop window for
+ * the desktop thread*/
+
+ if (!pti) pti = GetW32ThreadInfo();
+ if (!pDesktop) rpdesk = pti->rpdesk;
+ ppi = pti->ppi;
+
+ switch (type)
+ {
+ case otWindow:
+ // case otMenu:
+ case otHook:
+ case otCallProc:
+ case otInputContext:
+ Object = DesktopHeapAlloc(rpdesk, size);
+ dt = TRUE;
+ break;
+
+ default:
+ Object = UserHeapAlloc(size);
+ dt = FALSE;
+ break;
+ }
+
+ if (!Object)
+ return NULL;
+
+
+ hi = UserAllocHandle(ht, Object, type );
+ if (!hi)
+ {
+ if (dt)
+ DesktopHeapFree(rpdesk, Object);
+ else
+ UserHeapFree(Object);
+ return NULL;
+ }
+
+ #if DBG
+ ppi->DbgHandleCount[type]++;
+ #endif
+
+ RtlZeroMemory(Object, size);
+
+ switch (type)
+ {
+ case otWindow:
+ case otHook:
+ case otInputContext:
+ ((PTHRDESKHEAD)Object)->rpdesk = rpdesk;
+ ((PTHRDESKHEAD)Object)->pSelf = Object;
+ case otEvent:
+ ((PTHROBJHEAD)Object)->pti = pti;
+ break;
+
+ case otMenu:
+ case otCallProc:
+ ((PPROCDESKHEAD)Object)->rpdesk = rpdesk;
+ ((PPROCDESKHEAD)Object)->pSelf = Object;
+ break;
+
+ case otCursorIcon:
+ ((PPROCMARKHEAD)Object)->ppi = ppi;
+ break;
+
+ default:
+ break;
+ }
+ /* Now set default headers. */
+ ((PHEAD)Object)->h = hi;
+ ((PHEAD)Object)->cLockObj = 2; // We need this, because we create 2 refs: handle and pointer!
+
+ if (h)
+ *h = hi;
+ return Object;
+ }
+
+
+ BOOL
+ FASTCALL
+ UserDereferenceObject(PVOID object)
+ {
+ PUSER_HANDLE_ENTRY entry;
+ USER_OBJECT_TYPE type;
+
+ ASSERT(((PHEAD)object)->cLockObj >= 1);
+
+ if ((INT)--((PHEAD)object)->cLockObj <= 0)
+ {
+ entry = handle_to_entry(gHandleTable, ((PHEAD)object)->h );
+
+ if (!entry)
+ {
+ ERR("Warning! Dereference Object without ENTRY! Obj -> 0x%x\n", object);
+ return FALSE;
+ }
+ TRACE("Warning! Dereference to zero! Obj -> 0x%x\n", object);
+
+ ((PHEAD)object)->cLockObj = 0;
+
+ if (!(entry->flags & HANDLEENTRY_INDESTROY))
+ return TRUE;
+
+ type = entry->type;
+ free_user_entry(gHandleTable, entry );
+
+ switch (type)
+ {
+ case otWindow:
+ // case otMenu:
+ case otHook:
+ case otCallProc:
+ case otInputContext:
+ return DesktopHeapFree(((PTHRDESKHEAD)object)->rpdesk, object);
+
+ default:
+ return UserHeapFree(object);
+ }
+ }
+ return FALSE;
+ }
+
+ BOOL
+ FASTCALL
+ UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
+ {
+ PUSER_HANDLE_ENTRY entry;
+
+ if (!(entry = handle_to_entry( ht, handle )))
+ {
+ SetLastNtError( STATUS_INVALID_HANDLE );
+ return FALSE;
+ }
+
+ entry->flags = HANDLEENTRY_INDESTROY;
+
+ return UserDereferenceObject(entry->ptr);
+ }
+
+ BOOL
+ FASTCALL
+ UserObjectInDestroy(HANDLE h)
+ {
+ PUSER_HANDLE_ENTRY entry;
+
+ if (!(entry = handle_to_entry( gHandleTable, h )))
+ {
+ SetLastNtError( STATUS_INVALID_HANDLE );
+ return FALSE;
+ }
+ return (entry->flags & HANDLEENTRY_INDESTROY);
+ }
+
+ BOOL
+ FASTCALL
+ UserDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
+ {
+ PVOID body = UserGetObject(gHandleTable, h, type);
+
+ if (!body) return FALSE;
+
+ ASSERT( ((PHEAD)body)->cLockObj >= 1);
+
+ return UserFreeHandle(gHandleTable, h);
+ }
+
+ VOID
+ FASTCALL
+ UserReferenceObject(PVOID obj)
+ {
+ ASSERT(((PHEAD)obj)->cLockObj >= 0);
+
+ ((PHEAD)obj)->cLockObj++;
+ }
+
+ PVOID
+ FASTCALL
+ UserReferenceObjectByHandle(HANDLE handle, USER_OBJECT_TYPE type)
+ {
+ PVOID object;
+
+ object = UserGetObject(gHandleTable, handle, type);
+ if (object)
+ {
+ UserReferenceObject(object);
+ }
+ return object;
+ }
+
++ VOID
++ FASTCALL
++ UserSetObjectOwner(PVOID obj, USER_OBJECT_TYPE type, PVOID owner)
++ {
++ PUSER_HANDLE_ENTRY entry = handle_to_entry(gHandleTable, ((PHEAD)obj)->h );
++ PPROCESSINFO ppi, oldppi;
++
++ /* This must be called with a valid object */
++ ASSERT(entry);
++
++ /* For now, only supported for CursorIcon object */
++ switch(type)
++ {
++ case otCursorIcon:
++ ppi = (PPROCESSINFO)owner;
++ entry->pi = ppi;
++ oldppi = ((PPROCMARKHEAD)obj)->ppi;
++ ((PPROCMARKHEAD)obj)->ppi = ppi;
++ break;
++ default:
++ ASSERT(FALSE);
++ return;
++ }
++
++ oldppi->UserHandleCount--;
++ ppi->UserHandleCount++;
++ #if DBG
++ oldppi->DbgHandleCount[type]--;
++ ppi->DbgHandleCount[type]++;
++ #endif
++ }
++
+ /*
+ * NtUserValidateHandleSecure
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL
+ APIENTRY
+ NtUserValidateHandleSecure(
+ HANDLE handle,
+ BOOL Restricted)
+ {
+ if(!Restricted)
+ {
+ UINT uType;
+ {
+ PUSER_HANDLE_ENTRY entry;
+ if (!(entry = handle_to_entry(gHandleTable, handle )))
+ {
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ uType = entry->type;
+ }
+ switch (uType)
+ {
+ case otWindow:
+ {
+ if (UserGetWindowObject((HWND) handle)) return TRUE;
+ return FALSE;
+ }
+ case otMenu:
+ {
+ if (UserGetMenuObject((HMENU) handle)) return TRUE;
+ return FALSE;
+ }
+ case otAccel:
+ {
+ if (UserGetAccelObject((HACCEL) handle)) return TRUE;
+ return FALSE;
+ }
+ case otCursorIcon:
+ {
+ if (UserGetCurIconObject((HCURSOR) handle)) return TRUE;
+ return FALSE;
+ }
+ case otHook:
+ {
+ if (IntGetHookObject((HHOOK) handle)) return TRUE;
+ return FALSE;
+ }
+ case otMonitor:
+ {
+ if (UserGetMonitorObject((HMONITOR) handle)) return TRUE;
+ return FALSE;
+ }
+ case otCallProc:
+ {
+ WNDPROC_INFO Proc;
+ return UserGetCallProcInfo( handle, &Proc );
+ }
+ default:
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ }
+ }
+ else
+ { /* Is handle entry restricted? */
+ STUB
+ }
+ return FALSE;
+ }
--- /dev/null
+ #pragma once
+
+ typedef struct _USER_REFERENCE_ENTRY
+ {
+ SINGLE_LIST_ENTRY Entry;
+ PVOID obj;
+ } USER_REFERENCE_ENTRY, *PUSER_REFERENCE_ENTRY;
+
+ #define USER_ASSERT(exp,file,line) \
+ if (!(exp)) {RtlAssert(#exp,(PVOID)file,line,"");}
+
+ static __inline VOID
+ UserAssertLastRef(PVOID obj, const char *file, int line)
+ {
+ PTHREADINFO W32Thread;
+ PSINGLE_LIST_ENTRY ReferenceEntry;
+ PUSER_REFERENCE_ENTRY UserReferenceEntry;
+
+ USER_ASSERT(obj != NULL, file, line);
+ W32Thread = PsGetCurrentThreadWin32Thread();
+ USER_ASSERT(W32Thread != NULL, file, line);
+ ReferenceEntry = W32Thread->ReferencesList.Next;
+ USER_ASSERT(ReferenceEntry != NULL, file, line);
+ UserReferenceEntry = CONTAINING_RECORD(ReferenceEntry, USER_REFERENCE_ENTRY, Entry);
+ USER_ASSERT(UserReferenceEntry != NULL, file, line);
+ USER_ASSERT(obj == UserReferenceEntry->obj, file, line);
+ }
+ #define ASSERT_LAST_REF(_obj_) UserAssertLastRef(_obj,__FILE__,__LINE__)
+
+ #undef USER_ASSERT
+
+ extern PUSER_HANDLE_TABLE gHandleTable;
+ VOID FASTCALL UserReferenceObject(PVOID obj);
+ PVOID FASTCALL UserReferenceObjectByHandle(HANDLE handle, USER_OBJECT_TYPE type);
+ BOOL FASTCALL UserDereferenceObject(PVOID obj);
+ PVOID FASTCALL UserCreateObject(PUSER_HANDLE_TABLE ht, struct _DESKTOP* pDesktop, PTHREADINFO pti, HANDLE* h,USER_OBJECT_TYPE type , ULONG size);
+ BOOL FASTCALL UserDeleteObject(HANDLE h, USER_OBJECT_TYPE type );
+ PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type );
+ PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE, HANDLE, USER_OBJECT_TYPE);
+ BOOL FASTCALL UserCreateHandleTable(VOID);
+ BOOL FASTCALL UserObjectInDestroy(HANDLE);
+ void DbgUserDumpHandleTable();
++ VOID FASTCALL UserSetObjectOwner(PVOID obj, USER_OBJECT_TYPE type, PVOID owner);
+
+ static __inline VOID
+ UserRefObjectCo(PVOID obj, PUSER_REFERENCE_ENTRY UserReferenceEntry)
+ {
+ PTHREADINFO W32Thread;
+
+ W32Thread = PsGetCurrentThreadWin32Thread();
+ ASSERT(W32Thread != NULL);
+ ASSERT(UserReferenceEntry != NULL);
+ UserReferenceEntry->obj = obj;
+ UserReferenceObject(obj);
+ PushEntryList(&W32Thread->ReferencesList, &UserReferenceEntry->Entry);
+ }
+
+ static __inline VOID
+ UserDerefObjectCo(PVOID obj)
+ {
+ PTHREADINFO W32Thread;
+ PSINGLE_LIST_ENTRY ReferenceEntry;
+ PUSER_REFERENCE_ENTRY UserReferenceEntry;
+
+ ASSERT(obj != NULL);
+ W32Thread = PsGetCurrentThreadWin32Thread();
+ ASSERT(W32Thread != NULL);
+ ReferenceEntry = PopEntryList(&W32Thread->ReferencesList);
+ ASSERT(ReferenceEntry != NULL);
+ UserReferenceEntry = CONTAINING_RECORD(ReferenceEntry, USER_REFERENCE_ENTRY, Entry);
+ ASSERT(UserReferenceEntry != NULL);
+
+ ASSERT(obj == UserReferenceEntry->obj);
+ UserDereferenceObject(obj);
+ }
+
+ /* EOF */
--- /dev/null
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Window painting function
+ * FILE: subsystems/win32/win32k/ntuser/painting.c
+ * PROGRAMER: Filip Navara (xnavara@volny.cz)
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserPainting);
+
+ /* PRIVATE FUNCTIONS **********************************************************/
+
+ /**
+ * @name IntIntersectWithParents
+ *
+ * Intersect window rectangle with all parent client rectangles.
+ *
+ * @param Child
+ * Pointer to child window to start intersecting from.
+ * @param WindowRect
+ * Pointer to rectangle that we want to intersect in screen
+ * coordinates on input and intersected rectangle on output (if TRUE
+ * is returned).
+ *
+ * @return
+ * If any parent is minimized or invisible or the resulting rectangle
+ * is empty then FALSE is returned. Otherwise TRUE is returned.
+ */
+
+ BOOL FASTCALL
+ IntIntersectWithParents(PWND Child, RECTL *WindowRect)
+ {
+ PWND ParentWnd;
+
+ ParentWnd = Child->spwndParent;
+ while (ParentWnd != NULL)
+ {
+ if (!(ParentWnd->style & WS_VISIBLE) ||
+ (ParentWnd->style & WS_MINIMIZE))
+ {
+ return FALSE;
+ }
+
+ if (!RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient))
+ {
+ return FALSE;
+ }
+
+ /* FIXME: Layered windows. */
+
+ ParentWnd = ParentWnd->spwndParent;
+ }
+
+ return TRUE;
+ }
+
+ BOOL FASTCALL
+ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
+ {
+ PWND ParentWnd = Child;
+
+ if (ParentWnd->style & WS_CHILD)
+ {
+ do
+ ParentWnd = ParentWnd->spwndParent;
+ while (ParentWnd->style & WS_CHILD);
+ }
+ // Hax out for drawing issues.
+ // if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
+
+ ParentWnd = Child->spwndParent;
+ while (ParentWnd)
+ {
+ if (ParentWnd->style & WS_CLIPCHILDREN)
+ break;
+
+ if (ParentWnd->hrgnUpdate != 0)
+ {
+ if (Recurse)
+ return FALSE;
+
+ IntInvalidateWindows( ParentWnd,
+ hValidateRgn,
+ RDW_VALIDATE | RDW_NOCHILDREN);
+ }
+
+ ParentWnd = ParentWnd->spwndParent;
+ }
+
+ return TRUE;
+ }
+
+ /*
+ Synchronize painting to the top-level windows of other threads.
+ */
+ VOID FASTCALL
+ IntSendSyncPaint(PWND Wnd, ULONG Flags)
+ {
+ PTHREADINFO ptiCur;
+ PUSER_MESSAGE_QUEUE MessageQueue;
+ PUSER_SENT_MESSAGE Message;
+ PLIST_ENTRY Entry;
+ BOOL bSend = TRUE;
+
+ MessageQueue = Wnd->head.pti->MessageQueue;
+ ptiCur = PsGetCurrentThreadWin32Thread();
+ /*
+ Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
+ */
+ if ( Wnd->head.pti != ptiCur &&
+ Wnd->state & WNDS_SENDNCPAINT &&
+ Wnd->state & WNDS_SENDERASEBACKGROUND &&
+ Wnd->style & WS_VISIBLE)
+ {
+ // For testing, if you see this, break out the Champagne and have a party!
+ ERR("SendSyncPaint Wnd in State!\n");
+ if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
+ {
+ // Scan sent queue messages to see if we received sync paint messages.
+ Entry = MessageQueue->SentMessagesListHead.Flink;
+ Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+ do
+ {
+ ERR("LOOP it\n");
+ if (Message->Msg.message == WM_SYNCPAINT &&
+ Message->Msg.hwnd == UserHMGetHandle(Wnd))
+ { // Already received so exit out.
+ ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
+ bSend = FALSE;
+ break;
+ }
+ Entry = Message->ListEntry.Flink;
+ Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+ }
+ while (Entry != &MessageQueue->SentMessagesListHead);
+ }
+ if (bSend)
+ {
+ ERR("Sending WM_SYNCPAINT\n");
+ // This message has no parameters. But it does! Pass Flags along.
+ co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SYNCPAINT, Flags, 0);
+ Wnd->state |= WNDS_SYNCPAINTPENDING;
+ }
+ }
+
+ // Send to all the children if this is the desktop window.
+ if ( Wnd == UserGetDesktopWindow() )
+ {
+ if ( Flags & RDW_ALLCHILDREN ||
+ ( !(Flags & RDW_NOCHILDREN) && Wnd->style & WS_CLIPCHILDREN))
+ {
+ PWND spwndChild = Wnd->spwndChild;
+ while(spwndChild)
+ {
+ if ( spwndChild->style & WS_CHILD &&
+ spwndChild->head.pti != ptiCur)
+ {
+ spwndChild = spwndChild->spwndNext;
+ continue;
+ }
+ IntSendSyncPaint( spwndChild, Flags );
+ spwndChild = spwndChild->spwndNext;
+ }
+ }
+ }
+ }
+
+ /**
+ * @name IntCalcWindowRgn
+ *
+ * Get a window or client region.
+ */
+
+ HRGN FASTCALL
+ IntCalcWindowRgn(PWND Wnd, BOOL Client)
+ {
+ HRGN hRgnWindow;
+
+ if (Client)
+ hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
+ else
+ hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
+
+ if (Wnd->hrgnClip != NULL && !(Wnd->style & WS_MINIMIZE))
+ {
+ NtGdiOffsetRgn(hRgnWindow,
+ -Wnd->rcWindow.left,
+ -Wnd->rcWindow.top);
+ NtGdiCombineRgn(hRgnWindow, hRgnWindow, Wnd->hrgnClip, RGN_AND);
+ NtGdiOffsetRgn(hRgnWindow,
+ Wnd->rcWindow.left,
+ Wnd->rcWindow.top);
+ }
+
+ return hRgnWindow;
+ }
+
+ /**
+ * @name IntGetNCUpdateRgn
+ *
+ * Get non-client update region of a window and optionally validate it.
+ *
+ * @param Window
+ * Pointer to window to get the NC update region from.
+ * @param Validate
+ * Set to TRUE to force validating the NC update region.
+ *
+ * @return
+ * Handle to NC update region. The caller is responsible for deleting
+ * it.
+ */
+
+ HRGN FASTCALL
+ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
+ {
+ HRGN hRgnNonClient;
+ HRGN hRgnWindow;
+ UINT RgnType;
+
+ if (Window->hrgnUpdate != NULL &&
+ Window->hrgnUpdate != HRGN_WINDOW)
+ {
+ hRgnNonClient = IntCalcWindowRgn(Window, FALSE);
+
+ /*
+ * If region creation fails it's safe to fallback to whole
+ * window region.
+ */
+ if (hRgnNonClient == NULL)
+ {
+ return HRGN_WINDOW;
+ }
+
+ hRgnWindow = IntCalcWindowRgn(Window, TRUE);
+ if (hRgnWindow == NULL)
+ {
+ GreDeleteObject(hRgnNonClient);
+ return HRGN_WINDOW;
+ }
+
+ RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient,
+ hRgnWindow, RGN_DIFF);
+ if (RgnType == ERROR)
+ {
+ GreDeleteObject(hRgnWindow);
+ GreDeleteObject(hRgnNonClient);
+ return HRGN_WINDOW;
+ }
+ else if (RgnType == NULLREGION)
+ {
+ GreDeleteObject(hRgnWindow);
+ GreDeleteObject(hRgnNonClient);
+ Window->state &= ~WNDS_UPDATEDIRTY;
+ return NULL;
+ }
+
+ /*
+ * Remove the nonclient region from the standard update region if
+ * we were asked for it.
+ */
+
+ if (Validate)
+ {
+ if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate,
+ hRgnWindow, RGN_AND) == NULLREGION)
+ {
+ IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Window->hrgnUpdate);
+ Window->state &= ~WNDS_UPDATEDIRTY;
+ Window->hrgnUpdate = NULL;
+ if (!(Window->state & WNDS_INTERNALPAINT))
+ MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+ }
+ }
+
+ GreDeleteObject(hRgnWindow);
+
+ return hRgnNonClient;
+ }
+ else
+ {
+ return Window->hrgnUpdate;
+ }
+ }
+
+ /*
+ * IntPaintWindows
+ *
+ * Internal function used by IntRedrawWindow.
+ */
+
+ VOID FASTCALL
+ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
+ {
+ HDC hDC;
+ HWND hWnd = Wnd->head.h;
+ HRGN TempRegion;
+
+ Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
+
+ if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+ {
+ if (Wnd->hrgnUpdate)
+ {
+ if (!IntValidateParent(Wnd, Wnd->hrgnUpdate, Recurse))
+ return;
+ }
+
+ if (Flags & RDW_UPDATENOW)
+ {
+ if ((Wnd->hrgnUpdate != NULL ||
+ Wnd->state & WNDS_INTERNALPAINT))
+ {
+ Wnd->state2 |= WNDS2_WMPAINTSENT;
+ co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
+ }
+ }
+ else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
+ {
+ if (Wnd->state & WNDS_SENDNCPAINT)
+ {
+ TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
+ Wnd->state &= ~WNDS_SENDNCPAINT;
+ if ( Wnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
+ !(Wnd->state & WNDS_ACTIVEFRAME))
+ {
+ Wnd->state |= WNDS_ACTIVEFRAME;
+ Wnd->state &= ~WNDS_NONCPAINT;
+ }
+ if (TempRegion) co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
+ }
+
+ if (Wnd->state & WNDS_SENDERASEBACKGROUND)
+ {
+ if (Wnd->hrgnUpdate)
+ {
+ hDC = UserGetDCEx( Wnd,
+ Wnd->hrgnUpdate,
+ DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
+
+ Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ // Kill the loop, so Clear before we send.
+ if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
+ {
+ Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ }
+ UserReleaseDC(Wnd, hDC, FALSE);
+ }
+ }
+ }
+ }
+ else
+ {
+ Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ }
+
+ /*
+ * Check that the window is still valid at this point
+ */
+ if (!IntIsWindow(hWnd))
+ {
+ return;
+ }
+
+ /*
+ * Paint child windows.
+ */
+ if (!(Flags & RDW_NOCHILDREN) &&
+ !(Wnd->style & WS_MINIMIZE) &&
+ ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)) )
+ {
+ HWND *List, *phWnd;
+
+ if ((List = IntWinListChildren(Wnd)))
+ {
+ /* FIXME: Handle WS_EX_TRANSPARENT */
+ for (phWnd = List; *phWnd; ++phWnd)
+ {
+ Wnd = UserGetWindowObject(*phWnd);
+ if (Wnd && (Wnd->style & WS_VISIBLE))
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Wnd, &Ref);
+ co_IntPaintWindows(Wnd, Flags, TRUE);
+ UserDerefObjectCo(Wnd);
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ }
+ }
+
+ /*
+ * IntInvalidateWindows
+ *
+ * Internal function used by IntRedrawWindow, UserRedrawDesktop,
+ * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
+ */
+ VOID FASTCALL
+ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
+ {
+ INT RgnType;
+ BOOL HadPaintMessage;
+
+ TRACE("IntInvalidateWindows start\n");
+
+ Wnd->state |= WNDS_PAINTNOTPROCESSED;
+
+ /*
+ * If the nonclient is not to be redrawn, clip the region to the client
+ * rect
+ */
+ if (0 != (Flags & RDW_INVALIDATE) && 0 == (Flags & RDW_FRAME))
+ {
+ HRGN hRgnClient;
+
+ hRgnClient = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
+ RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnClient, RGN_AND);
+ GreDeleteObject(hRgnClient);
+ }
+
+ /*
+ * Clip the given region with window rectangle (or region)
+ */
+
+ if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
+ {
+ HRGN hRgnWindow;
+
+ hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
+ RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
+ GreDeleteObject(hRgnWindow);
+ }
+ else
+ {
+ NtGdiOffsetRgn( hRgn,
+ -Wnd->rcWindow.left,
+ -Wnd->rcWindow.top);
+ RgnType = NtGdiCombineRgn(hRgn, hRgn, Wnd->hrgnClip, RGN_AND);
+ NtGdiOffsetRgn( hRgn,
+ Wnd->rcWindow.left,
+ Wnd->rcWindow.top);
+ }
+
+ /*
+ * Save current state of pending updates
+ */
+
+ HadPaintMessage = IntIsWindowDirty(Wnd);
+
+ /*
+ * Update the region and flags
+ */
+
+ // The following flags are used to invalidate the window.
+ if (Flags & (RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_ERASE|RDW_FRAME))
+ {
+ if (Flags & RDW_INTERNALPAINT)
+ {
+ Wnd->state |= WNDS_INTERNALPAINT;
+ }
+
+ if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
+ {
+ Wnd->state &= ~WNDS_NONCPAINT;
+
+ /* If not the same thread set it dirty. */
+ if (Wnd->head.pti != PsGetCurrentThreadWin32Thread())
+ {
+ Wnd->state |= WNDS_UPDATEDIRTY;
+ if (Wnd->state2 & WNDS2_WMPAINTSENT)
+ Wnd->state2 |= WNDS2_ENDPAINTINVALIDATE;
+ }
+
+ if (Flags & RDW_FRAME)
+ Wnd->state |= WNDS_SENDNCPAINT;
+ if (Flags & RDW_ERASE)
+ Wnd->state |= WNDS_SENDERASEBACKGROUND;
+
+ if (Wnd->hrgnUpdate == NULL)
+ {
+ Wnd->hrgnUpdate = IntSysCreateRectRgn(0, 0, 0, 0);
+ IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
+ }
+
+ if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
+ hRgn, RGN_OR) == NULLREGION)
+ {
+ IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Wnd->hrgnUpdate);
+ Wnd->hrgnUpdate = NULL;
+ }
+ Flags |= RDW_FRAME; // For children.
+ }
+ } // The following flags are used to validate the window.
+ else if (Flags & (RDW_VALIDATE|RDW_NOINTERNALPAINT|RDW_NOERASE|RDW_NOFRAME))
+ {
+ /* FIXME: Handle WNDS_UPDATEDIRTY */
+
+ if (Flags & RDW_NOINTERNALPAINT)
+ {
+ Wnd->state &= ~WNDS_INTERNALPAINT;
+ }
+
+ if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
+ {
+ if (Flags & RDW_NOFRAME)
+ Wnd->state &= ~WNDS_SENDNCPAINT;
+ if (Flags & RDW_NOERASE)
+ Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+
+ if (Wnd->hrgnUpdate != NULL)
+ {
+ if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
+ hRgn, RGN_DIFF) == NULLREGION)
+ {
+ IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Wnd->hrgnUpdate);
+ Wnd->hrgnUpdate = NULL;
+ }
+ }
+
+ if (Wnd->hrgnUpdate == NULL)
+ Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ }
+ }
+
+ /*
+ * Process children if needed
+ */
+
+ if (!(Flags & RDW_NOCHILDREN) && !(Wnd->style & WS_MINIMIZE) &&
+ ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)))
+ {
+ PWND Child;
+
+ for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
+ {
+ if (Child->style & WS_VISIBLE)
+ {
+ /*
+ * Recursive call to update children hrgnUpdate
+ */
+ HRGN hRgnTemp = IntSysCreateRectRgn(0, 0, 0, 0);
+ NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
+ IntInvalidateWindows(Child, hRgnTemp, Flags);
+ GreDeleteObject(hRgnTemp);
+ }
+ }
+ }
+
+ /*
+ * Fake post paint messages to window message queue if needed
+ */
+
+ if (HadPaintMessage != IntIsWindowDirty(Wnd))
+ {
+ if (HadPaintMessage)
+ MsqDecPaintCountQueue(Wnd->head.pti->MessageQueue);
+ else
+ MsqIncPaintCountQueue(Wnd->head.pti->MessageQueue);
+ }
+ TRACE("IntInvalidateWindows exit\n");
+ }
+
+ /*
+ * IntIsWindowDrawable
+ *
+ * Remarks
+ * Window is drawable when it is visible and all parents are not
+ * minimized.
+ */
+
+ BOOL FASTCALL
+ IntIsWindowDrawable(PWND Wnd)
+ {
+ PWND WndObject;
+
+ for (WndObject = Wnd; WndObject != NULL; WndObject = WndObject->spwndParent)
+ {
+ if ( WndObject->state2 & WNDS2_INDESTROY ||
+ WndObject->state & WNDS_DESTROYED ||
+ !WndObject ||
+ !(WndObject->style & WS_VISIBLE) ||
+ ((WndObject->style & WS_MINIMIZE) && (WndObject != Wnd)))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ /*
+ * IntRedrawWindow
+ *
+ * Internal version of NtUserRedrawWindow that takes WND as
+ * first parameter.
+ */
+
+ BOOL FASTCALL
+ co_UserRedrawWindow(
+ PWND Window,
+ const RECTL* UpdateRect,
+ HRGN UpdateRgn,
+ ULONG Flags)
+ {
+ HRGN hRgn = NULL;
+ TRACE("co_UserRedrawWindow start\n");
+
+ /*
+ * Step 1.
+ * Validation of passed parameters.
+ */
+
+ if (!IntIsWindowDrawable(Window))
+ {
+ return TRUE; // Just do nothing!!!
+ }
+
+ /*
+ * Step 2.
+ * Transform the parameters UpdateRgn and UpdateRect into
+ * a region hRgn specified in screen coordinates.
+ */
+
+ if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY!
+ {
+ if (UpdateRgn != NULL)
+ {
+ hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
+ if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+ {
+ GreDeleteObject(hRgn);
+ hRgn = NULL;
+ }
+ else
+ NtGdiOffsetRgn(hRgn, Window->rcClient.left, Window->rcClient.top);
+ }
+ else if (UpdateRect != NULL)
+ {
+ if (!RECTL_bIsEmptyRect(UpdateRect))
+ {
+ hRgn = IntSysCreateRectRgnIndirect((RECTL *)UpdateRect);
+ NtGdiOffsetRgn(hRgn, Window->rcClient.left, Window->rcClient.top);
+ }
+ }
+ else if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
+ (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
+ {
+ if (!RECTL_bIsEmptyRect(&Window->rcWindow))
+ hRgn = IntSysCreateRectRgnIndirect(&Window->rcWindow);
+ }
+ else
+ {
+ if (!RECTL_bIsEmptyRect(&Window->rcClient))
+ hRgn = IntSysCreateRectRgnIndirect(&Window->rcClient);
+ }
+ }
+
+ /*
+ * Step 3.
+ * Adjust the window update region depending on hRgn and flags.
+ */
+
+ if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
+ hRgn != NULL)
+ {
+ IntInvalidateWindows(Window, hRgn, Flags);
+ }
+
+ /*
+ * Step 4.
+ * Repaint and erase windows if needed.
+ */
+
+ if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+ {
+ if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags);
+ co_IntPaintWindows(Window, Flags, FALSE);
+ }
+
+ /*
+ * Step 5.
+ * Cleanup ;-)
+ */
+
+ if (hRgn != NULL)
+ {
+ GreDeleteObject(hRgn);
+ }
+ TRACE("co_UserRedrawWindow exit\n");
+
+ return TRUE;
+ }
+
+ BOOL FASTCALL
+ IntIsWindowDirty(PWND Wnd)
+ {
+ return ( Wnd->style & WS_VISIBLE &&
+ ( Wnd->hrgnUpdate != NULL ||
+ Wnd->state & WNDS_INTERNALPAINT ) );
+ }
+
+ PWND FASTCALL
+ IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
+ {
+ PWND hChild;
+ PWND TempWindow;
+
+ for (; Window != NULL; Window = Window->spwndNext)
+ {
+ if (IntWndBelongsToThread(Window, Thread) &&
+ IntIsWindowDirty(Window))
+ {
+ /* Make sure all non-transparent siblings are already drawn. */
+ if (Window->ExStyle & WS_EX_TRANSPARENT)
+ {
+ for (TempWindow = Window->spwndNext; TempWindow != NULL;
+ TempWindow = TempWindow->spwndNext)
+ {
+ if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
+ IntWndBelongsToThread(TempWindow, Thread) &&
+ IntIsWindowDirty(TempWindow))
+ {
+ return TempWindow;
+ }
+ }
+ }
+
+ return Window;
+ }
+
+ if (Window->spwndChild)
+ {
+ hChild = IntFindWindowToRepaint(Window->spwndChild, Thread);
+ if (hChild != NULL)
+ return hChild;
+ }
+ }
+ return Window;
+ }
+
+ BOOL FASTCALL
+ IntGetPaintMessage(
+ PWND Window,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ PTHREADINFO Thread,
+ MSG *Message,
+ BOOL Remove)
+ {
+ PWND PaintWnd;
+
+ if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
+ (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
+ return FALSE;
+
+ if (Thread->TIF_flags & TIF_SYSTEMTHREAD )
+ {
+ ERR("WM_PAINT is in a System Thread!\n");
+ }
+
+ PaintWnd = IntFindWindowToRepaint(UserGetDesktopWindow(), Thread);
+
+ Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL;
+
+ if (Message->hwnd == NULL)
+ {
+ ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %d\n",Thread->cPaintsReady);
+ /* Hack to stop spamming the debuglog ! */
+ Thread->cPaintsReady = 0;
+ return FALSE;
+ }
+
+ if (Window != NULL && PaintWnd != Window)
+ return FALSE;
+
+ if (PaintWnd->state & WNDS_INTERNALPAINT)
+ {
+ PaintWnd->state &= ~WNDS_INTERNALPAINT;
+ if (!PaintWnd->hrgnUpdate)
+ MsqDecPaintCountQueue(Thread->MessageQueue);
+ }
+ PaintWnd->state2 &= ~WNDS2_WMPAINTSENT;
+ PaintWnd->state &= ~WNDS_UPDATEDIRTY;
+ Message->wParam = Message->lParam = 0;
+ Message->message = WM_PAINT;
+ return TRUE;
+ }
+
+ static
+ HWND FASTCALL
+ co_IntFixCaret(PWND Window, RECTL *lprc, UINT flags)
+ {
+ PDESKTOP Desktop;
+ PTHRDCARETINFO CaretInfo;
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE ActiveMessageQueue;
+ HWND hWndCaret;
+ PWND WndCaret;
+
+ ASSERT_REFS_CO(Window);
+
+ pti = PsGetCurrentThreadWin32Thread();
+ Desktop = pti->rpdesk;
+ ActiveMessageQueue = Desktop->ActiveMessageQueue;
+ if (!ActiveMessageQueue) return 0;
+ CaretInfo = ActiveMessageQueue->CaretInfo;
+ hWndCaret = CaretInfo->hWnd;
+
+ WndCaret = ValidateHwndNoErr(hWndCaret);
+
+ // FIXME: Check for WndCaret can be NULL
+ if (WndCaret == Window ||
+ ((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(Window, WndCaret)))
+ {
+ POINT pt, FromOffset, ToOffset;
+ RECTL rcCaret;
+
+ pt.x = CaretInfo->Pos.x;
+ pt.y = CaretInfo->Pos.y;
+ IntGetClientOrigin(WndCaret, &FromOffset);
+ IntGetClientOrigin(Window, &ToOffset);
+ rcCaret.left = pt.x;
+ rcCaret.top = pt.y;
+ rcCaret.right = pt.x + CaretInfo->Size.cx;
+ rcCaret.bottom = pt.y + CaretInfo->Size.cy;
+ if (RECTL_bIntersectRect(lprc, lprc, &rcCaret))
+ {
+ co_UserHideCaret(0);
+ lprc->left = pt.x;
+ lprc->top = pt.y;
+ return hWndCaret;
+ }
+ }
+
+ return 0;
+ }
+
+ BOOL
+ FASTCALL
+ IntPrintWindow(
+ PWND pwnd,
+ HDC hdcBlt,
+ UINT nFlags)
+ {
+ HDC hdcSrc;
+ INT cx, cy, xSrc, ySrc;
+
+ if ( nFlags & PW_CLIENTONLY)
+ {
+ cx = pwnd->rcClient.right - pwnd->rcClient.left;
+ cy = pwnd->rcClient.bottom - pwnd->rcClient.top;
+ xSrc = pwnd->rcClient.left - pwnd->rcWindow.left;
+ ySrc = pwnd->rcClient.top - pwnd->rcWindow.top;
+ }
+ else
+ {
+ cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
+ cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
+ xSrc = 0;
+ ySrc = 0;
+ }
+
+ // TODO: Setup Redirection for Print.
+ return FALSE;
+
+ /* Update the window just incase. */
+ co_IntPaintWindows( pwnd, RDW_ERASENOW|RDW_UPDATENOW, FALSE);
+
+ hdcSrc = UserGetDCEx( pwnd, NULL, DCX_CACHE|DCX_WINDOW);
+ /* Print window to printer context. */
+ NtGdiBitBlt( hdcBlt,
+ 0,
+ 0,
+ cx,
+ cy,
+ hdcSrc,
+ xSrc,
+ ySrc,
+ SRCCOPY,
+ 0,
+ 0);
+
+ UserReleaseDC( pwnd, hdcSrc, FALSE);
+
+ // TODO: Release Redirection from Print.
+
+ return TRUE;
+ }
+
+ BOOL
+ FASTCALL
+ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
+ {
+ PPROPERTY pprop;
+ DWORD FlashState;
+ BOOL Ret = FALSE;
+
+ pprop = IntGetProp(pWnd, AtomFlashWndState);
+ if (!pprop)
+ {
+ FlashState = pfwi->dwFlags;
+ IntSetProp(pWnd, AtomFlashWndState, (HANDLE) FlashState);
+ return TRUE;
+ }
+
+ FlashState = (DWORD)pprop->Data;
+ if ( pfwi->dwFlags == FLASHW_STOP )
+ {
+ IntRemoveProp(pWnd, AtomFlashWndState);
+ Ret = TRUE;
+ }
+ return Ret;
+ }
+
+ HDC FASTCALL
+ IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
+ {
+ co_UserHideCaret(Window);
+
+ Window->state2 |= WNDS2_STARTPAINT;
+ Window->state &= ~WNDS_PAINTNOTPROCESSED;
+
+ if (Window->state & WNDS_SENDNCPAINT)
+ {
+ HRGN hRgn;
+
+ Window->state &= ~WNDS_UPDATEDIRTY;
+ hRgn = IntGetNCUpdateRgn(Window, FALSE);
+ Window->state &= ~WNDS_SENDNCPAINT;
+ co_IntSendMessage(UserHMGetHandle(Window), WM_NCPAINT, (WPARAM)hRgn, 0);
+ if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn))
+ {
+ /* NOTE: The region can already be deleted! */
+ GreDeleteObject(hRgn);
+ }
+ }
+ else
+ {
+ Window->state &= ~WNDS_UPDATEDIRTY;
+ }
+
+ RtlZeroMemory(Ps, sizeof(PAINTSTRUCT));
+
+ Ps->hdc = UserGetDCEx( Window,
+ Window->hrgnUpdate,
+ DCX_INTERSECTRGN | DCX_USESTYLE);
+ if (!Ps->hdc)
+ {
+ return NULL;
+ }
+
+ if (Window->hrgnUpdate != NULL)
+ {
+ MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+ GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
+ IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+ /* The region is part of the dc now and belongs to the process! */
+ Window->hrgnUpdate = NULL;
+ }
+ else
+ {
+ if (Window->state & WNDS_INTERNALPAINT)
+ MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+
+ IntGetClientRect(Window, &Ps->rcPaint);
+ }
+
+ Window->state &= ~WNDS_INTERNALPAINT;
+
+ if (Window->state & WNDS_SENDERASEBACKGROUND)
+ {
+ Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0);
+ if ( Ps->fErase )
+ {
+ Window->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+ }
+ }
+ else
+ {
+ Ps->fErase = FALSE;
+ }
+ if (Window->hrgnUpdate)
+ {
+ if (!(Window->style & WS_CLIPCHILDREN))
+ {
+ PWND Child;
+ for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
+ {
+ if (Child->hrgnUpdate == NULL && Child->state & WNDS_SENDNCPAINT) // Helped fixing test_redrawnow.
+ IntInvalidateWindows(Child, Window->hrgnUpdate, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ }
+ }
+ }
+ return Ps->hdc;
+ }
+
+ BOOL FASTCALL
+ IntEndPaint(PWND Wnd, PPAINTSTRUCT Ps)
+ {
+ HDC hdc = NULL;
+
+ hdc = Ps->hdc;
+
+ UserReleaseDC(Wnd, hdc, TRUE);
+
+ Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT);
+
+ co_UserShowCaret(Wnd);
+
+ return TRUE;
+ }
+
+ /* PUBLIC FUNCTIONS ***********************************************************/
+
+ /*
+ * NtUserBeginPaint
+ *
+ * Status
+ * @implemented
+ */
+
+ HDC APIENTRY
+ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
+ {
+ PWND Window = NULL;
+ PAINTSTRUCT Ps;
+ NTSTATUS Status;
+ HDC hDC;
+ USER_REFERENCE_ENTRY Ref;
+ DECLARE_RETURN(HDC);
+
+ TRACE("Enter NtUserBeginPaint\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN( NULL);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ hDC = IntBeginPaint(Window, &Ps);
+
+ Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(NULL);
+ }
+
+ RETURN(hDC);
+
+ CLEANUP:
+ if (Window) UserDerefObjectCo(Window);
+
+ TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+
+ }
+
+ /*
+ * NtUserEndPaint
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL APIENTRY
+ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs)
+ {
+ NTSTATUS Status = STATUS_SUCCESS;
+ PWND Window = NULL;
+ PAINTSTRUCT Ps;
+ USER_REFERENCE_ENTRY Ref;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserEndPaint\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(FALSE);
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pUnsafePs, sizeof(*pUnsafePs), 1);
+ RtlCopyMemory(&Ps, pUnsafePs, sizeof(PAINTSTRUCT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ RETURN(FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ RETURN(IntEndPaint(Window, &Ps));
+
+ CLEANUP:
+ if (Window) UserDerefObjectCo(Window);
+
+ TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ /*
+ * @implemented
+ */
+ BOOL APIENTRY
+ NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
+ {
+ PWND pWnd;
+ FLASHWINFO finfo = {0};
+ BOOL Ret = TRUE;
+
+ UserEnterExclusive();
+
+ _SEH2_TRY
+ {
+ ProbeForRead(pfwi, sizeof(FLASHWINFO), sizeof(ULONG));
+ RtlCopyMemory(&finfo, pfwi, sizeof(FLASHWINFO));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Ret = FALSE;
+ }
+ _SEH2_END
+
+ if (!Ret) goto Exit;
+
+ if (!( pWnd = (PWND)UserGetObject(gHandleTable, finfo.hwnd, otWindow)) ||
+ finfo.cbSize != sizeof(FLASHWINFO) ||
+ finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) )
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ Ret = FALSE;
+ goto Exit;
+ }
+
+ Ret = IntFlashWindowEx(pWnd, &finfo);
+
+ Exit:
+ UserLeave();
+ return Ret;
+ }
+
+ INT FASTCALL
+ co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase)
+ {
+ int RegionType;
+ RECTL Rect;
+
+ ASSERT_REFS_CO(Window);
+
+ Window->state &= ~WNDS_UPDATEDIRTY;
+
+ if (Window->hrgnUpdate == NULL)
+ {
+ RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
+ }
+ else
+ {
+ Rect = Window->rcClient;
+ IntIntersectWithParents(Window, &Rect);
+ NtGdiSetRectRgn(hRgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
+ RegionType = NtGdiCombineRgn(hRgn, hRgn, Window->hrgnUpdate, RGN_AND);
+ NtGdiOffsetRgn(hRgn, -Window->rcClient.left, -Window->rcClient.top);
+ }
+
+ if (bErase && RegionType != NULLREGION && RegionType != ERROR)
+ {
+ co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
+ }
+
+ return RegionType;
+ }
+
+ /*
+ * NtUserGetUpdateRgn
+ *
+ * Status
+ * @implemented
+ */
+
+ INT APIENTRY
+ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
+ {
+ DECLARE_RETURN(INT);
+ PWND Window;
+ INT ret;
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserGetUpdateRgn\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(ERROR);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+ ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
+ UserDerefObjectCo(Window);
+
+ RETURN(ret);
+
+ CLEANUP:
+ TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ /*
+ * NtUserGetUpdateRect
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL APIENTRY
+ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
+ {
+ PWND Window;
+ RECTL Rect;
+ INT RegionType;
+ PROSRGNDATA RgnData;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserGetUpdateRect\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(FALSE);
+ }
+
+ Window->state &= ~WNDS_UPDATEDIRTY;
+
+ if (Window->hrgnUpdate == NULL)
+ {
+ Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
+ }
+ else
+ {
+ /* Get the update region bounding box. */
+ if (Window->hrgnUpdate == HRGN_WINDOW)
+ {
+ Rect = Window->rcClient;
+ }
+ else
+ {
+ RgnData = RGNOBJAPI_Lock(Window->hrgnUpdate, NULL);
+ ASSERT(RgnData != NULL);
+ RegionType = REGION_GetRgnBox(RgnData, &Rect);
+ RGNOBJAPI_Unlock(RgnData);
+
+ if (RegionType != ERROR && RegionType != NULLREGION)
+ RECTL_bIntersectRect(&Rect, &Rect, &Window->rcClient);
+ }
+
+ if (IntIntersectWithParents(Window, &Rect))
+ {
+ RECTL_vOffsetRect(&Rect,
+ -Window->rcClient.left,
+ -Window->rcClient.top);
+ } else
+ {
+ Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
+ }
+ }
+
+ if (bErase && !RECTL_bIsEmptyRect(&Rect))
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Window, &Ref);
+ co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
+ UserDerefObjectCo(Window);
+ }
+
+ if (UnsafeRect != NULL)
+ {
+ Status = MmCopyToCaller(UnsafeRect, &Rect, sizeof(RECTL));
+ if (!NT_SUCCESS(Status))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+ }
+
+ RETURN(!RECTL_bIsEmptyRect(&Rect));
+
+ CLEANUP:
+ TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ /*
+ * NtUserRedrawWindow
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL APIENTRY
+ NtUserRedrawWindow(
+ HWND hWnd,
+ CONST RECT *lprcUpdate,
+ HRGN hrgnUpdate,
+ UINT flags)
+ {
+ RECTL SafeUpdateRect;
+ PWND Wnd;
+ BOOL Ret;
+ USER_REFERENCE_ENTRY Ref;
+ NTSTATUS Status = STATUS_SUCCESS;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserRedrawWindow\n");
+ UserEnterExclusive();
+
+ if (!(Wnd = UserGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
+ {
+ RETURN( FALSE);
+ }
+
+ if (lprcUpdate)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead(lprcUpdate, sizeof(RECTL), 1);
+ RtlCopyMemory(&SafeUpdateRect, lprcUpdate, sizeof(RECTL));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ EngSetLastError(RtlNtStatusToDosError(Status));
+ RETURN( FALSE);
+ }
+ }
+
+ if ( flags & ~(RDW_ERASE|RDW_FRAME|RDW_INTERNALPAINT|RDW_INVALIDATE|
+ RDW_NOERASE|RDW_NOFRAME|RDW_NOINTERNALPAINT|RDW_VALIDATE|
+ RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN|RDW_NOCHILDREN) )
+ {
+ /* RedrawWindow fails only in case that flags are invalid */
+ EngSetLastError(ERROR_INVALID_FLAGS);
+ RETURN( FALSE);
+ }
+
+ UserRefObjectCo(Wnd, &Ref);
+
+ Ret = co_UserRedrawWindow( Wnd,
+ lprcUpdate ? &SafeUpdateRect : NULL,
+ hrgnUpdate,
+ flags);
+
+ UserDerefObjectCo(Wnd);
+
+ RETURN( Ret);
+
+ CLEANUP:
+ TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ static
+ INT FASTCALL
+ UserScrollDC(
+ HDC hDC,
+ INT dx,
+ INT dy,
+ const RECTL *prcScroll,
+ const RECTL *prcClip,
+ HRGN hrgnUpdate,
+ RECTL *prcUpdate)
+ {
+ PDC pDC;
+ RECTL rcScroll, rcClip, rcSrc, rcDst;
+ INT Result;
+
+ GdiGetClipBox(hDC, &rcClip);
+ rcScroll = rcClip;
+ if (prcClip)
+ {
+ RECTL_bIntersectRect(&rcClip, &rcClip, prcClip);
+ }
+
+ if (prcScroll)
+ {
+ rcScroll = *prcScroll;
+ RECTL_bIntersectRect(&rcSrc, &rcClip, prcScroll);
+ }
+ else
+ {
+ rcSrc = rcClip;
+ }
+
+ rcDst = rcSrc;
+ RECTL_vOffsetRect(&rcDst, dx, dy);
+ RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
+
+ if (!NtGdiBitBlt( hDC,
+ rcDst.left,
+ rcDst.top,
+ rcDst.right - rcDst.left,
+ rcDst.bottom - rcDst.top,
+ hDC,
+ rcDst.left - dx,
+ rcDst.top - dy,
+ SRCCOPY,
+ 0,
+ 0))
+ {
+ return ERROR;
+ }
+
+ /* Calculate the region that was invalidated by moving or
+ could not be copied, because it was not visible */
+ if (hrgnUpdate || prcUpdate)
+ {
+ HRGN hrgnOwn, hrgnTmp;
+ PREGION prgnTmp;
+
+ pDC = DC_LockDc(hDC);
+ if (!pDC)
+ {
+ return FALSE;
+ }
+
+ /* Begin with the shifted and then clipped scroll rect */
+ rcDst = rcScroll;
+ RECTL_vOffsetRect(&rcDst, dx, dy);
+ RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
+ if (hrgnUpdate)
+ {
+ hrgnOwn = hrgnUpdate;
+ if (!NtGdiSetRectRgn(hrgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom))
+ {
+ DC_UnlockDc(pDC);
+ return ERROR;
+ }
+ }
+ else
+ {
+ hrgnOwn = IntSysCreateRectRgnIndirect(&rcDst);
+ }
+
+ /* Add the source rect */
+ hrgnTmp = IntSysCreateRectRgnIndirect(&rcSrc);
+ NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_OR);
+
+ /* Substract the part of the dest that was visible in source */
+ prgnTmp = RGNOBJAPI_Lock(hrgnTmp, NULL);
+ IntGdiCombineRgn(prgnTmp, prgnTmp, pDC->prgnVis, RGN_AND);
+ RGNOBJAPI_Unlock(prgnTmp);
+ NtGdiOffsetRgn(hrgnTmp, dx, dy);
+ Result = NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_DIFF);
+
+ /* DO NOT Unlock DC while messing with prgnVis! */
+ DC_UnlockDc(pDC);
+
+ GreDeleteObject(hrgnTmp);
+
+ if (prcUpdate)
+ {
+ IntGdiGetRgnBox(hrgnOwn, prcUpdate);
+ }
+
+ if (!hrgnUpdate)
+ {
+ GreDeleteObject(hrgnOwn);
+ }
+ }
+ else
+ Result = NULLREGION;
+
+ return Result;
+ }
+
+ /*
+ * NtUserScrollDC
+ *
+ * Status
+ * @implemented
+ */
+ BOOL APIENTRY
+ NtUserScrollDC(
+ HDC hDC,
+ INT dx,
+ INT dy,
+ const RECT *prcUnsafeScroll,
+ const RECT *prcUnsafeClip,
+ HRGN hrgnUpdate,
+ LPRECT prcUnsafeUpdate)
+ {
+ DECLARE_RETURN(DWORD);
+ RECTL rcScroll, rcClip, rcUpdate;
+ NTSTATUS Status = STATUS_SUCCESS;
+ DWORD Result;
+
+ TRACE("Enter NtUserScrollDC\n");
+ UserEnterExclusive();
+
+ _SEH2_TRY
+ {
+ if (prcUnsafeScroll)
+ {
+ ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
+ rcScroll = *prcUnsafeScroll;
+ }
+ if (prcUnsafeClip)
+ {
+ ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
+ rcClip = *prcUnsafeClip;
+ }
+ if (prcUnsafeUpdate)
+ {
+ ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(FALSE);
+ }
+
+ Result = UserScrollDC( hDC,
+ dx,
+ dy,
+ prcUnsafeScroll? &rcScroll : 0,
+ prcUnsafeClip? &rcClip : 0,
+ hrgnUpdate,
+ prcUnsafeUpdate? &rcUpdate : NULL);
+ if(Result == ERROR)
+ {
+ /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
+ RETURN(FALSE);
+ }
+
+ if (prcUnsafeUpdate)
+ {
+ _SEH2_TRY
+ {
+ *prcUnsafeUpdate = rcUpdate;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ /* FIXME: SetLastError? */
+ /* FIXME: correct? We have already scrolled! */
+ RETURN(FALSE);
+ }
+ }
+
+ RETURN(TRUE);
+
+ CLEANUP:
+ TRACE("Leave NtUserScrollDC, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ /*
+ * NtUserScrollWindowEx
+ *
+ * Status
+ * @implemented
+ */
+
+ DWORD APIENTRY
+ NtUserScrollWindowEx(
+ HWND hWnd,
+ INT dx,
+ INT dy,
+ const RECT *prcUnsafeScroll,
+ const RECT *prcUnsafeClip,
+ HRGN hrgnUpdate,
+ LPRECT prcUnsafeUpdate,
+ UINT flags)
+ {
+ RECTL rcScroll, rcClip, rcCaret, rcUpdate;
+ INT Result;
+ PWND Window = NULL, CaretWnd;
+ HDC hDC;
+ HRGN hrgnOwn = NULL, hrgnTemp, hrgnWinupd = NULL;
+ HWND hwndCaret;
+ DWORD dcxflags = 0;
+ int rdw_flags;
+ BOOL bOwnRgn = TRUE;
+ NTSTATUS Status = STATUS_SUCCESS;
+ DECLARE_RETURN(DWORD);
+ USER_REFERENCE_ENTRY Ref, CaretRef;
+
+ TRACE("Enter NtUserScrollWindowEx\n");
+ UserEnterExclusive();
+
+ Window = UserGetWindowObject(hWnd);
+ if (!Window || !IntIsWindowDrawable(Window))
+ {
+ Window = NULL; /* prevent deref at cleanup */
+ RETURN( ERROR);
+ }
+ UserRefObjectCo(Window, &Ref);
+
+ IntGetClientRect(Window, &rcClip);
+
+ _SEH2_TRY
+ {
+ if (prcUnsafeScroll)
+ {
+ ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
+ RECTL_bIntersectRect(&rcScroll, &rcClip, prcUnsafeScroll);
+ }
+ else
+ rcScroll = rcClip;
+
+ if (prcUnsafeClip)
+ {
+ ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
+ RECTL_bIntersectRect(&rcClip, &rcClip, prcUnsafeClip);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(ERROR);
+ }
+
+ if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
+ (dx == 0 && dy == 0))
+ {
+ RETURN(NULLREGION);
+ }
+
+ if (hrgnUpdate)
+ {
+ hrgnOwn = hrgnUpdate;
+ bOwnRgn = FALSE;
+ }
+ else
+ hrgnOwn = IntSysCreateRectRgn(0, 0, 0, 0);
+
+ /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
+ if (flags & SW_SCROLLWNDDCE)
+ {
+ dcxflags = DCX_USESTYLE;
+
+ if (!(Window->pcls->style & (CS_OWNDC|CS_CLASSDC)))
+ dcxflags |= DCX_CACHE; // AH??? wine~ If not Powned or with Class go Cheap!
+
+ if (flags & SW_SCROLLCHILDREN && Window->style & WS_CLIPCHILDREN)
+ dcxflags |= DCX_CACHE|DCX_NOCLIPCHILDREN;
+ }
+ else
+ {
+ /* So in this case ScrollWindowEx uses Cache DC. */
+ dcxflags = DCX_CACHE|DCX_USESTYLE;
+ if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
+ }
+
+ hDC = UserGetDCEx(Window, 0, dcxflags);
+ if (!hDC)
+ {
+ /* FIXME: SetLastError? */
+ RETURN(ERROR);
+ }
+
+ rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
+
+ rcCaret = rcScroll;
+ hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
+
+ Result = UserScrollDC( hDC,
+ dx,
+ dy,
+ &rcScroll,
+ &rcClip,
+ hrgnOwn,
+ prcUnsafeUpdate? &rcUpdate : NULL);
+
+ UserReleaseDC(Window, hDC, FALSE);
+
+ /*
+ * Take into account the fact that some damage may have occurred during
+ * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
+ */
+
+ hrgnTemp = IntSysCreateRectRgn(0, 0, 0, 0);
+ if (co_UserGetUpdateRgn(Window, hrgnTemp, FALSE) != NULLREGION)
+ {
+ HRGN hrgnClip = IntSysCreateRectRgnIndirect(&rcClip);
+ if (!bOwnRgn)
+ {
+ hrgnWinupd = IntSysCreateRectRgn( 0, 0, 0, 0);
+ NtGdiCombineRgn( hrgnWinupd, hrgnTemp, 0, RGN_COPY);
+ }
+ NtGdiOffsetRgn(hrgnTemp, dx, dy);
+ NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
+ if (!bOwnRgn) NtGdiCombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR );
+ co_UserRedrawWindow(Window, NULL, hrgnTemp, rdw_flags );
+ GreDeleteObject(hrgnClip);
+ }
+ GreDeleteObject(hrgnTemp);
+
+ if (flags & SW_SCROLLCHILDREN)
+ {
+ PWND Child;
+ RECTL rcChild;
+ POINT ClientOrigin;
+ USER_REFERENCE_ENTRY WndRef;
+ RECTL rcDummy;
+
+ IntGetClientOrigin(Window, &ClientOrigin);
+ for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
+ {
+ rcChild = Child->rcWindow;
+ rcChild.left -= ClientOrigin.x;
+ rcChild.top -= ClientOrigin.y;
+ rcChild.right -= ClientOrigin.x;
+ rcChild.bottom -= ClientOrigin.y;
+
+ if (! prcUnsafeScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll))
+ {
+ UserRefObjectCo(Child, &WndRef);
+ co_WinPosSetWindowPos(Child, 0, rcChild.left + dx, rcChild.top + dy, 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
+ SWP_NOREDRAW | SWP_DEFERERASE);
+ UserDerefObjectCo(Child);
+ }
+ }
+ }
+
+ if (flags & (SW_INVALIDATE | SW_ERASE))
+ {
+ co_UserRedrawWindow(Window, NULL, hrgnOwn, rdw_flags |
+ ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
+ ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
+ }
+
+ if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
+ {
+ UserRefObjectCo(CaretWnd, &CaretRef);
+
+ co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
+ co_UserShowCaret(CaretWnd);
+
+ UserDerefObjectCo(CaretWnd);
+ }
+
+ if (prcUnsafeUpdate)
+ {
+ _SEH2_TRY
+ {
+ /* Probe here, to not fail on invalid pointer before scrolling */
+ ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
+ *prcUnsafeUpdate = rcUpdate;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(ERROR);
+ }
+ }
+
+ RETURN(Result);
+
+ CLEANUP:
+ if (hrgnWinupd && !bOwnRgn)
+ {
+ NtGdiCombineRgn( hrgnOwn, hrgnOwn, hrgnWinupd, RGN_OR);
+ GreDeleteObject(hrgnWinupd);
+ }
+
+ if (hrgnOwn && !hrgnUpdate)
+ {
+ GreDeleteObject(hrgnOwn);
+ }
+
+ if (Window)
+ UserDerefObjectCo(Window);
+
+ TRACE("Leave NtUserScrollWindowEx, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+ }
+
+ BOOL
+ UserDrawCaptionText(
+ HDC hDc,
+ const PUNICODE_STRING Text,
+ const RECTL *lpRc,
+ UINT uFlags,
+ HFONT hFont)
+ {
+ HFONT hOldFont = NULL;
+ COLORREF OldTextColor;
+ NONCLIENTMETRICSW nclm;
+ NTSTATUS Status;
+ BOOLEAN bDeleteFont = FALSE;
+ SIZE Size;
+
+ TRACE("UserDrawCaptionText: %wZ\n", Text);
+
+ nclm.cbSize = sizeof(nclm);
+ if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS,
+ sizeof(NONCLIENTMETRICS), &nclm, 0))
+ {
+ ERR("UserSystemParametersInfo() failed!\n");
+ return FALSE;
+ }
+
+ if (!hFont)
+ {
+ if(uFlags & DC_SMALLCAP)
+ Status = TextIntCreateFontIndirect(&nclm.lfSmCaptionFont, &hFont);
+ else
+ Status = TextIntCreateFontIndirect(&nclm.lfCaptionFont, &hFont);
+
+ if(!NT_SUCCESS(Status))
+ {
+ ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status);
+ return FALSE;
+ }
+
+ bDeleteFont = TRUE;
+ }
+
+ IntGdiSetBkMode(hDc, TRANSPARENT);
+
+ hOldFont = NtGdiSelectFont(hDc, hFont);
+ if(!hOldFont)
+ {
+ ERR("SelectFont() failed!\n");
+ /* Don't fail */
+ }
+
+ if(uFlags & DC_INBUTTON)
+ OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(COLOR_BTNTEXT));
+ else
+ OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(uFlags & DC_ACTIVE
+ ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
+
+ // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
+ GreGetTextExtentW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), &Size, 0);
+ GreExtTextOutW(hDc,
+ lpRc->left, (lpRc->top + lpRc->bottom)/2 - Size.cy/2,
+ 0, NULL, Text->Buffer, Text->Length/sizeof(WCHAR), NULL, 0);
+
+ IntGdiSetTextColor(hDc, OldTextColor);
+ if (hOldFont)
+ NtGdiSelectFont(hDc, hOldFont);
+ if (bDeleteFont)
+ GreDeleteObject(hFont);
+
+ return TRUE;
+ }
+
+ BOOL UserDrawCaption(
+ PWND pWnd,
+ HDC hDc,
+ RECTL *lpRc,
+ HFONT hFont,
+ HICON hIcon,
+ const PUNICODE_STRING Str,
+ UINT uFlags)
+ {
+ BOOL Ret = FALSE;
+ HBRUSH hBgBrush, hOldBrush = NULL;
+ RECTL Rect = *lpRc;
+ BOOL HasIcon;
+
+ RECTL_vMakeWellOrdered(lpRc);
+
+ if (!hIcon && pWnd != NULL)
+ {
+ HasIcon = (uFlags & DC_ICON) && (pWnd->style & WS_SYSMENU)
+ && !(uFlags & DC_SMALLCAP) && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME)
+ && !(pWnd->ExStyle & WS_EX_TOOLWINDOW);
+ }
+ else
+ HasIcon = (hIcon != 0);
+
+ // Draw the caption background
+ if((uFlags & DC_GRADIENT) && !(uFlags & DC_INBUTTON))
+ {
+ static GRADIENT_RECT gcap = {0, 1};
+ TRIVERTEX Vertices[2];
+ COLORREF Colors[2];
+
+ Colors[0] = IntGetSysColor((uFlags & DC_ACTIVE) ?
+ COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
+
+ Colors[1] = IntGetSysColor((uFlags & DC_ACTIVE) ?
+ COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION);
+
+ Vertices[0].x = Rect.left;
+ Vertices[0].y = Rect.top;
+ Vertices[0].Red = (WORD)Colors[0]<<8;
+ Vertices[0].Green = (WORD)Colors[0] & 0xFF00;
+ Vertices[0].Blue = (WORD)(Colors[0]>>8) & 0xFF00;
+ Vertices[0].Alpha = 0;
+
+ Vertices[1].x = Rect.right;
+ Vertices[1].y = Rect.bottom;
+ Vertices[1].Red = (WORD)Colors[1]<<8;
+ Vertices[1].Green = (WORD)Colors[1] & 0xFF00;
+ Vertices[1].Blue = (WORD)(Colors[1]>>8) & 0xFF00;
+ Vertices[1].Alpha = 0;
+
+ if(!GreGradientFill(hDc, Vertices, 2, &gcap, 1, GRADIENT_FILL_RECT_H))
+ {
+ ERR("GreGradientFill() failed!\n");
+ goto cleanup;
+ }
+ }
+ else
+ {
+ if(uFlags & DC_INBUTTON)
+ hBgBrush = IntGetSysColorBrush(COLOR_3DFACE);
+ else if(uFlags & DC_ACTIVE)
+ hBgBrush = IntGetSysColorBrush(COLOR_ACTIVECAPTION);
+ else
+ hBgBrush = IntGetSysColorBrush(COLOR_INACTIVECAPTION);
+
+ hOldBrush = NtGdiSelectBrush(hDc, hBgBrush);
+
+ if(!hOldBrush)
+ {
+ ERR("NtGdiSelectBrush() failed!\n");
+ goto cleanup;
+ }
+
+ if(!NtGdiPatBlt(hDc, Rect.left, Rect.top,
+ Rect.right - Rect.left,
+ Rect.bottom - Rect.top,
+ PATCOPY))
+ {
+ ERR("NtGdiPatBlt() failed!\n");
+ goto cleanup;
+ }
+ }
+
+ /* Draw icon */
+ if (HasIcon)
+ {
+ PCURICON_OBJECT pIcon = NULL;
+
+ if (!hIcon && pWnd)
+ {
+ hIcon = pWnd->pcls->hIconSm; // FIXME: Windows does not do that
+ if(!hIcon)
+ hIcon = pWnd->pcls->hIcon;
+ }
+
+ if (hIcon)
+ pIcon = UserGetCurIconObject(hIcon);
+
+ if (pIcon)
+ {
+ LONG cx = UserGetSystemMetrics(SM_CXSMICON);
+ LONG cy = UserGetSystemMetrics(SM_CYSMICON);
+ LONG x = Rect.left - cx/2 + 1 + (Rect.bottom - Rect.top)/2; // this is really what Window does
+ LONG y = (Rect.top + Rect.bottom)/2 - cy/2; // center
+ UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
++ UserDereferenceObject(pIcon);
+ }
+ }
+
+ if (hIcon)
+ Rect.left += Rect.bottom - Rect.top;
+
+ if((uFlags & DC_TEXT))
+ {
+ Rect.left += 2;
+
+ if (Str)
+ UserDrawCaptionText(hDc, Str, &Rect, uFlags, hFont);
+ else if (pWnd != NULL) // FIXME: Windows does not do that
+ {
+ UNICODE_STRING ustr;
+ ustr.Buffer = pWnd->strName.Buffer; // FIXME: LARGE_STRING truncated!
+ ustr.Length = (USHORT)min(pWnd->strName.Length, MAXUSHORT);
+ ustr.MaximumLength = (USHORT)min(pWnd->strName.MaximumLength, MAXUSHORT);
+ UserDrawCaptionText(hDc, &ustr, &Rect, uFlags, hFont);
+ }
+ }
+
+ Ret = TRUE;
+
+ cleanup:
+ if (hOldBrush) NtGdiSelectBrush(hDc, hOldBrush);
+
+ return Ret;
+ }
+
+ INT
+ FASTCALL
+ UserRealizePalette(HDC hdc)
+ {
+ HWND hWnd, hWndDesktop;
+ DWORD Ret;
+
+ Ret = IntGdiRealizePalette(hdc);
+ if (Ret) // There was a change.
+ {
+ hWnd = IntWindowFromDC(hdc);
+ if (hWnd) // Send broadcast if dc is associated with a window.
+ { // FYI: Thread locked in CallOneParam.
+ hWndDesktop = IntGetDesktopWindow();
+ if ( hWndDesktop != hWnd )
+ {
+ PWND pWnd = UserGetWindowObject(hWndDesktop);
+ ERR("RealizePalette Desktop.");
+ hdc = UserGetWindowDC(pWnd);
+ IntPaintDesktop(hdc);
+ UserReleaseDC(pWnd,hdc,FALSE);
+ }
+ UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0);
+ }
+ }
+ return Ret;
+ }
+
+ BOOL
+ APIENTRY
+ NtUserDrawCaptionTemp(
+ HWND hWnd,
+ HDC hDC,
+ LPCRECT lpRc,
+ HFONT hFont,
+ HICON hIcon,
+ const PUNICODE_STRING str,
+ UINT uFlags)
+ {
+ PWND pWnd = NULL;
+ UNICODE_STRING SafeStr = {0};
+ NTSTATUS Status = STATUS_SUCCESS;
+ RECTL SafeRect;
+ BOOL Ret;
+
+ UserEnterExclusive();
+
+ if (hWnd != NULL)
+ {
+ if(!(pWnd = UserGetWindowObject(hWnd)))
+ {
+ UserLeave();
+ return FALSE;
+ }
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(lpRc, sizeof(RECTL), sizeof(ULONG));
+ RtlCopyMemory(&SafeRect, lpRc, sizeof(RECTL));
+ if (str != NULL)
+ {
+ SafeStr = ProbeForReadUnicodeString(str);
+ if (SafeStr.Length != 0)
+ {
+ ProbeForRead( SafeStr.Buffer,
+ SafeStr.Length,
+ sizeof(WCHAR));
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ if (Status != STATUS_SUCCESS)
+ {
+ SetLastNtError(Status);
+ UserLeave();
+ return FALSE;
+ }
+
+ if (str != NULL)
+ Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags);
+ else
+ Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags);
+
+ UserLeave();
+ return Ret;
+ }
+
+ BOOL
+ APIENTRY
+ NtUserDrawCaption(HWND hWnd,
+ HDC hDC,
+ LPCRECT lpRc,
+ UINT uFlags)
+ {
+ return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
+ }
+
+ BOOL
+ APIENTRY
+ NtUserInvalidateRect(
+ HWND hWnd,
+ CONST RECT *lpUnsafeRect,
+ BOOL bErase)
+ {
+ return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
+ }
+
+ BOOL
+ APIENTRY
+ NtUserInvalidateRgn(
+ HWND hWnd,
+ HRGN hRgn,
+ BOOL bErase)
+ {
+ return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
+ }
+
+ BOOL
+ APIENTRY
+ NtUserPrintWindow(
+ HWND hwnd,
+ HDC hdcBlt,
+ UINT nFlags)
+ {
+ PWND Window;
+ BOOL Ret = FALSE;
+
+ UserEnterExclusive();
+
+ if (hwnd)
+ {
+ if (!(Window = UserGetWindowObject(hwnd)) || // FIXME:
+ Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ goto Exit;
+ }
+
+ if ( Window )
+ {
+ /* Validate flags and check it as a mask for 0 or 1. */
+ if ( (nFlags & PW_CLIENTONLY) == nFlags)
+ Ret = IntPrintWindow( Window, hdcBlt, nFlags);
+ else
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ }
+ }
+ Exit:
+ UserLeave();
+ return Ret;
+ }
+
+ /* ValidateRect gets redirected to NtUserValidateRect:
+ http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
+ BOOL
+ APIENTRY
+ NtUserValidateRect(
+ HWND hWnd,
+ const RECT *lpRect)
+ {
+ if (hWnd)
+ {
+ return NtUserRedrawWindow(hWnd, lpRect, NULL, RDW_VALIDATE );
+ }
+ return NtUserRedrawWindow(hWnd, lpRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ERASENOW|RDW_ALLCHILDREN);
+ }
+
+ /* EOF */
--- /dev/null
- ERR("Attempted to close process window station");
+ /*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Window stations
+ * FILE: subsystems/win32/win32k/ntuser/winsta.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * TODO: The process window station is created on
+ * the first USER32/GDI32 call not related
+ * to window station/desktop handling
+ */
+
+ #include <win32k.h>
+ DBG_DEFAULT_CHANNEL(UserWinsta);
+
+ /* GLOBALS *******************************************************************/
+
+ /* Currently active window station */
+ PWINSTATION_OBJECT InputWindowStation = NULL;
+
+ /* Winlogon SAS window */
+ HWND hwndSAS = NULL;
+
+ /* Full path to WindowStations directory */
+ UNICODE_STRING gustrWindowStationsDir;
+
+ /* INITALIZATION FUNCTIONS ****************************************************/
+
+ INIT_FUNCTION
+ NTSTATUS
+ NTAPI
+ InitWindowStationImpl(VOID)
+ {
+ GENERIC_MAPPING IntWindowStationMapping = { WINSTA_READ,
+ WINSTA_WRITE,
+ WINSTA_EXECUTE,
+ WINSTA_ACCESS_ALL};
+
+ /* Set Winsta Object Attributes */
+ ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
+ ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
+ ExWindowStationObjectType->TypeInfo.ValidAccessMask = WINSTA_ACCESS_ALL;
+
+ return STATUS_SUCCESS;
+ }
+
+ NTSTATUS
+ NTAPI
+ UserCreateWinstaDirectoy()
+ {
+ PPEB Peb;
+ NTSTATUS Status;
+ WCHAR wstrWindowStationsDir[MAX_PATH];
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hWinstaDir;
+
+ /* Create the WindowStations directory and cache its path for later use */
+ Peb = NtCurrentPeb();
+ if(Peb->SessionId == 0)
+ {
+ RtlCreateUnicodeString(&gustrWindowStationsDir, WINSTA_OBJ_DIR);
+ }
+ else
+ {
+ swprintf(wstrWindowStationsDir,
+ L"%ws\\%ld%ws",
+ SESSION_DIR,
+ Peb->SessionId,
+ WINSTA_OBJ_DIR);
+
+ RtlCreateUnicodeString( &gustrWindowStationsDir, wstrWindowStationsDir);
+ }
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &gustrWindowStationsDir,
+ 0,
+ NULL,
+ NULL);
+ Status = ZwCreateDirectoryObject(&hWinstaDir, 0, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir, Status);
+ return Status;
+ }
+
+ TRACE("Created directory %wZ for session %d\n", &gustrWindowStationsDir, Peb->SessionId);
+
+ return Status;
+ }
+
+ /* OBJECT CALLBACKS **********************************************************/
+
+ VOID APIENTRY
+ IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
+ {
+ PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)Parameters->Object;
+
+ TRACE("Deleting window station (0x%X)\n", WinSta);
+
+ UserEmptyClipboardData(WinSta);
+
+ RtlDestroyAtomTable(WinSta->AtomTable);
+
+ RtlFreeUnicodeString(&WinSta->Name);
+ }
+
+ NTSTATUS
+ APIENTRY
+ IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters)
+ {
+ PUNICODE_STRING RemainingName = Parameters->RemainingName;
+
+ /* Assume we don't find anything */
+ *Parameters->Object = NULL;
+
+ /* Check for an empty name */
+ if (!RemainingName->Length)
+ {
+ /* Make sure this is a window station, can't parse a desktop now */
+ if (Parameters->ObjectType != ExWindowStationObjectType)
+ {
+ /* Fail */
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ /* Reference the window station and return */
+ ObReferenceObject(Parameters->ParseObject);
+ *Parameters->Object = Parameters->ParseObject;
+ return STATUS_SUCCESS;
+ }
+
+ /* Check for leading slash */
+ if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ /* Skip it */
+ RemainingName->Buffer++;
+ RemainingName->Length -= sizeof(WCHAR);
+ RemainingName->MaximumLength -= sizeof(WCHAR);
+ }
+
+ /* Check if there is still a slash */
+ if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
+ {
+ /* In this case, fail */
+ return STATUS_OBJECT_PATH_INVALID;
+ }
+
+ /*
+ * Check if we are parsing a desktop.
+ */
+ if (Parameters->ObjectType == ExDesktopObjectType)
+ {
+ /* Then call the desktop parse routine */
+ return IntDesktopObjectParse(Parameters->ParseObject,
+ Parameters->ObjectType,
+ Parameters->AccessState,
+ Parameters->AccessMode,
+ Parameters->Attributes,
+ Parameters->CompleteName,
+ RemainingName,
+ Parameters->Context,
+ Parameters->SecurityQos,
+ Parameters->Object);
+ }
+
+ /* Should hopefully never get here */
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ NTSTATUS
+ NTAPI
+ IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters)
+ {
+ PPROCESSINFO ppi;
+
+ ppi = PsGetCurrentProcessWin32Process();
+
+ if(ppi && (Parameters->Handle == ppi->hwinsta))
+ {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* PRIVATE FUNCTIONS **********************************************************/
+
+ /*
+ * IntValidateWindowStationHandle
+ *
+ * Validates the window station handle.
+ *
+ * Remarks
+ * If the function succeeds, the handle remains referenced. If the
+ * fucntion fails, last error is set.
+ */
+
+ NTSTATUS FASTCALL
+ IntValidateWindowStationHandle(
+ HWINSTA WindowStation,
+ KPROCESSOR_MODE AccessMode,
+ ACCESS_MASK DesiredAccess,
+ PWINSTATION_OBJECT *Object)
+ {
+ NTSTATUS Status;
+
+ if (WindowStation == NULL)
+ {
+ ERR("Invalid window station handle\n");
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ Status = ObReferenceObjectByHandle(
+ WindowStation,
+ DesiredAccess,
+ ExWindowStationObjectType,
+ AccessMode,
+ (PVOID*)Object,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ SetLastNtError(Status);
+
+ return Status;
+ }
+
+ BOOL FASTCALL
+ co_IntInitializeDesktopGraphics(VOID)
+ {
+ TEXTMETRICW tmw;
+ UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
+
+ ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
+ if (NULL == ScreenDeviceContext)
+ {
+ IntDestroyPrimarySurface();
+ return FALSE;
+ }
+ GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
+
+ if (! IntCreatePrimarySurface())
+ {
+ return FALSE;
+ }
+
+ /* Setup the cursor */
+ co_IntLoadDefaultCursors();
+
+ hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
+
+ NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
+ GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
+
+ // FIXME: Move these to a update routine.
+ gpsi->Planes = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
+ gpsi->BitsPixel = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
+ gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
+ gpsi->dmLogPixels = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
+ if (NtGdiGetDeviceCaps(ScreenDeviceContext, RASTERCAPS) & RC_PALETTE)
+ {
+ gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
+ }
+ else
+ gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
+ // Font is realized and this dc was previously set to internal DC_ATTR.
+ gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
+ gpsi->tmSysFont = tmw;
+
+ return TRUE;
+ }
+
+ VOID FASTCALL
+ IntEndDesktopGraphics(VOID)
+ {
+ if (NULL != ScreenDeviceContext)
+ { // No need to allocate a new dcattr.
+ GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(ScreenDeviceContext);
+ ScreenDeviceContext = NULL;
+ }
+ IntHideDesktop(IntGetActiveDesktop());
+ IntDestroyPrimarySurface();
+ }
+
+ HDC FASTCALL
+ IntGetScreenDC(VOID)
+ {
+ return ScreenDeviceContext;
+ }
+
+ /* PUBLIC FUNCTIONS ***********************************************************/
+
+ /*
+ * NtUserCreateWindowStation
+ *
+ * Creates a new window station.
+ *
+ * Parameters
+ * lpszWindowStationName
+ * Pointer to a null-terminated string specifying the name of the
+ * window station to be created. Window station names are
+ * case-insensitive and cannot contain backslash characters (\).
+ * Only members of the Administrators group are allowed to specify a
+ * name.
+ *
+ * dwDesiredAccess
+ * Requested type of access
+ *
+ * lpSecurity
+ * Security descriptor
+ *
+ * Unknown3, Unknown4, Unknown5
+ * Unused
+ *
+ * Return Value
+ * If the function succeeds, the return value is a handle to the newly
+ * created window station. If the specified window station already
+ * exists, the function succeeds and returns a handle to the existing
+ * window station. If the function fails, the return value is NULL.
+ *
+ * Todo
+ * Correct the prototype to match the Windows one (with 7 parameters
+ * on Windows XP).
+ *
+ * Status
+ * @implemented
+ */
+
+ HWINSTA APIENTRY
+ NtUserCreateWindowStation(
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ ACCESS_MASK dwDesiredAccess,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4,
+ DWORD Unknown5,
+ DWORD Unknown6)
+ {
+ UNICODE_STRING WindowStationName;
+ PWINSTATION_OBJECT WindowStationObject;
+ HWINSTA WindowStation;
+ NTSTATUS Status;
+
+ TRACE("NtUserCreateWindowStation called\n");
+
+ Status = ObOpenObjectByName(
+ ObjectAttributes,
+ ExWindowStationObjectType,
+ UserMode,
+ NULL,
+ dwDesiredAccess,
+ NULL,
+ (PVOID*)&WindowStation);
+
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName);
+ return (HWINSTA)WindowStation;
+ }
+
+ /*
+ * No existing window station found, try to create new one
+ */
+
+ /* Capture window station name */
+ _SEH2_TRY
+ {
+ ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
+ Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName, ObjectAttributes->ObjectName);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status =_SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+
+ if (! NT_SUCCESS(Status))
+ {
+ ERR("Failed reading capturing window station name\n");
+ SetLastNtError(Status);
+ return NULL;
+ }
+
+ /* Create the window station object */
+ Status = ObCreateObject(
+ UserMode,
+ ExWindowStationObjectType,
+ ObjectAttributes,
+ UserMode,
+ NULL,
+ sizeof(WINSTATION_OBJECT),
+ 0,
+ 0,
+ (PVOID*)&WindowStationObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("ObCreateObject failed for window station %wZ\n", &WindowStationName);
+ ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
+ SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+ return 0;
+ }
+
+ Status = ObInsertObject(
+ (PVOID)WindowStationObject,
+ NULL,
+ dwDesiredAccess,
+ 0,
+ NULL,
+ (PVOID*)&WindowStation);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("ObInsertObject failed for window station %wZ\n", &WindowStationName);
+ ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
+ SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+ ObDereferenceObject(WindowStationObject);
+ return 0;
+ }
+
+ /* Initialize the window station */
+ RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
+
+ KeInitializeSpinLock(&WindowStationObject->Lock);
+ InitializeListHead(&WindowStationObject->DesktopListHead);
+ Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
+ WindowStationObject->SystemMenuTemplate = (HANDLE)0;
+ WindowStationObject->Name = WindowStationName;
+
+ if (InputWindowStation == NULL)
+ {
+ TRACE("Initializeing input window station\n");
+ InputWindowStation = WindowStationObject;
+
+ InitCursorImpl();
+ }
+
+ TRACE("NtUserCreateWindowStation created object 0x%x with name %wZ handle 0x%x\n",
+ WindowStation, &WindowStationObject->Name, WindowStation);
+ return WindowStation;
+ }
+
+ /*
+ * NtUserOpenWindowStation
+ *
+ * Opens an existing window station.
+ *
+ * Parameters
+ * lpszWindowStationName
+ * Name of the existing window station.
+ *
+ * dwDesiredAccess
+ * Requested type of access.
+ *
+ * Return Value
+ * If the function succeeds, the return value is the handle to the
+ * specified window station. If the function fails, the return value
+ * is NULL.
+ *
+ * Remarks
+ * The returned handle can be closed with NtUserCloseWindowStation.
+ *
+ * Status
+ * @implemented
+ */
+
+ HWINSTA APIENTRY
+ NtUserOpenWindowStation(
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ ACCESS_MASK dwDesiredAccess)
+ {
+ HWINSTA hwinsta;
+ NTSTATUS Status;
+
+ Status = ObOpenObjectByName(
+ ObjectAttributes,
+ ExWindowStationObjectType,
+ UserMode,
+ NULL,
+ dwDesiredAccess,
+ NULL,
+ (PVOID*)&hwinsta);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("NtUserOpenWindowStation failed\n");
+ SetLastNtError(Status);
+ return 0;
+ }
+
+ TRACE("Opened window station %wZ with handle 0x%x\n", ObjectAttributes->ObjectName, hwinsta);
+
+ return hwinsta;
+ }
+
+ /*
+ * NtUserCloseWindowStation
+ *
+ * Closes a window station handle.
+ *
+ * Parameters
+ * hWinSta
+ * Handle to the window station.
+ *
+ * Return Value
+ * Status
+ *
+ * Remarks
+ * The window station handle can be created with NtUserCreateWindowStation
+ * or NtUserOpenWindowStation. Attemps to close a handle to the window
+ * station assigned to the calling process will fail.
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL
+ APIENTRY
+ NtUserCloseWindowStation(
+ HWINSTA hWinSta)
+ {
+ PWINSTATION_OBJECT Object;
+ NTSTATUS Status;
+
+ TRACE("NtUserCloseWindowStation called (0x%x)\n", hWinSta);
+
+ if (hWinSta == UserGetProcessWindowStation())
+ {
- Status = IntValidateWindowStationHandle(
++ ERR("Attempted to close process window station\n");
+ return FALSE;
+ }
+
+ Status = IntValidateWindowStationHandle(
+ hWinSta,
+ KernelMode,
+ 0,
+ &Object);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Validation of window station handle (0x%x) failed\n", hWinSta);
+ return FALSE;
+ }
+
+ ObDereferenceObject(Object);
+
+ TRACE("Closing window station handle (0x%x)\n", hWinSta);
+
+ Status = ObCloseHandle(hWinSta, UserMode);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /*
+ * NtUserGetObjectInformation
+ *
+ * The NtUserGetObjectInformation function retrieves information about a
+ * window station or desktop object.
+ *
+ * Parameters
+ * hObj
+ * Handle to the window station or desktop object for which to
+ * return information. This can be a handle of type HDESK or HWINSTA
+ * (for example, a handle returned by NtUserCreateWindowStation,
+ * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
+ *
+ * nIndex
+ * Specifies the object information to be retrieved.
+ *
+ * pvInfo
+ * Pointer to a buffer to receive the object information.
+ *
+ * nLength
+ * Specifies the size, in bytes, of the buffer pointed to by the
+ * pvInfo parameter.
+ *
+ * lpnLengthNeeded
+ * Pointer to a variable receiving the number of bytes required to
+ * store the requested information. If this variable's value is
+ * greater than the value of the nLength parameter when the function
+ * returns, the function returns FALSE, and none of the information
+ * is copied to the pvInfo buffer. If the value of the variable pointed
+ * to by lpnLengthNeeded is less than or equal to the value of nLength,
+ * the entire information block is copied.
+ *
+ * Return Value
+ * If the function succeeds, the return value is nonzero. If the function
+ * fails, the return value is zero.
+ *
+ * Status
+ * @unimplemented
+ */
+
+ BOOL APIENTRY
+ NtUserGetObjectInformation(
+ HANDLE hObject,
+ DWORD nIndex,
+ PVOID pvInformation,
+ DWORD nLength,
+ PDWORD nLengthNeeded)
+ {
+ PWINSTATION_OBJECT WinStaObject = NULL;
+ PDESKTOP DesktopObject = NULL;
+ NTSTATUS Status;
+ PVOID pvData = NULL;
+ DWORD nDataSize = 0;
+
+ /* try windowstation */
+ TRACE("Trying to open window station 0x%x\n", hObject);
- UserMode,
++ Status = ObReferenceObjectByHandle(
+ hObject,
- &WinStaObject);
-
-
- if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_TYPE_MISMATCH)
- {
- TRACE("Failed: 0x%x\n", Status);
- SetLastNtError(Status);
- return FALSE;
- }
+ 0,
- if (!NT_SUCCESS(Status))
- {
- TRACE("Failed: 0x%x\n", Status);
- SetLastNtError(Status);
- return FALSE;
- }
++ ExWindowStationObjectType,
++ UserMode,
++ (PVOID*)&WinStaObject,
++ NULL);
+
+ if (Status == STATUS_OBJECT_TYPE_MISMATCH)
+ {
+ /* try desktop */
+ TRACE("Trying to open desktop 0x%x\n", hObject);
+ Status = IntValidateDesktopHandle(
+ hObject,
+ UserMode,
+ 0,
+ &DesktopObject);
- SetLastNtError(Status);
- return NT_SUCCESS(Status);
+ }
++
++ if (!NT_SUCCESS(Status))
++ {
++ ERR("Failed: 0x%x\n", Status);
++ SetLastNtError(Status);
++ return FALSE;
++ }
++
+ TRACE("WinSta or Desktop opened!!\n");
+
+ /* get data */
+ switch (nIndex)
+ {
+ case UOI_FLAGS:
+ Status = STATUS_NOT_IMPLEMENTED;
+ ERR("UOI_FLAGS unimplemented!\n");
+ break;
+
+ case UOI_NAME:
+ if (WinStaObject != NULL)
+ {
+ pvData = WinStaObject->Name.Buffer;
+ nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
+ Status = STATUS_SUCCESS;
+ }
+ else if (DesktopObject != NULL)
+ {
+ pvData = DesktopObject->pDeskInfo->szDesktopName;
+ nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
+ Status = STATUS_SUCCESS;
+ }
+ else
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+
+ case UOI_TYPE:
+ if (WinStaObject != NULL)
+ {
+ pvData = L"WindowStation";
+ nDataSize = sizeof(L"WindowStation");
+ Status = STATUS_SUCCESS;
+ }
+ else if (DesktopObject != NULL)
+ {
+ pvData = L"Desktop";
+ nDataSize = sizeof(L"Desktop");
+ Status = STATUS_SUCCESS;
+ }
+ else
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+
+ case UOI_USER_SID:
+ Status = STATUS_NOT_IMPLEMENTED;
+ ERR("UOI_USER_SID unimplemented!\n");
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ /* try to copy data to caller */
+ if (Status == STATUS_SUCCESS)
+ {
+ TRACE("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength, nDataSize);
+ *nLengthNeeded = nDataSize;
+ if (nLength >= nDataSize)
+ Status = MmCopyToCaller(pvInformation, pvData, nDataSize);
+ else
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* release objects */
+ if (WinStaObject != NULL)
+ ObDereferenceObject(WinStaObject);
+ if (DesktopObject != NULL)
+ ObDereferenceObject(DesktopObject);
+
++ if (!NT_SUCCESS(Status))
++ {
++ SetLastNtError(Status);
++ return FALSE;
++ }
++
++ return TRUE;
+ }
+
+ /*
+ * NtUserSetObjectInformation
+ *
+ * The NtUserSetObjectInformation function sets information about a
+ * window station or desktop object.
+ *
+ * Parameters
+ * hObj
+ * Handle to the window station or desktop object for which to set
+ * object information. This value can be a handle of type HDESK or
+ * HWINSTA.
+ *
+ * nIndex
+ * Specifies the object information to be set.
+ *
+ * pvInfo
+ * Pointer to a buffer containing the object information.
+ *
+ * nLength
+ * Specifies the size, in bytes, of the information contained in the
+ * buffer pointed to by pvInfo.
+ *
+ * Return Value
+ * If the function succeeds, the return value is nonzero. If the function
+ * fails the return value is zero.
+ *
+ * Status
+ * @unimplemented
+ */
+
+ BOOL
+ APIENTRY
+ NtUserSetObjectInformation(
+ HANDLE hObject,
+ DWORD nIndex,
+ PVOID pvInformation,
+ DWORD nLength)
+ {
+ /* FIXME: ZwQueryObject */
+ /* FIXME: ZwSetInformationObject */
+ SetLastNtError(STATUS_UNSUCCESSFUL);
+ return FALSE;
+ }
+
+
+
+
+ HWINSTA FASTCALL
+ UserGetProcessWindowStation(VOID)
+ {
+ PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
+
+ return ppi->hwinsta;
+ }
+
+
+ /*
+ * NtUserGetProcessWindowStation
+ *
+ * Returns a handle to the current process window station.
+ *
+ * Return Value
+ * If the function succeeds, the return value is handle to the window
+ * station assigned to the current process. If the function fails, the
+ * return value is NULL.
+ *
+ * Status
+ * @implemented
+ */
+
+ HWINSTA APIENTRY
+ NtUserGetProcessWindowStation(VOID)
+ {
+ return UserGetProcessWindowStation();
+ }
+
+ BOOL FASTCALL
+ UserSetProcessWindowStation(HWINSTA hWindowStation)
+ {
+ PPROCESSINFO ppi;
+ NTSTATUS Status;
+ HWINSTA hwinstaOld;
+ PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
+
+ ppi = PsGetCurrentProcessWin32Process();
+
+ /* Reference the new window station */
+ if(hWindowStation !=NULL)
+ {
+ Status = IntValidateWindowStationHandle( hWindowStation,
+ KernelMode,
+ 0,
+ &NewWinSta);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Validation of window station handle (0x%X) failed\n",
+ hWindowStation);
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ }
+
+ OldWinSta = ppi->prpwinsta;
+ hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
+
+ /* Dereference the previous window station */
+ if(OldWinSta != NULL)
+ {
+ ObDereferenceObject(OldWinSta);
+ }
+
+ /* Check if we have a stale handle (it should happen for console apps) */
+ if(hwinstaOld != ppi->hwinsta)
+ {
+ ObCloseHandle(hwinstaOld, UserMode);
+ }
+
+ /*
+ * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
+ */
+
+ PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
+
+ ppi->prpwinsta = NewWinSta;
+ ppi->hwinsta = hWindowStation;
+
+ return TRUE;
+ }
+
+ /*
+ * NtUserSetProcessWindowStation
+ *
+ * Assigns a window station to the current process.
+ *
+ * Parameters
+ * hWinSta
+ * Handle to the window station.
+ *
+ * Return Value
+ * Status
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL APIENTRY
+ NtUserSetProcessWindowStation(HWINSTA hWindowStation)
+ {
+ BOOL ret;
+
+ UserEnterExclusive();
+
+ ret = UserSetProcessWindowStation(hWindowStation);
+
+ UserLeave();
+
+ return ret;
+ }
+
+ /*
+ * NtUserLockWindowStation
+ *
+ * Locks switching desktops. Only the logon application is allowed to call this function.
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL APIENTRY
+ NtUserLockWindowStation(HWINSTA hWindowStation)
+ {
+ PWINSTATION_OBJECT Object;
+ NTSTATUS Status;
+
+ TRACE("About to set process window station with handle (0x%X)\n",
+ hWindowStation);
+
+ if(PsGetCurrentProcessWin32Process() != LogonProcess)
+ {
+ ERR("Unauthorized process attempted to lock the window station!\n");
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+
+ Status = IntValidateWindowStationHandle(
+ hWindowStation,
+ KernelMode,
+ 0,
+ &Object);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Validation of window station handle (0x%X) failed\n",
+ hWindowStation);
+ SetLastNtError(Status);
+ return FALSE;
+ }
+
+ Object->Flags |= WSS_LOCKED;
+
+ ObDereferenceObject(Object);
+ return TRUE;
+ }
+
+ /*
+ * NtUserUnlockWindowStation
+ *
+ * Unlocks switching desktops. Only the logon application is allowed to call this function.
+ *
+ * Status
+ * @implemented
+ */
+
+ BOOL APIENTRY
+ NtUserUnlockWindowStation(HWINSTA hWindowStation)
+ {
+ PWINSTATION_OBJECT Object;
+ NTSTATUS Status;
+ BOOL Ret;
+
+ TRACE("About to set process window station with handle (0x%X)\n",
+ hWindowStation);
+
+ if(PsGetCurrentProcessWin32Process() != LogonProcess)
+ {
+ ERR("Unauthorized process attempted to unlock the window station!\n");
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+
+ Status = IntValidateWindowStationHandle(
+ hWindowStation,
+ KernelMode,
+ 0,
+ &Object);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Validation of window station handle (0x%X) failed\n",
+ hWindowStation);
+ SetLastNtError(Status);
+ return FALSE;
+ }
+
+ Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
+ Object->Flags &= ~WSS_LOCKED;
+
+ ObDereferenceObject(Object);
+ return Ret;
+ }
+
+ static NTSTATUS FASTCALL
+ BuildWindowStationNameList(
+ ULONG dwSize,
+ PVOID lpBuffer,
+ PULONG pRequiredSize)
+ {
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE DirectoryHandle;
+ char InitialBuffer[256], *Buffer;
+ ULONG Context, ReturnLength, BufferSize;
+ DWORD EntryCount;
+ POBJECT_DIRECTORY_INFORMATION DirEntry;
+ WCHAR NullWchar;
+
+ /*
+ * Try to open the directory.
+ */
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &gustrWindowStationsDir,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenDirectoryObject(
+ &DirectoryHandle,
+ DIRECTORY_QUERY,
+ &ObjectAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* First try to query the directory using a fixed-size buffer */
+ Context = 0;
+ Buffer = NULL;
+ Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
+ FALSE, TRUE, &Context, &ReturnLength);
+ if (NT_SUCCESS(Status))
+ {
+ if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
+ FALSE, &Context, NULL))
+ {
+ /* Our fixed-size buffer is large enough */
+ Buffer = InitialBuffer;
+ }
+ }
+
+ if (NULL == Buffer)
+ {
+ /* Need a larger buffer, check how large exactly */
+ Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
+ &ReturnLength);
+ if (STATUS_BUFFER_TOO_SMALL == Status)
+ {
+ BufferSize = ReturnLength;
+ Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
+ if (NULL == Buffer)
+ {
+ ObDereferenceObject(DirectoryHandle);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* We should have a sufficiently large buffer now */
+ Context = 0;
+ Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
+ FALSE, TRUE, &Context, &ReturnLength);
+ if (! NT_SUCCESS(Status) ||
+ STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
+ FALSE, &Context, NULL))
+ {
+ /* Something went wrong, maybe someone added a directory entry? Just give up. */
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ ObDereferenceObject(DirectoryHandle);
+ return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
+ }
+ }
+ }
+
+ ZwClose(DirectoryHandle);
+
+ /*
+ * Count the required size of buffer.
+ */
+ ReturnLength = sizeof(DWORD);
+ EntryCount = 0;
+ for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
+ DirEntry++)
+ {
+ ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
+ EntryCount++;
+ }
+ TRACE("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
+ if (NULL != pRequiredSize)
+ {
+ Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
+ if (! NT_SUCCESS(Status))
+ {
+ if (Buffer != InitialBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ }
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ /*
+ * Check if the supplied buffer is large enough.
+ */
+ if (dwSize < ReturnLength)
+ {
+ if (Buffer != InitialBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ }
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * Generate the resulting buffer contents.
+ */
+ Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
+ if (! NT_SUCCESS(Status))
+ {
+ if (Buffer != InitialBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ }
+ return Status;
+ }
+ lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
+
+ NullWchar = L'\0';
+ for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
+ DirEntry++)
+ {
+ Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
+ if (! NT_SUCCESS(Status))
+ {
+ if (Buffer != InitialBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ }
+ return Status;
+ }
+ lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
+ Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
+ if (! NT_SUCCESS(Status))
+ {
+ if (Buffer != InitialBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ }
+ return Status;
+ }
+ lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
+ }
+
+ /*
+ * Clean up
+ */
+ if (NULL != Buffer && Buffer != InitialBuffer)
+ {
+ ExFreePoolWithTag(Buffer, TAG_WINSTA);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ static NTSTATUS FASTCALL
+ BuildDesktopNameList(
+ HWINSTA hWindowStation,
+ ULONG dwSize,
+ PVOID lpBuffer,
+ PULONG pRequiredSize)
+ {
+ NTSTATUS Status;
+ PWINSTATION_OBJECT WindowStation;
+ KIRQL OldLevel;
+ PLIST_ENTRY DesktopEntry;
+ PDESKTOP DesktopObject;
+ DWORD EntryCount;
+ ULONG ReturnLength;
+ WCHAR NullWchar;
+
+ Status = IntValidateWindowStationHandle(hWindowStation,
+ KernelMode,
+ 0,
+ &WindowStation);
+ if (! NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
+
+ /*
+ * Count the required size of buffer.
+ */
+ ReturnLength = sizeof(DWORD);
+ EntryCount = 0;
+ for (DesktopEntry = WindowStation->DesktopListHead.Flink;
+ DesktopEntry != &WindowStation->DesktopListHead;
+ DesktopEntry = DesktopEntry->Flink)
+ {
+ DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
+ ReturnLength += ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + sizeof(WCHAR);
+ EntryCount++;
+ }
+ TRACE("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
+ if (NULL != pRequiredSize)
+ {
+ Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
+ if (! NT_SUCCESS(Status))
+ {
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ /*
+ * Check if the supplied buffer is large enough.
+ */
+ if (dwSize < ReturnLength)
+ {
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /*
+ * Generate the resulting buffer contents.
+ */
+ Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
+ if (! NT_SUCCESS(Status))
+ {
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
+ return Status;
+ }
+ lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
+
+ NullWchar = L'\0';
+ for (DesktopEntry = WindowStation->DesktopListHead.Flink;
+ DesktopEntry != &WindowStation->DesktopListHead;
+ DesktopEntry = DesktopEntry->Flink)
+ {
+ DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
+ Status = MmCopyToCaller(lpBuffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
+ if (! NT_SUCCESS(Status))
+ {
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
+ return Status;
+ }
+ lpBuffer = (PVOID) ((PCHAR) lpBuffer + ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
+ Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
+ if (! NT_SUCCESS(Status))
+ {
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
+ return Status;
+ }
+ lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
+ }
+
+ /*
+ * Clean up
+ */
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
+
+ return STATUS_SUCCESS;
+ }
+
+ /*
+ * NtUserBuildNameList
+ *
+ * Function used for enumeration of desktops or window stations.
+ *
+ * Parameters
+ * hWinSta
+ * For enumeration of window stations this parameter must be set to
+ * zero. Otherwise it's handle for window station.
+ *
+ * dwSize
+ * Size of buffer passed by caller.
+ *
+ * lpBuffer
+ * Buffer passed by caller. If the function succedes, the buffer is
+ * filled with window station/desktop count (in first DWORD) and
+ * NULL-terminated window station/desktop names.
+ *
+ * pRequiredSize
+ * If the function suceedes, this is the number of bytes copied.
+ * Otherwise it's size of buffer needed for function to succeed.
+ *
+ * Status
+ * @implemented
+ */
+
+ NTSTATUS APIENTRY
+ NtUserBuildNameList(
+ HWINSTA hWindowStation,
+ ULONG dwSize,
+ PVOID lpBuffer,
+ PULONG pRequiredSize)
+ {
+ /* The WindowStation name list and desktop name list are build in completely
+ different ways. Call the appropriate function */
+ return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
+ BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
+ }
+
+ /*
+ * @implemented
+ */
+ BOOL APIENTRY
+ NtUserSetLogonNotifyWindow(HWND hWnd)
+ {
+ if(LogonProcess != PsGetCurrentProcessWin32Process())
+ {
+ return FALSE;
+ }
+
+ if(!IntIsWindow(hWnd))
+ {
+ return FALSE;
+ }
+
+ hwndSAS = hWnd;
+
+ return TRUE;
+ }
+
+ /* EOF */
--- /dev/null
- windows/cursoricon.c
+
+ spec2def(user32.dll user32.spec ADD_IMPORTLIB)
+
+ include_directories(
+ BEFORE ${REACTOS_SOURCE_DIR}/include/reactos/wine
+ ${REACTOS_SOURCE_DIR}/include/reactos/subsys
+ include
+ ${REACTOS_SOURCE_DIR}/win32ss/include)
+
+ set_rc_compiler()
+
+ list(APPEND SOURCE
+ controls/appswitch.c
+ controls/button.c
+ controls/combo.c
+ controls/edit.c
+ controls/icontitle.c
+ controls/listbox.c
+ controls/regcontrol.c
+ controls/scrollbar.c
+ controls/static.c
+ misc/dde.c
+ misc/ddeclient.c
+ misc/ddeserver.c
+ misc/desktop.c
+ misc/display.c
+ misc/dllmain.c
+ misc/exit.c
+ misc/exticon.c
+ misc/imm.c
+ misc/misc.c
+ misc/object.c
+ misc/resources.c
+ misc/rtlstr.c
+ misc/stubs.c
+ misc/timer.c
+ misc/usrapihk.c
+ misc/winhelp.c
+ misc/winsta.c
+ windows/accel.c
+ windows/caret.c
+ windows/class.c
+ windows/clipboard.c
++ # windows/cursoricon.c
+ windows/dc.c
+ windows/defwnd.c
+ windows/dialog.c
+ windows/draw.c
+ windows/font.c
+ windows/hook.c
+ windows/input.c
+ windows/mdi.c
+ windows/menu.c
+ windows/messagebox.c
+ windows/message.c
+ windows/nonclient.c
+ windows/paint.c
+ windows/prop.c
+ windows/rect.c
+ windows/spy.c
+ windows/text.c
+ windows/window.c
+ windows/winpos.c
+ user32.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/user32.def)
+
++ if(USE_NEW_CURSORICON)
++ list(APPEND SOURCE windows/cursoricon_new.c)
++ else()
++ list(APPEND SOURCE windows/cursoricon.c)
++ endif()
++
+ add_library(user32 SHARED ${SOURCE})
+ set_module_type(user32 win32dll UNICODE)
+
+ target_link_libraries(user32
+ user32_wsprintf
+ wine
+ win32ksys
+ ${PSEH_LIB})
+
+ add_delay_importlibs(user32 imm32 usp10)
+ add_importlibs(user32 gdi32 advapi32 msvcrt kernel32 ntdll)
+ add_pch(user32 include/user32.h)
+ add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all)
+
--- /dev/null
- #include "pshpack1.h"
-
- typedef struct
- {
- BYTE bWidth; /* Width, in pixels, of the image */
- BYTE bHeight; /* Height, in pixels, of the image */
- BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */
- BYTE bReserved; /* Reserved ( must be 0) */
- WORD wPlanes; /* Color Planes */
- WORD wBitCount; /* Bits per pixel */
- DWORD dwBytesInRes; /* How many bytes in this resource? */
- DWORD dwImageOffset; /* Where in the file is this image? */
- } icoICONDIRENTRY, *LPicoICONDIRENTRY;
-
- typedef struct
- {
- WORD idReserved; /* Reserved (must be 0) */
- WORD idType; /* Resource Type (RES_ICON or RES_CURSOR) */
- WORD idCount; /* How many images */
- icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
- } icoICONDIR, *LPicoICONDIR;
-
- #include "poppack.h"
-
+ /*
+ * icon extracting
+ *
+ * taken and slightly changed from shell
+ * this should replace the icon extraction code in shell32 and shell16 once
+ * it needs a serious test for compliance with the native API
+ *
+ * Copyright 2000 Juergen Schmied
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+ #include <user32.h>
+
+ #include <wine/debug.h>
+
+ /* Start of Hack section */
+
+ WINE_DEFAULT_DEBUG_CHANNEL(icon);
+
+ #if 0
+ static void dumpIcoDirEnty ( LPicoICONDIRENTRY entry )
+ {
+ TRACE("width = 0x%08x height = 0x%08x\n", entry->bWidth, entry->bHeight);
+ TRACE("colors = 0x%08x planes = 0x%08x\n", entry->bColorCount, entry->wPlanes);
+ TRACE("bitcount = 0x%08x bytesinres = 0x%08lx offset = 0x%08lx\n",
+ entry->wBitCount, entry->dwBytesInRes, entry->dwImageOffset);
+ }
+ static void dumpIcoDir ( LPicoICONDIR entry )
+ {
+ TRACE("type = 0x%08x count = 0x%08x\n", entry->idType, entry->idCount);
+ }
+ #endif
+
+ /**********************************************************************
+ * find_entry_by_id
+ *
+ * Find an entry by id in a resource directory
+ * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
+ */
+ static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
+ WORD id, const void *root )
+ {
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
+ int min, max, pos;
+
+ entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
+ min = dir->NumberOfNamedEntries;
+ max = min + dir->NumberOfIdEntries - 1;
+ while (min <= max)
+ {
+ pos = (min + max) / 2;
+ if (entry[pos].Id == id)
+ return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry[pos].OffsetToDirectory);
+ if (entry[pos].Id > id) max = pos - 1;
+ else min = pos + 1;
+ }
+ return NULL;
+ }
+
+ /**********************************************************************
+ * find_entry_default
+ *
+ * Find a default entry in a resource directory
+ * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
+ */
+ static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
+ const void *root )
+ {
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
+ entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
+ return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry->OffsetToDirectory);
+ }
+
+ /*************************************************************************
+ * USER32_GetResourceTable
+ */
+ static DWORD USER32_GetResourceTable(LPBYTE peimage,DWORD pesize,LPBYTE *retptr)
+ {
+ IMAGE_DOS_HEADER * mz_header;
+
+ TRACE("%p %p\n", peimage, retptr);
+
+ *retptr = NULL;
+
+ mz_header = (IMAGE_DOS_HEADER*) peimage;
+
+ if (mz_header->e_magic != IMAGE_DOS_SIGNATURE)
+ {
+ if (mz_header->e_cblp == 1) /* .ICO file ? */
+ {
+ *retptr = (LPBYTE)-1; /* ICONHEADER.idType, must be 1 */
+ return 1;
+ }
+ else
+ return 0; /* failed */
+ }
+ if (mz_header->e_lfanew >= pesize) {
+ return 0; /* failed, happens with PKZIP DOS Exes for instance. */
+ }
+ if (*((DWORD*)(peimage + mz_header->e_lfanew)) == IMAGE_NT_SIGNATURE )
+ return IMAGE_NT_SIGNATURE;
+ #if 0
+ if (*((WORD*)(peimage + mz_header->e_lfanew)) == IMAGE_OS2_SIGNATURE )
+ {
+ IMAGE_OS2_HEADER * ne_header;
+
+ ne_header = (IMAGE_OS2_HEADER*)(peimage + mz_header->e_lfanew);
+
+ if (ne_header->ne_magic != IMAGE_OS2_SIGNATURE)
+ return 0;
+
+ if( (ne_header->ne_restab - ne_header->ne_rsrctab) <= sizeof(NE_TYPEINFO) )
+ *retptr = (LPBYTE)-1;
+ else
+ *retptr = peimage + mz_header->e_lfanew + ne_header->ne_rsrctab;
+
+ return IMAGE_OS2_SIGNATURE;
+ }
+ #endif
+ return 0; /* failed */
+ }
+ #if 0
+ /*************************************************************************
+ * USER32_LoadResource
+ */
+ static BYTE * USER32_LoadResource( LPBYTE peimage, NE_NAMEINFO* pNInfo, WORD sizeShift, ULONG *uSize)
+ {
+ TRACE("%p %p 0x%08x\n", peimage, pNInfo, sizeShift);
+
+ *uSize = (DWORD)pNInfo->length << sizeShift;
+ return peimage + ((DWORD)pNInfo->offset << sizeShift);
+ }
+
+ /*************************************************************************
+ * ICO_LoadIcon
+ */
+ static BYTE * ICO_LoadIcon( LPBYTE peimage, LPicoICONDIRENTRY lpiIDE, ULONG *uSize)
+ {
+ TRACE("%p %p\n", peimage, lpiIDE);
+
+ *uSize = lpiIDE->dwBytesInRes;
+ return peimage + lpiIDE->dwImageOffset;
+ }
+
+ /*************************************************************************
+ * ICO_GetIconDirectory
+ *
+ * Reads .ico file and build phony ICONDIR struct
+ */
+ #define HEADER_SIZE (sizeof(CURSORICONDIR) - sizeof (CURSORICONDIRENTRY))
+ #define HEADER_SIZE_FILE (sizeof(icoICONDIR) - sizeof (icoICONDIRENTRY))
+
+ static BYTE * ICO_GetIconDirectory( LPBYTE peimage, LPicoICONDIR* lplpiID, ULONG *uSize )
+ {
+ CURSORICONDIR * lpcid; /* icon resource in resource-dir format */
+ CURSORICONDIR * lpID; /* icon resource in resource format */
+ int i;
+
+ TRACE("%p %p\n", peimage, lplpiID);
+
+ lpcid = (CURSORICONDIR*)peimage;
+
+ if( lpcid->idReserved || (lpcid->idType != 1) || (!lpcid->idCount) )
+ return 0;
+
+ /* allocate the phony ICONDIR structure */
+ *uSize = lpcid->idCount * sizeof(CURSORICONDIRENTRY) + HEADER_SIZE;
+ if( (lpID = HeapAlloc(GetProcessHeap(),0, *uSize) ))
+ {
+ /* copy the header */
+ lpID->idReserved = lpcid->idReserved;
+ lpID->idType = lpcid->idType;
+ lpID->idCount = lpcid->idCount;
+
+ /* copy the entries */
+ for( i=0; i < lpcid->idCount; i++ )
+ {
+ memcpy(&lpID->idEntries[i], &lpcid->idEntries[i], sizeof(CURSORICONDIRENTRY) - 2);
+ lpID->idEntries[i].wResId = i;
+ }
+
+ *lplpiID = (LPicoICONDIR)peimage;
+ return (BYTE *)lpID;
+ }
+ return 0;
+ }
+ #endif
+ /*************************************************************************
+ * ICO_ExtractIconExW [internal]
+ *
+ * NOTES
+ * nIcons = 0: returns number of Icons in file
+ *
+ * returns
+ * invalid file: -1
+ * failure:0;
+ * success: number of icons in file (nIcons = 0) or nr of icons retrieved
+ */
+ static UINT ICO_ExtractIconExW(
+ LPCWSTR lpszExeFileName,
+ HICON * RetPtr,
+ INT nIconIndex,
+ UINT nIcons,
+ UINT cxDesired,
+ UINT cyDesired,
+ UINT *pIconId,
+ UINT flags)
+ {
+ UINT ret = 0;
+ UINT cx1, cx2, cy1, cy2;
+ LPBYTE pData;
+ DWORD sig;
+ HANDLE hFile;
+ UINT16 iconDirCount = 0; //,iconCount = 0;
+ LPBYTE peimage;
+ HANDLE fmapping;
+ DWORD fsizeh,fsizel;
+ WCHAR szExePath[MAX_PATH];
+ DWORD dwSearchReturn;
+
+ TRACE("%s, %d, %d %p 0x%08x\n", debugstr_w(lpszExeFileName), nIconIndex, nIcons, pIconId, flags);
+
+ dwSearchReturn = SearchPathW(NULL, lpszExeFileName, NULL, sizeof(szExePath) / sizeof(szExePath[0]), szExePath, NULL);
+ if ((dwSearchReturn == 0) || (dwSearchReturn > sizeof(szExePath) / sizeof(szExePath[0])))
+ {
+ WARN("File %s not found or path too long\n", debugstr_w(lpszExeFileName));
+ return -1;
+ }
+
+ hFile = CreateFileW(szExePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+ if (hFile == INVALID_HANDLE_VALUE) return ret;
+ fsizel = GetFileSize(hFile,&fsizeh);
+
+ /* Map the file */
+ fmapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
+ CloseHandle(hFile);
+ if (!fmapping)
+ {
+ WARN("CreateFileMapping error %ld\n", GetLastError() );
+ return 0xFFFFFFFF;
+ }
+
+ if (!(peimage = MapViewOfFile(fmapping, FILE_MAP_READ, 0, 0, 0)))
+ {
+ WARN("MapViewOfFile error %ld\n", GetLastError() );
+ CloseHandle(fmapping);
+ return 0xFFFFFFFF;
+ }
+ CloseHandle(fmapping);
+
+ cx1 = LOWORD(cxDesired);
+ cx2 = HIWORD(cxDesired);
+ cy1 = LOWORD(cyDesired);
+ cy2 = HIWORD(cyDesired);
+
+ if (pIconId) /* Invalidate first icon identifier */
+ *pIconId = 0xFFFFFFFF;
+
+ if (!pIconId) /* if no icon identifier array present use the icon handle array as intermediate storage */
+ pIconId = (UINT*)RetPtr;
+
+ sig = USER32_GetResourceTable(peimage, fsizel, &pData);
+
+ /* ico file or NE exe/dll*/
+ #if 0
+ if (sig==IMAGE_OS2_SIGNATURE || sig==1) /* .ICO file */
+ {
+ BYTE *pCIDir = 0;
+ NE_TYPEINFO *pTInfo = (NE_TYPEINFO*)(pData + 2);
+ NE_NAMEINFO *pIconStorage = NULL;
+ NE_NAMEINFO *pIconDir = NULL;
+ LPicoICONDIR lpiID = NULL;
+
+ TRACE("-- OS2/icon Signature (0x%08lx)\n", sig);
+
+ if (pData == (BYTE*)-1)
+ {
+ pCIDir = ICO_GetIconDirectory(peimage, &lpiID, &uSize); /* check for .ICO file */
+ if (pCIDir)
+ {
+ iconDirCount = 1; iconCount = lpiID->idCount;
+ TRACE("-- icon found %p 0x%08lx 0x%08x 0x%08x\n", pCIDir, uSize, iconDirCount, iconCount);
+ }
+ }
+ else while (pTInfo->type_id && !(pIconStorage && pIconDir))
+ {
+ if (pTInfo->type_id == NE_RSCTYPE_GROUP_ICON) /* find icon directory and icon repository */
+ {
+ iconDirCount = pTInfo->count;
+ pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
+ TRACE("\tfound directory - %i icon families\n", iconDirCount);
+ }
+ if (pTInfo->type_id == NE_RSCTYPE_ICON)
+ {
+ iconCount = pTInfo->count;
+ pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
+ TRACE("\ttotal icons - %i\n", iconCount);
+ }
+ pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
+ }
+
+ if ((pIconStorage && pIconDir) || lpiID) /* load resources and create icons */
+ {
+ if (nIcons == 0)
+ {
+ ret = iconDirCount;
+ if (lpiID && pCIDir) /* *.ico file, deallocate heap pointer*/
+ HeapFree(GetProcessHeap(), 0, pCIDir);
+ }
+ else if (nIconIndex < iconDirCount)
+ {
+ UINT16 i, icon;
+ if (nIcons > iconDirCount - nIconIndex)
+ nIcons = iconDirCount - nIconIndex;
+
+ for (i = 0; i < nIcons; i++)
+ {
+ /* .ICO files have only one icon directory */
+ if (lpiID == NULL) /* not *.ico */
+ pCIDir = USER32_LoadResource(peimage, pIconDir + i + nIconIndex, *(WORD*)pData, &uSize);
+ pIconId[i] = LookupIconIdFromDirectoryEx(pCIDir, TRUE, (i & 1) ? cx2 : cx1, (i & 1) ? cy2 : cy1, flags);
+ }
+ if (lpiID && pCIDir) /* *.ico file, deallocate heap pointer*/
+ HeapFree(GetProcessHeap(), 0, pCIDir);
+
+ for (icon = 0; icon < nIcons; icon++)
+ {
+ pCIDir = NULL;
+ if (lpiID)
+ pCIDir = ICO_LoadIcon(peimage, lpiID->idEntries + (int)pIconId[icon], &uSize);
+ else
+ for (i = 0; i < iconCount; i++)
+ if (pIconStorage[i].id == ((int)pIconId[icon] | 0x8000) )
+ pCIDir = USER32_LoadResource(peimage, pIconStorage + i, *(WORD*)pData, &uSize);
+
+ if (pCIDir)
+ RetPtr[icon] = (HICON)CreateIconFromResourceEx(pCIDir, uSize, TRUE, 0x00030000,
+ (icon & 1) ? cx2 : cx1, (icon & 1) ? cy2 : cy1, flags);
+ else
+ RetPtr[icon] = 0;
+ }
+ ret = icon; /* return number of retrieved icons */
+ }
+ }
+ }
+ /* end ico file */
+
+ /* exe/dll */
+ else if( sig == IMAGE_NT_SIGNATURE )
+ #endif
+ if( sig == IMAGE_NT_SIGNATURE )
+ {
+ LPBYTE idata,igdata;
+ PIMAGE_DOS_HEADER dheader;
+ PIMAGE_NT_HEADERS pe_header;
+ PIMAGE_SECTION_HEADER pe_sections;
+ const IMAGE_RESOURCE_DIRECTORY *rootresdir,*iconresdir,*icongroupresdir;
+ const IMAGE_RESOURCE_DATA_ENTRY *idataent,*igdataent;
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent;
+ UINT i, j;
+
+ dheader = (PIMAGE_DOS_HEADER)peimage;
+ pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew); /* it is a pe header, USER32_GetResourceTable checked that */
+ pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER)
+ + pe_header->FileHeader.SizeOfOptionalHeader);
+ rootresdir = NULL;
+
+ /* search for the root resource directory */
+ for (i=0;i<pe_header->FileHeader.NumberOfSections;i++)
+ {
+ if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ continue;
+ if (fsizel < pe_sections[i].PointerToRawData+pe_sections[i].SizeOfRawData) {
+ FIXME("File %s too short (section is at %ld bytes, real size is %ld)\n",
+ debugstr_w(lpszExeFileName),
+ pe_sections[i].PointerToRawData+pe_sections[i].SizeOfRawData,
+ fsizel
+ );
+ goto end;
+ }
+ /* FIXME: doesn't work when the resources are not in a separate section */
+ if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
+ {
+ rootresdir = (PIMAGE_RESOURCE_DIRECTORY)(peimage+pe_sections[i].PointerToRawData);
+ break;
+ }
+ }
+
+ if (!rootresdir)
+ {
+ WARN("haven't found section for resource directory.\n");
+ goto end; /* failure */
+ }
+
+ /* search for the group icon directory */
+ if (!(icongroupresdir = find_entry_by_id(rootresdir, LOWORD(RT_GROUP_ICON), rootresdir)))
+ {
+ WARN("No Icongroupresourcedirectory!\n");
+ goto end; /* failure */
+ }
+ iconDirCount = icongroupresdir->NumberOfNamedEntries + icongroupresdir->NumberOfIdEntries;
+
+ /* only number of icons requested */
+ if( !pIconId )
+ {
+ ret = iconDirCount;
+ goto end; /* success */
+ }
+
+ if( nIconIndex < 0 )
+ {
+ /* search resource id */
+ int n = 0;
+ int iId = abs(nIconIndex);
+ const IMAGE_RESOURCE_DIRECTORY_ENTRY* xprdeTmp = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1);
+
+ while(n<iconDirCount && xprdeTmp)
+ {
+ if(xprdeTmp->Id == iId)
+ {
+ nIconIndex = n;
+ break;
+ }
+ n++;
+ xprdeTmp++;
+ }
+ if (nIconIndex < 0)
+ {
+ WARN("resource id %d not found\n", iId);
+ goto end; /* failure */
+ }
+ }
+ else
+ {
+ /* check nIconIndex to be in range */
+ if (nIconIndex >= iconDirCount)
+ {
+ WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
+ goto end; /* failure */
+ }
+ }
+
+ /* assure we don't get too much */
+ if( nIcons > iconDirCount - nIconIndex )
+ nIcons = iconDirCount - nIconIndex;
+
+ /* starting from specified index */
+ xresent = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1) + nIconIndex;
+
+ for (i=0; i < nIcons; i++,xresent++)
+ {
+ const IMAGE_RESOURCE_DIRECTORY *resdir;
+
+ /* go down this resource entry, name */
+ resdir = (const IMAGE_RESOURCE_DIRECTORY*)((const char *)rootresdir+(xresent->OffsetToDirectory));
+
+ /* default language (0) */
+ resdir = find_entry_default(resdir,rootresdir);
+ igdataent = (const IMAGE_RESOURCE_DATA_ENTRY*)resdir;
+
+ /* lookup address in mapped image for virtual address */
+ igdata = NULL;
+
+ for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
+ {
+ if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
+ continue;
+ if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
+ continue;
+
+ if (igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData+igdataent->Size > fsizel) {
+ FIXME("overflow in PE lookup (%s has len %ld, have offset %ld), short file?\n", debugstr_w(lpszExeFileName), fsizel,
+ igdataent->OffsetToData - pe_sections[j].VirtualAddress + pe_sections[j].PointerToRawData + igdataent->Size);
+ goto end; /* failure */
+ }
+ igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
+ }
+
+ if (!igdata)
+ {
+ FIXME("no matching real address for icongroup!\n");
+ goto end; /* failure */
+ }
+ pIconId[i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx1, cy1, flags);
+ if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx2, cy2, flags);
+ }
+
+ if (!(iconresdir=find_entry_by_id(rootresdir,LOWORD(RT_ICON),rootresdir)))
+ {
+ WARN("No Iconresourcedirectory!\n");
+ goto end; /* failure */
+ }
+
+ for (i=0; i<nIcons; i++)
+ {
+ const IMAGE_RESOURCE_DIRECTORY *xresdir;
+ xresdir = find_entry_by_id(iconresdir, LOWORD(pIconId[i]), rootresdir);
+ if (!xresdir)
+ {
+ WARN("icon entry %d not found\n", LOWORD(pIconId[i]));
+ RetPtr[i]=0;
+ continue;
+ }
+ xresdir = find_entry_default(xresdir, rootresdir);
+ if (!xresdir)
+ {
+ WARN("icon entry %d not found\n", LOWORD(pIconId[i]));
+ RetPtr[i]=0;
+ continue;
+ }
+ idataent = (const IMAGE_RESOURCE_DATA_ENTRY*)xresdir;
+ idata = NULL;
+
+ /* map virtual to address in image */
+ for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
+ {
+ if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
+ continue;
+ if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
+ continue;
+ idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
+ }
+ if (!idata)
+ {
+ WARN("no matching real address found for icondata!\n");
+ RetPtr[i]=0;
+ continue;
+ }
+ RetPtr[i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx1, cy1, flags);
+ if (cx2 && cy2)
+ RetPtr[++i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx2, cy2, flags);
+ }
+ ret = i; /* return number of retrieved icons */
+ } /* if(sig == IMAGE_NT_SIGNATURE) */
+
+ end:
+ UnmapViewOfFile(peimage); /* success */
+ return ret;
+ }
+
+ /***********************************************************************
+ * PrivateExtractIconsW [USER32.@]
+ *
+ * NOTES
+ * If HIWORD(sizeX) && HIWORD(sizeY) 2 * ((nIcons + 1) MOD 2) icons are
+ * returned, with the LOWORD size icon first and the HIWORD size icon
+ * second.
+ * Also the Windows equivalent does extract icons in a strange way if
+ * nIndex is negative. Our implementation treats a negative nIndex as
+ * looking for that resource identifier for the first icon to retrieve.
+ *
+ * FIXME:
+ * should also support 16 bit EXE + DLLs, cursor and animated cursor as
+ * well as bitmap files.
+ */
+
+ UINT WINAPI PrivateExtractIconsW (
+ LPCWSTR lpwstrFile,
+ int nIndex,
+ int sizeX,
+ int sizeY,
+ HICON * phicon, /* [out] pointer to array of nIcons HICON handles */
+ UINT* pIconId, /* [out] pointer to array of nIcons icon identifiers or NULL */
+ UINT nIcons, /* [in] number of icons to retrieve */
+ UINT flags ) /* [in] LR_* flags used by LoadImage */
+ {
+ TRACE("%s %d %dx%d %p %p %d 0x%08x\n",
+ debugstr_w(lpwstrFile), nIndex, sizeX, sizeY, phicon, pIconId, nIcons, flags);
+
+ if ((nIcons & 1) && HIWORD(sizeX) && HIWORD(sizeY))
+ {
+ WARN("Uneven number %d of icons requested for small and large icons!\n", nIcons);
+ }
+ return ICO_ExtractIconExW(lpwstrFile, phicon, nIndex, nIcons, sizeX, sizeY, pIconId, flags);
+ }
+
+ /***********************************************************************
+ * PrivateExtractIconsA [USER32.@]
+ */
+
+ UINT WINAPI PrivateExtractIconsA (
+ LPCSTR lpstrFile,
+ int nIndex,
+ int sizeX,
+ int sizeY,
+ HICON * phicon, /* [out] pointer to array of nIcons HICON handles */
+ UINT* piconid, /* [out] pointer to array of nIcons icon identifiers or NULL */
+ UINT nIcons, /* [in] number of icons to retrieve */
+ UINT flags ) /* [in] LR_* flags used by LoadImage */
+ {
+ UINT ret;
+ INT len = MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, NULL, 0);
+ LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (lpwstrFile == NULL)
+ return 0;
+
+ MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, lpwstrFile, len);
+ ret = PrivateExtractIconsW(lpwstrFile, nIndex, sizeX, sizeY, phicon, piconid, nIcons, flags);
+
+ HeapFree(GetProcessHeap(), 0, lpwstrFile);
+ return ret;
+ }
+
+ /***********************************************************************
+ * PrivateExtractIconExW [USER32.@]
+ * NOTES
+ * if nIndex == -1 it returns the number of icons in any case !!!
+ */
+ UINT WINAPI PrivateExtractIconExW (
+ LPCWSTR lpwstrFile,
+ int nIndex,
+ HICON * phIconLarge,
+ HICON * phIconSmall,
+ UINT nIcons )
+ {
+ DWORD cyicon, cysmicon, cxicon, cxsmicon;
+ UINT ret = 0;
+
+ TRACE("%s %d %p %p %d\n",
+ debugstr_w(lpwstrFile),nIndex,phIconLarge, phIconSmall, nIcons);
+
+ if (nIndex == -1)
+ /* get the number of icons */
+ return ICO_ExtractIconExW(lpwstrFile, NULL, 0, 0, 0, 0, NULL, LR_DEFAULTCOLOR);
+
+ if (nIcons == 1 && phIconSmall && phIconLarge)
+ {
+ HICON hIcon[2];
+ cxicon = GetSystemMetrics(SM_CXICON);
+ cyicon = GetSystemMetrics(SM_CYICON);
+ cxsmicon = GetSystemMetrics(SM_CXSMICON);
+ cysmicon = GetSystemMetrics(SM_CYSMICON);
+
+ ret = ICO_ExtractIconExW(lpwstrFile, hIcon, nIndex, 2, cxicon | (cxsmicon<<16),
+ cyicon | (cysmicon<<16), NULL, LR_DEFAULTCOLOR);
+ *phIconLarge = hIcon[0];
+ *phIconSmall = hIcon[1];
+ return ret;
+ }
+
+ if (phIconSmall)
+ {
+ /* extract n small icons */
+ cxsmicon = GetSystemMetrics(SM_CXSMICON);
+ cysmicon = GetSystemMetrics(SM_CYSMICON);
+ ret = ICO_ExtractIconExW(lpwstrFile, phIconSmall, nIndex, nIcons, cxsmicon,
+ cysmicon, NULL, LR_DEFAULTCOLOR);
+ }
+ if (phIconLarge)
+ {
+ /* extract n large icons */
+ cxicon = GetSystemMetrics(SM_CXICON);
+ cyicon = GetSystemMetrics(SM_CYICON);
+ ret = ICO_ExtractIconExW(lpwstrFile, phIconLarge, nIndex, nIcons, cxicon,
+ cyicon, NULL, LR_DEFAULTCOLOR);
+ }
+ return ret;
+ }
+
+ /***********************************************************************
+ * PrivateExtractIconExA [USER32.@]
+ */
+ UINT WINAPI PrivateExtractIconExA (
+ LPCSTR lpstrFile,
+ int nIndex,
+ HICON * phIconLarge,
+ HICON * phIconSmall,
+ UINT nIcons )
+ {
+ UINT ret;
+ INT len = MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, NULL, 0);
+ LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ if (lpwstrFile == NULL)
+ return 0;
+
+ TRACE("%s %d %p %p %d\n", lpstrFile, nIndex, phIconLarge, phIconSmall, nIcons);
+
+ MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, lpwstrFile, len);
+ ret = PrivateExtractIconExW(lpwstrFile, nIndex, phIconLarge, phIconSmall, nIcons);
+ HeapFree(GetProcessHeap(), 0, lpwstrFile);
+ return ret;
+ }
--- /dev/null
- BOOL ret = TRUE;
+ /*
+ * ReactOS kernel
+ * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+ /* $Id$
+ *
+ * PROJECT: ReactOS user32.dll
+ * FILE: lib/user32/misc/dde.c
+ * PURPOSE: DDE
+ * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ * 09-05-2001 CSH Created
+ */
+
+ /* INCLUDES ******************************************************************/
+
+ #include <user32.h>
+
+ #include <wine/debug.h>
+ WINE_DEFAULT_DEBUG_CHANNEL(user32);
+
+ /* FUNCTIONS *****************************************************************/
+
+ /*
+ * @implemented
+ */
+ BOOL
+ WINAPI
+ GetUserObjectInformationA(
+ HANDLE hObj,
+ int nIndex,
+ PVOID pvInfo,
+ DWORD nLength,
+ LPDWORD lpnLengthNeeded)
+ {
+ LPWSTR buffer;
- if (!GetUserObjectInformationW(hObj, nIndex, buffer, nLength*2, lpnLengthNeeded))
- ret = FALSE;
- *lpnLengthNeeded /= 2;
-
- if (ret)
++ BOOL ret = FALSE;
++ DWORD LengthNeeded;
+
+ TRACE("GetUserObjectInformationA(%x %d %x %d %x)\n", hObj, nIndex,
+ pvInfo, nLength, lpnLengthNeeded);
+
+ if (nIndex != UOI_NAME && nIndex != UOI_TYPE)
+ return GetUserObjectInformationW(hObj, nIndex, pvInfo, nLength, lpnLengthNeeded);
+
+ /* allocate unicode buffer */
+ buffer = HeapAlloc(GetProcessHeap(), 0, nLength*2);
+ if (buffer == NULL)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ /* get unicode string */
- if (WideCharToMultiByte(CP_THREAD_ACP, 0, buffer, -1,
- pvInfo, nLength, NULL, NULL) == 0)
++ if (GetUserObjectInformationW(hObj, nIndex, buffer, nLength*2, lpnLengthNeeded))
+ {
+ /* convert string */
- ret = FALSE;
++ LengthNeeded = WideCharToMultiByte(CP_THREAD_ACP, 0, buffer, -1,
++ pvInfo, nLength, NULL, NULL);
++
++ if (LengthNeeded != 0)
+ {
++ *lpnLengthNeeded = LengthNeeded;
++ ret = TRUE;
+ }
+ }
+
+ /* free resources */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return ret;
+ }
--- /dev/null
--- /dev/null