[Win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / message.c
index 5cd37b0..9d5b72b 100644 (file)
@@ -16,6 +16,7 @@
 #include <debug.h>
 
 BOOLEAN NTAPI PsGetProcessExitProcessCalled(PEPROCESS Process);
+HWND FASTCALL co_UserSetCapture(HWND hWnd);
 
 #define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
 
@@ -33,6 +34,81 @@ IntCleanupMessageImpl(VOID)
     return STATUS_SUCCESS;
 }
 
+/* From wine: */
+/* flag for messages that contain pointers */
+/* 32 messages per entry, messages 0..31 map to bits 0..31 */
+
+#define SET(msg) (1 << ((msg) & 31))
+
+static const unsigned int message_pointer_flags[] =
+{
+    /* 0x00 - 0x1f */
+    SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
+    SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
+    /* 0x20 - 0x3f */
+    SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
+    SET(WM_COMPAREITEM),
+    /* 0x40 - 0x5f */
+    SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
+    SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
+    /* 0x60 - 0x7f */
+    SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
+    /* 0x80 - 0x9f */
+    SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
+    /* 0xa0 - 0xbf */
+    SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
+    /* 0xc0 - 0xdf */
+    SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
+    /* 0xe0 - 0xff */
+    SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
+    /* 0x100 - 0x11f */
+    0,
+    /* 0x120 - 0x13f */
+    0,
+    /* 0x140 - 0x15f */
+    SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
+    SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
+    SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
+    /* 0x160 - 0x17f */
+    0,
+    /* 0x180 - 0x19f */
+    SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
+    SET(LB_DIR) | SET(LB_FINDSTRING) |
+    SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
+    /* 0x1a0 - 0x1bf */
+    SET(LB_FINDSTRINGEXACT),
+    /* 0x1c0 - 0x1df */
+    0,
+    /* 0x1e0 - 0x1ff */
+    0,
+    /* 0x200 - 0x21f */
+    SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
+    /* 0x220 - 0x23f */
+    SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
+    SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
+    /* 0x240 - 0x25f */
+    0,
+    /* 0x260 - 0x27f */
+    0,
+    /* 0x280 - 0x29f */
+    0,
+    /* 0x2a0 - 0x2bf */
+    0,
+    /* 0x2c0 - 0x2df */
+    0,
+    /* 0x2e0 - 0x2ff */
+    0,
+    /* 0x300 - 0x31f */
+    SET(WM_ASKCBFORMATNAME)
+};
+
+/* check whether a given message type includes pointers */
+static inline int is_pointer_message( UINT message )
+{
+    if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
+        return (message_pointer_flags[message / 32] & SET(message)) != 0;
+}
+
 #define MMS_SIZE_WPARAM      -1
 #define MMS_SIZE_WPARAMWCHAR -2
 #define MMS_SIZE_LPARAMSZ    -3
@@ -61,6 +137,7 @@ static MSGMEMORY MsgMemory[] =
     { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
     { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
     { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
+    { WM_COPYGLOBALDATA, MMS_SIZE_WPARAM, MMS_FLAG_READ },
     { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
     { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
 };
@@ -134,10 +211,6 @@ MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
                 Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
                 break;
 
-            case WM_COPYGLOBALDATA:
-                Size = wParam;
-                break;
-
             default:
                 ASSERT(FALSE);
                 Size = 0;
@@ -243,7 +316,6 @@ PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL Non
         ASSERT(CsData == (PCHAR) PackedCs + Size);
         *lParamPacked = (LPARAM) PackedCs;
     }
-
     else if (PoolType == NonPagedPool)
     {
         PMSGMEMORY MsgMemoryEntry;
@@ -317,6 +389,100 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL No
     return STATUS_INVALID_PARAMETER;
 }
 
+static NTSTATUS FASTCALL
+CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
+{
+    NTSTATUS Status;
+
+    PVOID KernelMem;
+    UINT Size;
+
+    *KernelModeMsg = *UserModeMsg;
+
+    /* See if this message type is present in the table */
+    if (NULL == MsgMemoryEntry)
+    {
+        /* Not present, no copying needed */
+        return STATUS_SUCCESS;
+    }
+
+    /* Determine required size */
+    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+
+    if (0 != Size)
+    {
+        /* Allocate kernel mem */
+        KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
+        if (NULL == KernelMem)
+        {
+            DPRINT1("Not enough memory to copy message to kernel mem\n");
+            return STATUS_NO_MEMORY;
+        }
+        KernelModeMsg->lParam = (LPARAM) KernelMem;
+
+        /* Copy data if required */
+        if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
+        {
+            Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
+            if (! NT_SUCCESS(Status))
+            {
+                DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
+                ExFreePoolWithTag(KernelMem, TAG_MSG);
+                return Status;
+            }
+        }
+        else
+        {
+            /* Make sure we don't pass any secrets to usermode */
+            RtlZeroMemory(KernelMem, Size);
+        }
+    }
+    else
+    {
+        KernelModeMsg->lParam = 0;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS FASTCALL
+CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
+{
+    NTSTATUS Status;
+    PMSGMEMORY MsgMemoryEntry;
+    UINT Size;
+
+    /* See if this message type is present in the table */
+    MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
+    if (NULL == MsgMemoryEntry)
+    {
+        /* Not present, no copying needed */
+        return STATUS_SUCCESS;
+    }
+
+    /* Determine required size */
+    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
+
+    if (0 != Size)
+    {
+        /* Copy data if required */
+        if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
+        {
+            Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
+            if (! NT_SUCCESS(Status))
+            {
+                DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
+                ExFreePool((PVOID) KernelModeMsg->lParam);
+                return Status;
+            }
+        }
+
+        ExFreePool((PVOID) KernelModeMsg->lParam);
+    }
+
+    return STATUS_SUCCESS;
+}
+
 //
 // Wakeup any thread/process waiting on idle input.
 //
@@ -331,10 +497,10 @@ IdlePing(VOID)
 
    if (ForegroundQueue)
       ptiForeground = ForegroundQueue->Thread->Tcb.Win32Thread;
-     
+
    pti = PsGetCurrentThreadWin32Thread();
 
-   if ( pti ) 
+   if ( pti )
    {
       pti->pClientInfo->cSpins = 0; // Reset spins.
 
@@ -439,7 +605,7 @@ IntDispatchMessage(PMSG pMsg)
 
     if ( Window->head.pti != pti)
     {
-       SetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY );
+       EngSetLastError( ERROR_MESSAGE_SYNC_ONLY );
        return 0;
     }
 
@@ -461,7 +627,7 @@ IntDispatchMessage(PMSG pMsg)
                                               (LPARAM)Time,
                                               0);
             }
-            return retval;        
+            return retval;
         }
         else
         {
@@ -478,7 +644,7 @@ IntDispatchMessage(PMSG pMsg)
     // Need a window!
     if ( !Window ) return 0;
 
-    /* Since we are doing a callback on the same thread right away, there is 
+    /* Since we are doing a callback on the same thread right away, there is
        no need to copy the lparam to kernel mode and then back to usermode.
        We just pretend it isn't a pointer */
 
@@ -607,12 +773,12 @@ co_IntPeekMessage( PMSG Msg,
         }
 
         if ((ProcessMask & QS_INPUT) &&
-            co_MsqPeekHardwareMessage( ThreadQueue, 
-                                       RemoveMessages, 
-                                       Window, 
-                                       MsgFilterMin, 
+            co_MsqPeekHardwareMessage( ThreadQueue,
+                                       RemoveMessages,
+                                       Window,
+                                       MsgFilterMin,
                                        MsgFilterMax,
-                                       ProcessMask, 
+                                       ProcessMask,
                                        Msg))
         {
             return TRUE;
@@ -654,100 +820,6 @@ co_IntPeekMessage( PMSG Msg,
     return TRUE;
 }
 
-static NTSTATUS FASTCALL
-CopyMsgToKernelMem(MSG *KernelModeMsg, MSG *UserModeMsg, PMSGMEMORY MsgMemoryEntry)
-{
-    NTSTATUS Status;
-
-    PVOID KernelMem;
-    UINT Size;
-
-    *KernelModeMsg = *UserModeMsg;
-
-    /* See if this message type is present in the table */
-    if (NULL == MsgMemoryEntry)
-    {
-        /* Not present, no copying needed */
-        return STATUS_SUCCESS;
-    }
-
-    /* Determine required size */
-    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
-
-    if (0 != Size)
-    {
-        /* Allocate kernel mem */
-        KernelMem = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
-        if (NULL == KernelMem)
-        {
-            DPRINT1("Not enough memory to copy message to kernel mem\n");
-            return STATUS_NO_MEMORY;
-        }
-        KernelModeMsg->lParam = (LPARAM) KernelMem;
-
-        /* Copy data if required */
-        if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_READ))
-        {
-            Status = MmCopyFromCaller(KernelMem, (PVOID) UserModeMsg->lParam, Size);
-            if (! NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to copy message to kernel: invalid usermode buffer\n");
-                ExFreePoolWithTag(KernelMem, TAG_MSG);
-                return Status;
-            }
-        }
-        else
-        {
-            /* Make sure we don't pass any secrets to usermode */
-            RtlZeroMemory(KernelMem, Size);
-        }
-    }
-    else
-    {
-        KernelModeMsg->lParam = 0;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS FASTCALL
-CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
-{
-    NTSTATUS Status;
-    PMSGMEMORY MsgMemoryEntry;
-    UINT Size;
-
-    /* See if this message type is present in the table */
-    MsgMemoryEntry = FindMsgMemory(UserModeMsg->message);
-    if (NULL == MsgMemoryEntry)
-    {
-        /* Not present, no copying needed */
-        return STATUS_SUCCESS;
-    }
-
-    /* Determine required size */
-    Size = MsgMemorySize(MsgMemoryEntry, UserModeMsg->wParam, UserModeMsg->lParam);
-
-    if (0 != Size)
-    {
-        /* Copy data if required */
-        if (0 != (MsgMemoryEntry->Flags & MMS_FLAG_WRITE))
-        {
-            Status = MmCopyToCaller((PVOID) UserModeMsg->lParam, (PVOID) KernelModeMsg->lParam, Size);
-            if (! NT_SUCCESS(Status))
-            {
-                DPRINT1("Failed to copy message from kernel: invalid usermode buffer\n");
-                ExFreePool((PVOID) KernelModeMsg->lParam);
-                return Status;
-            }
-        }
-
-        ExFreePool((PVOID) KernelModeMsg->lParam);
-    }
-
-    return STATUS_SUCCESS;
-}
-
 static BOOL FASTCALL
 co_IntWaitMessage( PWND Window,
                    UINT MsgFilterMin,
@@ -775,9 +847,9 @@ co_IntWaitMessage( PWND Window,
 
         /* Nothing found. Wait for new messages. */
         Status = co_MsqWaitForNewMessages( ThreadQueue,
-                                            Window,
-                                            MsgFilterMin,
-                                            MsgFilterMax);
+                                           Window,
+                                           MsgFilterMin,
+                                           MsgFilterMax);
     }
     while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
             STATUS_TIMEOUT == Status );
@@ -834,6 +906,7 @@ co_IntGetPeekMessage( PMSG pMsg,
     }
 
     pti = PsGetCurrentThreadWin32Thread();
+    pti->pClientInfo->cSpins++; // Bump up the spin count.
 
     do
     {
@@ -848,8 +921,11 @@ co_IntGetPeekMessage( PMSG pMsg,
            /* GetMessage or PostMessage must never get messages that contain pointers */
            ASSERT(FindMsgMemory(pMsg->message) == NULL);
 
-           pti->timeLast = pMsg->time;
-           pti->ptLast   = pMsg->pt;
+           if (pMsg->message != WM_PAINT && pMsg->message != WM_QUIT)
+           {
+              pti->timeLast = pMsg->time;
+              pti->ptLast   = pMsg->pt;
+           }
 
            // The WH_GETMESSAGE hook enables an application to monitor messages about to
            // be returned by the GetMessage or PeekMessage function.
@@ -910,9 +986,9 @@ UserPostThreadMessage( DWORD idThread,
     LARGE_INTEGER LargeTickCount;
     NTSTATUS Status;
 
-    if (FindMsgMemory(Msg) != 0)
+    if (is_pointer_message(Msg))
     {
-        SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+        EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
         return FALSE;
     }
 
@@ -976,23 +1052,23 @@ UserPostMessage( HWND Wnd,
         Status = CopyMsgToKernelMem(&KernelModeMsg, &Message, MsgMemoryEntry);
         if (! NT_SUCCESS(Status))
         {
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
+            EngSetLastError(ERROR_INVALID_PARAMETER);
             return FALSE;
         }
-        co_IntSendMessageNoWait(KernelModeMsg.hwnd, 
-                                KernelModeMsg.message, 
-                                KernelModeMsg.wParam, 
+        co_IntSendMessageNoWait(KernelModeMsg.hwnd,
+                                KernelModeMsg.message,
+                                KernelModeMsg.wParam,
                                 KernelModeMsg.lParam);
 
-        if(MsgMemoryEntry)
+        if (MsgMemoryEntry && KernelModeMsg.lParam)
             ExFreePool((PVOID) KernelModeMsg.lParam);
 
         return TRUE;
     }
 
-    if (MsgMemoryEntry)
+    if (is_pointer_message(Message.message))
     {
-        SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+        EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
         return FALSE;
     }
 
@@ -1019,7 +1095,7 @@ UserPostMessage( HWND Wnd,
             {
                 UserPostMessage(List[i], Msg, wParam, lParam);
             }
-            ExFreePool(List);
+            ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
         }
     }
     else
@@ -1045,13 +1121,13 @@ UserPostMessage( HWND Wnd,
             /* FIXME - last error code? */
             return FALSE;
         }
-               
+
         if (WM_QUIT == Msg)
         {
             MsqPostQuitMessage(Window->head.pti->MessageQueue, wParam);
         }
         else
-        { 
+        {
             MsqPostMessage(Window->head.pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
         }
     }
@@ -1196,7 +1272,7 @@ MSDN says:
     To get extended error information, call GetLastError. If GetLastError
     returns ERROR_TIMEOUT, then the function timed out.
 */
-        SetLastWin32Error(ERROR_TIMEOUT);
+        EngSetLastError(ERROR_TIMEOUT);
         RETURN( FALSE);
     }
     else if (! NT_SUCCESS(Status))
@@ -1233,7 +1309,7 @@ co_IntSendMessageTimeout( HWND hWnd,
     DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
     if (NULL == DesktopWindow)
     {
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        EngSetLastError(ERROR_INTERNAL_ERROR);
         return 0;
     }
 
@@ -1256,7 +1332,7 @@ co_IntSendMessageTimeout( HWND hWnd,
     return (LRESULT) TRUE;
 }
 
-LRESULT FASTCALL 
+LRESULT FASTCALL
 co_IntSendMessageNoWait(HWND hWnd,
                         UINT Msg,
                         WPARAM wParam,
@@ -1393,7 +1469,7 @@ co_IntSendMessageWithCallBack( HWND hWnd,
 
     Message->QS_Flags = QS_SENDMESSAGE;
     MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
-    
+
     InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
     IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
 
@@ -1487,7 +1563,7 @@ co_IntDoSendMessage( HWND hWnd,
     Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
     if (! NT_SUCCESS(Status))
     {
-       SetLastWin32Error(ERROR_INVALID_PARAMETER);
+       EngSetLastError(ERROR_INVALID_PARAMETER);
        return (dsm ? 0 : -1);
     }
 
@@ -1512,7 +1588,7 @@ co_IntDoSendMessage( HWND hWnd,
     Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
     if (! NT_SUCCESS(Status))
     {
-       SetLastWin32Error(ERROR_INVALID_PARAMETER);
+       EngSetLastError(ERROR_INVALID_PARAMETER);
        return(dsm ? 0 : -1);
     }
 
@@ -1527,9 +1603,9 @@ UserSendNotifyMessage( HWND hWnd,
 {
     BOOL Ret = TRUE;
 
-    if (FindMsgMemory(Msg) != 0)
+    if (is_pointer_message(Msg))
     {
-        SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+        EngSetLastError(ERROR_MESSAGE_SYNC_ONLY );
         return FALSE;
     }
 
@@ -1549,11 +1625,6 @@ UserSendNotifyMessage( HWND hWnd,
             for (i = 0; List[i]; i++)
             {
                 Ret = UserSendNotifyMessage(List[i], Msg, wParam, lParam);
-                if (!Ret)
-                {
-                   DPRINT1("SendNotifyMessage: Failed in Broadcast!\n");
-                   break;
-                }
             }
             ExFreePool(List);
         }
@@ -1585,9 +1656,9 @@ IntGetQueueStatus(DWORD Changes)
 // wine:
     Changes &= (QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SMRESULT);
 
-    /* High word, types of messages currently in the queue. 
+    /* High word, types of messages currently in the queue.
        Low  word, types of messages that have been added to the queue and that
-                  are still in the queue 
+                  are still in the queue
      */
     Result = MAKELONG(pti->pcti->fsChangeBits & Changes, pti->pcti->fsWakeBits & Changes);
 
@@ -1628,6 +1699,76 @@ IntUninitMessagePumpHook()
 
 /** Functions ******************************************************************/
 
+BOOL
+APIENTRY
+NtUserDragDetect(
+   HWND hWnd,
+   POINT pt) // Just like the User call.
+{
+    MSG msg;
+    RECT rect;
+    WORD wDragWidth, wDragHeight;
+    DECLARE_RETURN(BOOL);
+
+    DPRINT("Enter NtUserDragDetect(%x)\n", hWnd);
+    UserEnterExclusive();
+
+    wDragWidth = UserGetSystemMetrics(SM_CXDRAG);
+    wDragHeight= UserGetSystemMetrics(SM_CYDRAG);
+
+    rect.left = pt.x - wDragWidth;
+    rect.right = pt.x + wDragWidth;
+
+    rect.top = pt.y - wDragHeight;
+    rect.bottom = pt.y + wDragHeight;
+
+    co_UserSetCapture(hWnd);
+
+    for (;;)
+    {
+        while (co_IntGetPeekMessage( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, FALSE ) ||
+               co_IntGetPeekMessage( &msg, 0, WM_QUEUESYNC,  WM_QUEUESYNC, PM_REMOVE, FALSE ) ||
+               co_IntGetPeekMessage( &msg, 0, WM_KEYFIRST,   WM_KEYLAST,   PM_REMOVE, FALSE ) )
+        {
+            if ( msg.message == WM_LBUTTONUP )
+            {
+                co_UserSetCapture(NULL);
+                RETURN( FALSE);
+            }
+            if ( msg.message == WM_MOUSEMOVE )
+            {
+                POINT tmp;
+                tmp.x = (short)LOWORD(msg.lParam);
+                tmp.y = (short)HIWORD(msg.lParam);
+                if( !IntPtInRect( &rect, tmp ) )
+                {
+                    co_UserSetCapture(NULL);
+                    RETURN( TRUE);
+                }
+            }
+            if ( msg.message == WM_KEYDOWN )
+            {
+                if ( msg.wParam == VK_ESCAPE )
+                {
+                   co_UserSetCapture(NULL);
+                   RETURN( TRUE);
+                }
+            }
+            if ( msg.message == WM_QUEUESYNC )
+            {
+                co_HOOK_CallHooks( WH_CBT, HCBT_QS, 0, 0 );
+            }
+        }
+        co_IntWaitMessage(NULL, 0, 0);
+    }
+    RETURN( FALSE);
+
+CLEANUP:
+   DPRINT("Leave NtUserDragDetect, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
 BOOL APIENTRY
 NtUserPostMessage(HWND hWnd,
                   UINT Msg,
@@ -1658,7 +1799,7 @@ NtUserPostThreadMessage(DWORD idThread,
     ret = UserPostThreadMessage( idThread, Msg, wParam, lParam);
 
     UserLeave();
-    
+
     return ret;
 }
 
@@ -1672,7 +1813,7 @@ NtUserWaitMessage(VOID)
     ret = co_IntWaitMessage(NULL, 0, 0);
     DPRINT("NtUserWaitMessage Leave\n");
     UserLeave();
-    
+
     return ret;
 }
 
@@ -1687,7 +1828,7 @@ NtUserGetMessage(PMSG pMsg,
 
     if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
     {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        EngSetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
@@ -1729,7 +1870,7 @@ NtUserPeekMessage( PMSG pMsg,
 
     if ( RemoveMsg & PM_BADMSGFLAGS )
     {
-        SetLastWin32Error(ERROR_INVALID_FLAGS);
+        EngSetLastError(ERROR_INVALID_FLAGS);
         return FALSE;
     }
 
@@ -1755,7 +1896,7 @@ NtUserPeekMessage( PMSG pMsg,
         }
         _SEH2_END;
     }
-    
+
     return Ret;
 }
 
@@ -1859,7 +2000,7 @@ NtUserTranslateMessage(LPMSG lpMsg, UINT flags)
 
 BOOL APIENTRY
 NtUserMessageCall( HWND hWnd,
-                   UINT Msg, 
+                   UINT Msg,
                    WPARAM wParam,
                    LPARAM lParam,
                    ULONG_PTR ResultInfo,
@@ -1972,7 +2113,7 @@ NtUserMessageCall( HWND hWnd,
         {
             CALL_BACK_INFO CallBackInfo;
             ULONG_PTR uResult;
-            
+
             _SEH2_TRY
             {
                 ProbeForRead((PVOID)ResultInfo, sizeof(CALL_BACK_INFO), 1);
@@ -2029,7 +2170,7 @@ NtUserMessageCall( HWND hWnd,
                 }
                 _SEH2_END;
             }
-            
+
             Ret = co_IntDoSendMessage( hWnd, Msg, wParam, lParam, &dsm );
 
             if (pdsm)
@@ -2186,7 +2327,7 @@ NtUserWaitForInputIdle( IN HANDLE hProcess,
     {
         ObDereferenceObject(Process);
         UserLeave();
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        EngSetLastError(ERROR_INVALID_PARAMETER);
         return WAIT_FAILED;
     }