--- /dev/null
- XLATEOBJ* ColorTranslation,
- XLATEOBJ* SrcColorTranslation,
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: GDI BitBlt Functions
+ * FILE: subsys/win32k/eng/bitblt.c
+ * PROGRAMER: Jason Filby
+ * Timo Kreuzer
+ * REVISION HISTORY:
+ * 2/10/1999: Created
+ */
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+typedef BOOLEAN (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
+ SURFOBJ* InputObj,
+ SURFOBJ* Mask,
+ XLATEOBJ* ColorTranslation,
+ RECTL* OutputRect,
+ POINTL* InputPoint,
+ POINTL* MaskOrigin,
+ BRUSHOBJ* pbo,
+ POINTL* BrushOrigin,
+ ROP4 Rop4);
+
+static BOOLEAN APIENTRY
+BltMask(SURFOBJ* psoDest,
+ SURFOBJ* psoSource, // unused
+ SURFOBJ* psoMask,
+ XLATEOBJ* ColorTranslation, // unused
+ RECTL* prclDest,
+ POINTL* pptlSource, // unused
+ POINTL* pptlMask,
+ BRUSHOBJ* pbo,
+ POINTL* pptlBrush,
+ ROP4 Rop4)
+{
+ LONG x, y;
+ BYTE *pjMskLine, *pjMskCurrent;
+ BYTE fjMaskBit0, fjMaskBit;
+ /* Pattern brushes */
+ PEBRUSHOBJ pebo = NULL;
+ SURFOBJ *psoPattern = NULL;
+ PSURFACE psurfPattern;
+ ULONG PatternWidth = 0, PatternHeight = 0;
+ LONG PatternX0 = 0, PatternX = 0, PatternY = 0;
+ PFN_DIB_PutPixel fnDest_PutPixel = NULL;
+ PFN_DIB_GetPixel fnPattern_GetPixel = NULL;
+ ULONG Pattern = 0;
+ HBITMAP hbmPattern;
+
++ ASSERT(psoSource == NULL);
++ ASSERT(pptlSource == NULL);
++
+ if (psoMask == NULL)
+ {
+ return FALSE;
+ }
+
+ if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
+ {
+ pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+
+ hbmPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
+ psurfPattern = SURFACE_LockSurface(hbmPattern);
+ if (psurfPattern != NULL)
+ {
+ psoPattern = &psurfPattern->SurfObj;
+ PatternWidth = psoPattern->sizlBitmap.cx;
+ PatternHeight = psoPattern->sizlBitmap.cy;
+ fnPattern_GetPixel = DibFunctionsForBitmapFormat[psoPattern->iBitmapFormat].DIB_GetPixel;
+ }
+ }
+ else
+ psurfPattern = NULL;
+
+ pjMskLine = (PBYTE)psoMask->pvScan0 + pptlMask->y * psoMask->lDelta + (pptlMask->x >> 3);
+ fjMaskBit0 = 0x80 >> (pptlMask->x & 0x07);
+
+ fnDest_PutPixel = DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel;
+ if (psurfPattern)
+ {
+ PatternY = (prclDest->top - pptlBrush->y) % PatternHeight;
+ if (PatternY < 0)
+ {
+ PatternY += PatternHeight;
+ }
+ PatternX0 = (prclDest->left - pptlBrush->x) % PatternWidth;
+ if (PatternX0 < 0)
+ {
+ PatternX0 += PatternWidth;
+ }
+
+ for (y = prclDest->top; y < prclDest->bottom; y++)
+ {
+ pjMskCurrent = pjMskLine;
+ fjMaskBit = fjMaskBit0;
+ PatternX = PatternX0;
+
+ for (x = prclDest->left; x < prclDest->right; x++)
+ {
+ if (*pjMskCurrent & fjMaskBit)
+ {
+ fnDest_PutPixel(psoDest, x, y,
+ fnPattern_GetPixel(psoPattern, PatternX, PatternY));
+ }
+ fjMaskBit = _rotr8(fjMaskBit, 1);
+ pjMskCurrent += (fjMaskBit >> 7);
+ PatternX++;
+ PatternX %= PatternWidth;
+ }
+ pjMskLine += psoMask->lDelta;
+ PatternY++;
+ PatternY %= PatternHeight;
+ }
+ }
+ else
+ {
+ Pattern = pbo ? pbo->iSolidColor : 0;
+ for (y = prclDest->top; y < prclDest->bottom; y++)
+ {
+ pjMskCurrent = pjMskLine;
+ fjMaskBit = fjMaskBit0;
+
+ for (x = prclDest->left; x < prclDest->right; x++)
+ {
+ if (*pjMskCurrent & fjMaskBit)
+ {
+ fnDest_PutPixel(psoDest, x, y, Pattern);
+ }
+ fjMaskBit = _rotr8(fjMaskBit, 1);
+ pjMskCurrent += (fjMaskBit >> 7);
+ }
+ pjMskLine += psoMask->lDelta;
+ }
+ }
+
+ if (psurfPattern)
+ SURFACE_UnlockSurface(psurfPattern);
+
+ return TRUE;
+}
+
+static BOOLEAN APIENTRY
+BltPatCopy(SURFOBJ* Dest,
+ SURFOBJ* Source,
+ SURFOBJ* Mask,
+ XLATEOBJ* ColorTranslation,
+ RECTL* DestRect,
+ POINTL* SourcePoint,
+ POINTL* MaskPoint,
+ BRUSHOBJ* pbo,
+ POINTL* BrushPoint,
+ ROP4 Rop4)
+{
+ // These functions are assigned if we're working with a DIB
+ // The assigned functions depend on the bitsPerPixel of the DIB
+
+ DibFunctionsForBitmapFormat[Dest->iBitmapFormat].DIB_ColorFill(Dest, DestRect, pbo ? pbo->iSolidColor : 0);
+
+ return TRUE;
+}
+
+static BOOLEAN APIENTRY
+CallDibBitBlt(SURFOBJ* OutputObj,
+ SURFOBJ* InputObj,
+ SURFOBJ* Mask,
+ XLATEOBJ* ColorTranslation,
+ RECTL* OutputRect,
+ POINTL* InputPoint,
+ POINTL* MaskOrigin,
+ BRUSHOBJ* pbo,
+ POINTL* BrushOrigin,
+ ROP4 Rop4)
+{
+ BLTINFO BltInfo;
+ PEBRUSHOBJ GdiBrush = NULL;
+ SURFACE *psurfPattern;
+ BOOLEAN Result;
+ HBITMAP hbmPattern;
+
+ BltInfo.DestSurface = OutputObj;
+ BltInfo.SourceSurface = InputObj;
+ BltInfo.PatternSurface = NULL;
+ BltInfo.XlateSourceToDest = ColorTranslation;
+ BltInfo.DestRect = *OutputRect;
+ BltInfo.SourcePoint = *InputPoint;
+
+ if (ROP3_TO_ROP4(SRCCOPY) == Rop4)
+ return DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBltSrcCopy(&BltInfo);
+
+ BltInfo.Brush = pbo;
+ BltInfo.BrushOrigin = *BrushOrigin;
+ BltInfo.Rop4 = Rop4;
+
+ /* Pattern brush */
+ if (ROP4_USES_PATTERN(Rop4) && pbo && pbo->iSolidColor == 0xFFFFFFFF)
+ {
+ GdiBrush = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
+ hbmPattern = EBRUSHOBJ_pvGetEngBrush(GdiBrush);
+ psurfPattern = SURFACE_LockSurface(hbmPattern);
+ if (psurfPattern)
+ {
+ BltInfo.PatternSurface = &psurfPattern->SurfObj;
+ }
+ else
+ {
+ /* FIXME - What to do here? */
+ }
+ }
+ else
+ {
+ psurfPattern = NULL;
+ }
+
+ Result = DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_BitBlt(&BltInfo);
+
+ /* Pattern brush */
+ if (psurfPattern)
+ {
+ SURFACE_UnlockSurface(psurfPattern);
+ }
+
+ return Result;
+}
+
+INT __cdecl abs(INT nm);
+
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtGdiEngBitBlt(
+ IN SURFOBJ *psoTrg,
+ IN SURFOBJ *psoSrc,
+ IN SURFOBJ *psoMask,
+ IN CLIPOBJ *pco,
+ IN XLATEOBJ *pxlo,
+ IN RECTL *prclTrg,
+ IN POINTL *pptlSrc,
+ IN POINTL *pptlMask,
+ IN BRUSHOBJ *pbo,
+ IN POINTL *pptlBrush,
+ IN ROP4 rop4 )
+{
+ RECTL rclTrg;
+ POINTL ptlSrc;
+ POINTL ptlMask;
+ POINTL ptlBrush;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(prclTrg, sizeof(RECTL), 1);
+ RtlCopyMemory(&rclTrg,prclTrg, sizeof(RECTL));
+
+ ProbeForRead(pptlSrc, sizeof(POINTL), 1);
+ RtlCopyMemory(&ptlSrc, pptlSrc, sizeof(POINTL));
+
+ ProbeForRead(pptlMask, sizeof(POINTL), 1);
+ RtlCopyMemory(&ptlMask, pptlMask, sizeof(POINTL));
+
+ ProbeForRead(pptlBrush, sizeof(POINTL), 1);
+ RtlCopyMemory(&ptlBrush, pptlBrush, sizeof(POINTL));
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return FALSE);
+ }
+ _SEH2_END;
+
+ return EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg, &ptlSrc, &ptlMask, pbo, &ptlBrush, rop4);
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+EngBitBlt(SURFOBJ *DestObj,
+ SURFOBJ *SourceObj,
+ SURFOBJ *Mask,
+ CLIPOBJ *ClipRegion,
+ XLATEOBJ *ColorTranslation,
+ RECTL *DestRect,
+ POINTL *SourcePoint,
+ POINTL *MaskOrigin,
+ BRUSHOBJ *pbo,
+ POINTL *BrushOrigin,
+ ROP4 rop4)
+{
+ BYTE clippingType;
+ RECTL CombinedRect;
+ RECT_ENUM RectEnum;
+ BOOL EnumMore;
+ POINTL InputPoint;
+ RECTL InputRect;
+ RECTL OutputRect;
+ SURFOBJ* InputObj = 0;
+ SURFOBJ* OutputObj;
+ PBLTRECTFUNC BltRectFunc;
+ BOOLEAN Ret = TRUE;
+ RECTL ClipRect;
+ unsigned i;
+ POINTL Pt;
+ ULONG Direction;
+ BOOL UsesSource;
+ BOOL UsesPattern;
+ POINTL AdjustedBrushOrigin;
+
+ UsesSource = ROP4_USES_SOURCE(rop4);
+ UsesPattern = ROP4_USES_PATTERN(rop4);
+ if (R4_NOOP == rop4)
+ {
+ /* Copy destination onto itself: nop */
+ return TRUE;
+ }
+
+ OutputRect = *DestRect;
+ if (OutputRect.right < OutputRect.left)
+ {
+ OutputRect.left = DestRect->right;
+ OutputRect.right = DestRect->left;
+ }
+ if (OutputRect.bottom < OutputRect.top)
+ {
+ OutputRect.left = DestRect->right;
+ OutputRect.right = DestRect->left;
+ }
+
+ if (UsesSource)
+ {
+ if (NULL == SourcePoint)
+ {
+ return FALSE;
+ }
+
+ /* Make sure we don't try to copy anything outside the valid source
+ region */
+ InputPoint = *SourcePoint;
+ if (InputPoint.x < 0)
+ {
+ OutputRect.left -= InputPoint.x;
+ InputPoint.x = 0;
+ }
+ if (InputPoint.y < 0)
+ {
+ OutputRect.top -= InputPoint.y;
+ InputPoint.y = 0;
+ }
+ if (SourceObj->sizlBitmap.cx < InputPoint.x +
+ OutputRect.right - OutputRect.left)
+ {
+ OutputRect.right = OutputRect.left +
+ SourceObj->sizlBitmap.cx - InputPoint.x;
+ }
+ if (SourceObj->sizlBitmap.cy < InputPoint.y +
+ OutputRect.bottom - OutputRect.top)
+ {
+ OutputRect.bottom = OutputRect.top +
+ SourceObj->sizlBitmap.cy - InputPoint.y;
+ }
+
+ InputRect.left = InputPoint.x;
+ InputRect.right = InputPoint.x + (OutputRect.right - OutputRect.left);
+ InputRect.top = InputPoint.y;
+ InputRect.bottom = InputPoint.y + (OutputRect.bottom - OutputRect.top);
+
+ InputObj = SourceObj;
+ }
+ else
+ {
+ InputRect.left = 0;
+ InputRect.right = DestRect->right - DestRect->left;
+ InputRect.top = 0;
+ InputRect.bottom = DestRect->bottom - DestRect->top;
+ }
+
+ if (NULL != ClipRegion)
+ {
+ if (OutputRect.left < ClipRegion->rclBounds.left)
+ {
+ InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
+ InputPoint.x += ClipRegion->rclBounds.left - OutputRect.left;
+ OutputRect.left = ClipRegion->rclBounds.left;
+ }
+ if (ClipRegion->rclBounds.right < OutputRect.right)
+ {
+ InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
+ OutputRect.right = ClipRegion->rclBounds.right;
+ }
+ if (OutputRect.top < ClipRegion->rclBounds.top)
+ {
+ InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
+ InputPoint.y += ClipRegion->rclBounds.top - OutputRect.top;
+ OutputRect.top = ClipRegion->rclBounds.top;
+ }
+ if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
+ {
+ InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
+ OutputRect.bottom = ClipRegion->rclBounds.bottom;
+ }
+ }
+
+ /* Check for degenerate case: if height or width of OutputRect is 0 pixels
+ there's nothing to do */
+ if (OutputRect.right <= OutputRect.left ||
+ OutputRect.bottom <= OutputRect.top)
+ {
+ return TRUE;
+ }
+
+ OutputObj = DestObj;
+
+ if (BrushOrigin)
+ {
+ AdjustedBrushOrigin.x = BrushOrigin->x;
+ AdjustedBrushOrigin.y = BrushOrigin->y;
+ }
+ else
+ {
+ AdjustedBrushOrigin.x = 0;
+ AdjustedBrushOrigin.y = 0;
+ }
+
+ /* Determine clipping type */
+ if (ClipRegion == (CLIPOBJ *) NULL)
+ {
+ clippingType = DC_TRIVIAL;
+ }
+ else
+ {
+ clippingType = ClipRegion->iDComplexity;
+ }
+
+ if (R4_MASK == rop4)
+ {
+ BltRectFunc = BltMask;
+ }
+ else if (ROP3_TO_ROP4(PATCOPY) == rop4)
+ {
+ if (pbo && pbo->iSolidColor == 0xFFFFFFFF)
+ BltRectFunc = CallDibBitBlt;
+ else
+ BltRectFunc = BltPatCopy;
+ }
+ else
+ {
+ BltRectFunc = CallDibBitBlt;
+ }
+
+
+ switch (clippingType)
+ {
+ case DC_TRIVIAL:
+ Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+ &OutputRect, &InputPoint, MaskOrigin, pbo,
+ &AdjustedBrushOrigin, rop4);
+ break;
+ case DC_RECT:
+ /* Clip the blt to the clip rectangle */
+ ClipRect.left = ClipRegion->rclBounds.left;
+ ClipRect.right = ClipRegion->rclBounds.right;
+ ClipRect.top = ClipRegion->rclBounds.top;
+ ClipRect.bottom = ClipRegion->rclBounds.bottom;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ Ret = (*BltRectFunc)(OutputObj, InputObj, Mask, ColorTranslation,
+ &CombinedRect, &Pt, MaskOrigin, pbo,
+ &AdjustedBrushOrigin, rop4);
+ }
+ break;
+ case DC_COMPLEX:
+ Ret = TRUE;
+ if (OutputObj == InputObj)
+ {
+ if (OutputRect.top < InputPoint.y)
+ {
+ Direction = OutputRect.left < InputPoint.x ?
+ CD_RIGHTDOWN : CD_LEFTDOWN;
+ }
+ else
+ {
+ Direction = OutputRect.left < InputPoint.x ?
+ CD_RIGHTUP : CD_LEFTUP;
+ }
+ }
+ else
+ {
+ Direction = CD_ANY;
+ }
+ CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
+ do
+ {
+ EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum),
+ (PVOID) &RectEnum);
+
+ for (i = 0; i < RectEnum.c; i++)
+ {
+ ClipRect.left = RectEnum.arcl[i].left;
+ ClipRect.right = RectEnum.arcl[i].right;
+ ClipRect.top = RectEnum.arcl[i].top;
+ ClipRect.bottom = RectEnum.arcl[i].bottom;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ Ret = (*BltRectFunc)(OutputObj, InputObj, Mask,
+ ColorTranslation, &CombinedRect, &Pt,
+ MaskOrigin, pbo, &AdjustedBrushOrigin,
+ rop4) && Ret;
+ }
+ }
+ }
+ while (EnumMore);
+ break;
+ }
+
+ return Ret;
+}
+
+BOOL APIENTRY
+IntEngBitBlt(
+ SURFOBJ *psoTrg,
+ SURFOBJ *psoSrc,
+ SURFOBJ *psoMask,
+ CLIPOBJ *pco,
+ XLATEOBJ *pxlo,
+ RECTL *prclTrg,
+ POINTL *pptlSrc,
+ POINTL *pptlMask,
+ BRUSHOBJ *pbo,
+ POINTL *pptlBrush,
+ ROP4 rop4)
+{
+ SURFACE *psurfTrg;
+ SURFACE *psurfSrc = NULL;
+ BOOL bResult;
+ RECTL rclClipped;
+ RECTL rclSrc;
+// INTENG_ENTER_LEAVE EnterLeaveSource;
+// INTENG_ENTER_LEAVE EnterLeaveDest;
+ PFN_DrvBitBlt pfnBitBlt;
+
+ ASSERT(psoTrg);
+ psurfTrg = CONTAINING_RECORD(psoTrg, SURFACE, SurfObj);
+
+ /* FIXME: Should we really allow to pass non-well-ordered rects? */
+ rclClipped = *prclTrg;
+ RECTL_vMakeWellOrdered(&rclClipped);
+
+ /* Clip target rect against the bounds of the clipping region */
+ if (pco)
+ {
+ if (!RECTL_bIntersectRect(&rclClipped, &rclClipped, &pco->rclBounds))
+ {
+ /* Nothing left */
+ return TRUE;
+ }
+
+ /* Don't pass a clipobj with only a single rect */
+ if (pco->iDComplexity == DC_RECT)
+ pco = NULL;
+ }
+
+ if (ROP4_USES_SOURCE(rop4))
+ {
+ ASSERT(psoSrc);
+ psurfSrc = CONTAINING_RECORD(psoSrc, SURFACE, SurfObj);
+
+ /* Calculate source rect */
+ rclSrc.left = pptlSrc->x + rclClipped.left - prclTrg->left;
+ rclSrc.top = pptlSrc->y + rclClipped.top - prclTrg->top;
+ rclSrc.right = rclSrc.left + rclClipped.right - rclClipped.left;
+ rclSrc.bottom = rclSrc.top + rclClipped.bottom - rclClipped.top;
+ }
+ else
+ {
+ psoSrc = NULL;
+ psurfSrc = NULL;
+ }
+
+ /* Is the target surface device managed? */
+ if (psurfTrg->flHooks & HOOK_BITBLT)
+ {
+ /* Is the source a different device managed surface? */
+ if (psoSrc && psoSrc->hdev != psoTrg->hdev && psurfSrc->flHooks & HOOK_BITBLT)
+ {
+ DPRINT1("Need to copy to standard bitmap format!\n");
+ ASSERT(FALSE);
+ }
+
+ pfnBitBlt = GDIDEVFUNCS(psoTrg).BitBlt;
+ }
+
+ /* Is the source surface device managed? */
+ else if (psoSrc && psurfSrc->flHooks & HOOK_BITBLT)
+ {
+ pfnBitBlt = GDIDEVFUNCS(psoSrc).BitBlt;
+ }
+ else
+ {
+ pfnBitBlt = EngBitBlt;
+ }
+
+ bResult = pfnBitBlt(psoTrg,
+ psoSrc,
+ psoMask,
+ pco,
+ pxlo,
+ &rclClipped,
+ (POINTL*)&rclSrc,
+ pptlMask,
+ pbo,
+ pptlBrush,
+ rop4);
+
+ // FIXME: cleanup temp surface!
+
+ return bResult;
+}
+
+
+/**** REACTOS FONT RENDERING CODE *********************************************/
+
+/* renders the alpha mask bitmap */
+static BOOLEAN APIENTRY
+AlphaBltMask(SURFOBJ* psoDest,
+ SURFOBJ* psoSource, // unused
+ SURFOBJ* psoMask,
- BrushColor = XLATEOBJ_iXlate(SrcColorTranslation, pbo ? pbo->iSolidColor : 0);
++ XLATEOBJ* pxloRGB2Dest,
++ XLATEOBJ* pxloBrush,
+ RECTL* prclDest,
+ POINTL* pptlSource, // unused
+ POINTL* pptlMask,
+ BRUSHOBJ* pbo,
+ POINTL* pptlBrush)
+{
+ LONG i, j, dx, dy;
+ int r, g, b;
+ ULONG Background, BrushColor, NewColor;
+ BYTE *tMask, *lMask;
+
++ ASSERT(psoSource == NULL);
++ ASSERT(pptlSource == NULL);
++
+ dx = prclDest->right - prclDest->left;
+ dy = prclDest->bottom - prclDest->top;
+
+ if (psoMask != NULL)
+ {
- SrcColorTranslation);
++ BrushColor = XLATEOBJ_iXlate(pxloBrush, pbo ? pbo->iSolidColor : 0);
+ r = (int)GetRValue(BrushColor);
+ g = (int)GetGValue(BrushColor);
+ b = (int)GetBValue(BrushColor);
+
+ tMask = (PBYTE)psoMask->pvScan0 + (pptlMask->y * psoMask->lDelta) + pptlMask->x;
+ for (j = 0; j < dy; j++)
+ {
+ lMask = tMask;
+ for (i = 0; i < dx; i++)
+ {
+ if (*lMask > 0)
+ {
+ if (*lMask == 0xff)
+ {
+ DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
+ psoDest, prclDest->left + i, prclDest->top + j, pbo ? pbo->iSolidColor : 0);
+ }
+ else
+ {
+ Background = DIB_GetSource(psoDest, prclDest->left + i, prclDest->top + j,
- Background = XLATEOBJ_iXlate(ColorTranslation, NewColor);
++ pxloBrush);
+
+ NewColor =
+ RGB((*lMask * (r - GetRValue(Background)) >> 8) + GetRValue(Background),
+ (*lMask * (g - GetGValue(Background)) >> 8) + GetGValue(Background),
+ (*lMask * (b - GetBValue(Background)) >> 8) + GetBValue(Background));
+
- &OutputRect, &InputPoint, pptlMask, pbo, &AdjustedBrushOrigin);
++ Background = XLATEOBJ_iXlate(pxloRGB2Dest, NewColor);
+ DibFunctionsForBitmapFormat[psoDest->iBitmapFormat].DIB_PutPixel(
+ psoDest, prclDest->left + i, prclDest->top + j, Background);
+ }
+ }
+ lMask++;
+ }
+ tMask += psoMask->lDelta;
+ }
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static
+BOOL APIENTRY
+EngMaskBitBlt(SURFOBJ *psoDest,
+ SURFOBJ *psoMask,
+ CLIPOBJ *ClipRegion,
+ XLATEOBJ *DestColorTranslation,
+ XLATEOBJ *SourceColorTranslation,
+ RECTL *DestRect,
+ POINTL *pptlMask,
+ BRUSHOBJ *pbo,
+ POINTL *BrushOrigin)
+{
+ BYTE clippingType;
+ RECTL CombinedRect;
+ RECT_ENUM RectEnum;
+ BOOL EnumMore;
+ POINTL InputPoint;
+ RECTL InputRect;
+ RECTL OutputRect;
+ POINTL Translate;
+ INTENG_ENTER_LEAVE EnterLeaveSource;
+ INTENG_ENTER_LEAVE EnterLeaveDest;
+ SURFOBJ* psoInput;
+ SURFOBJ* psoOutput;
+ BOOLEAN Ret = TRUE;
+ RECTL ClipRect;
+ unsigned i;
+ POINTL Pt;
+ ULONG Direction;
+ POINTL AdjustedBrushOrigin;
+
+ ASSERT(psoMask);
+
+ if (pptlMask)
+ {
+ InputRect.left = pptlMask->x;
+ InputRect.right = pptlMask->x + (DestRect->right - DestRect->left);
+ InputRect.top = pptlMask->y;
+ InputRect.bottom = pptlMask->y + (DestRect->bottom - DestRect->top);
+ }
+ else
+ {
+ InputRect.left = 0;
+ InputRect.right = DestRect->right - DestRect->left;
+ InputRect.top = 0;
+ InputRect.bottom = DestRect->bottom - DestRect->top;
+ }
+
+ OutputRect = *DestRect;
+ if (NULL != ClipRegion)
+ {
+ if (OutputRect.left < ClipRegion->rclBounds.left)
+ {
+ InputRect.left += ClipRegion->rclBounds.left - OutputRect.left;
+ OutputRect.left = ClipRegion->rclBounds.left;
+ }
+ if (ClipRegion->rclBounds.right < OutputRect.right)
+ {
+ InputRect.right -= OutputRect.right - ClipRegion->rclBounds.right;
+ OutputRect.right = ClipRegion->rclBounds.right;
+ }
+ if (OutputRect.top < ClipRegion->rclBounds.top)
+ {
+ InputRect.top += ClipRegion->rclBounds.top - OutputRect.top;
+ OutputRect.top = ClipRegion->rclBounds.top;
+ }
+ if (ClipRegion->rclBounds.bottom < OutputRect.bottom)
+ {
+ InputRect.bottom -= OutputRect.bottom - ClipRegion->rclBounds.bottom;
+ OutputRect.bottom = ClipRegion->rclBounds.bottom;
+ }
+ }
+
+ if (! IntEngEnter(&EnterLeaveSource, psoMask, &InputRect, TRUE, &Translate, &psoInput))
+ {
+ return FALSE;
+ }
+
+ InputPoint.x = InputRect.left + Translate.x;
+ InputPoint.y = InputRect.top + Translate.y;
+
+ /* Check for degenerate case: if height or width of OutputRect is 0 pixels there's
+ nothing to do */
+ if (OutputRect.right <= OutputRect.left || OutputRect.bottom <= OutputRect.top)
+ {
+ IntEngLeave(&EnterLeaveSource);
+ return TRUE;
+ }
+
+ if (! IntEngEnter(&EnterLeaveDest, psoDest, &OutputRect, FALSE, &Translate, &psoOutput))
+ {
+ IntEngLeave(&EnterLeaveSource);
+ return FALSE;
+ }
+
+ OutputRect.left = DestRect->left + Translate.x;
+ OutputRect.right = DestRect->right + Translate.x;
+ OutputRect.top = DestRect->top + Translate.y;
+ OutputRect.bottom = DestRect->bottom + Translate.y;
+
+ if (BrushOrigin)
+ {
+ AdjustedBrushOrigin.x = BrushOrigin->x + Translate.x;
+ AdjustedBrushOrigin.y = BrushOrigin->y + Translate.y;
+ }
+ else
+ AdjustedBrushOrigin = Translate;
+
+ // Determine clipping type
+ if (ClipRegion == (CLIPOBJ *) NULL)
+ {
+ clippingType = DC_TRIVIAL;
+ } else {
+ clippingType = ClipRegion->iDComplexity;
+ }
+
+ switch (clippingType)
+ {
+ case DC_TRIVIAL:
+ if (psoMask->iBitmapFormat == BMF_8BPP)
+ Ret = AlphaBltMask(psoOutput, NULL , psoInput, DestColorTranslation, SourceColorTranslation,
- &OutputRect, &InputPoint, pptlMask, pbo, &AdjustedBrushOrigin,
++ &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin);
+ else
+ Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
- Ret = AlphaBltMask(psoOutput, psoInput, psoMask, DestColorTranslation, SourceColorTranslation,
- &CombinedRect, &Pt, pptlMask, pbo, &AdjustedBrushOrigin);
++ &OutputRect, NULL, &InputPoint, pbo, &AdjustedBrushOrigin,
+ R4_MASK);
+ break;
+ case DC_RECT:
+ // Clip the blt to the clip rectangle
+ ClipRect.left = ClipRegion->rclBounds.left + Translate.x;
+ ClipRect.right = ClipRegion->rclBounds.right + Translate.x;
+ ClipRect.top = ClipRegion->rclBounds.top + Translate.y;
+ ClipRect.bottom = ClipRegion->rclBounds.bottom + Translate.y;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ if (psoMask->iBitmapFormat == BMF_8BPP)
+ {
- Ret = BltMask(psoOutput, psoInput, psoMask, DestColorTranslation,
- &CombinedRect, &Pt, pptlMask, pbo, &AdjustedBrushOrigin, R4_MASK);
++ Ret = AlphaBltMask(psoOutput, NULL, psoInput, DestColorTranslation, SourceColorTranslation,
++ &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin);
+ }
+ else
+ {
- Ret = AlphaBltMask(psoOutput, psoInput, psoMask,
++ Ret = BltMask(psoOutput, NULL, psoInput, DestColorTranslation,
++ &CombinedRect, NULL, &Pt, pbo, &AdjustedBrushOrigin, R4_MASK);
+ }
+ }
+ break;
+ case DC_COMPLEX:
+ Ret = TRUE;
+ if (psoOutput == psoInput)
+ {
+ if (OutputRect.top < InputPoint.y)
+ {
+ Direction = OutputRect.left < InputPoint.x ? CD_RIGHTDOWN : CD_LEFTDOWN;
+ }
+ else
+ {
+ Direction = OutputRect.left < InputPoint.x ? CD_RIGHTUP : CD_LEFTUP;
+ }
+ }
+ else
+ {
+ Direction = CD_ANY;
+ }
+ CLIPOBJ_cEnumStart(ClipRegion, FALSE, CT_RECTANGLES, Direction, 0);
+ do
+ {
+ EnumMore = CLIPOBJ_bEnum(ClipRegion,(ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
+
+ for (i = 0; i < RectEnum.c; i++)
+ {
+ ClipRect.left = RectEnum.arcl[i].left + Translate.x;
+ ClipRect.right = RectEnum.arcl[i].right + Translate.x;
+ ClipRect.top = RectEnum.arcl[i].top + Translate.y;
+ ClipRect.bottom = RectEnum.arcl[i].bottom + Translate.y;
+ if (RECTL_bIntersectRect(&CombinedRect, &OutputRect, &ClipRect))
+ {
+ Pt.x = InputPoint.x + CombinedRect.left - OutputRect.left;
+ Pt.y = InputPoint.y + CombinedRect.top - OutputRect.top;
+ if (psoMask->iBitmapFormat == BMF_8BPP)
+ {
- &CombinedRect, &Pt, pptlMask, pbo,
++ Ret = AlphaBltMask(psoOutput, NULL, psoInput,
+ DestColorTranslation,
+ SourceColorTranslation,
- Ret = BltMask(psoOutput, psoInput, psoMask,
- DestColorTranslation, &CombinedRect, &Pt,
- pptlMask, pbo, &AdjustedBrushOrigin,
++ &CombinedRect, NULL, &Pt, pbo,
+ &AdjustedBrushOrigin) && Ret;
+ }
+ else
+ {
++ Ret = BltMask(psoOutput, NULL, psoInput,
++ DestColorTranslation, &CombinedRect, NULL,
++ &Pt, pbo, &AdjustedBrushOrigin,
+ R4_MASK) && Ret;
+ }
+ }
+ }
+ }
+ while (EnumMore);
+ break;
+ }
+
+
+ IntEngLeave(&EnterLeaveDest);
+ IntEngLeave(&EnterLeaveSource);
+
+ return Ret;
+}
+
+BOOL APIENTRY
+IntEngMaskBlt(SURFOBJ *psoDest,
+ SURFOBJ *psoMask,
+ CLIPOBJ *ClipRegion,
+ XLATEOBJ *DestColorTranslation,
+ XLATEOBJ *SourceColorTranslation,
+ RECTL *DestRect,
+ POINTL *pptlMask,
+ BRUSHOBJ *pbo,
+ POINTL *BrushOrigin)
+{
+ BOOLEAN ret;
+ RECTL OutputRect;
+ POINTL InputPoint;
+ SURFACE *psurfDest;
+
+ ASSERT(psoMask);
+
+ if (pptlMask)
+ {
+ InputPoint = *pptlMask;
+ }
+
+ /* Clip against the bounds of the clipping region so we won't try to write
+ * outside the surface */
+ if (NULL != ClipRegion)
+ {
+ if (!RECTL_bIntersectRect(&OutputRect, DestRect, &ClipRegion->rclBounds))
+ {
+ return TRUE;
+ }
+ InputPoint.x += OutputRect.left - DestRect->left;
+ InputPoint.y += OutputRect.top - DestRect->top;
+ }
+ else
+ {
+ OutputRect = *DestRect;
+ }
+
+ /* No success yet */
+ ret = FALSE;
+ ASSERT(psoDest);
+ psurfDest = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
+
+ /* Dummy BitBlt to let driver know that it should flush its changes.
+ This should really be done using a call to DrvSynchronizeSurface,
+ but the VMware driver doesn't hook that call. */
+ IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
+ DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
+ R4_NOOP);
+
+ ret = EngMaskBitBlt(psoDest, psoMask, ClipRegion, DestColorTranslation, SourceColorTranslation,
+ &OutputRect, &InputPoint, pbo, BrushOrigin);
+
+ /* Dummy BitBlt to let driver know that something has changed. */
+ IntEngBitBlt(psoDest, NULL, psoMask, ClipRegion, DestColorTranslation,
+ DestRect, pptlMask, pptlMask, pbo, BrushOrigin,
+ R4_NOOP);
+
+ return ret;
+}
+
+/* EOF */
--- /dev/null
- PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Messages
+ * FILE: subsys/win32k/ntuser/message.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISION HISTORY:
+ * 06-06-2001 CSH Created
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <win32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#define PM_BADMSGFLAGS ~((QS_RAWINPUT << 16)|PM_QS_SENDMESSAGE|PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_QS_INPUT|PM_NOYIELD|PM_REMOVE)
+
+typedef struct
+{
+ UINT uFlags;
+ UINT uTimeout;
+ ULONG_PTR Result;
+}
+DOSENDMESSAGE, *PDOSENDMESSAGE;
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS FASTCALL
+IntInitMessageImpl(VOID)
+{
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS FASTCALL
+IntCleanupMessageImpl(VOID)
+{
+ return STATUS_SUCCESS;
+}
+
+#define MMS_SIZE_WPARAM -1
+#define MMS_SIZE_WPARAMWCHAR -2
+#define MMS_SIZE_LPARAMSZ -3
+#define MMS_SIZE_SPECIAL -4
+#define MMS_FLAG_READ 0x01
+#define MMS_FLAG_WRITE 0x02
+#define MMS_FLAG_READWRITE (MMS_FLAG_READ | MMS_FLAG_WRITE)
+typedef struct tagMSGMEMORY
+{
+ UINT Message;
+ UINT Size;
+ INT Flags;
+}
+MSGMEMORY, *PMSGMEMORY;
+
+static MSGMEMORY MsgMemory[] =
+ {
+ { WM_CREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
+ { WM_DDE_ACK, sizeof(KMDDELPARAM), MMS_FLAG_READ },
+ { WM_DDE_EXECUTE, MMS_SIZE_WPARAM, MMS_FLAG_READ },
+ { WM_GETMINMAXINFO, sizeof(MINMAXINFO), MMS_FLAG_READWRITE },
+ { WM_GETTEXT, MMS_SIZE_WPARAMWCHAR, MMS_FLAG_WRITE },
+ { WM_NCCALCSIZE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
+ { WM_NCCREATE, MMS_SIZE_SPECIAL, MMS_FLAG_READWRITE },
+ { WM_SETTEXT, MMS_SIZE_LPARAMSZ, MMS_FLAG_READ },
+ { WM_STYLECHANGED, sizeof(STYLESTRUCT), MMS_FLAG_READ },
+ { WM_STYLECHANGING, sizeof(STYLESTRUCT), MMS_FLAG_READWRITE },
+ { WM_COPYDATA, MMS_SIZE_SPECIAL, MMS_FLAG_READ },
+ { WM_WINDOWPOSCHANGED, sizeof(WINDOWPOS), MMS_FLAG_READ },
+ { WM_WINDOWPOSCHANGING, sizeof(WINDOWPOS), MMS_FLAG_READWRITE },
+ };
+
+static PMSGMEMORY FASTCALL
+FindMsgMemory(UINT Msg)
+{
+ PMSGMEMORY MsgMemoryEntry;
+
+ /* See if this message type is present in the table */
+ for (MsgMemoryEntry = MsgMemory;
+ MsgMemoryEntry < MsgMemory + sizeof(MsgMemory) / sizeof(MSGMEMORY);
+ MsgMemoryEntry++)
+ {
+ if (Msg == MsgMemoryEntry->Message)
+ {
+ return MsgMemoryEntry;
+ }
+ }
+
+ return NULL;
+}
+
+static UINT FASTCALL
+MsgMemorySize(PMSGMEMORY MsgMemoryEntry, WPARAM wParam, LPARAM lParam)
+{
+ CREATESTRUCTW *Cs;
+ PUNICODE_STRING WindowName;
+ PUNICODE_STRING ClassName;
+ UINT Size = 0;
+
+ _SEH2_TRY
+ {
+ if (MMS_SIZE_WPARAM == MsgMemoryEntry->Size)
+ {
+ Size = (UINT)wParam;
+ }
+ else if (MMS_SIZE_WPARAMWCHAR == MsgMemoryEntry->Size)
+ {
+ Size = (UINT) (wParam * sizeof(WCHAR));
+ }
+ else if (MMS_SIZE_LPARAMSZ == MsgMemoryEntry->Size)
+ {
+ Size = (UINT) ((wcslen((PWSTR) lParam) + 1) * sizeof(WCHAR));
+ }
+ else if (MMS_SIZE_SPECIAL == MsgMemoryEntry->Size)
+ {
+ switch(MsgMemoryEntry->Message)
+ {
+ case WM_CREATE:
+ case WM_NCCREATE:
+ Cs = (CREATESTRUCTW *) lParam;
+ WindowName = (PUNICODE_STRING) Cs->lpszName;
+ ClassName = (PUNICODE_STRING) Cs->lpszClass;
+ Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
+ if (IS_ATOM(ClassName->Buffer))
+ {
+ Size += sizeof(WCHAR) + sizeof(ATOM);
+ }
+ else
+ {
+ Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
+ }
+ break;
+
+ case WM_NCCALCSIZE:
+ Size = wParam ? sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS) : sizeof(RECT);
+ break;
+
+ case WM_COPYDATA:
+ Size = sizeof(COPYDATASTRUCT) + ((PCOPYDATASTRUCT)lParam)->cbData;
+ break;
+
+ case WM_COPYGLOBALDATA:
+ Size = wParam;
+ break;
+
+ default:
+ assert(FALSE);
+ Size = 0;
+ break;
+ }
+ }
+ else
+ {
+ Size = MsgMemoryEntry->Size;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DPRINT1("Exception caught in MsgMemorySize()! Status: 0x%x\n", _SEH2_GetExceptionCode());
+ Size = 0;
+ }
+ _SEH2_END;
+ return Size;
+}
+
+static NTSTATUS
- if (UnpackedNcCalcsize->lppos != (PWINDOWPOS) (UnpackedNcCalcsize + 1))
++PackParam(LPARAM *lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolNeeded)
+{
+ NCCALCSIZE_PARAMS *UnpackedNcCalcsize;
+ NCCALCSIZE_PARAMS *PackedNcCalcsize;
+ CREATESTRUCTW *UnpackedCs;
+ CREATESTRUCTW *PackedCs;
+ PUNICODE_STRING WindowName;
+ PUNICODE_STRING ClassName;
++ POOL_TYPE PoolType;
+ UINT Size;
+ PCHAR CsData;
+
+ *lParamPacked = lParam;
++
++ if (NonPagedPoolNeeded)
++ PoolType = NonPagedPool;
++ else
++ PoolType = PagedPool;
++
+ if (WM_NCCALCSIZE == Msg && wParam)
+ {
++
+ UnpackedNcCalcsize = (NCCALCSIZE_PARAMS *) lParam;
- PackedNcCalcsize = ExAllocatePoolWithTag(PagedPool,
- sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
- TAG_MSG);
- if (NULL == PackedNcCalcsize)
- {
- DPRINT1("Not enough memory to pack lParam\n");
- return STATUS_NO_MEMORY;
- }
- RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
- PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
- RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
- *lParamPacked = (LPARAM) PackedNcCalcsize;
++ PackedNcCalcsize = ExAllocatePoolWithTag(PoolType,
++ sizeof(NCCALCSIZE_PARAMS) + sizeof(WINDOWPOS),
++ TAG_MSG);
++
++ if (NULL == PackedNcCalcsize)
+ {
- PackedCs = ExAllocatePoolWithTag(PagedPool, Size, TAG_MSG);
++ DPRINT1("Not enough memory to pack lParam\n");
++ return STATUS_NO_MEMORY;
+ }
++ RtlCopyMemory(PackedNcCalcsize, UnpackedNcCalcsize, sizeof(NCCALCSIZE_PARAMS));
++ PackedNcCalcsize->lppos = (PWINDOWPOS) (PackedNcCalcsize + 1);
++ RtlCopyMemory(PackedNcCalcsize->lppos, UnpackedNcCalcsize->lppos, sizeof(WINDOWPOS));
++ *lParamPacked = (LPARAM) PackedNcCalcsize;
+ }
+ else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
+ {
+ UnpackedCs = (CREATESTRUCTW *) lParam;
+ WindowName = (PUNICODE_STRING) UnpackedCs->lpszName;
+ ClassName = (PUNICODE_STRING) UnpackedCs->lpszClass;
+ Size = sizeof(CREATESTRUCTW) + WindowName->Length + sizeof(WCHAR);
+ if (IS_ATOM(ClassName->Buffer))
+ {
+ Size += sizeof(WCHAR) + sizeof(ATOM);
+ }
+ else
+ {
+ Size += sizeof(WCHAR) + ClassName->Length + sizeof(WCHAR);
+ }
- UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
++ PackedCs = ExAllocatePoolWithTag(PoolType, Size, TAG_MSG);
+ if (NULL == PackedCs)
+ {
+ DPRINT1("Not enough memory to pack lParam\n");
+ return STATUS_NO_MEMORY;
+ }
+ RtlCopyMemory(PackedCs, UnpackedCs, sizeof(CREATESTRUCTW));
+ CsData = (PCHAR) (PackedCs + 1);
+ PackedCs->lpszName = (LPCWSTR) (CsData - (PCHAR) PackedCs);
+ RtlCopyMemory(CsData, WindowName->Buffer, WindowName->Length);
+ CsData += WindowName->Length;
+ *((WCHAR *) CsData) = L'\0';
+ CsData += sizeof(WCHAR);
+ PackedCs->lpszClass = (LPCWSTR) (CsData - (PCHAR) PackedCs);
+ if (IS_ATOM(ClassName->Buffer))
+ {
+ *((WCHAR *) CsData) = L'A';
+ CsData += sizeof(WCHAR);
+ *((ATOM *) CsData) = (ATOM)(DWORD_PTR) ClassName->Buffer;
+ CsData += sizeof(ATOM);
+ }
+ else
+ {
+ *((WCHAR *) CsData) = L'S';
+ CsData += sizeof(WCHAR);
+ RtlCopyMemory(CsData, ClassName->Buffer, ClassName->Length);
+ CsData += ClassName->Length;
+ *((WCHAR *) CsData) = L'\0';
+ CsData += sizeof(WCHAR);
+ }
+ ASSERT(CsData == (PCHAR) PackedCs + Size);
+ *lParamPacked = (LPARAM) PackedCs;
+ }
+
++ else if (PoolType == NonPagedPool)
++ {
++ PMSGMEMORY MsgMemoryEntry;
++ PVOID PackedData;
++
++ MsgMemoryEntry = FindMsgMemory(Msg);
++
++ if ((!MsgMemoryEntry) || (MsgMemoryEntry->Size < 0))
++ {
++ /* Keep previous behavior */
++ return STATUS_SUCCESS;
++ }
++ PackedData = ExAllocatePoolWithTag(NonPagedPool, MsgMemorySize(MsgMemoryEntry, wParam, lParam), TAG_MSG);
++ RtlCopyMemory(PackedData, (PVOID)lParam, MsgMemorySize(MsgMemoryEntry, wParam, lParam));
++ *lParamPacked = (LPARAM)PackedData;
++ }
++
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
- if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam)))
++UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL NonPagedPoolUsed)
+{
+ NCCALCSIZE_PARAMS *UnpackedParams;
+ NCCALCSIZE_PARAMS *PackedParams;
+ PWINDOWPOS UnpackedWindowPos;
+
+ if (lParamPacked == lParam)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ if (WM_NCCALCSIZE == Msg && wParam)
+ {
+ PackedParams = (NCCALCSIZE_PARAMS *) lParamPacked;
+ UnpackedParams = (NCCALCSIZE_PARAMS *) lParam;
+ UnpackedWindowPos = UnpackedParams->lppos;
+ RtlCopyMemory(UnpackedParams, PackedParams, sizeof(NCCALCSIZE_PARAMS));
+ UnpackedParams->lppos = UnpackedWindowPos;
+ RtlCopyMemory(UnpackedWindowPos, PackedParams + 1, sizeof(WINDOWPOS));
+ ExFreePool((PVOID) lParamPacked);
+
+ return STATUS_SUCCESS;
+ }
+ else if (WM_CREATE == Msg || WM_NCCREATE == Msg)
+ {
+ ExFreePool((PVOID) lParamPacked);
+
+ return STATUS_SUCCESS;
+ }
++ else if (NonPagedPoolUsed)
++ {
++ PMSGMEMORY MsgMemoryEntry;
++ MsgMemoryEntry = FindMsgMemory(Msg);
++ if (MsgMemoryEntry->Size < 0)
++ {
++ /* Keep previous behavior */
++ return STATUS_INVALID_PARAMETER;
++ }
++
++ if (MsgMemory->Flags == MMS_FLAG_READWRITE)
++ {
++ //RtlCopyMemory((PVOID)lParam, (PVOID)lParamPacked, MsgMemory->Size);
++ }
++ ExFreePool((PVOID) lParamPacked);
++ return STATUS_SUCCESS;
++ }
+
+ ASSERT(FALSE);
+
+ return STATUS_INVALID_PARAMETER;
+}
+
+static
+VOID
+FASTCALL
+IntCallWndProc
+( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL SameThread = FALSE;
+
+ if (Window->pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
+ SameThread = TRUE;
+
+ if ((!SameThread && (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROC))) ||
+ (SameThread && ISITHOOKED(WH_CALLWNDPROC)) )
+ {
+ CWPSTRUCT CWP;
+ CWP.hwnd = hWnd;
+ CWP.message = Msg;
+ CWP.wParam = wParam;
+ CWP.lParam = lParam;
+ co_HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, SameThread, (LPARAM)&CWP );
+ }
+}
+
+static
+VOID
+FASTCALL
+IntCallWndProcRet
+( PWINDOW_OBJECT Window, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *uResult)
+{
+ BOOL SameThread = FALSE;
+
+ if (Window->pti == ((PTHREADINFO)PsGetCurrentThreadWin32Thread()))
+ SameThread = TRUE;
+
+ if ((!SameThread && (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_CALLWNDPROCRET))) ||
+ (SameThread && ISITHOOKED(WH_CALLWNDPROCRET)) )
+ {
+ CWPRETSTRUCT CWPR;
+ CWPR.hwnd = hWnd;
+ CWPR.message = Msg;
+ CWPR.wParam = wParam;
+ CWPR.lParam = lParam;
+ CWPR.lResult = *uResult;
+ co_HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, SameThread, (LPARAM)&CWPR );
+ }
+}
+
+LRESULT
+FASTCALL
+IntDispatchMessage(PMSG pMsg)
+{
+ LARGE_INTEGER TickCount;
+ LONG Time;
+ LRESULT retval;
+ PMSGMEMORY MsgMemoryEntry;
+ INT lParamBufferSize;
+ LPARAM lParamPacked;
+ PWINDOW_OBJECT Window = NULL;
+
+ if (pMsg->hwnd)
+ {
+ Window = UserGetWindowObject(pMsg->hwnd);
+ if (!Window || !Window->Wnd) return 0;
+ }
+
+ if (((pMsg->message == WM_SYSTIMER) ||
+ (pMsg->message == WM_TIMER)) &&
+ (pMsg->lParam) )
+ {
+ if (pMsg->message == WM_TIMER)
+ {
+ if (ValidateTimerCallback(PsGetCurrentThreadWin32Thread(),Window,pMsg->wParam,pMsg->lParam))
+ {
+ KeQueryTickCount(&TickCount);
+ Time = MsqCalculateMessageTime(&TickCount);
+ return co_IntCallWindowProc((WNDPROC)pMsg->lParam,
+ TRUE,
+ pMsg->hwnd,
+ WM_TIMER,
+ pMsg->wParam,
+ (LPARAM)Time,
+ sizeof(LPARAM));
+ }
+ return 0;
+ }
+ else
+ {
+ PTIMER pTimer = FindSystemTimer(pMsg);
+ if (pTimer && pTimer->pfn)
+ {
+ KeQueryTickCount(&TickCount);
+ Time = MsqCalculateMessageTime(&TickCount);
+ pTimer->pfn(pMsg->hwnd, WM_SYSTIMER, (UINT)pMsg->wParam, Time);
+ }
+ return 0;
+ }
+ }
+ // Need a window!
+ if ( !Window || !Window->Wnd ) return 0;
+
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(pMsg->message);
+ if ( !MsgMemoryEntry )
+ {
+ lParamBufferSize = -1;
+ }
+ else
+ {
+ lParamBufferSize = MsgMemorySize(MsgMemoryEntry, pMsg->wParam, pMsg->lParam);
+ }
+
- if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam)))
++ if (! NT_SUCCESS(PackParam(&lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
+ {
+ DPRINT1("Failed to pack message parameters\n");
+ return 0;
+ }
+
+ retval = co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
+ !Window->Wnd->Unicode,
+ pMsg->hwnd,
+ pMsg->message,
+ pMsg->wParam,
+ lParamPacked,
+ lParamBufferSize);
+
- if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
++ if (! NT_SUCCESS(UnpackParam(lParamPacked, pMsg->message, pMsg->wParam, pMsg->lParam, FALSE)))
+ {
+ DPRINT1("Failed to unpack message parameters\n");
+ }
+
+ if (pMsg->message == WM_PAINT)
+ {
+ /* send a WM_NCPAINT and WM_ERASEBKGND if the non-client area is still invalid */
+ HRGN hrgn = IntSysCreateRectRgn( 0, 0, 0, 0 );
+ co_UserGetUpdateRgn( Window, hrgn, TRUE );
+ REGION_FreeRgnByHandle( hrgn );
+ }
+ return retval;
+}
+
+VOID FASTCALL
+co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
+{
+ if(!Msg->hwnd || ThreadQueue->CaptureWindow)
+ {
+ return;
+ }
+
+ switch(Msg->message)
+ {
+ case WM_MOUSEMOVE:
+ {
+ co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
+ break;
+ }
+ case WM_NCMOUSEMOVE:
+ {
+ co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_XBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_XBUTTONDBLCLK:
+ {
+ WPARAM wParam;
+ PSYSTEM_CURSORINFO CurInfo;
+ CurInfo = IntGetSysCursorInfo();
+
+ wParam = (WPARAM)(CurInfo->ButtonsDown);
+
+ co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
+ co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
+ break;
+ }
+ case WM_NCLBUTTONDOWN:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ case WM_NCXBUTTONDOWN:
+ case WM_NCLBUTTONDBLCLK:
+ case WM_NCMBUTTONDBLCLK:
+ case WM_NCRBUTTONDBLCLK:
+ case WM_NCXBUTTONDBLCLK:
+ {
+ co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
+ co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
+ break;
+ }
+ }
+}
+
+BOOL FASTCALL
+co_IntActivateWindowMouse(
+ PUSER_MESSAGE_QUEUE ThreadQueue,
+ LPMSG Msg,
+ PWINDOW_OBJECT MsgWindow,
+ USHORT *HitTest)
+{
+ ULONG Result;
+ PWINDOW_OBJECT Parent;
+
+ ASSERT_REFS_CO(MsgWindow);
+
+ if(*HitTest == (USHORT)HTTRANSPARENT)
+ {
+ /* eat the message, search again! */
+ return TRUE;
+ }
+
+ Parent = IntGetParent(MsgWindow);//fixme: deref retval?
+
+ /* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
+ Result = co_IntSendMessage(MsgWindow->hSelf,
+ WM_MOUSEACTIVATE,
+ (WPARAM) (Parent ? Parent->hSelf : MsgWindow->hSelf),
+ (LPARAM)MAKELONG(*HitTest, Msg->message)
+ );
+
+ switch (Result)
+ {
+ case MA_NOACTIVATEANDEAT:
+ return TRUE;
+ case MA_NOACTIVATE:
+ break;
+ case MA_ACTIVATEANDEAT:
+ co_IntMouseActivateWindow(MsgWindow);
+ return TRUE;
+ default:
+ /* MA_ACTIVATE */
+ co_IntMouseActivateWindow(MsgWindow);
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL FASTCALL
+co_IntTranslateMouseMessage(
+ PUSER_MESSAGE_QUEUE ThreadQueue,
+ LPMSG Msg,
+ USHORT *HitTest,
+ BOOL Remove)
+{
+ PWINDOW_OBJECT Window;
+ USER_REFERENCE_ENTRY Ref, DesktopRef;
+
+ if(!(Window = UserGetWindowObject(Msg->hwnd)))
+ {
+ /* let's just eat the message?! */
+ return TRUE;
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ if ( ThreadQueue == Window->pti->MessageQueue &&
+ ThreadQueue->CaptureWindow != Window->hSelf)
+ {
+ /* only send WM_NCHITTEST messages if we're not capturing the window! */
+ *HitTest = co_IntSendMessage(Window->hSelf, WM_NCHITTEST, 0,
+ MAKELONG(Msg->pt.x, Msg->pt.y));
+
+ if (*HitTest == (USHORT)HTTRANSPARENT)
+ {
+ PWINDOW_OBJECT DesktopWindow;
+ HWND hDesktop = IntGetDesktopWindow();
+
+ if ((DesktopWindow = UserGetWindowObject(hDesktop)))
+ {
+ PWINDOW_OBJECT Wnd;
+
+ UserRefObjectCo(DesktopWindow, &DesktopRef);
+
+ co_WinPosWindowFromPoint(DesktopWindow, Window->pti->MessageQueue, &Msg->pt, &Wnd);
+ if (Wnd)
+ {
+ if (Wnd != Window)
+ {
+ /* post the message to the other window */
+ Msg->hwnd = Wnd->hSelf;
+ if(!(Wnd->state & WINDOWSTATUS_DESTROYING))
+ {
+ MsqPostMessage(Wnd->pti->MessageQueue, Msg, FALSE,
+ Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
+ QS_MOUSEBUTTON);
+ }
+
+ /* eat the message */
+ UserDereferenceObject(Wnd);
+ UserDerefObjectCo(DesktopWindow);
+ UserDerefObjectCo(Window);
+ return TRUE;
+ }
+ UserDereferenceObject(Wnd);
+ }
+
+ UserDerefObjectCo(DesktopWindow);
+ }
+ }
+ }
+ else
+ {
+ *HitTest = HTCLIENT;
+ }
+
+ if ( gspv.bMouseClickLock &&
+ ( (Msg->message == WM_LBUTTONUP) ||
+ (Msg->message == WM_LBUTTONDOWN) ) )
+ {
+ if (MsqIsClkLck(Msg, Remove))
+ {
+ // FIXME: drop the message, hack: use WM_NULL
+ Msg->message = WM_NULL;
+ }
+ }
+
+ if (IS_BTN_MESSAGE(Msg->message, DOWN))
+ {
+ /* generate double click messages, if necessary */
+ if ((((*HitTest) != HTCLIENT) ||
+ (Window->Wnd->pcls->style & CS_DBLCLKS)) &&
+ MsqIsDblClk(Msg, Remove))
+ {
+ Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
+ }
+ }
+
+ if(Msg->message != WM_MOUSEWHEEL)
+ {
+
+ if ((*HitTest) != HTCLIENT)
+ {
+ Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
+ if ( (Msg->message == WM_NCRBUTTONUP) &&
+ (((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)) )
+ {
+ Msg->message = WM_CONTEXTMENU;
+ Msg->wParam = (WPARAM)Window->hSelf;
+ }
+ else
+ {
+ Msg->wParam = *HitTest;
+ }
+ Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
+ }
+ else if ( ThreadQueue->MoveSize == NULL &&
+ ThreadQueue->MenuOwner == NULL )
+ {
+ /* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
+ Msg->lParam = MAKELONG(
+ Msg->pt.x - (WORD)Window->Wnd->rcClient.left,
+ Msg->pt.y - (WORD)Window->Wnd->rcClient.top);
+ }
+ }
+
+ UserDerefObjectCo(Window);
+ return FALSE;
+}
+
+BOOL ProcessMouseMessage(MSG* Msg, USHORT HitTest, UINT RemoveMsg)
+{
+ MOUSEHOOKSTRUCT MHook;
+ EVENTMSG Event;
+
+ Event.message = Msg->message;
+ Event.time = Msg->time;
+ Event.hwnd = Msg->hwnd;
+ Event.paramL = Msg->pt.x;
+ Event.paramH = Msg->pt.y;
+ co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+
+ MHook.pt = Msg->pt;
+ MHook.hwnd = Msg->hwnd;
+ MHook.wHitTestCode = HitTest;
+ MHook.dwExtraInfo = 0;
+ if (co_HOOK_CallHooks( WH_MOUSE,
+ RemoveMsg ? HC_ACTION : HC_NOREMOVE,
+ Msg->message,
+ (LPARAM)&MHook ))
+ {
+ if (ISITHOOKED(WH_CBT))
+ {
+ MHook.pt = Msg->pt;
+ MHook.hwnd = Msg->hwnd;
+ MHook.wHitTestCode = HitTest;
+ MHook.dwExtraInfo = 0;
+ co_HOOK_CallHooks( WH_CBT,
+ HCBT_CLICKSKIPPED,
+ Msg->message,
+ (LPARAM)&MHook);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL ProcessKeyboardMessage(MSG* Msg, UINT RemoveMsg)
+{
+ EVENTMSG Event;
+
+ Event.message = Msg->message;
+ Event.hwnd = Msg->hwnd;
+ Event.time = Msg->time;
+ Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
+ Event.paramH = Msg->lParam & 0x7FFF;
+ if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
+ co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+ if (co_HOOK_CallHooks( WH_KEYBOARD,
+ RemoveMsg ? HC_ACTION : HC_NOREMOVE,
+ LOWORD(Msg->wParam),
+ Msg->lParam))
+ {
+ if (ISITHOOKED(WH_CBT))
+ {
+ /* skip this message */
+ co_HOOK_CallHooks( WH_CBT,
+ HCBT_KEYSKIPPED,
+ LOWORD(Msg->wParam),
+ Msg->lParam );
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+/*
+ * Internal version of PeekMessage() doing all the work
+ */
+BOOL FASTCALL
+co_IntPeekMessage( PUSER_MESSAGE Msg,
+ PWINDOW_OBJECT Window,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg )
+{
+ PTHREADINFO pti;
+ LARGE_INTEGER LargeTickCount;
+ PUSER_MESSAGE_QUEUE ThreadQueue;
+ PUSER_MESSAGE Message;
+ BOOL Present, RemoveMessages;
+ USER_REFERENCE_ENTRY Ref;
+ USHORT HitTest;
+
+ /* The queues and order in which they are checked are documented in the MSDN
+ article on GetMessage() */
+
+ pti = PsGetCurrentThreadWin32Thread();
+ ThreadQueue = pti->MessageQueue;
+
+ /* Inspect RemoveMsg flags */
+ /* Note:
+ The only flag we process is PM_REMOVE.
+ Processing (High word) PM_QS_Xx Is needed. This and MsgFilterXxx can result
+ with QS_Xx flags to be used to isolate which message check to test for.
+ ATM, we look at all messages and the filters are sent to co_MsqFindMessage
+ and there, it is cross checked.
+ Example: Wine server/queue.c is_keyboard_msg, check_msg_filter and
+ filter_contains_hw_range.
+ */
+ RemoveMessages = RemoveMsg & PM_REMOVE;
+
+/*
+ If no filter is specified, messages are processed in the following order:
+
+ * Sent messages
+ * Posted messages
+ * Input (hardware) messages and system internal events
+ * Sent messages (again)
+ * WM_PAINT messages
+ * WM_TIMER messages
+ */
+CheckMessages:
+
+ Present = FALSE;
+
+ KeQueryTickCount(&LargeTickCount);
+ ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
+
+ /* Dispatch sent messages here. */
+ while (co_MsqDispatchOneSentMessage(ThreadQueue))
+ ;
+
+ /* Now look for a quit message. */
+
+ if (ThreadQueue->QuitPosted)
+ {
+ /* According to the PSDK, WM_QUIT messages are always returned, regardless
+ of the filter specified */
+ Msg->Msg.hwnd = NULL;
+ Msg->Msg.message = WM_QUIT;
+ Msg->Msg.wParam = ThreadQueue->QuitExitCode;
+ Msg->Msg.lParam = 0;
+ Msg->FreeLParam = FALSE;
+ if (RemoveMessages)
+ {
+ ThreadQueue->QuitPosted = FALSE;
+ }
+ goto MsgExit;
+ }
+
+ /* Now check for normal messages. */
+ Present = co_MsqFindMessage( ThreadQueue,
+ FALSE,
+ RemoveMessages,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ &Message );
+ if (Present)
+ {
+ RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
+ if (RemoveMessages)
+ {
+ MsqDestroyMessage(Message);
+ }
+ goto MessageFound;
+ }
+
+ /* Check for hardware events. */
+ Present = co_MsqFindMessage( ThreadQueue,
+ TRUE,
+ RemoveMessages,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ &Message );
+ if (Present)
+ {
+ RtlCopyMemory(Msg, Message, sizeof(USER_MESSAGE));
+ if (RemoveMessages)
+ {
+ MsqDestroyMessage(Message);
+ }
+ goto MessageFound;
+ }
+
+ /* Check for sent messages again. */
+ while (co_MsqDispatchOneSentMessage(ThreadQueue))
+ ;
+
+ /* Check for paint messages. */
+ if ( IntGetPaintMessage( Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ pti,
+ &Msg->Msg,
+ RemoveMessages))
+ {
+ Msg->FreeLParam = FALSE;
+ goto MsgExit;
+ }
+
+ if (ThreadQueue->WakeMask & QS_TIMER)
+ if (PostTimerMessages(Window)) // If there are timers ready,
+ goto CheckMessages; // go back and process them.
+
+ // LOL! Polling Timer Queue? How much time is spent doing this?
+ /* Check for WM_(SYS)TIMER messages */
+ Present = MsqGetTimerMessage( ThreadQueue,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ &Msg->Msg,
+ RemoveMessages);
+ if (Present)
+ {
+ Msg->FreeLParam = FALSE;
+ goto MessageFound;
+ }
+
+ if(Present)
+ {
+MessageFound:
+
+ if(RemoveMessages)
+ {
+ PWINDOW_OBJECT MsgWindow = NULL;
+
+ /* Mouse message process */
+
+ if( Msg->Msg.hwnd &&
+ ( MsgWindow = UserGetWindowObject(Msg->Msg.hwnd) ) &&
+ Msg->Msg.message >= WM_MOUSEFIRST &&
+ Msg->Msg.message <= WM_MOUSELAST )
+ {
+ USHORT HitTest;
+
+ UserRefObjectCo(MsgWindow, &Ref);
+
+ if ( co_IntTranslateMouseMessage( ThreadQueue,
+ &Msg->Msg,
+ &HitTest,
+ TRUE))
+ /* FIXME - check message filter again, if the message doesn't match anymore,
+ search again */
+ {
+ UserDerefObjectCo(MsgWindow);
+ /* eat the message, search again */
+ goto CheckMessages;
+ }
+
+ if(ThreadQueue->CaptureWindow == NULL)
+ {
+ co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
+
+ if ( ( Msg->Msg.message != WM_MOUSEMOVE &&
+ Msg->Msg.message != WM_NCMOUSEMOVE ) &&
+ IS_BTN_MESSAGE(Msg->Msg.message, DOWN) &&
+ co_IntActivateWindowMouse(ThreadQueue, &Msg->Msg, MsgWindow, &HitTest) )
+ {
+ UserDerefObjectCo(MsgWindow);
+ /* eat the message, search again */
+ goto CheckMessages;
+ }
+ }
+
+ UserDerefObjectCo(MsgWindow);
+ }
+ else
+ {
+ co_IntSendHitTestMessages(ThreadQueue, &Msg->Msg);
+ }
+
+// if(MsgWindow)
+// {
+// UserDereferenceObject(MsgWindow);
+// }
+
+ goto MsgExit;
+ }
+
+ if ( ( Msg->Msg.hwnd &&
+ Msg->Msg.message >= WM_MOUSEFIRST &&
+ Msg->Msg.message <= WM_MOUSELAST ) &&
+ co_IntTranslateMouseMessage( ThreadQueue,
+ &Msg->Msg,
+ &HitTest,
+ FALSE) )
+ /* FIXME - check message filter again, if the message doesn't match anymore,
+ search again */
+ {
+ /* eat the message, search again */
+ goto CheckMessages;
+ }
+
+MsgExit:
+ if ( ISITHOOKED(WH_MOUSE) && IS_MOUSE_MESSAGE(Msg->Msg.message))
+ {
+ if(!ProcessMouseMessage(&Msg->Msg, HitTest, RemoveMsg))
+ {
+ return FALSE;
+ }
+ }
+
+ if ( ISITHOOKED(WH_KEYBOARD) && IS_KBD_MESSAGE(Msg->Msg.message))
+ {
+ if(!ProcessKeyboardMessage(&Msg->Msg, RemoveMsg))
+ {
+ return FALSE;
+ }
+ }
+ // The WH_GETMESSAGE hook enables an application to monitor messages about to
+ // be returned by the GetMessage or PeekMessage function.
+ if (ISITHOOKED(WH_GETMESSAGE))
+ {
+ //DPRINT1("Peek WH_GETMESSAGE -> %x\n",&Msg);
+ co_HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, RemoveMsg & PM_REMOVE, (LPARAM)&Msg->Msg);
+ }
+ return TRUE;
+ }
+
+ return Present;
+}
+
+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( PWINDOW_OBJECT Window,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax )
+{
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE ThreadQueue;
+ NTSTATUS Status = STATUS_SUCCESS;
+ USER_MESSAGE Msg;
+
+ pti = PsGetCurrentThreadWin32Thread();
+ ThreadQueue = pti->MessageQueue;
+
+ do
+ {
+ if ( co_IntPeekMessage( &Msg,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ PM_NOREMOVE))
+ {
+ return TRUE;
+ }
+ /* Nothing found. Wait for new messages. */
+ Status = co_MsqWaitForNewMessages( ThreadQueue,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax);
+ }
+ while ( (STATUS_WAIT_0 <= Status && Status <= STATUS_WAIT_63) ||
+ STATUS_TIMEOUT == Status );
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ DPRINT1("Exit co_IntWaitMessage on error!\n");
+ }
+
+ return FALSE;
+}
+
+BOOL FASTCALL
+co_IntGetPeekMessage( PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg,
+ BOOL bGMSG )
+{
+ BOOL Present;
+ PWINDOW_OBJECT Window;
+ USER_MESSAGE Msg;
+
+ if ( hWnd == HWND_TOPMOST ||
+ hWnd == HWND_BROADCAST )
+ hWnd = HWND_BOTTOM;
+
+ /* Validate input */
+ if (hWnd && hWnd != HWND_BOTTOM)
+ {
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ if (bGMSG)
+ return -1;
+ else
+ return FALSE;
+ }
+ }
+ else
+ {
+ Window = (PWINDOW_OBJECT)hWnd;
+ }
+
+ if (MsgFilterMax < MsgFilterMin)
+ {
+ MsgFilterMin = 0;
+ MsgFilterMax = 0;
+ }
+
+ do
+ {
+ Present = co_IntPeekMessage( &Msg,
+ Window,
+ MsgFilterMin,
+ MsgFilterMax,
+ RemoveMsg );
+ if (Present)
+ {
+ RtlCopyMemory( pMsg, &Msg.Msg, sizeof(MSG));
+
+ if (bGMSG)
+ return (WM_QUIT != pMsg->message);
+ else
+ return TRUE;
+ }
+
+ if ( bGMSG && !co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax) )
+ {
+ return -1;
+ }
+ else
+ {
+ if (!(RemoveMsg & PM_NOYIELD))
+ {
+ // Yield this thread!
+ UserLeave();
+ ZwYieldExecution();
+ UserEnterExclusive();
+ // Fall through to fail.
+ }
+ }
+ }
+ while( bGMSG && !Present );
+
+ return FALSE;
+}
+
+BOOL FASTCALL
+UserPostThreadMessage( DWORD idThread,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ MSG Message;
+ PETHREAD peThread;
+ PTHREADINFO pThread;
+ LARGE_INTEGER LargeTickCount;
+ NTSTATUS Status;
+
+ DPRINT1("UserPostThreadMessage wParam 0x%x lParam 0x%x\n", wParam,lParam);
+
+ if (FindMsgMemory(Msg) != 0)
+ {
+ SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+ return FALSE;
+ }
+
+ Status = PsLookupThreadByThreadId((HANDLE)idThread,&peThread);
+
+ if( Status == STATUS_SUCCESS )
+ {
+ pThread = (PTHREADINFO)peThread->Tcb.Win32Thread;
+ if( !pThread ||
+ !pThread->MessageQueue ||
+ (pThread->TIF_flags & TIF_INCLEANUP))
+ {
+ ObDereferenceObject( peThread );
+ return FALSE;
+ }
+
+ Message.hwnd = NULL;
+ Message.message = Msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+ Message.pt = gpsi->ptCursor;
+
+ KeQueryTickCount(&LargeTickCount);
+ pThread->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+ MsqPostMessage(pThread->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
+ ObDereferenceObject( peThread );
+ return TRUE;
+ }
+ else
+ {
+ SetLastNtError( Status );
+ }
+ return FALSE;
+}
+
+BOOL FASTCALL
+UserPostMessage( HWND Wnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ PTHREADINFO pti;
+ MSG Message;
+ LARGE_INTEGER LargeTickCount;
+
+ if (FindMsgMemory(Msg) != 0)
+ {
+ SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+ return FALSE;
+ }
+
+ if (!Wnd)
+ return UserPostThreadMessage( PtrToInt(PsGetCurrentThreadId()),
+ Msg,
+ wParam,
+ lParam);
+
+ if (Wnd == HWND_BROADCAST)
+ {
+ HWND *List;
+ PWINDOW_OBJECT DesktopWindow;
+ ULONG i;
+
+ DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
+ List = IntWinListChildren(DesktopWindow);
+
+ if (List != NULL)
+ {
+ UserPostMessage(DesktopWindow->hSelf, Msg, wParam, lParam);
+ for (i = 0; List[i]; i++)
+ UserPostMessage(List[i], Msg, wParam, lParam);
+ ExFreePool(List);
+ }
+ }
+ else
+ {
+ PWINDOW_OBJECT Window;
+
+ Window = UserGetWindowObject(Wnd);
+ if ( !Window || !Window->Wnd )
+ {
+ return FALSE;
+ }
+
+ pti = Window->Wnd->head.pti;
+ if ( pti->TIF_flags & TIF_INCLEANUP )
+ {
+ DPRINT1("Attempted to post message to window 0x%x when the thread is in cleanup!\n", Wnd);
+ return FALSE;
+ }
+
+ if ( Window->state & WINDOWSTATUS_DESTROYING )
+ {
+ DPRINT1("Attempted to post message to window 0x%x that is being destroyed!\n", Wnd);
+ /* FIXME - last error code? */
+ return FALSE;
+ }
+
+ if (WM_QUIT == Msg)
+ {
+ MsqPostQuitMessage(Window->pti->MessageQueue, wParam);
+ }
+ else
+ {
+ Message.hwnd = Wnd;
+ Message.message = Msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+ Message.pt = gpsi->ptCursor;
+ KeQueryTickCount(&LargeTickCount);
+ pti->timeLast = Message.time = MsqCalculateMessageTime(&LargeTickCount);
+ MsqPostMessage(Window->pti->MessageQueue, &Message, FALSE, QS_POSTMESSAGE);
+ }
+ }
+ return TRUE;
+}
+
+
+LRESULT FASTCALL
+co_IntSendMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ ULONG_PTR Result = 0;
+ if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
+ {
+ return (LRESULT)Result;
+ }
+ return 0;
+}
+
+static
+LRESULT FASTCALL
+co_IntSendMessageTimeoutSingle( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ UINT uFlags,
+ UINT uTimeout,
+ ULONG_PTR *uResult )
+{
+ ULONG_PTR Result;
+ NTSTATUS Status;
+ PWINDOW_OBJECT Window = NULL;
+ PMSGMEMORY MsgMemoryEntry;
+ INT lParamBufferSize;
+ LPARAM lParamPacked;
+ PTHREADINFO Win32Thread;
+ DECLARE_RETURN(LRESULT);
+ USER_REFERENCE_ENTRY Ref;
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN( FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ Win32Thread = PsGetCurrentThreadWin32Thread();
+
+ IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
+
+ if ( NULL != Win32Thread &&
+ Window->pti->MessageQueue == Win32Thread->MessageQueue)
+ {
+ if (Win32Thread->TIF_flags & TIF_INCLEANUP)
+ {
+ /* Never send messages to exiting threads */
+ RETURN( FALSE);
+ }
+
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(Msg);
+ if (NULL == MsgMemoryEntry)
+ {
+ lParamBufferSize = -1;
+ }
+ else
+ {
+ lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
+ }
+
- if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
++ if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, FALSE)))
+ {
+ DPRINT1("Failed to pack message parameters\n");
+ RETURN( FALSE);
+ }
+
+ Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
+ !Window->Wnd->Unicode,
+ hWnd,
+ Msg,
+ wParam,
+ lParamPacked,
+ lParamBufferSize );
+ if(uResult)
+ {
+ *uResult = Result;
+ }
+
+ IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
++ if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
+ {
+ DPRINT1("Failed to unpack message parameters\n");
+ RETURN( TRUE);
+ }
+
+ RETURN( TRUE);
+ }
+
+ if (uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->pti->MessageQueue))
+ {
+ /* FIXME - Set a LastError? */
+ RETURN( FALSE);
+ }
+
+ if (Window->state & WINDOWSTATUS_DESTROYING)
+ {
+ /* FIXME - last error? */
+ DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
+ RETURN( FALSE);
+ }
+
+ do
+ {
+ Status = co_MsqSendMessage( Window->pti->MessageQueue,
+ hWnd,
+ Msg,
+ wParam,
+ lParam,
+ uTimeout,
+ (uFlags & SMTO_BLOCK),
+ MSQ_NORMAL,
+ uResult );
+ }
+ while ((STATUS_TIMEOUT == Status) &&
+ (uFlags & SMTO_NOTIMEOUTIFNOTHUNG) &&
+ !MsqIsHung(Window->pti->MessageQueue));
+
+ IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
+
+ if (STATUS_TIMEOUT == Status)
+ {
+/*
+ MSDN says:
+ Microsoft Windows 2000: If GetLastError returns zero, then the function
+ timed out.
+ XP+ : If the function fails or times out, the return value is zero.
+ To get extended error information, call GetLastError. If GetLastError
+ returns ERROR_TIMEOUT, then the function timed out.
+ */
+ SetLastWin32Error(ERROR_TIMEOUT);
+ RETURN( FALSE);
+ }
+ else if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( FALSE);
+ }
+
+ RETURN( TRUE);
+
+CLEANUP:
+ if (Window) UserDerefObjectCo(Window);
+ END_CLEANUP;
+}
+
+LRESULT FASTCALL
+co_IntSendMessageTimeout( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ UINT uFlags,
+ UINT uTimeout,
+ ULONG_PTR *uResult )
+{
+ PWINDOW_OBJECT DesktopWindow;
+ HWND *Children;
+ HWND *Child;
+
+ if (HWND_BROADCAST != hWnd)
+ {
+ return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+ }
+
+ DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
+ if (NULL == DesktopWindow)
+ {
+ SetLastWin32Error(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Send message to the desktop window too! */
+ co_IntSendMessageTimeoutSingle(DesktopWindow->hSelf, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+
+ Children = IntWinListChildren(DesktopWindow);
+ if (NULL == Children)
+ {
+ return 0;
+ }
+
+ for (Child = Children; NULL != *Child; Child++)
+ {
+ co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
+ }
+
+ ExFreePool(Children);
+
+ return (LRESULT) TRUE;
+}
+
++LRESULT FASTCALL co_IntSendMessageNoWait(HWND hWnd,
++ UINT Msg,
++ WPARAM wParam,
++ LPARAM lParam)
++{
++ ULONG_PTR Result = 0;
++ co_IntSendMessageWithCallBack(hWnd,
++ Msg,
++ wParam,
++ lParam,
++ NULL,
++ 0,
++ &Result);
++ return Result;
++}
++
++LRESULT FASTCALL
++co_IntSendMessageWithCallBack( HWND hWnd,
++ UINT Msg,
++ WPARAM wParam,
++ LPARAM lParam,
++ SENDASYNCPROC CompletionCallback,
++ ULONG_PTR CompletionCallbackContext,
++ ULONG_PTR *uResult)
++{
++ ULONG_PTR Result;
++ PWINDOW_OBJECT Window = NULL;
++ PMSGMEMORY MsgMemoryEntry;
++ INT lParamBufferSize;
++ LPARAM lParamPacked;
++ PTHREADINFO Win32Thread;
++ DECLARE_RETURN(LRESULT);
++ USER_REFERENCE_ENTRY Ref;
++ PUSER_SENT_MESSAGE Message;
++
++ if (!(Window = UserGetWindowObject(hWnd)))
++ {
++ RETURN(FALSE);
++ }
++
++ UserRefObjectCo(Window, &Ref);
++
++ if (Window->state & WINDOWSTATUS_DESTROYING)
++ {
++ /* FIXME - last error? */
++ DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
++ RETURN(FALSE);
++ }
++
++ Win32Thread = PsGetCurrentThreadWin32Thread();
++
++ IntCallWndProc( Window, hWnd, Msg, wParam, lParam);
++
++ if (Win32Thread == NULL)
++ {
++ ASSERT(FALSE);
++ RETURN(FALSE);
++ }
++
++ if (Win32Thread->TIF_flags & TIF_INCLEANUP)
++ {
++ /* Never send messages to exiting threads */
++ RETURN(FALSE);
++ }
++
++ /* See if this message type is present in the table */
++ MsgMemoryEntry = FindMsgMemory(Msg);
++ if (NULL == MsgMemoryEntry)
++ {
++ lParamBufferSize = -1;
++ }
++ else
++ {
++ lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
++ }
++
++ if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam, Window->pti->MessageQueue != Win32Thread->MessageQueue)))
++ {
++ DPRINT1("Failed to pack message parameters\n");
++ RETURN( FALSE);
++ }
++
++ /* If this is not a callback and it can be sent now, then send it. */
++ if ((Window->pti->MessageQueue == Win32Thread->MessageQueue) && (CompletionCallback == NULL))
++ {
++
++ Result = (ULONG_PTR)co_IntCallWindowProc( Window->Wnd->lpfnWndProc,
++ !Window->Wnd->Unicode,
++ hWnd,
++ Msg,
++ wParam,
++ lParamPacked,
++ lParamBufferSize );
++ if(uResult)
++ {
++ *uResult = Result;
++ }
++ }
++
++ IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
++
++ if (Window->pti->MessageQueue == Win32Thread->MessageQueue)
++ {
++ if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam, FALSE)))
++ {
++ DPRINT1("Failed to unpack message parameters\n");
++ RETURN(TRUE);
++ }
++ RETURN(TRUE);
++ }
++
++ if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
++ {
++ DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
++ return STATUS_INSUFFICIENT_RESOURCES;
++ }
++
++ Message->Msg.hwnd = hWnd;
++ Message->Msg.message = Msg;
++ Message->Msg.wParam = wParam;
++ Message->Msg.lParam = lParamPacked;
++ Message->CompletionEvent = NULL;
++ Message->Result = 0;
++ Message->SenderQueue = Win32Thread->MessageQueue;
++ IntReferenceMessageQueue(Message->SenderQueue);
++ IntReferenceMessageQueue(Window->pti->MessageQueue);
++ Message->CompletionCallback = CompletionCallback;
++ Message->CompletionCallbackContext = CompletionCallbackContext;
++ Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
++ Message->HasPackedLParam = (lParamBufferSize > 0);
++
++ InsertTailList(&Window->pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
++ InsertTailList(&Win32Thread->MessageQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
++ IntDereferenceMessageQueue(Window->pti->MessageQueue);
++ IntDereferenceMessageQueue(Message->SenderQueue);
++
++ RETURN(TRUE);
++
++CLEANUP:
++ if (Window) UserDerefObjectCo(Window);
++ END_CLEANUP;
++}
+
+/* This function posts a message if the destination's message queue belongs to
+ another thread, otherwise it sends the message. It does not support broadcast
+ messages! */
+LRESULT FASTCALL
+co_IntPostOrSendMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ ULONG_PTR Result;
+ PTHREADINFO pti;
+ PWINDOW_OBJECT Window;
+
+ if ( hWnd == HWND_BROADCAST )
+ {
+ return 0;
+ }
+
+ if(!(Window = UserGetWindowObject(hWnd)))
+ {
+ return 0;
+ }
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if ( Window->pti->MessageQueue != pti->MessageQueue &&
+ FindMsgMemory(Msg) == 0 )
+ {
+ Result = UserPostMessage(hWnd, Msg, wParam, lParam);
+ }
+ else
+ {
+ if ( !co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result) )
+ {
+ Result = 0;
+ }
+ }
+
+ return (LRESULT)Result;
+}
+
+LRESULT FASTCALL
+co_IntDoSendMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ PDOSENDMESSAGE dsm,
+ PNTUSERSENDMESSAGEINFO UnsafeInfo )
+{
+ PTHREADINFO pti;
+ LRESULT Result = TRUE;
+ NTSTATUS Status;
+ PWINDOW_OBJECT Window = NULL;
+ NTUSERSENDMESSAGEINFO Info;
+ MSG UserModeMsg;
+ MSG KernelModeMsg;
+ PMSGMEMORY MsgMemoryEntry;
+
+ RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));
+
+ /* FIXME: Call hooks. */
+ if (HWND_BROADCAST != hWnd)
+ {
+ Window = UserGetWindowObject(hWnd);
+ if ( !Window || !Window->Wnd )
+ {
+ /* Tell usermode to not touch this one */
+ Info.HandledByKernel = TRUE;
+ MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
+ return 0;
+ }
+ }
+
+ /* Check for an exiting window. */
+ if (Window && Window->state & WINDOWSTATUS_DESTROYING)
+ {
+ DPRINT1("co_IntDoSendMessage Window Exiting!\n");
+ }
+
+ /* See if the current thread can handle the message */
+ pti = PsGetCurrentThreadWin32Thread();
+
+ // This is checked in user mode!!!!!!!
+ if ( HWND_BROADCAST != hWnd &&
+ NULL != pti &&
+ Window->pti->MessageQueue == pti->MessageQueue &&
+ !ISITHOOKED(WH_CALLWNDPROC) &&
+ !ISITHOOKED(WH_CALLWNDPROCRET) &&
+ ( Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST ) )
+ {
+ /* Gather the information usermode needs to call the window proc directly */
+ Info.HandledByKernel = FALSE;
+
+ Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
+ sizeof(BOOL));
+ if (! NT_SUCCESS(Status))
+ {
+ Info.Ansi = ! Window->Wnd->Unicode;
+ }
+
+ Info.Ansi = !Window->Wnd->Unicode;
+ Info.Proc = Window->Wnd->lpfnWndProc;
+ }
+ else
+ {
+ /* Must be handled by other thread */
+// if (HWND_BROADCAST != hWnd)
+// {
+// UserDereferenceObject(Window);
+// }
+ Info.HandledByKernel = TRUE;
+ UserModeMsg.hwnd = hWnd;
+ UserModeMsg.message = Msg;
+ UserModeMsg.wParam = wParam;
+ UserModeMsg.lParam = lParam;
+ MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
+
+ Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
+ if (! NT_SUCCESS(Status))
+ {
+ MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return (dsm ? 0 : -1);
+ }
+
+ if(!dsm)
+ {
+ Result = co_IntSendMessage( KernelModeMsg.hwnd,
+ KernelModeMsg.message,
+ KernelModeMsg.wParam,
+ KernelModeMsg.lParam );
+ }
+ else
+ {
+ Result = co_IntSendMessageTimeout( KernelModeMsg.hwnd,
+ KernelModeMsg.message,
+ KernelModeMsg.wParam,
+ KernelModeMsg.lParam,
+ dsm->uFlags,
+ dsm->uTimeout,
+ &dsm->Result );
+ }
+
+ Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
+ if (! NT_SUCCESS(Status))
+ {
+ MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return(dsm ? 0 : -1);
+ }
+ }
+
+ Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ }
+
+ return (LRESULT)Result;
+}
+
+
+BOOL FASTCALL
+UserSendNotifyMessage( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam )
+{
+ BOOL Result = TRUE;
+
+ if (FindMsgMemory(Msg) != 0)
+ {
+ SetLastWin32Error(ERROR_MESSAGE_SYNC_ONLY );
+ return FALSE;
+ }
+
+ // Basicly the same as IntPostOrSendMessage
+ if (hWnd == HWND_BROADCAST) //Handle Broadcast
+ {
+ HWND *List;
+ PWINDOW_OBJECT DesktopWindow;
+ ULONG i;
+
+ DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
+ List = IntWinListChildren(DesktopWindow);
+
+ if (List != NULL)
+ {
+ UserSendNotifyMessage(DesktopWindow->hSelf, Msg, wParam, lParam);
+ for (i = 0; List[i]; i++)
+ {
+ UserSendNotifyMessage(List[i], Msg, wParam, lParam);
+ }
+ ExFreePool(List);
+ }
+ }
+ else
+ {
+ ULONG_PTR PResult;
+ PTHREADINFO pti;
+ PWINDOW_OBJECT Window;
+ MSG Message;
+
+ if ( !(Window = UserGetWindowObject(hWnd)) ) return FALSE;
+
+ pti = PsGetCurrentThreadWin32Thread();
+
+ if (Window->pti->MessageQueue != pti->MessageQueue)
+ { // Send message w/o waiting for it.
+ Result = UserPostMessage(hWnd, Msg, wParam, lParam);
+ }
+ else
+ { // Handle message and callback.
+ Message.hwnd = hWnd;
+ Message.message = Msg;
+ Message.wParam = wParam;
+ Message.lParam = lParam;
+
+ Result = co_IntSendMessageTimeoutSingle( hWnd,
+ Msg,
+ wParam,
+ lParam,
+ SMTO_NORMAL,
+ 0,
+ &PResult );
+ }
+ }
+ return Result;
+}
+
+
+DWORD APIENTRY
+IntGetQueueStatus(BOOL ClearChanges)
+{
+ PTHREADINFO pti;
+ PUSER_MESSAGE_QUEUE Queue;
+ DWORD Result;
+ DECLARE_RETURN(DWORD);
+
+ DPRINT("Enter IntGetQueueStatus\n");
+
+ pti = PsGetCurrentThreadWin32Thread();
+ Queue = pti->MessageQueue;
+
+ Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
+ if (ClearChanges)
+ {
+ Queue->ChangedBits = 0;
+ }
+
+ RETURN(Result);
+
+CLEANUP:
+ DPRINT("Leave IntGetQueueStatus, ret=%i\n",_ret_);
+ END_CLEANUP;
+}
+
+BOOL APIENTRY
+IntInitMessagePumpHook()
+{
+ if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
+ {
+ ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL APIENTRY
+IntUninitMessagePumpHook()
+{
+ if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti)
+ {
+ if (((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook <= 0)
+ {
+ return FALSE;
+ }
+ ((PTHREADINFO)PsGetCurrentThread()->Tcb.Win32Thread)->pcti->dwcPumpHook--;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/** Functions ******************************************************************/
+
+BOOL APIENTRY
+NtUserPostMessage(HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserPostMessage\n");
+ UserEnterExclusive();
+
+ RETURN( UserPostMessage(hWnd, Msg, wParam, lParam));
+
+CLEANUP:
+ DPRINT("Leave NtUserPostMessage, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL APIENTRY
+NtUserPostThreadMessage(DWORD idThread,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserPostThreadMessage\n");
+ UserEnterExclusive();
+
+ RETURN( UserPostThreadMessage( idThread,
+ Msg,
+ wParam,
+ lParam));
+
+CLEANUP:
+ DPRINT("Leave NtUserPostThreadMessage, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+DWORD APIENTRY
+NtUserQuerySendMessage(DWORD Unknown0)
+{
+ UNIMPLEMENTED;
+
+ return 0;
+}
+
+
+////////// API on the way out!
+LRESULT APIENTRY
+NtUserSendMessageTimeout( HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ UINT uFlags,
+ UINT uTimeout,
+ ULONG_PTR *uResult,
+ PNTUSERSENDMESSAGEINFO UnsafeInfo )
+{
+ DOSENDMESSAGE dsm;
+ LRESULT Result;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserSendMessageTimeout\n");
+ UserEnterExclusive();
+
+ dsm.uFlags = uFlags;
+ dsm.uTimeout = uTimeout;
+ Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
+ if(uResult != NULL && Result != 0)
+ {
+ NTSTATUS Status;
+
+ Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN( FALSE);
+ }
+ }
+ RETURN( Result);
+
+CLEANUP:
+ DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+LRESULT APIENTRY
+NtUserSendMessage( HWND Wnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ PNTUSERSENDMESSAGEINFO UnsafeInfo )
+{
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserSendMessage\n");
+ UserEnterExclusive();
+
+ RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));
+
+CLEANUP:
+ DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+//////////
+
+BOOL APIENTRY
+NtUserWaitMessage(VOID)
+{
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("EnterNtUserWaitMessage\n");
+ UserEnterExclusive();
+
+ RETURN(co_IntWaitMessage(NULL, 0, 0));
+
+CLEANUP:
+ DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+BOOL APIENTRY
+NtUserGetMessage( PNTUSERGETMESSAGEINFO UnsafeInfo,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax )
+/*
+ * FUNCTION: Get a message from the calling thread's message queue.
+ * ARGUMENTS:
+ * UnsafeMsg - Pointer to the structure which receives the returned message.
+ * Wnd - Window whose messages are to be retrieved.
+ * MsgFilterMin - Integer value of the lowest message value to be
+ * retrieved.
+ * MsgFilterMax - Integer value of the highest message value to be
+ * retrieved.
+ */
+{
+ BOOL GotMessage;
+ NTUSERGETMESSAGEINFO Info;
+ NTSTATUS Status;
+ /* FIXME: if initialization is removed, gcc complains that this may be used before initialization. Please review */
+ PWINDOW_OBJECT Window = NULL;
+ PMSGMEMORY MsgMemoryEntry;
+ PVOID UserMem;
+ UINT Size;
+ USER_MESSAGE Msg;
+ DECLARE_RETURN(BOOL);
+// USER_REFERENCE_ENTRY Ref;
+
+ DPRINT("Enter NtUserGetMessage\n");
+ UserEnterExclusive();
+
+ /* Validate input */
+ if (hWnd && !(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(-1);
+ }
+
+// if (Window) UserRefObjectCo(Window, &Ref);
+
+ if (MsgFilterMax < MsgFilterMin)
+ {
+ MsgFilterMin = 0;
+ MsgFilterMax = 0;
+ }
+
+ do
+ {
+ GotMessage = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, PM_REMOVE);
+ if (GotMessage)
+ {
+ Info.Msg = Msg.Msg;
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
+ if (NULL == MsgMemoryEntry)
+ {
+ /* Not present, no copying needed */
+ Info.LParamSize = 0;
+ }
+ else
+ {
+ /* Determine required size */
+ Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
+ Info.Msg.lParam);
+ /* Allocate required amount of user-mode memory */
+ Info.LParamSize = Size;
+ UserMem = NULL;
+ Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
+ &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
+
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( (BOOL) -1);
+ }
+ /* Transfer lParam data to user-mode mem */
+ Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
+ if (! NT_SUCCESS(Status))
+ {
+ ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
+ &Info.LParamSize, MEM_DECOMMIT);
+ SetLastNtError(Status);
+ RETURN( (BOOL) -1);
+ }
+ Info.Msg.lParam = (LPARAM) UserMem;
+ }
+ if (Msg.FreeLParam && 0 != Msg.Msg.lParam)
+ {
+ ExFreePool((void *) Msg.Msg.lParam);
+ }
+ Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( (BOOL) -1);
+ }
+ }
+ else if (! co_IntWaitMessage(Window, MsgFilterMin, MsgFilterMax))
+ {
+ RETURN( (BOOL) -1);
+ }
+ }
+ while (! GotMessage);
+
+ RETURN( WM_QUIT != Info.Msg.message);
+
+CLEANUP:
+// if (Window) UserDerefObjectCo(Window);
+
+ DPRINT("Leave NtUserGetMessage\n");
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+BOOL
+APIENTRY
+NtUserGetMessageX(
+ PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax)
+{
+ MSG Msg;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserGetMessage\n");
+ UserEnterExclusive();
+
+ if ( (MsgFilterMin|MsgFilterMax) & ~WM_MAXIMUM )
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN( Ret);
+ }
+
+ RtlZeroMemory(&Msg, sizeof(MSG));
+
+ Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, PM_REMOVE, TRUE);
+
+ if (Ret)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pMsg, sizeof(MSG), 1);
+ RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Ret = FALSE;
+ }
+ _SEH2_END;
+ }
+ RETURN( Ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserGetMessage\n");
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL APIENTRY
+NtUserPeekMessage(PNTUSERGETMESSAGEINFO UnsafeInfo,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg)
+{
+ NTSTATUS Status;
+ BOOL Present;
+ NTUSERGETMESSAGEINFO Info;
+ PWINDOW_OBJECT Window;
+ PMSGMEMORY MsgMemoryEntry;
+ PVOID UserMem;
+ UINT Size;
+ USER_MESSAGE Msg;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserPeekMessage\n");
+ UserEnterExclusive();
+
+ if (hWnd == (HWND)-1 || hWnd == (HWND)0x0000FFFF || hWnd == (HWND)0xFFFFFFFF)
+ hWnd = (HWND)1;
+
+ /* Validate input */
+ if (hWnd && hWnd != (HWND)1)
+ {
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(-1);
+ }
+ }
+ else
+ {
+ Window = (PWINDOW_OBJECT)hWnd;
+ }
+
+ if (MsgFilterMax < MsgFilterMin)
+ {
+ MsgFilterMin = 0;
+ MsgFilterMax = 0;
+ }
+
+ Present = co_IntPeekMessage(&Msg, Window, MsgFilterMin, MsgFilterMax, RemoveMsg);
+ if (Present)
+ {
+
+ Info.Msg = Msg.Msg;
+ /* See if this message type is present in the table */
+ MsgMemoryEntry = FindMsgMemory(Info.Msg.message);
+ if (NULL == MsgMemoryEntry)
+ {
+ /* Not present, no copying needed */
+ Info.LParamSize = 0;
+ }
+ else
+ {
+ /* Determine required size */
+ Size = MsgMemorySize(MsgMemoryEntry, Info.Msg.wParam,
+ Info.Msg.lParam);
+ /* Allocate required amount of user-mode memory */
+ Info.LParamSize = Size;
+ UserMem = NULL;
+ Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &UserMem, 0,
+ &Info.LParamSize, MEM_COMMIT, PAGE_READWRITE);
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( (BOOL) -1);
+ }
+ /* Transfer lParam data to user-mode mem */
+ Status = MmCopyToCaller(UserMem, (PVOID) Info.Msg.lParam, Size);
+ if (! NT_SUCCESS(Status))
+ {
+ ZwFreeVirtualMemory(NtCurrentProcess(), (PVOID *) &UserMem,
+ &Info.LParamSize, MEM_RELEASE);
+ SetLastNtError(Status);
+ RETURN( (BOOL) -1);
+ }
+ Info.Msg.lParam = (LPARAM) UserMem;
+ }
+ if (RemoveMsg && Msg.FreeLParam && 0 != Msg.Msg.lParam)
+ {
+ ExFreePool((void *) Msg.Msg.lParam);
+ }
+ Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERGETMESSAGEINFO));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( (BOOL) -1);
+ }
+ }
+
+ RETURN( Present);
+
+CLEANUP:
+ DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL
+APIENTRY
+NtUserPeekMessageX(
+ PMSG pMsg,
+ HWND hWnd,
+ UINT MsgFilterMin,
+ UINT MsgFilterMax,
+ UINT RemoveMsg)
+{
+ MSG Msg;
+ BOOL Ret = FALSE;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserPeekMessage\n");
+ UserEnterExclusive();
+
+ if ( RemoveMsg & PM_BADMSGFLAGS )
+ {
+ SetLastWin32Error(ERROR_INVALID_FLAGS);
+ RETURN( Ret);
+ }
+
+ RtlZeroMemory(&Msg, sizeof(MSG));
+
+ Ret = co_IntGetPeekMessage(&Msg, hWnd, MsgFilterMin, MsgFilterMax, RemoveMsg, FALSE);
+
+ if (Ret)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pMsg, sizeof(MSG), 1);
+ RtlCopyMemory(pMsg, &Msg, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Ret = FALSE;
+ }
+ _SEH2_END;
+ }
+ RETURN( Ret);
+
+CLEANUP:
+ DPRINT("Leave NtUserPeekMessage, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL
+APIENTRY
+NtUserCallMsgFilter(
+ LPMSG lpmsg,
+ INT code)
+{
+ BOOL BadChk = FALSE, Ret = FALSE;
+ MSG Msg;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserCallMsgFilter\n");
+ UserEnterExclusive();
+ if (lpmsg)
+ {
+ _SEH2_TRY
+ {
+ ProbeForRead((PVOID)lpmsg,
+ sizeof(MSG),
+ 1);
+ RtlCopyMemory( &Msg,
+ (PVOID)lpmsg,
+ sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+ }
+ else
+ RETURN( FALSE);
+
+ if (BadChk) RETURN( FALSE);
+
+ if ( ISITHOOKED(WH_SYSMSGFILTER) &&
+ co_HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)&Msg))
+ {
+ Ret = TRUE;
+ }
+ else
+ {
+ if ( ISITHOOKED(WH_MSGFILTER) )
+ {
+ Ret = co_HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)&Msg);
+ }
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)lpmsg,
+ sizeof(MSG),
+ 1);
+ RtlCopyMemory((PVOID)lpmsg,
+ &Msg,
+ sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+ if (BadChk) RETURN( FALSE);
+ RETURN( Ret)
+
+CLEANUP:
+ DPRINT("Leave NtUserCallMsgFilter. ret=%i\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+LRESULT APIENTRY
+NtUserDispatchMessage(PMSG UnsafeMsgInfo)
+{
+ LRESULT Res = 0;
+ BOOL Hit = FALSE;
+ MSG SafeMsg;
+
+ UserEnterExclusive();
+ _SEH2_TRY
+ {
+ ProbeForRead(UnsafeMsgInfo, sizeof(MSG), 1);
+ RtlCopyMemory(&SafeMsg, UnsafeMsgInfo, sizeof(MSG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Hit = TRUE;
+ }
+ _SEH2_END;
+
+ if (!Hit) Res = IntDispatchMessage(&SafeMsg);
+
+ UserLeave();
+ return Res;
+}
+
+
+BOOL APIENTRY
+NtUserTranslateMessage(LPMSG lpMsg,
+ UINT flags)
+{
+ NTSTATUS Status;
+ MSG SafeMsg;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserTranslateMessage\n");
+ UserEnterExclusive();
+
+ Status = MmCopyFromCaller(&SafeMsg, lpMsg, sizeof(MSG));
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( FALSE);
+ }
+
+ RETURN( IntTranslateKbdMessage(&SafeMsg, flags));
+
+CLEANUP:
+ DPRINT("Leave NtUserTranslateMessage: ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+BOOL APIENTRY
+NtUserMessageCall(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ ULONG_PTR ResultInfo,
+ DWORD dwType, // fnID?
+ BOOL Ansi)
+{
+ LRESULT lResult = 0;
+ BOOL Ret = FALSE;
+ BOOL BadChk = FALSE;
+ PWINDOW_OBJECT Window = NULL;
+ USER_REFERENCE_ENTRY Ref;
+
+ UserEnterExclusive();
+
+ /* Validate input */
+ if (hWnd && (hWnd != INVALID_HANDLE_VALUE) && !(Window = UserGetWindowObject(hWnd)))
+ {
+ UserLeave();
+ return FALSE;
+ }
+ switch(dwType)
+ {
+ case FNID_DEFWINDOWPROC:
+ UserRefObjectCo(Window, &Ref);
+ lResult = IntDefWindowProc(Window, Msg, wParam, lParam, Ansi);
+ Ret = TRUE;
+ UserDerefObjectCo(Window);
+ break;
+ case FNID_SENDNOTIFYMESSAGE:
+ Ret = UserSendNotifyMessage(hWnd, Msg, wParam, lParam);
+ break;
+ case FNID_BROADCASTSYSTEMMESSAGE:
+ {
+ BROADCASTPARM parm;
+ DWORD_PTR RetVal = 0;
+
+ if (ResultInfo)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)ResultInfo,
+ sizeof(BROADCASTPARM),
+ 1);
+ RtlCopyMemory(&parm, (PVOID)ResultInfo, sizeof(BROADCASTPARM));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+ if (BadChk) break;
+ }
+ else
+ break;
+
+ if ( parm.recipients & BSM_ALLDESKTOPS ||
+ parm.recipients == BSM_ALLCOMPONENTS )
+ {
+ }
+ else if (parm.recipients & BSM_APPLICATIONS)
+ {
+ if (parm.flags & BSF_QUERY)
+ {
+ if (parm.flags & BSF_FORCEIFHUNG || parm.flags & BSF_NOHANG)
+ {
+ co_IntSendMessageTimeout( HWND_BROADCAST,
+ Msg,
+ wParam,
+ lParam,
+ SMTO_ABORTIFHUNG,
+ 2000,
+ &RetVal);
+ }
+ else if (parm.flags & BSF_NOTIMEOUTIFNOTHUNG)
+ {
+ co_IntSendMessageTimeout( HWND_BROADCAST,
+ Msg,
+ wParam,
+ lParam,
+ SMTO_NOTIMEOUTIFNOTHUNG,
+ 2000,
+ &RetVal);
+ }
+ else
+ {
+ co_IntSendMessageTimeout( HWND_BROADCAST,
+ Msg,
+ wParam,
+ lParam,
+ SMTO_NORMAL,
+ 2000,
+ &RetVal);
+ }
+ }
+ else if (parm.flags & BSF_POSTMESSAGE)
+ {
+ Ret = UserPostMessage(HWND_BROADCAST, Msg, wParam, lParam);
+ }
+ else if ( parm.flags & BSF_SENDNOTIFYMESSAGE)
+ {
+ Ret = UserSendNotifyMessage(HWND_BROADCAST, Msg, wParam, lParam);
+ }
+ }
+ }
+ break;
+ case FNID_SENDMESSAGECALLBACK:
+ break;
+ // CallNextHook bypass.
+ case FNID_CALLWNDPROC:
+ case FNID_CALLWNDPROCRET:
+ {
+ PCLIENTINFO ClientInfo = GetWin32ClientInfo();
+ PHOOK NextObj, Hook = ClientInfo->phkCurrent;
+
+ if (!ClientInfo || !Hook) break;
+
+ UserReferenceObject(Hook);
+
+ if (Hook->Thread && (Hook->Thread != PsGetCurrentThread()))
+ {
+ UserDereferenceObject(Hook);
+ break;
+ }
+
+ NextObj = IntGetNextHook(Hook);
+ ClientInfo->phkCurrent = NextObj;
+
+ if ( Hook->HookId == WH_CALLWNDPROC)
+ {
+ CWPSTRUCT CWP;
+ CWP.hwnd = hWnd;
+ CWP.message = Msg;
+ CWP.wParam = wParam;
+ CWP.lParam = lParam;
+ DPRINT("WH_CALLWNDPROC: Hook %x NextHook %x\n", Hook, NextObj );
+
+ lResult = co_IntCallHookProc( Hook->HookId,
+ HC_ACTION,
+ ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
+ (LPARAM)&CWP,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+ else
+ {
+ CWPRETSTRUCT CWPR;
+ CWPR.hwnd = hWnd;
+ CWPR.message = Msg;
+ CWPR.wParam = wParam;
+ CWPR.lParam = lParam;
+ CWPR.lResult = ClientInfo->dwHookData;
+
+ lResult = co_IntCallHookProc( Hook->HookId,
+ HC_ACTION,
+ ((ClientInfo->CI_flags & CI_CURTHPRHOOK) ? 1 : 0),
+ (LPARAM)&CWPR,
+ Hook->Proc,
+ Hook->Ansi,
+ &Hook->ModuleName);
+ }
+ UserDereferenceObject(Hook);
+ lResult = (LRESULT) NextObj;
+ }
+ break;
+ }
+
+ switch(dwType)
+ {
+ case FNID_DEFWINDOWPROC:
+ case FNID_CALLWNDPROC:
+ case FNID_CALLWNDPROCRET:
+ if (ResultInfo)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite((PVOID)ResultInfo, sizeof(LRESULT), 1);
+ RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(LRESULT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BadChk = TRUE;
+ }
+ _SEH2_END;
+ }
+ break;
+ default:
+ break;
+ }
+
+ UserLeave();
+
+ return BadChk ? FALSE : Ret;
+}
+
+#define INFINITE 0xFFFFFFFF
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
+DWORD
+APIENTRY
+NtUserWaitForInputIdle(
+ IN HANDLE hProcess,
+ IN DWORD dwMilliseconds,
+ IN BOOL Unknown2)
+{
+ PEPROCESS Process;
+ PPROCESSINFO W32Process;
+ NTSTATUS Status;
+ HANDLE Handles[2];
+ LARGE_INTEGER Timeout;
+ ULONGLONG StartTime, Run, Elapsed = 0;
+
+ UserEnterExclusive();
+
+ Status = ObReferenceObjectByHandle(hProcess,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ UserMode,
+ (PVOID*)&Process,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ UserLeave();
+ SetLastNtError(Status);
+ return WAIT_FAILED;
+ }
+
+ W32Process = (PPROCESSINFO)Process->Win32Process;
+ if (!W32Process)
+ {
+ ObDereferenceObject(Process);
+ UserLeave();
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return WAIT_FAILED;
+ }
+
+ EngCreateEvent((PEVENT *)&W32Process->InputIdleEvent);
+
+ Handles[0] = Process;
+ Handles[1] = W32Process->InputIdleEvent;
+
+ if (!Handles[1])
+ {
+ ObDereferenceObject(Process);
+ UserLeave();
+ return STATUS_SUCCESS; /* no event to wait on */
+ }
+
+ StartTime = EngGetTickCount();
+
+ Run = dwMilliseconds;
+
+ DPRINT("WFII: waiting for %p\n", Handles[1] );
+ do
+ {
+ Timeout.QuadPart = Run - Elapsed;
+ UserLeave();
+ Status = KeWaitForMultipleObjects( 2,
+ Handles,
+ WaitAny,
+ UserRequest,
+ UserMode,
+ FALSE,
+ dwMilliseconds == INFINITE ? NULL : &Timeout,
+ NULL);
+ UserEnterExclusive();
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ Status = WAIT_FAILED;
+ goto WaitExit;
+ }
+
+ switch (Status)
+ {
+ case STATUS_WAIT_0:
+ Status = WAIT_FAILED;
+ goto WaitExit;
+
+ case STATUS_WAIT_2:
+ {
+ USER_MESSAGE Msg;
+ co_IntPeekMessage( &Msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE );
+ break;
+ }
+
+ case STATUS_USER_APC:
+ case STATUS_ALERTED:
+ case STATUS_TIMEOUT:
+ DPRINT1("WFII: timeout\n");
+ Status = STATUS_TIMEOUT;
+ goto WaitExit;
+
+ default:
+ DPRINT1("WFII: finished\n");
+ Status = STATUS_SUCCESS;
+ goto WaitExit;
+ }
+
+ if (dwMilliseconds != INFINITE)
+ {
+ Elapsed = EngGetTickCount() - StartTime;
+
+ if (Elapsed > Run)
+ Status = STATUS_TIMEOUT;
+ break;
+ }
+ }
+ while (1);
+
+WaitExit:
+ if (W32Process->InputIdleEvent)
+ {
+ EngFreeMem((PVOID)W32Process->InputIdleEvent);
+ W32Process->InputIdleEvent = NULL;
+ }
+ ObDereferenceObject(Process);
+ UserLeave();
+ return Status;
+}
+
+/* EOF */