Synchronize with trunk's revision r57652.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 31 Oct 2012 00:26:38 +0000 (00:26 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 31 Oct 2012 00:26:38 +0000 (00:26 +0000)
svn path=/branches/ros-csrss/; revision=57653

19 files changed:
1  2  3 
dll/win32/kernel32/k32.h
win32ss/CMakeLists.txt
win32ss/gdi/ntgdi/misc.h
win32ss/include/ntuser.h
win32ss/user/ntuser/callproc.c
win32ss/user/ntuser/clipboard.c
win32ss/user/ntuser/cursoricon.c
win32ss/user/ntuser/cursoricon.h
win32ss/user/ntuser/cursoricon_new.c
win32ss/user/ntuser/hook.c
win32ss/user/ntuser/msgqueue.c
win32ss/user/ntuser/object.c
win32ss/user/ntuser/object.h
win32ss/user/ntuser/painting.c
win32ss/user/ntuser/winsta.c
win32ss/user/user32/CMakeLists.txt
win32ss/user/user32/misc/exticon.c
win32ss/user/user32/misc/object.c
win32ss/user/user32/windows/cursoricon_new.c

index 77df40d,0000000,0000000..745fc78
mode 100644,000000,000000..100644
--- /dev/null
--- /dev/null
@@@@ -1,66 -1,0 -1,0 +1,65 @@@@
-  //#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
index 0abce0e,0000000,0000000..164a161
mode 100644,000000,000000..100644
--- /dev/null
--- /dev/null
@@@@ -1,230 -1,0 -1,0 +1,237 @@@@
-      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)
index addd259,0000000,22297f0..22297f0
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,168 -1,0 -1,168 +1,168 @@@@
-           &(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))
index 3a0e963,0000000,7c6d5a4..7c6d5a4
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,3392 -1,0 -1,3391 +1,3391 @@@@
-    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 */
index 3d0f2fc,0000000,815cee5..815cee5
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,184 -1,0 -1,187 +1,187 @@@@
 + /*
 +  * 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;
 + }
 + 
index e238e54,0000000,72bac91..72bac91
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,1163 -1,0 -1,1172 +1,1172 @@@@
 + /*
 +  * 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 */
index 593e6ae,0000000,7ba56db..7ba56db
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,1525 -1,0 -1,1504 +1,1504 @@@@
-  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 */
index ca48c93,0000000,3bf5e19..3bf5e19
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,78 -1,0 -1,104 +1,104 @@@@
 + #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 */
index 0000000,0000000,0c772a2..0c772a2
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 31ebcbd,0000000,2c43691..2c43691
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,1781 -1,0 -1,1779 +1,1779 @@@@
-      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 */
index 084f04d,0000000,0ae8612..0ae8612
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,2378 -1,0 -1,2398 +1,2398 @@@@
 + /*
 +  * 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 )
 +    {