ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

msgqueue.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:        See COPYING in the top level directory
00003  * PROJECT:          ReactOS Win32k subsystem
00004  * PURPOSE:          Message queues
00005  * FILE:             subsystems/win32/win32k/ntuser/msgqueue.c
00006  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
00007                      Alexandre Julliard
00008                      Maarten Lankhorst
00009  */
00010 
00011 #include <win32k.h>
00012 DBG_DEFAULT_CHANNEL(UserMsgQ);
00013 
00014 /* GLOBALS *******************************************************************/
00015 
00016 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
00017 PUSER_MESSAGE_QUEUE gpqCursor;
00018 
00019 /* FUNCTIONS *****************************************************************/
00020 
00021 INIT_FUNCTION
00022 NTSTATUS
00023 NTAPI
00024 MsqInitializeImpl(VOID)
00025 {
00026     pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
00027     if(!pgMessageLookasideList)
00028         return STATUS_NO_MEMORY;
00029    ExInitializePagedLookasideList(pgMessageLookasideList,
00030                                   NULL,
00031                                   NULL,
00032                                   0,
00033                                   sizeof(USER_MESSAGE),
00034                                   TAG_USRMSG,
00035                                   256);
00036 
00037    return(STATUS_SUCCESS);
00038 }
00039 
00040 PWND FASTCALL
00041 IntChildrenWindowFromPoint(PWND pWndTop, INT x, INT y)
00042 {
00043     PWND pWnd, pWndChild;
00044 
00045     if (!(pWndTop->style & WS_VISIBLE)) return NULL;
00046     if ((pWndTop->style & WS_DISABLED)) return NULL;
00047     if (!IntPtInWindow(pWndTop, x, y)) return NULL;
00048 
00049     if (x - pWndTop->rcClient.left < pWndTop->rcClient.right &&
00050         y - pWndTop->rcClient.top  < pWndTop->rcClient.bottom )
00051     {
00052        for (pWnd = pWndTop->spwndChild;
00053             pWnd != NULL;
00054             pWnd = pWnd->spwndNext)
00055        {
00056            if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED )
00057            {
00058                TRACE("The Window is in DESTROY!\n");
00059                continue;
00060            }
00061 
00062            pWndChild = IntChildrenWindowFromPoint(pWnd, x, y);
00063 
00064            if (pWndChild)
00065            {
00066               return pWndChild;
00067            }
00068        }
00069     }
00070     return pWndTop;
00071 }
00072 
00073 PWND FASTCALL
00074 IntTopLevelWindowFromPoint(INT x, INT y)
00075 {
00076     PWND pWnd, pwndDesktop;
00077 
00078     /* Get the desktop window */
00079     pwndDesktop = UserGetDesktopWindow();
00080     if (!pwndDesktop)
00081         return NULL;
00082 
00083     /* Loop all top level windows */
00084     for (pWnd = pwndDesktop->spwndChild;
00085          pWnd != NULL;
00086          pWnd = pWnd->spwndNext)
00087     {
00088         if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED)
00089         {
00090             TRACE("The Window is in DESTROY!\n");
00091             continue;
00092         }
00093 
00094         if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y))
00095             return pWnd;
00096     }
00097 
00098     /* Window has not been found */
00099     return NULL;
00100 }
00101 
00102 PCURICON_OBJECT
00103 FASTCALL
00104 UserSetCursor(
00105     PCURICON_OBJECT NewCursor,
00106     BOOL ForceChange)
00107 {
00108     PCURICON_OBJECT OldCursor;
00109     HDC hdcScreen;
00110     PTHREADINFO pti;
00111     PUSER_MESSAGE_QUEUE MessageQueue;
00112     PWND pWnd;
00113 
00114     pti = PsGetCurrentThreadWin32Thread();
00115     MessageQueue = pti->MessageQueue;
00116 
00117     /* Get the screen DC */
00118     if(!(hdcScreen = IntGetScreenDC()))
00119     {
00120         return NULL;
00121     }
00122 
00123     OldCursor = MessageQueue->CursorObject;
00124 
00125     /* Check if cursors are different */
00126     if (OldCursor == NewCursor)
00127         return OldCursor;
00128 
00129     /* Update cursor for this message queue */
00130     MessageQueue->CursorObject = NewCursor;
00131 
00132     /* If cursor is not visible we have nothing to do */
00133     if (MessageQueue->ShowingCursor < 0)
00134         return OldCursor;
00135 
00136     /* Update cursor if this message queue controls it */
00137     pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
00138     if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
00139     {
00140         if (NewCursor)
00141         {
00142             /* Call GDI to set the new screen cursor */
00143             GreSetPointerShape(hdcScreen,
00144                                NewCursor->IconInfo.hbmMask,
00145                                NewCursor->IconInfo.hbmColor,
00146                                NewCursor->IconInfo.xHotspot,
00147                                NewCursor->IconInfo.yHotspot,
00148                                gpsi->ptCursor.x,
00149                                gpsi->ptCursor.y);
00150         }
00151         else /* Note: OldCursor != NewCursor so we have to hide cursor */
00152         {
00153             /* Remove the cursor */
00154             GreMovePointer(hdcScreen, -1, -1);
00155             TRACE("Removing pointer!\n");
00156         }
00157         IntGetSysCursorInfo()->CurrentCursorObject = NewCursor;
00158     }
00159 
00160     /* Return the old cursor */
00161     return OldCursor;
00162 }
00163 
00164 /* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR
00165  * User32 macro NtUserShowCursor */
00166 int UserShowCursor(BOOL bShow)
00167 {
00168     HDC hdcScreen;
00169     PTHREADINFO pti;
00170     PUSER_MESSAGE_QUEUE MessageQueue;
00171     PWND pWnd;
00172 
00173     if (!(hdcScreen = IntGetScreenDC()))
00174     {
00175         return -1; /* No mouse */
00176     }
00177 
00178     pti = PsGetCurrentThreadWin32Thread();
00179     MessageQueue = pti->MessageQueue;
00180 
00181     /* Update counter */
00182     MessageQueue->ShowingCursor += bShow ? 1 : -1;
00183 
00184     /* Check for trivial cases */
00185     if ((bShow && MessageQueue->ShowingCursor != 0) ||
00186         (!bShow && MessageQueue->ShowingCursor != -1))
00187     {
00188         /* Note: w don't update global info here because it is used only
00189           internally to check if cursor is visible */
00190         return MessageQueue->ShowingCursor;
00191     }
00192 
00193     /* Check if cursor is above window owned by this MessageQueue */
00194     pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y);
00195     if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue)
00196     {
00197         if (bShow)
00198         {
00199             /* Show the pointer */
00200             GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y);
00201             TRACE("Showing pointer!\n");
00202         }
00203         else
00204         {
00205             /* Remove the pointer */
00206             GreMovePointer(hdcScreen, -1, -1);
00207             TRACE("Removing pointer!\n");
00208         }
00209 
00210         /* Update global info */
00211         IntGetSysCursorInfo()->ShowingCursor = MessageQueue->ShowingCursor;
00212     }
00213 
00214     return MessageQueue->ShowingCursor;
00215 }
00216 
00217 DWORD FASTCALL
00218 UserGetKeyState(DWORD dwKey)
00219 {
00220    DWORD dwRet = 0;
00221    PTHREADINFO pti;
00222    PUSER_MESSAGE_QUEUE MessageQueue;
00223 
00224    pti = PsGetCurrentThreadWin32Thread();
00225    MessageQueue = pti->MessageQueue;
00226 
00227    if (dwKey < 0x100)
00228    {
00229        if (IS_KEY_DOWN(MessageQueue->afKeyState, dwKey))
00230            dwRet |= 0xFF80; // If down, windows returns 0xFF80.
00231        if (IS_KEY_LOCKED(MessageQueue->afKeyState, dwKey))
00232            dwRet |= 0x1;
00233    }
00234    else
00235    {
00236       EngSetLastError(ERROR_INVALID_PARAMETER);
00237    }
00238    return dwRet;
00239 }
00240 
00241 /* change the input key state for a given key */
00242 static VOID
00243 UpdateKeyState(PUSER_MESSAGE_QUEUE MessageQueue, WORD wVk, BOOL bIsDown)
00244 {
00245     TRACE("UpdateKeyState wVk: %d, bIsDown: %d\n", wVk, bIsDown);
00246 
00247     if (bIsDown)
00248     {
00249         /* If it's first key down event, xor lock bit */
00250         if (!IS_KEY_DOWN(MessageQueue->afKeyState, wVk))
00251             SET_KEY_LOCKED(MessageQueue->afKeyState, wVk, !IS_KEY_LOCKED(MessageQueue->afKeyState, wVk));
00252 
00253         SET_KEY_DOWN(MessageQueue->afKeyState, wVk, TRUE);
00254         MessageQueue->afKeyRecentDown[wVk / 8] |= (1 << (wVk % 8));
00255     }
00256     else
00257         SET_KEY_DOWN(MessageQueue->afKeyState, wVk, FALSE);
00258 }
00259 
00260 /* update the input key state for a keyboard message */
00261 static VOID
00262 UpdateKeyStateFromMsg(PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg)
00263 {
00264     UCHAR key;
00265     BOOL down = FALSE;
00266 
00267     TRACE("UpdateKeyStateFromMsg message:%d\n", msg->message);
00268 
00269     switch (msg->message)
00270     {
00271     case WM_LBUTTONDOWN:
00272         down = TRUE;
00273         /* fall through */
00274     case WM_LBUTTONUP:
00275         UpdateKeyState(MessageQueue, VK_LBUTTON, down);
00276         break;
00277     case WM_MBUTTONDOWN:
00278         down = TRUE;
00279         /* fall through */
00280     case WM_MBUTTONUP:
00281         UpdateKeyState(MessageQueue, VK_MBUTTON, down);
00282         break;
00283     case WM_RBUTTONDOWN:
00284         down = TRUE;
00285         /* fall through */
00286     case WM_RBUTTONUP:
00287         UpdateKeyState(MessageQueue, VK_RBUTTON, down);
00288         break;
00289     case WM_XBUTTONDOWN:
00290         down = TRUE;
00291         /* fall through */
00292     case WM_XBUTTONUP:
00293         if (msg->wParam == XBUTTON1)
00294             UpdateKeyState(MessageQueue, VK_XBUTTON1, down);
00295         else if (msg->wParam == XBUTTON2)
00296             UpdateKeyState(MessageQueue, VK_XBUTTON2, down);
00297         break;
00298     case WM_KEYDOWN:
00299     case WM_SYSKEYDOWN:
00300         down = TRUE;
00301         /* fall through */
00302     case WM_KEYUP:
00303     case WM_SYSKEYUP:
00304         key = (UCHAR)msg->wParam;
00305         UpdateKeyState(MessageQueue, key, down);
00306         switch(key)
00307         {
00308         case VK_LCONTROL:
00309         case VK_RCONTROL:
00310             down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LCONTROL) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RCONTROL);
00311             UpdateKeyState(MessageQueue, VK_CONTROL, down);
00312             break;
00313         case VK_LMENU:
00314         case VK_RMENU:
00315             down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LMENU) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RMENU);
00316             UpdateKeyState(MessageQueue, VK_MENU, down);
00317             break;
00318         case VK_LSHIFT:
00319         case VK_RSHIFT:
00320             down = IS_KEY_DOWN(MessageQueue->afKeyState, VK_LSHIFT) || IS_KEY_DOWN(MessageQueue->afKeyState, VK_RSHIFT);
00321             UpdateKeyState(MessageQueue, VK_SHIFT, down);
00322             break;
00323         }
00324         break;
00325     }
00326 }
00327 
00328 HANDLE FASTCALL
00329 IntMsqSetWakeMask(DWORD WakeMask)
00330 {
00331    PTHREADINFO Win32Thread;
00332    PUSER_MESSAGE_QUEUE MessageQueue;
00333    HANDLE MessageEventHandle;
00334    DWORD dwFlags = HIWORD(WakeMask);
00335 
00336    Win32Thread = PsGetCurrentThreadWin32Thread();
00337    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
00338       return 0;
00339 
00340    MessageQueue = Win32Thread->MessageQueue;
00341 // Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
00342    MessageEventHandle = MessageQueue->NewMessagesHandle;
00343 
00344    if (Win32Thread->pcti)
00345    {
00346       if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
00347            ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
00348       {
00349          ERR("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
00350          KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up!
00351          return MessageEventHandle;
00352       }
00353    }
00354 
00355    IdlePing();
00356 
00357    return MessageEventHandle;
00358 }
00359 
00360 BOOL FASTCALL
00361 IntMsqClearWakeMask(VOID)
00362 {
00363    PTHREADINFO Win32Thread;
00364 
00365    Win32Thread = PsGetCurrentThreadWin32Thread();
00366    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
00367       return FALSE;
00368    // Very hacky, but that is what they do.
00369    Win32Thread->pcti->fsWakeBits = 0;
00370 
00371    IdlePong();
00372 
00373    return TRUE;
00374 }
00375 
00376 /*
00377    Due to the uncertainty of knowing what was set in our multilevel message queue,
00378    and even if the bits are all cleared. The same as cTimers/cPaintsReady.
00379    I think this is the best solution... (jt) */
00380 VOID FASTCALL
00381 MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent)
00382 {
00383    PTHREADINFO pti;
00384 
00385    pti = Queue->Thread->Tcb.Win32Thread;
00386    pti->pcti->fsWakeBits |= MessageBits;
00387    pti->pcti->fsChangeBits |= MessageBits;
00388 
00389    // Start bit accounting to help clear the main set of bits.
00390    if (MessageBits & QS_KEY)         Queue->nCntsQBits[QSRosKey]++;
00391    if (MessageBits & QS_MOUSEMOVE)   Queue->nCntsQBits[QSRosMouseMove]++;
00392    if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++;
00393    if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++;
00394    if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++;
00395    if (MessageBits & QS_HOTKEY)      Queue->nCntsQBits[QSRosHotKey]++;
00396 
00397    if (KeyEvent)
00398       KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
00399 }
00400 
00401 VOID FASTCALL
00402 ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits)
00403 {
00404    PTHREADINFO pti;
00405    UINT ClrMask = 0;
00406 
00407    pti = Queue->Thread->Tcb.Win32Thread;
00408 
00409    if (MessageBits & QS_KEY)
00410    {
00411       if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
00412    }
00413    if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
00414    {  // Account for tracking mouse moves..
00415       if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
00416       // Handle mouse move bits here.
00417       if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
00418    }
00419    if (MessageBits & QS_MOUSEBUTTON)
00420    {
00421       if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
00422    }
00423    if (MessageBits & QS_POSTMESSAGE)
00424    {
00425       if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
00426    }
00427    if (MessageBits & QS_TIMER) // ReactOS hard coded.
00428    {  // Handle timer bits here.
00429       if ( pti->cTimersReady )
00430       {
00431          if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
00432       }
00433    }
00434    if (MessageBits & QS_PAINT) // ReactOS hard coded.
00435    {  // Handle paint bits here.
00436       if ( pti->cPaintsReady )
00437       {
00438          if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
00439       }
00440    }
00441    if (MessageBits & QS_SENDMESSAGE)
00442    {
00443       if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
00444    }
00445    if (MessageBits & QS_HOTKEY)
00446    {
00447       if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
00448    }
00449 
00450    pti->pcti->fsWakeBits &= ~ClrMask;
00451    pti->pcti->fsChangeBits &= ~ClrMask;
00452 }
00453 
00454 VOID FASTCALL
00455 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
00456 {
00457    PTHREADINFO pti;
00458    pti = Queue->Thread->Tcb.Win32Thread;
00459    pti->cPaintsReady++;
00460    MsqWakeQueue(Queue, QS_PAINT, TRUE);
00461 }
00462 
00463 VOID FASTCALL
00464 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
00465 {
00466    ClearMsgBitsMask(Queue, QS_PAINT);
00467 }
00468 
00469 VOID FASTCALL
00470 MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg)
00471 {
00472     MessageQueue->MouseMoveMsg = *Msg;
00473     MessageQueue->MouseMoved = TRUE;
00474     MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE);
00475 }
00476 
00477 VOID FASTCALL
00478 co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
00479 {
00480    LARGE_INTEGER LargeTickCount;
00481    MSLLHOOKSTRUCT MouseHookData;
00482    PDESKTOP pDesk;
00483    PWND pwnd, pwndDesktop;
00484    HDC hdcScreen;
00485    PSYSTEM_CURSORINFO CurInfo;
00486 
00487    KeQueryTickCount(&LargeTickCount);
00488    Msg->time = MsqCalculateMessageTime(&LargeTickCount);
00489 
00490    MouseHookData.pt.x = LOWORD(Msg->lParam);
00491    MouseHookData.pt.y = HIWORD(Msg->lParam);
00492    switch (Msg->message)
00493    {
00494       case WM_MOUSEWHEEL:
00495          MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
00496          break;
00497       case WM_XBUTTONDOWN:
00498       case WM_XBUTTONUP:
00499       case WM_XBUTTONDBLCLK:
00500       case WM_NCXBUTTONDOWN:
00501       case WM_NCXBUTTONUP:
00502       case WM_NCXBUTTONDBLCLK:
00503          MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
00504          break;
00505       default:
00506          MouseHookData.mouseData = 0;
00507          break;
00508    }
00509 
00510    MouseHookData.flags = flags; // LLMHF_INJECTED
00511    MouseHookData.time = Msg->time;
00512    MouseHookData.dwExtraInfo = dwExtraInfo;
00513 
00514    /* If the hook procedure returned non zero, dont send the message */
00515    if (Hook)
00516    {
00517       if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
00518          return;
00519    }
00520 
00521    /* Get the desktop window */
00522    pwndDesktop = UserGetDesktopWindow();
00523    if (!pwndDesktop) return;
00524    pDesk = pwndDesktop->head.rpdesk;
00525 
00526    /* Check if the mouse is captured */
00527    Msg->hwnd = IntGetCaptureWindow();
00528    if (Msg->hwnd != NULL)
00529    {
00530        pwnd = UserGetWindowObject(Msg->hwnd);
00531    }
00532    else
00533    {
00534        pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y);
00535        if (pwnd) Msg->hwnd = pwnd->head.h;
00536    }
00537 
00538    hdcScreen = IntGetScreenDC();
00539    CurInfo = IntGetSysCursorInfo();
00540 
00541    /* Check if we found a window */
00542    if (Msg->hwnd != NULL && pwnd != NULL)
00543    {
00544        if (Msg->message == WM_MOUSEMOVE)
00545        {
00546            PUSER_MESSAGE_QUEUE MessageQueue = pwnd->head.pti->MessageQueue;
00547 
00548            /* Check if cursor should be visible */
00549            if(hdcScreen &&
00550               MessageQueue->CursorObject &&
00551               MessageQueue->ShowingCursor >= 0)
00552            {
00553                /* Check if shape has changed */
00554                if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject)
00555                {
00556                    /* Call GDI to set the new screen cursor */
00557                    GreSetPointerShape(hdcScreen,
00558                                       MessageQueue->CursorObject->IconInfo.hbmMask,
00559                                       MessageQueue->CursorObject->IconInfo.hbmColor,
00560                                       MessageQueue->CursorObject->IconInfo.xHotspot,
00561                                       MessageQueue->CursorObject->IconInfo.yHotspot,
00562                                       gpsi->ptCursor.x,
00563                                       gpsi->ptCursor.y);
00564                } else
00565                    GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
00566            }
00567            /* Check if w have to hide cursor */
00568            else if (CurInfo->ShowingCursor >= 0)
00569                GreMovePointer(hdcScreen, -1, -1);
00570 
00571            /* Update global cursor info */
00572            CurInfo->ShowingCursor = MessageQueue->ShowingCursor;
00573            CurInfo->CurrentCursorObject = MessageQueue->CursorObject;
00574            gpqCursor = MessageQueue;
00575 
00576            /* Mouse move is a special case */
00577            MsqPostMouseMove(MessageQueue, Msg);
00578        }
00579        else
00580        {
00581            TRACE("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
00582            MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON);
00583        }
00584    }
00585    else if (hdcScreen)
00586    {
00587        /* always show cursor on background; FIXME: set default pointer */
00588        GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y);
00589        CurInfo->ShowingCursor = 0;
00590    }
00591 }
00592 
00593 VOID FASTCALL
00594 MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
00595 {
00596    PWND Window;
00597    PTHREADINFO Win32Thread;
00598    MSG Mesg;
00599    LARGE_INTEGER LargeTickCount;
00600    NTSTATUS Status;
00601    INT id;
00602    DWORD Type;
00603 
00604    Status = ObReferenceObjectByPointer (Thread,
00605                                         THREAD_ALL_ACCESS,
00606                                         PsThreadType,
00607                                         KernelMode);
00608    if (!NT_SUCCESS(Status))
00609       return;
00610 
00611    Win32Thread = ((PETHREAD)Thread)->Tcb.Win32Thread;
00612    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
00613    {
00614       ObDereferenceObject ((PETHREAD)Thread);
00615       return;
00616    }
00617 
00618    Window = IntGetWindowObject(hWnd);
00619    if (!Window)
00620    {
00621       ObDereferenceObject ((PETHREAD)Thread);
00622       return;
00623    }
00624 
00625    id = wParam; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
00626 
00627    Mesg.hwnd    = hWnd;
00628    Mesg.message = id != IDHK_REACTOS ? WM_HOTKEY : WM_SYSCOMMAND;
00629    Mesg.wParam  = id != IDHK_REACTOS ? wParam    : SC_HOTKEY;
00630    Mesg.lParam  = id != IDHK_REACTOS ? lParam    : (LPARAM)hWnd;
00631    Type         = id != IDHK_REACTOS ? QS_HOTKEY : QS_POSTMESSAGE;
00632    KeQueryTickCount(&LargeTickCount);
00633    Mesg.time    = MsqCalculateMessageTime(&LargeTickCount);
00634    Mesg.pt      = gpsi->ptCursor;
00635    MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, Type);
00636    UserDereferenceObject(Window);
00637    ObDereferenceObject (Thread);
00638 
00639 }
00640 
00641 PUSER_MESSAGE FASTCALL
00642 MsqCreateMessage(LPMSG Msg)
00643 {
00644    PUSER_MESSAGE Message;
00645 
00646    Message = ExAllocateFromPagedLookasideList(pgMessageLookasideList);
00647    if (!Message)
00648    {
00649       return NULL;
00650    }
00651 
00652    RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
00653 
00654    return Message;
00655 }
00656 
00657 VOID FASTCALL
00658 MsqDestroyMessage(PUSER_MESSAGE Message)
00659 {
00660    ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
00661 }
00662 
00663 BOOLEAN FASTCALL
00664 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
00665 {
00666    PUSER_SENT_MESSAGE SaveMsg, Message;
00667    PLIST_ENTRY Entry;
00668    PTHREADINFO pti;
00669    BOOL Ret;
00670    LRESULT Result = 0;
00671 
00672    if (IsListEmpty(&MessageQueue->SentMessagesListHead))
00673    {
00674       return(FALSE);
00675    }
00676 
00677    /* remove it from the list of pending messages */
00678    Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
00679    Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
00680 
00681    pti = MessageQueue->Thread->Tcb.Win32Thread;
00682 
00683    SaveMsg = pti->pusmCurrent;
00684    pti->pusmCurrent = Message;
00685 
00686    // Processing a message sent to it from another thread.
00687    if ( ( Message->SenderQueue && MessageQueue != Message->SenderQueue) ||
00688         ( Message->CallBackSenderQueue && MessageQueue != Message->CallBackSenderQueue ))
00689    {  // most likely, but, to be sure.
00690       pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
00691    }
00692 
00693    /* insert it to the list of messages that are currently dispatched by this
00694       message queue */
00695    InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
00696                   &Message->ListEntry);
00697 
00698    ClearMsgBitsMask(MessageQueue, Message->QS_Flags);
00699 
00700    if (Message->HookMessage == MSQ_ISHOOK)
00701    {  // Direct Hook Call processor
00702       Result = co_CallHook( Message->Msg.message,     // HookId
00703                            (INT)(INT_PTR)Message->Msg.hwnd, // Code
00704                             Message->Msg.wParam,
00705                             Message->Msg.lParam);
00706    }
00707    else if (Message->HookMessage == MSQ_ISEVENT)
00708    {  // Direct Event Call processor
00709       Result = co_EVENT_CallEvents( Message->Msg.message,
00710                                     Message->Msg.hwnd,
00711                                     Message->Msg.wParam,
00712                                     Message->Msg.lParam);
00713    }
00714    else if(Message->HookMessage == MSQ_INJECTMODULE)
00715    {
00716        Result = IntLoadHookModule(Message->Msg.message,
00717                                   (HHOOK)Message->Msg.lParam,
00718                                   Message->Msg.wParam);
00719    }
00720    else if ((Message->CompletionCallback) &&
00721             (Message->CallBackSenderQueue == MessageQueue))
00722    {   /* Call the callback routine */
00723       if (Message->QS_Flags & QS_SMRESULT)
00724       {
00725          co_IntCallSentMessageCallback(Message->CompletionCallback,
00726                                        Message->Msg.hwnd,
00727                                        Message->Msg.message,
00728                                        Message->CompletionCallbackContext,
00729                                        Message->lResult);
00730          /* Set callback to NULL to prevent reentry */
00731          Message->CompletionCallback = NULL;
00732       }
00733       else
00734       {
00735          /* The message has not been processed yet, reinsert it. */
00736          RemoveEntryList(&Message->ListEntry);
00737          InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
00738          TRACE("Callback Message not processed yet. Requeuing the message\n");
00739          Ret = FALSE;
00740          goto Exit;
00741       }
00742    }
00743    else
00744    {  /* Call the window procedure. */
00745       Result = co_IntSendMessage( Message->Msg.hwnd,
00746                                   Message->Msg.message,
00747                                   Message->Msg.wParam,
00748                                   Message->Msg.lParam);
00749    }
00750 
00751    /* remove the message from the local dispatching list, because it doesn't need
00752       to be cleaned up on thread termination anymore */
00753    RemoveEntryList(&Message->ListEntry);
00754 
00755    /* If the message is a callback, insert it in the callback senders MessageQueue */
00756    if (Message->CompletionCallback)
00757    {
00758       if (Message->CallBackSenderQueue)
00759       {
00760          Message->lResult = Result;
00761          Message->QS_Flags |= QS_SMRESULT;
00762 
00763          /* insert it in the callers message queue */
00764          InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
00765          MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE);
00766          IntDereferenceMessageQueue(Message->CallBackSenderQueue);
00767       }
00768       Ret = TRUE;
00769       goto Exit;
00770    }
00771 
00772    /* remove the message from the dispatching list if needed, so lock the sender's message queue */
00773    if (Message->SenderQueue)
00774    {
00775       if (Message->DispatchingListEntry.Flink != NULL)
00776       {
00777          /* only remove it from the dispatching list if not already removed by a timeout */
00778          RemoveEntryList(&Message->DispatchingListEntry);
00779       }
00780    }
00781    /* still keep the sender's message queue locked, so the sender can't exit the
00782       MsqSendMessage() function (if timed out) */
00783 
00784    if (Message->QS_Flags & QS_SMRESULT)
00785    {
00786       Result = Message->lResult;
00787    }
00788 
00789    /* Let the sender know the result. */
00790    if (Message->Result != NULL)
00791    {
00792       *Message->Result = Result;
00793    }
00794 
00795    if (Message->HasPackedLParam == TRUE)
00796    {
00797       if (Message->Msg.lParam)
00798          ExFreePool((PVOID)Message->Msg.lParam);
00799    }
00800 
00801    /* Notify the sender. */
00802    if (Message->CompletionEvent != NULL)
00803    {
00804       KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
00805    }
00806 
00807    /* if the message has a sender */
00808    if (Message->SenderQueue)
00809    {
00810        /* dereference our and the sender's message queue */
00811       IntDereferenceMessageQueue(Message->SenderQueue);
00812       IntDereferenceMessageQueue(MessageQueue);
00813    }
00814 
00815    /* free the message */
00816    ExFreePoolWithTag(Message, TAG_USRMSG);
00817    Ret = TRUE;
00818 Exit:
00819    /* do not hangup on the user if this is reentering */
00820    if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
00821    pti->pusmCurrent = SaveMsg;
00822 
00823    return Ret;
00824 }
00825 
00826 VOID APIENTRY
00827 MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
00828 {
00829    PUSER_SENT_MESSAGE SentMessage;
00830    PUSER_MESSAGE PostedMessage;
00831    PUSER_MESSAGE_QUEUE MessageQueue;
00832    PLIST_ENTRY CurrentEntry, ListHead;
00833    PWND Window = pWindow;
00834 
00835    ASSERT(Window);
00836 
00837    MessageQueue = Window->head.pti->MessageQueue;
00838    ASSERT(MessageQueue);
00839 
00840    /* remove the posted messages for this window */
00841    CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
00842    ListHead = &MessageQueue->PostedMessagesListHead;
00843    while (CurrentEntry != ListHead)
00844    {
00845       PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
00846                                         ListEntry);
00847       if (PostedMessage->Msg.hwnd == Window->head.h)
00848       {
00849          RemoveEntryList(&PostedMessage->ListEntry);
00850          ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags);
00851          MsqDestroyMessage(PostedMessage);
00852          CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
00853       }
00854       else
00855       {
00856          CurrentEntry = CurrentEntry->Flink;
00857       }
00858    }
00859 
00860    /* remove the sent messages for this window */
00861    CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
00862    ListHead = &MessageQueue->SentMessagesListHead;
00863    while (CurrentEntry != ListHead)
00864    {
00865       SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
00866                                       ListEntry);
00867       if(SentMessage->Msg.hwnd == Window->head.h)
00868       {
00869          TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
00870 
00871          RemoveEntryList(&SentMessage->ListEntry);
00872          ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
00873 
00874          /* if it is a callback and this queue is not the sender queue, dereference queue */
00875          if ((SentMessage->CompletionCallback) && (SentMessage->CallBackSenderQueue != MessageQueue))
00876          {
00877             IntDereferenceMessageQueue(SentMessage->CallBackSenderQueue);
00878          }
00879          /* Only if the message has a sender was the queue referenced */
00880          if ((SentMessage->SenderQueue)
00881             && (SentMessage->DispatchingListEntry.Flink != NULL))
00882          {
00883             RemoveEntryList(&SentMessage->DispatchingListEntry);
00884          }
00885 
00886          /* wake the sender's thread */
00887          if (SentMessage->CompletionEvent != NULL)
00888          {
00889             KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
00890          }
00891 
00892          if (SentMessage->HasPackedLParam == TRUE)
00893          {
00894             if (SentMessage->Msg.lParam)
00895                ExFreePool((PVOID)SentMessage->Msg.lParam);
00896          }
00897 
00898          /* if the message has a sender */
00899          if (SentMessage->SenderQueue)
00900          {
00901             /* dereference our and the sender's message queue */
00902             IntDereferenceMessageQueue(MessageQueue);
00903             IntDereferenceMessageQueue(SentMessage->SenderQueue);
00904          }
00905 
00906          /* free the message */
00907          ExFreePoolWithTag(SentMessage, TAG_USRMSG);
00908 
00909          CurrentEntry = MessageQueue->SentMessagesListHead.Flink;
00910       }
00911       else
00912       {
00913          CurrentEntry = CurrentEntry->Flink;
00914       }
00915    }
00916 }
00917 
00918 BOOL FASTCALL
00919 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
00920                        HWND hwnd,
00921                        UINT Msg,
00922                        WPARAM wParam,
00923                        LPARAM lParam,
00924                        SENDASYNCPROC CompletionCallback,
00925                        ULONG_PTR CompletionCallbackContext,
00926                        BOOL HasPackedLParam,
00927                        INT HookMessage)
00928 {
00929 
00930     PTHREADINFO ptiSender;
00931     PUSER_SENT_MESSAGE Message;
00932 
00933     if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
00934     {
00935         ERR("MsqSendMessage(): Not enough memory to allocate a message");
00936         return FALSE;
00937     }
00938 
00939     ptiSender = PsGetCurrentThreadWin32Thread();
00940 
00941     IntReferenceMessageQueue(ptiReceiver->MessageQueue);
00942     /* Take reference on this MessageQueue if its a callback. It will be released
00943        when message is processed or removed from target hwnd MessageQueue */
00944     if (CompletionCallback)
00945        IntReferenceMessageQueue(ptiSender->MessageQueue);
00946 
00947     Message->Msg.hwnd = hwnd;
00948     Message->Msg.message = Msg;
00949     Message->Msg.wParam = wParam;
00950     Message->Msg.lParam = lParam;
00951     Message->CompletionEvent = NULL;
00952     Message->Result = 0;
00953     Message->lResult = 0;
00954     Message->SenderQueue = NULL;
00955     Message->CallBackSenderQueue = ptiSender->MessageQueue;
00956     Message->DispatchingListEntry.Flink = NULL;
00957     Message->CompletionCallback = CompletionCallback;
00958     Message->CompletionCallbackContext = CompletionCallbackContext;
00959     Message->HookMessage = HookMessage;
00960     Message->HasPackedLParam = HasPackedLParam;
00961     Message->QS_Flags = QS_SENDMESSAGE;
00962 
00963     InsertTailList(&ptiReceiver->MessageQueue->SentMessagesListHead, &Message->ListEntry);
00964     MsqWakeQueue(ptiReceiver->MessageQueue, QS_SENDMESSAGE, TRUE);
00965     IntDereferenceMessageQueue(ptiReceiver->MessageQueue);
00966 
00967     return TRUE;
00968 }
00969 
00970 NTSTATUS FASTCALL
00971 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
00972                   HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
00973                   UINT uTimeout, BOOL Block, INT HookMessage,
00974                   ULONG_PTR *uResult)
00975 {
00976    PTHREADINFO pti, ptirec;
00977    PUSER_SENT_MESSAGE Message;
00978    KEVENT CompletionEvent;
00979    NTSTATUS WaitStatus;
00980    PUSER_MESSAGE_QUEUE ThreadQueue;
00981    LARGE_INTEGER Timeout;
00982    PLIST_ENTRY Entry;
00983    LRESULT Result = 0;   
00984 
00985    pti = PsGetCurrentThreadWin32Thread();
00986    ThreadQueue = pti->MessageQueue;
00987    ptirec = MessageQueue->Thread->Tcb.Win32Thread;
00988    ASSERT(ThreadQueue != MessageQueue);
00989    ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
00990 
00991    /* Don't send from or to a dying thread */
00992     if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
00993     {
00994         if (uResult) *uResult = -1;
00995         ERR("MsqSM: Current pti %d or Rec pti %d\n",pti->TIF_flags & TIF_INCLEANUP, ptirec->TIF_flags & TIF_INCLEANUP);
00996         return STATUS_UNSUCCESSFUL;
00997     }
00998 
00999    if ( HookMessage == MSQ_NORMAL )
01000    {
01001       // These can not cross International Border lines!
01002       if ( pti->ppi != ptirec->ppi )
01003       {
01004          switch(Msg)
01005          {
01006              case EM_GETLINE:
01007              case EM_SETPASSWORDCHAR:
01008              case WM_GETTEXT:
01009              case WM_NOTIFY:
01010                 if (uResult) *uResult = -1;
01011                 ERR("Running across the border without a passport!\n");
01012                 return STATUS_UNSUCCESSFUL;
01013          }
01014       }
01015 
01016       // These can not cross State lines!
01017       if ( Msg == WM_CREATE || Msg == WM_NCCREATE )
01018       {
01019          if (uResult) *uResult = -1;
01020          ERR("Can not tell the other State we have Create!\n");
01021          return STATUS_UNSUCCESSFUL;
01022       }
01023    }
01024 
01025    if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
01026    {
01027       ERR("MsqSendMessage(): Not enough memory to allocate a message");
01028       return STATUS_INSUFFICIENT_RESOURCES;
01029    }
01030 
01031    KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
01032 
01033    Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
01034 
01035    /* FIXME: Increase reference counter of sender's message queue here */
01036 
01037    Message->Msg.hwnd = Wnd;
01038    Message->Msg.message = Msg;
01039    Message->Msg.wParam = wParam;
01040    Message->Msg.lParam = lParam;
01041    Message->CompletionEvent = &CompletionEvent;
01042    Message->Result = &Result;
01043    Message->lResult = 0;
01044    Message->QS_Flags = 0;
01045    Message->SenderQueue = ThreadQueue;
01046    Message->CallBackSenderQueue = NULL;
01047    IntReferenceMessageQueue(ThreadQueue);
01048    Message->CompletionCallback = NULL;
01049    Message->CompletionCallbackContext = 0;
01050    Message->HookMessage = HookMessage;
01051    Message->HasPackedLParam = FALSE;
01052 
01053    IntReferenceMessageQueue(MessageQueue);
01054 
01055    /* Add it to the list of pending messages */
01056    InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
01057 
01058    /* Queue it in the destination's message queue */
01059    InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
01060 
01061    Message->QS_Flags = QS_SENDMESSAGE;
01062    MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
01063 
01064    /* We can't access the Message anymore since it could have already been deleted! */
01065 
01066    if(Block)
01067    {
01068       UserLeaveCo();
01069 
01070       /* Don't process messages sent to the thread */
01071       WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
01072                                          FALSE, (uTimeout ? &Timeout : NULL));
01073 
01074       UserEnterCo();
01075 
01076       if(WaitStatus == STATUS_TIMEOUT)
01077       {
01078          /* Look up if the message has not yet dispatched, if so
01079             make sure it can't pass a result and it must not set the completion event anymore */
01080          Entry = MessageQueue->SentMessagesListHead.Flink;
01081          while (Entry != &MessageQueue->SentMessagesListHead)
01082          {
01083             if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
01084                   == Message)
01085             {
01086                /* We can access Message here, it's secure because the message queue is locked
01087                   and the message is still hasn't been dispatched */
01088                Message->CompletionEvent = NULL;
01089                Message->Result = NULL;
01090                break;
01091             }
01092             Entry = Entry->Flink;
01093          }
01094 
01095          /* Remove from the local dispatching list so the other thread knows,
01096             it can't pass a result and it must not set the completion event anymore */
01097          Entry = ThreadQueue->DispatchingMessagesHead.Flink;
01098          while (Entry != &ThreadQueue->DispatchingMessagesHead)
01099          {
01100             if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
01101                   == Message)
01102             {
01103                /* We can access Message here, it's secure because the sender's message is locked
01104                   and the message has definitely not yet been destroyed, otherwise it would
01105                   have been removed from this list by the dispatching routine right after
01106                   dispatching the message */
01107                Message->CompletionEvent = NULL;
01108                Message->Result = NULL;
01109                RemoveEntryList(&Message->DispatchingListEntry);
01110                Message->DispatchingListEntry.Flink = NULL;
01111                break;
01112             }
01113             Entry = Entry->Flink;
01114          }
01115 
01116          TRACE("MsqSendMessage (blocked) timed out 1\n");
01117       }
01118       while (co_MsqDispatchOneSentMessage(ThreadQueue))
01119          ;
01120    }
01121    else
01122    {
01123       PVOID WaitObjects[2];
01124 
01125       WaitObjects[0] = &CompletionEvent;
01126       WaitObjects[1] = ThreadQueue->NewMessages;
01127       do
01128       {
01129          UserLeaveCo();
01130 
01131          WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
01132                                                UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
01133 
01134          UserEnterCo();
01135 
01136          if(WaitStatus == STATUS_TIMEOUT)
01137          {
01138             /* Look up if the message has not yet been dispatched, if so
01139                make sure it can't pass a result and it must not set the completion event anymore */
01140             Entry = MessageQueue->SentMessagesListHead.Flink;
01141             while (Entry != &MessageQueue->SentMessagesListHead)
01142             {
01143                if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
01144                      == Message)
01145                {
01146                   /* We can access Message here, it's secure because the message queue is locked
01147                      and the message is still hasn't been dispatched */
01148                   Message->CompletionEvent = NULL;
01149                   Message->Result = NULL;
01150                   break;
01151                }
01152                Entry = Entry->Flink;
01153             }
01154 
01155             /* Remove from the local dispatching list so the other thread knows,
01156                it can't pass a result and it must not set the completion event anymore */
01157             Entry = ThreadQueue->DispatchingMessagesHead.Flink;
01158             while (Entry != &ThreadQueue->DispatchingMessagesHead)
01159             {
01160                if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
01161                      == Message)
01162                {
01163                   /* We can access Message here, it's secure because the sender's message is locked
01164                      and the message has definitely not yet been destroyed, otherwise it would
01165                      have been removed from this list by the dispatching routine right after
01166                      dispatching the message */
01167                   Message->CompletionEvent = NULL;
01168                   Message->Result = NULL;
01169                   RemoveEntryList(&Message->DispatchingListEntry);
01170                   Message->DispatchingListEntry.Flink = NULL;
01171                   break;
01172                }
01173                Entry = Entry->Flink;
01174             }
01175 
01176             TRACE("MsqSendMessage timed out 2\n");
01177             break;
01178          }
01179          while (co_MsqDispatchOneSentMessage(ThreadQueue))
01180             ;
01181       }
01182       while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
01183    }
01184 
01185    if(WaitStatus != STATUS_TIMEOUT)
01186       *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
01187 
01188    return WaitStatus;
01189 }
01190 
01191 VOID FASTCALL
01192 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessage,
01193                DWORD MessageBits)
01194 {
01195    PUSER_MESSAGE Message;
01196 
01197    if(!(Message = MsqCreateMessage(Msg)))
01198    {
01199       return;
01200    }
01201 
01202    if(!HardwareMessage)
01203    {
01204        InsertTailList(&MessageQueue->PostedMessagesListHead,
01205                       &Message->ListEntry);
01206    }
01207    else
01208    {
01209        InsertTailList(&MessageQueue->HardwareMessagesListHead,
01210                       &Message->ListEntry);
01211    }
01212 
01213    Message->QS_Flags = MessageBits;
01214    MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
01215 }
01216 
01217 VOID FASTCALL
01218 MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
01219 {
01220    MessageQueue->QuitPosted = TRUE;
01221    MessageQueue->QuitExitCode = ExitCode;
01222    MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
01223 }
01224 
01225 /***********************************************************************
01226  *           MsqSendParentNotify
01227  *
01228  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
01229  * the window has the WS_EX_NOPARENTNOTIFY style.
01230  */
01231 static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
01232 {
01233     PWND pwndDesktop = UserGetDesktopWindow();
01234 
01235     /* pt has to be in the client coordinates of the parent window */
01236     pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
01237     pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
01238 
01239     for (;;)
01240     {
01241         PWND pwndParent;
01242 
01243         if (!(pwnd->style & WS_CHILD)) break;
01244         if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
01245         if (!(pwndParent = IntGetParent(pwnd))) break;
01246         if (pwndParent == pwndDesktop) break;
01247         pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
01248         pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
01249 
01250         pwnd = pwndParent;
01251         co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
01252                       MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
01253     }
01254 }
01255 
01256 VOID
01257 FASTCALL
01258 IntTrackMouseMove(PWND pwndTrack, PDESKTOP pDesk, PMSG msg, USHORT hittest)
01259 {
01260 //   PWND pwndTrack = IntChildrenWindowFromPoint(pwndMsg, msg->pt.x, msg->pt.y);
01261    hittest = GetNCHitEx(pwndTrack, msg->pt);
01262 
01263    if ( pDesk->spwndTrack != pwndTrack || // Change with tracking window or
01264         msg->message != WM_MOUSEMOVE   || // Mouse click changes or
01265         pDesk->htEx != hittest)           // Change in current hit test states.
01266    {
01267       TRACE("ITMM: Track Mouse Move!\n");
01268 
01269       /* Handle only the changing window track and mouse move across a border. */
01270       if ( pDesk->spwndTrack != pwndTrack ||
01271           (pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT) )
01272       {
01273          TRACE("ITMM: Another Wnd %d or Across Border %d\n",
01274               pDesk->spwndTrack != pwndTrack,(pDesk->htEx == HTCLIENT) ^ (hittest == HTCLIENT));
01275 
01276          if ( pDesk->dwDTFlags & DF_TME_LEAVE )
01277             UserPostMessage( UserHMGetHandle(pDesk->spwndTrack),
01278                             (pDesk->htEx != HTCLIENT) ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
01279                              0, 0);
01280 
01281          if ( pDesk->dwDTFlags & DF_TME_HOVER )
01282             IntKillTimer(UserHMGetHandle(pDesk->spwndTrack), ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
01283 
01284          /* Clear the flags to sign a change. */
01285          pDesk->dwDTFlags &= ~(DF_TME_LEAVE|DF_TME_HOVER);
01286       }
01287       /* Set the Track window and hit test. */
01288       pDesk->spwndTrack = pwndTrack;
01289       pDesk->htEx = hittest;
01290    }
01291 
01292    /* Reset, Same Track window, Hover set and Mouse Clicks or Clobbered Hover box. */
01293    if ( pDesk->spwndTrack == pwndTrack &&
01294        ( msg->message != WM_MOUSEMOVE || !RECTL_bPointInRect(&pDesk->rcMouseHover, msg->pt.x, msg->pt.y)) &&
01295         pDesk->dwDTFlags & DF_TME_HOVER )
01296    {
01297       TRACE("ITMM: Reset Hover points!\n");
01298       // Restart timer for the hover period.
01299       IntSetTimer(pDesk->spwndTrack, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
01300       // Reset desktop mouse hover from the system default hover rectangle.
01301       RECTL_vSetRect(&pDesk->rcMouseHover,
01302                       msg->pt.x - gspv.iMouseHoverWidth  / 2,
01303                       msg->pt.y - gspv.iMouseHoverHeight / 2,
01304                       msg->pt.x + gspv.iMouseHoverWidth  / 2,
01305                       msg->pt.y + gspv.iMouseHoverHeight / 2);
01306    }
01307 }
01308 
01309 BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last)
01310 {
01311     MSG clk_msg;
01312     POINT pt;
01313     UINT message;
01314     USHORT hittest;
01315     EVENTMSG event;
01316     MOUSEHOOKSTRUCT hook;
01317     BOOL eatMsg;
01318 
01319     PWND pwndMsg, pwndDesktop;
01320     PUSER_MESSAGE_QUEUE MessageQueue;
01321     PTHREADINFO pti;
01322     PSYSTEM_CURSORINFO CurInfo;
01323     PDESKTOP pDesk;
01324     DECLARE_RETURN(BOOL);
01325 
01326     pti = PsGetCurrentThreadWin32Thread();
01327     pwndDesktop = UserGetDesktopWindow();
01328     MessageQueue = pti->MessageQueue;
01329     CurInfo = IntGetSysCursorInfo();
01330     pwndMsg = UserGetWindowObject(msg->hwnd);
01331     clk_msg = MessageQueue->msgDblClk;
01332     pDesk = pwndDesktop->head.rpdesk;
01333 
01334     /* find the window to dispatch this mouse message to */
01335     if (MessageQueue->CaptureWindow)
01336     {
01337         hittest = HTCLIENT;
01338         pwndMsg = IntGetWindowObject(MessageQueue->CaptureWindow);
01339     }
01340     else
01341     {
01342         pwndMsg = co_WinPosWindowFromPoint(pwndMsg, &msg->pt, &hittest);
01343     }
01344 
01345     TRACE("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest );
01346 
01347     if (pwndMsg == NULL || pwndMsg->head.pti != pti)
01348     {
01349         /* Remove and ignore the message */
01350         *RemoveMessages = TRUE;
01351         RETURN(FALSE);
01352     }
01353 
01354     if ( MessageQueue == gpqCursor ) // Cursor must use the same Queue!
01355     {
01356        IntTrackMouseMove(pwndMsg, pDesk, msg, hittest);
01357     }
01358     else
01359     {
01360        ERR("Not the same cursor!\n");
01361     }
01362 
01363     msg->hwnd = UserHMGetHandle(pwndMsg);
01364 
01365 #if 0
01366     if (!check_hwnd_filter( msg, hwnd_filter )) RETURN(FALSE);
01367 #endif
01368 
01369     pt = msg->pt;
01370     message = msg->message;
01371     /* Note: windows has no concept of a non-client wheel message */
01372     if (message != WM_MOUSEWHEEL)
01373     {
01374         if (hittest != HTCLIENT)
01375         {
01376             message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
01377             msg->wParam = hittest;
01378         }
01379         else
01380         {
01381             /* coordinates don't get translated while tracking a menu */
01382             /* FIXME: should differentiate popups and top-level menus */
01383             if (!(MessageQueue->MenuOwner))
01384             {
01385                 pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
01386                 pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
01387             }
01388         }
01389     }
01390     msg->lParam = MAKELONG( pt.x, pt.y );
01391 
01392     /* translate double clicks */
01393 
01394     if ((msg->message == WM_LBUTTONDOWN) ||
01395         (msg->message == WM_RBUTTONDOWN) ||
01396         (msg->message == WM_MBUTTONDOWN) ||
01397         (msg->message == WM_XBUTTONDOWN))
01398     {
01399         BOOL update = *RemoveMessages;
01400 
01401         /* translate double clicks -
01402          * note that ...MOUSEMOVEs can slip in between
01403          * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
01404 
01405         if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
01406             hittest != HTCLIENT ||
01407             (pwndMsg->pcls->style & CS_DBLCLKS))
01408         {
01409            if ((msg->message == clk_msg.message) &&
01410                (msg->hwnd == clk_msg.hwnd) &&
01411                (msg->wParam == clk_msg.wParam) &&
01412                ((msg->time - clk_msg.time) < (ULONG)gspv.iDblClickTime) &&
01413                (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
01414                (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
01415            {
01416                message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
01417                if (update)
01418                {
01419                    MessageQueue->msgDblClk.message = 0;  /* clear the double click conditions */
01420                    update = FALSE;
01421                }
01422            }
01423         }
01424 
01425         if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
01426         {
01427             TRACE("Message out of range!!!\n");
01428             RETURN(FALSE);
01429         }
01430 
01431         /* update static double click conditions */
01432         if (update) MessageQueue->msgDblClk = *msg;
01433     }
01434     else
01435     {
01436         if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
01437         {
01438             TRACE("Message out of range!!!\n");
01439             RETURN(FALSE);
01440         }
01441     }
01442 
01443     if(gspv.bMouseClickLock)
01444     {
01445         BOOL IsClkLck = FALSE;
01446 
01447         if(msg->message == WM_LBUTTONUP)
01448         {
01449             IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
01450             if (IsClkLck && (!CurInfo->ClickLockActive))
01451             {
01452                 CurInfo->ClickLockActive = TRUE;
01453             }
01454         }
01455         else if (msg->message == WM_LBUTTONDOWN)
01456         {
01457             if (CurInfo->ClickLockActive)
01458             {
01459                 IsClkLck = TRUE;
01460                 CurInfo->ClickLockActive = FALSE;
01461             }
01462 
01463             CurInfo->ClickLockTime = msg->time;
01464         }
01465 
01466         if(IsClkLck)
01467         {
01468             /* Remove and ignore the message */
01469             *RemoveMessages = TRUE;
01470             RETURN(FALSE);
01471         }
01472     }
01473 
01474     /* message is accepted now (but may still get dropped) */
01475 
01476     event.message = msg->message;
01477     event.time    = msg->time;
01478     event.hwnd    = msg->hwnd;
01479     event.paramL  = msg->pt.x;
01480     event.paramH  = msg->pt.y;
01481     co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
01482 
01483     hook.pt           = msg->pt;
01484     hook.hwnd         = msg->hwnd;
01485     hook.wHitTestCode = hittest;
01486     hook.dwExtraInfo  = 0 /* extra_info */ ;
01487     if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
01488                         message, (LPARAM)&hook ))
01489     {
01490         hook.pt           = msg->pt;
01491         hook.hwnd         = msg->hwnd;
01492         hook.wHitTestCode = hittest;
01493         hook.dwExtraInfo  = 0 /* extra_info */ ;
01494         co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
01495 
01496         ERR("WH_MOUSE dorpped mouse message!\n");
01497 
01498         /* Remove and skip message */
01499         *RemoveMessages = TRUE;
01500         RETURN(FALSE);
01501     }
01502 
01503     if ((hittest == HTERROR) || (hittest == HTNOWHERE))
01504     {
01505         co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
01506                       MAKELONG( hittest, msg->message ));
01507 
01508         /* Remove and skip message */
01509         *RemoveMessages = TRUE;
01510         RETURN(FALSE);
01511     }
01512 
01513     if ((*RemoveMessages == FALSE) || MessageQueue->CaptureWindow)
01514     {
01515         /* Accept the message */
01516         msg->message = message;
01517         RETURN(TRUE);
01518     }
01519 
01520     eatMsg = FALSE;
01521 
01522     if ((msg->message == WM_LBUTTONDOWN) ||
01523         (msg->message == WM_RBUTTONDOWN) ||
01524         (msg->message == WM_MBUTTONDOWN) ||
01525         (msg->message == WM_XBUTTONDOWN))
01526     {
01527         /* Send the WM_PARENTNOTIFY,
01528          * note that even for double/nonclient clicks
01529          * notification message is still WM_L/M/RBUTTONDOWN.
01530          */
01531         MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
01532 
01533         /* Activate the window if needed */
01534 
01535         if (msg->hwnd != UserGetForegroundWindow())
01536         {
01537             PWND pwndTop = pwndMsg;
01538             while (pwndTop)
01539             {
01540                 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
01541                 pwndTop = IntGetParent( pwndTop );
01542             }
01543 
01544             if (pwndTop && pwndTop != pwndDesktop)
01545             {
01546                 LONG ret = co_IntSendMessage( msg->hwnd,
01547                                               WM_MOUSEACTIVATE,
01548                                               (WPARAM)UserHMGetHandle(pwndTop),
01549                                               MAKELONG( hittest, msg->message));
01550                 switch(ret)
01551                 {
01552                 case MA_NOACTIVATEANDEAT:
01553                     eatMsg = TRUE;
01554                     /* fall through */
01555                 case MA_NOACTIVATE:
01556                     break;
01557                 case MA_ACTIVATEANDEAT:
01558                     eatMsg = TRUE;
01559                     /* fall through */
01560                 case MA_ACTIVATE:
01561                 case 0:
01562                     if(!co_IntMouseActivateWindow(pwndMsg)) eatMsg = TRUE;
01563                     break;
01564                 default:
01565                     ERR( "unknown WM_MOUSEACTIVATE code %d\n", ret );
01566                     break;
01567                 }
01568             }
01569         }
01570     }
01571 
01572     /* send the WM_SETCURSOR message */
01573 
01574     /* Windows sends the normal mouse message as the message parameter
01575        in the WM_SETCURSOR message even if it's non-client mouse message */
01576     co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
01577 
01578     msg->message = message;
01579     RETURN(!eatMsg);
01580 
01581 CLEANUP:
01582     if(pwndMsg)
01583         UserDereferenceObject(pwndMsg);
01584 
01585     END_CLEANUP;
01586 }
01587 
01588 BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
01589 {
01590     EVENTMSG Event;
01591 
01592     if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
01593         Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
01594     {
01595         switch (Msg->wParam)
01596         {
01597             case VK_LSHIFT: case VK_RSHIFT:
01598                 Msg->wParam = VK_SHIFT;
01599                 break;
01600             case VK_LCONTROL: case VK_RCONTROL:
01601                 Msg->wParam = VK_CONTROL;
01602                 break;
01603             case VK_LMENU: case VK_RMENU:
01604                 Msg->wParam = VK_MENU;
01605                 break;
01606         }
01607     }
01608 
01609     Event.message = Msg->message;
01610     Event.hwnd    = Msg->hwnd;
01611     Event.time    = Msg->time;
01612     Event.paramL  = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
01613     Event.paramH  = Msg->lParam & 0x7FFF;
01614     if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
01615     co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
01616 
01617     if (co_HOOK_CallHooks( WH_KEYBOARD,
01618                            *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
01619                            LOWORD(Msg->wParam),
01620                            Msg->lParam))
01621     {
01622         /* skip this message */
01623         co_HOOK_CallHooks( WH_CBT,
01624                            HCBT_KEYSKIPPED,
01625                            LOWORD(Msg->wParam),
01626                            Msg->lParam );
01627         ERR("KeyboardMessage WH_CBT Call Hook return!\n");
01628         return FALSE;
01629     }
01630     return TRUE;
01631 }
01632 
01633 BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
01634 {
01635     if ( IS_MOUSE_MESSAGE(Msg->message))
01636     {
01637         return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
01638     }
01639     else if ( IS_KBD_MESSAGE(Msg->message))
01640     {
01641         return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
01642     }
01643 
01644     return TRUE;
01645 }
01646 
01647 BOOL APIENTRY
01648 co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
01649                    IN BOOL Remove,
01650                    IN PWND Window,
01651                    IN UINT MsgFilterLow,
01652                    IN UINT MsgFilterHigh,
01653                    OUT MSG* pMsg)
01654 {
01655     BOOL AcceptMessage;
01656     MSG msg;
01657 
01658     if(!(MessageQueue->MouseMoved))
01659         return FALSE;
01660 
01661     msg = MessageQueue->MouseMoveMsg;
01662 
01663     AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
01664 
01665     if(AcceptMessage)
01666         *pMsg = msg;
01667 
01668     if(Remove)
01669     {
01670         ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE);
01671         MessageQueue->MouseMoved = FALSE;
01672     }
01673 
01674    return AcceptMessage;
01675 }
01676 
01677 /* check whether a message filter contains at least one potential hardware message */
01678 static INT FASTCALL
01679 filter_contains_hw_range( UINT first, UINT last )
01680 {
01681    /* hardware message ranges are (in numerical order):
01682     *   WM_NCMOUSEFIRST .. WM_NCMOUSELAST
01683     *   WM_KEYFIRST .. WM_KEYLAST
01684     *   WM_MOUSEFIRST .. WM_MOUSELAST
01685     */
01686     if (!last) --last;
01687     if (last < WM_NCMOUSEFIRST) return 0;
01688     if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
01689     if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
01690     if (first > WM_MOUSELAST) return 0;
01691     return 1;
01692 }
01693 
01694 BOOL APIENTRY
01695 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
01696                          IN BOOL Remove,
01697                          IN PWND Window,
01698                          IN UINT MsgFilterLow,
01699                          IN UINT MsgFilterHigh,
01700                          IN UINT QSflags,
01701                          OUT MSG* pMsg)
01702 {
01703 
01704     BOOL AcceptMessage;
01705     PUSER_MESSAGE CurrentMessage;
01706     PLIST_ENTRY ListHead, CurrentEntry = NULL;
01707     MSG msg;
01708 
01709     if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
01710 
01711     ListHead = &MessageQueue->HardwareMessagesListHead;
01712     CurrentEntry = ListHead->Flink;
01713 
01714     if (IsListEmpty(CurrentEntry)) return FALSE;
01715 
01716     CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
01717                                           ListEntry);
01718     do
01719     {
01720         if (IsListEmpty(CurrentEntry)) break;
01721         if (!CurrentMessage) break;
01722         CurrentEntry = CurrentMessage->ListEntry.Flink;
01723 /*
01724  MSDN:
01725  1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
01726  2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
01727  3: handle to the window whose messages are to be retrieved.
01728  */
01729       if ( ( !Window || // 1
01730             ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
01731             ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
01732             ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
01733               ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
01734         {
01735            msg = CurrentMessage->Msg;
01736 
01737            UpdateKeyStateFromMsg(MessageQueue, &msg);
01738            AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
01739 
01740            if (Remove)
01741            {
01742                RemoveEntryList(&CurrentMessage->ListEntry);
01743                ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
01744                MsqDestroyMessage(CurrentMessage);
01745            }
01746 
01747            if (AcceptMessage)
01748            {
01749               *pMsg = msg;
01750               return TRUE;
01751            }
01752         }
01753         CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
01754                                           ListEntry);
01755     }
01756     while(CurrentEntry != ListHead);
01757 
01758     return FALSE;
01759 }
01760 
01761 BOOLEAN APIENTRY
01762 MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
01763                   IN BOOLEAN Remove,
01764                   IN PWND Window,
01765                   IN UINT MsgFilterLow,
01766                   IN UINT MsgFilterHigh,
01767                   IN UINT QSflags,
01768                   OUT PMSG Message)
01769 {
01770    PLIST_ENTRY CurrentEntry;
01771    PUSER_MESSAGE CurrentMessage;
01772    PLIST_ENTRY ListHead;
01773 
01774    CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
01775    ListHead = &MessageQueue->PostedMessagesListHead;
01776 
01777    if (IsListEmpty(CurrentEntry)) return FALSE;
01778 
01779    CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
01780                                          ListEntry);
01781    do
01782    {
01783       if (IsListEmpty(CurrentEntry)) break;
01784       if (!CurrentMessage) break;
01785       CurrentEntry = CurrentEntry->Flink;
01786 /*
01787  MSDN:
01788  1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
01789  2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
01790  3: handle to the window whose messages are to be retrieved.
01791  */
01792       if ( ( !Window || // 1
01793             ( Window == PWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
01794             ( Window != PWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
01795             ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
01796               ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
01797       {
01798          *Message = CurrentMessage->Msg;
01799 
01800          if (Remove)
01801          {
01802              RemoveEntryList(&CurrentMessage->ListEntry);
01803              ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
01804              MsqDestroyMessage(CurrentMessage);
01805          }
01806          return(TRUE);
01807       }
01808       CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
01809                                          ListEntry);
01810    }
01811    while (CurrentEntry != ListHead);
01812 
01813    return(FALSE);
01814 }
01815 
01816 NTSTATUS FASTCALL
01817 co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
01818                          UINT MsgFilterMin, UINT MsgFilterMax)
01819 {
01820    NTSTATUS ret;
01821    UserLeaveCo();
01822    ret = KeWaitForSingleObject( MessageQueue->NewMessages,
01823                                 UserRequest,
01824                                 UserMode,
01825                                 FALSE,
01826                                 NULL );
01827    UserEnterCo();
01828    return ret;
01829 }
01830 
01831 BOOL FASTCALL
01832 MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
01833 {
01834    LARGE_INTEGER LargeTickCount;
01835 
01836    KeQueryTickCount(&LargeTickCount);
01837    return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
01838 }
01839 
01840 VOID
01841 CALLBACK
01842 HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
01843 {
01844    DoTheScreenSaver();
01845    TRACE("HungAppSysTimerProc\n");
01846    // Process list of windows that are hung and waiting.
01847 }
01848 
01849 BOOLEAN FASTCALL
01850 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
01851 {
01852    LARGE_INTEGER LargeTickCount;
01853    NTSTATUS Status;
01854 
01855    MessageQueue->Thread = Thread;
01856    MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
01857    InitializeListHead(&MessageQueue->PostedMessagesListHead);
01858    InitializeListHead(&MessageQueue->SentMessagesListHead);
01859    InitializeListHead(&MessageQueue->HardwareMessagesListHead);
01860    InitializeListHead(&MessageQueue->DispatchingMessagesHead);
01861    InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
01862    MessageQueue->QuitPosted = FALSE;
01863    MessageQueue->QuitExitCode = 0;
01864    KeQueryTickCount(&LargeTickCount);
01865    MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
01866    MessageQueue->spwndFocus = NULL;
01867    MessageQueue->NewMessagesHandle = NULL;
01868    MessageQueue->ShowingCursor = 0;
01869    MessageQueue->CursorObject = NULL;
01870    RtlCopyMemory(MessageQueue->afKeyState, gafAsyncKeyState, sizeof(gafAsyncKeyState));
01871 
01872    Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
01873                           NULL, SynchronizationEvent, FALSE);
01874    if (!NT_SUCCESS(Status))
01875    {
01876       return FALSE;
01877    }
01878 
01879    Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
01880                                       ExEventObjectType, KernelMode,
01881                                       (PVOID*)&MessageQueue->NewMessages, NULL);
01882    if (!NT_SUCCESS(Status))
01883    {
01884       ZwClose(MessageQueue->NewMessagesHandle);
01885       MessageQueue->NewMessagesHandle = NULL;
01886       return FALSE;
01887    }
01888 
01889    return TRUE;
01890 }
01891 
01892 VOID FASTCALL
01893 MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
01894 {
01895    PLIST_ENTRY CurrentEntry;
01896    PUSER_MESSAGE CurrentMessage;
01897    PUSER_SENT_MESSAGE CurrentSentMessage;
01898    PTHREADINFO pti;
01899 
01900    pti = MessageQueue->Thread->Tcb.Win32Thread;
01901 
01902 
01903    /* cleanup posted messages */
01904    while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
01905    {
01906       CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
01907       CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
01908                                          ListEntry);
01909       MsqDestroyMessage(CurrentMessage);
01910    }
01911 
01912    /* remove the messages that have not yet been dispatched */
01913    while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
01914    {
01915       CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
01916       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
01917                                              ListEntry);
01918 
01919       /* if it is a callback and this queue is not the sender queue, dereference queue */
01920       if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
01921       {
01922          IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
01923       }
01924 
01925       TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
01926       /* Only if the message has a sender was the message in the DispatchingList */
01927       if ((CurrentSentMessage->SenderQueue)
01928          && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
01929       {
01930          RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
01931       }
01932 
01933       /* wake the sender's thread */
01934       if (CurrentSentMessage->CompletionEvent != NULL)
01935       {
01936          KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
01937       }
01938 
01939       if (CurrentSentMessage->HasPackedLParam == TRUE)
01940       {
01941          if (CurrentSentMessage->Msg.lParam)
01942             ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
01943       }
01944 
01945       /* if the message has a sender */
01946       if (CurrentSentMessage->SenderQueue)
01947       {
01948          /* dereference our and the sender's message queue */
01949          IntDereferenceMessageQueue(MessageQueue);
01950          IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
01951       }
01952 
01953       /* free the message */
01954       ExFreePool(CurrentSentMessage);
01955    }
01956 
01957    /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
01958       ExitThread() was called in a SendMessage() umode callback */
01959    while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
01960    {
01961       CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
01962       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
01963                                              ListEntry);
01964 
01965       /* if it is a callback and this queue is not the sender queue, dereference queue */
01966       if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
01967       {
01968          IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
01969       }
01970 
01971       /* remove the message from the dispatching list */
01972       if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
01973       {
01974          RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
01975       }
01976 
01977       TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
01978 
01979       /* wake the sender's thread */
01980       if (CurrentSentMessage->CompletionEvent != NULL)
01981       {
01982          KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
01983       }
01984 
01985       if (CurrentSentMessage->HasPackedLParam == TRUE)
01986       {
01987          if (CurrentSentMessage->Msg.lParam)
01988             ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
01989       }
01990 
01991       /* if the message has a sender */
01992       if (CurrentSentMessage->SenderQueue)
01993       {
01994          /* dereference our and the sender's message queue */
01995          IntDereferenceMessageQueue(MessageQueue);
01996          IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
01997       }
01998 
01999       /* free the message */
02000       ExFreePool(CurrentSentMessage);
02001    }
02002 
02003    /* tell other threads not to bother returning any info to us */
02004    while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
02005    {
02006       CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
02007       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
02008                                              DispatchingListEntry);
02009       CurrentSentMessage->CompletionEvent = NULL;
02010       CurrentSentMessage->Result = NULL;
02011 
02012       /* do NOT dereference our message queue as it might get attempted to be
02013          locked later */
02014    }
02015 
02016    // Clear it all out.
02017    if(pti->pcti)
02018    {
02019        pti->pcti->fsWakeBits = 0;
02020        pti->pcti->fsChangeBits = 0;
02021    }
02022 
02023    MessageQueue->nCntsQBits[QSRosKey] = 0;
02024    MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
02025    MessageQueue->nCntsQBits[QSRosMouseButton] = 0;
02026    MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
02027    MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
02028    MessageQueue->nCntsQBits[QSRosHotKey] = 0;
02029 
02030    if (MessageQueue->CursorObject)
02031    {
02032        PCURICON_OBJECT pCursor = MessageQueue->CursorObject;
02033 
02034        /* Change to another cursor if we going to dereference current one
02035           Note: we can't use UserSetCursor because it uses current thread
02036                 message queue instead of queue given for cleanup */
02037        if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor)
02038        {
02039            HDC hdcScreen;
02040 
02041            /* Get the screen DC */
02042            hdcScreen = IntGetScreenDC();
02043            if (hdcScreen)
02044                GreMovePointer(hdcScreen, -1, -1);
02045            IntGetSysCursorInfo()->CurrentCursorObject = NULL;
02046        }
02047 
02048        UserDereferenceObject(pCursor);
02049    }
02050 
02051 }
02052 
02053 PUSER_MESSAGE_QUEUE FASTCALL
02054 MsqCreateMessageQueue(struct _ETHREAD *Thread)
02055 {
02056    PUSER_MESSAGE_QUEUE MessageQueue;
02057 
02058    MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
02059                   sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
02060                   USERTAG_Q);
02061 
02062    if (!MessageQueue)
02063    {
02064       return NULL;
02065    }
02066 
02067    RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
02068    /* hold at least one reference until it'll be destroyed */
02069    IntReferenceMessageQueue(MessageQueue);
02070    /* initialize the queue */
02071    if (!MsqInitializeMessageQueue(Thread, MessageQueue))
02072    {
02073       IntDereferenceMessageQueue(MessageQueue);
02074       return NULL;
02075    }
02076 
02077    return MessageQueue;
02078 }
02079 
02080 VOID FASTCALL
02081 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
02082 {
02083    PDESKTOP desk;
02084 
02085    MessageQueue->QF_flags |= QF_INDESTROY;
02086 
02087    /* remove the message queue from any desktops */
02088    if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
02089    {
02090       (void)InterlockedExchangePointer((PVOID*)&desk->ActiveMessageQueue, 0);
02091       IntDereferenceMessageQueue(MessageQueue);
02092    }
02093 
02094    /* clean it up */
02095    MsqCleanupMessageQueue(MessageQueue);
02096 
02097    if (MessageQueue->NewMessagesHandle != NULL)
02098       ZwClose(MessageQueue->NewMessagesHandle);
02099    MessageQueue->NewMessagesHandle = NULL;
02100    /* decrease the reference counter, if it hits zero, the queue will be freed */
02101    IntDereferenceMessageQueue(MessageQueue);
02102 }
02103 
02104 LPARAM FASTCALL
02105 MsqSetMessageExtraInfo(LPARAM lParam)
02106 {
02107    LPARAM Ret;
02108    PTHREADINFO pti;
02109    PUSER_MESSAGE_QUEUE MessageQueue;
02110 
02111    pti = PsGetCurrentThreadWin32Thread();
02112    MessageQueue = pti->MessageQueue;
02113    if(!MessageQueue)
02114    {
02115       return 0;
02116    }
02117 
02118    Ret = MessageQueue->ExtraInfo;
02119    MessageQueue->ExtraInfo = lParam;
02120 
02121    return Ret;
02122 }
02123 
02124 LPARAM FASTCALL
02125 MsqGetMessageExtraInfo(VOID)
02126 {
02127    PTHREADINFO pti;
02128    PUSER_MESSAGE_QUEUE MessageQueue;
02129 
02130    pti = PsGetCurrentThreadWin32Thread();
02131    MessageQueue = pti->MessageQueue;
02132    if(!MessageQueue)
02133    {
02134       return 0;
02135    }
02136 
02137    return MessageQueue->ExtraInfo;
02138 }
02139 
02140 // ReplyMessage is called by the thread receiving the window message.
02141 BOOL FASTCALL
02142 co_MsqReplyMessage( LRESULT lResult )
02143 {
02144    PUSER_SENT_MESSAGE Message;
02145    PTHREADINFO pti;
02146 
02147    pti = PsGetCurrentThreadWin32Thread();
02148    Message = pti->pusmCurrent;
02149 
02150    if (!Message) return FALSE;
02151 
02152    if (Message->QS_Flags & QS_SMRESULT) return FALSE;
02153 
02154    //     SendMessageXxx    || Callback msg and not a notify msg
02155    if (Message->SenderQueue || Message->CompletionCallback)
02156    {
02157       Message->lResult = lResult;
02158       Message->QS_Flags |= QS_SMRESULT;
02159    // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
02160    }
02161    return TRUE;
02162 }
02163 
02164 HWND FASTCALL
02165 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
02166 {
02167    HWND Prev;
02168 
02169    switch(Type)
02170    {
02171       case MSQ_STATE_CAPTURE:
02172          Prev = MessageQueue->CaptureWindow;
02173          MessageQueue->CaptureWindow = hWnd;
02174          return Prev;
02175       case MSQ_STATE_ACTIVE:
02176          Prev = MessageQueue->spwndActive ? UserHMGetHandle(MessageQueue->spwndActive) : 0;
02177          MessageQueue->spwndActive = UserGetWindowObject(hWnd);
02178          return Prev;
02179       case MSQ_STATE_FOCUS:
02180          Prev = MessageQueue->spwndFocus ? UserHMGetHandle(MessageQueue->spwndFocus) : 0;
02181          MessageQueue->spwndFocus = UserGetWindowObject(hWnd);
02182          return Prev;
02183       case MSQ_STATE_MENUOWNER:
02184          Prev = MessageQueue->MenuOwner;
02185          MessageQueue->MenuOwner = hWnd;
02186          return Prev;
02187       case MSQ_STATE_MOVESIZE:
02188          Prev = MessageQueue->MoveSize;
02189          MessageQueue->MoveSize = hWnd;
02190          return Prev;
02191       case MSQ_STATE_CARET:
02192          ASSERT(MessageQueue->CaretInfo);
02193          Prev = MessageQueue->CaretInfo->hWnd;
02194          MessageQueue->CaretInfo->hWnd = hWnd;
02195          return Prev;
02196    }
02197 
02198    return NULL;
02199 }
02200 
02201 SHORT
02202 APIENTRY
02203 NtUserGetKeyState(INT key)
02204 {
02205    DWORD Ret;
02206 
02207    UserEnterShared();
02208 
02209    Ret = UserGetKeyState(key);
02210 
02211    UserLeave();
02212 
02213    return (SHORT)Ret;
02214 }
02215 
02216 
02217 DWORD
02218 APIENTRY
02219 NtUserGetKeyboardState(LPBYTE lpKeyState)
02220 {
02221    DWORD i, ret = TRUE;
02222    PTHREADINFO pti;
02223    PUSER_MESSAGE_QUEUE MessageQueue;
02224 
02225    UserEnterShared();
02226 
02227    pti = PsGetCurrentThreadWin32Thread();
02228    MessageQueue = pti->MessageQueue;
02229 
02230    _SEH2_TRY
02231    {
02232        /* Probe and copy key state to an array */
02233        ProbeForWrite(lpKeyState, 256 * sizeof(BYTE), 1);
02234        for (i = 0; i < 256; ++i)
02235        {
02236            lpKeyState[i] = 0;
02237            if (IS_KEY_DOWN(MessageQueue->afKeyState, i))
02238                lpKeyState[i] |= KS_DOWN_BIT;
02239            if (IS_KEY_LOCKED(MessageQueue->afKeyState, i))
02240                lpKeyState[i] |= KS_LOCK_BIT;
02241        }
02242    }
02243    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02244    {
02245        SetLastNtError(_SEH2_GetExceptionCode());
02246        ret = FALSE;
02247    }
02248    _SEH2_END;
02249 
02250    UserLeave();
02251 
02252    return ret;
02253 }
02254 
02255 BOOL
02256 APIENTRY
02257 NtUserSetKeyboardState(LPBYTE pKeyState)
02258 {
02259    UINT i;
02260    BOOL bRet = TRUE;
02261    PTHREADINFO pti;
02262    PUSER_MESSAGE_QUEUE MessageQueue;
02263 
02264    UserEnterExclusive();
02265 
02266    pti = PsGetCurrentThreadWin32Thread();
02267    MessageQueue = pti->MessageQueue;
02268 
02269    _SEH2_TRY
02270    {
02271        ProbeForRead(pKeyState, 256 * sizeof(BYTE), 1);
02272        for (i = 0; i < 256; ++i)
02273        {
02274             SET_KEY_DOWN(MessageQueue->afKeyState, i, pKeyState[i] & KS_DOWN_BIT);
02275             SET_KEY_LOCKED(MessageQueue->afKeyState, i, pKeyState[i] & KS_LOCK_BIT);
02276        }
02277    }
02278    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
02279    {
02280        SetLastNtError(_SEH2_GetExceptionCode());
02281        bRet = FALSE;
02282    }
02283    _SEH2_END;
02284 
02285    UserLeave();
02286 
02287    return bRet;
02288 }
02289 
02290 /* EOF */

Generated on Sun May 27 2012 04:38:34 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.