Mirror Driver Tracking Changes Issue

Hello,

To begin with, I’m aware of the diminishing prevalence of mirror drivers - this is more of a learning exercise than anything. I’ve implemented a mirror driver, loosely based off of the DDK example. This only implements the routines for a remote display driver and no others, and renders to a shared memory map file that is consumed in a user-mode application. Changes are tracked using a combination of the DrvEscape routine and the same shared memory used for the framebuffer.

The question relates to the DrvBitBlt routine. I use this to populate an internal buffer of changes, later consumed by a user-mode application. In that routine, if the CLIPOBJ (pco) is NULL, then I just populate the changes buffer with the prclDst RECTL, otherwise, the following routine is called, utilising the iDComplexity field to determine the clipping regions. EngBitBlt is finally called too. This works well and as expected for the vast majority of changes, but doesn’t seem to correctly identify changes in the title bar in Windows 7. All changes are rendered on a surface in a user-mode app; however, the image linked below shows the result of maximising a window - part of the title bar is cut off. The black part shown is the black desktop wallpaper that was previously visible. Hovering over or clicking the minimise, maximise or close buttons aren’t detected either.

Example of the issue:
https://imgur.com/a/MDFMDqX

Any help is greatly appreciated. Thanks,

Jamie

The code in question:

VOID AddClipRegion(
INTERNAL_CHANGES_BUFFER* cb,
CLIPOBJ* pco,
RECTL* dest)
{
if (!pco)
{
return;
}

switch (pco->iDComplexity)
{
	case DC_TRIVIAL:
	{
		// The clip region is not used, add the destination bounds as is.
		AddChange(cb, dest);

		break;
	}
	case DC_RECT:
	{
		// There is one clip region.

		RECTL bounds = { 0 };
		bounds.left = dest->left;
		bounds.right = dest->right;
		bounds.top = dest->top;
		bounds.bottom = dest->bottom;

		if (bounds.left < pco->rclBounds.left)
		{
			bounds.left = pco->rclBounds.left;
		}
		if (bounds.right > pco->rclBounds.right)
		{
			bounds.right = pco->rclBounds.right;
		}
		if (bounds.top < pco->rclBounds.top)
		{
			bounds.top = pco->rclBounds.top;
		}
		if (bounds.bottom > pco->rclBounds.bottom)
		{
			bounds.bottom = pco->rclBounds.bottom;
		}

		if ((bounds.right - bounds.left) <= 0 || (bounds.bottom - bounds.top) <= 0)
		{
			return;
		}

		AddChange(cb, &bounds);

		break;
	}
	case DC_COMPLEX:
	{
		BOOL overflow;
		ENUMRECTS crs;

		CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);

		do
		{
			overflow = CLIPOBJ_bEnum(pco, sizeof(crs), (ULONG*)&crs);

			for (RECTL* cr = &crs.arcl[0]; crs.c != 0; cr++, crs.c--)
			{
				RECTL bounds = { 0 };
				bounds.left = dest->left;
				bounds.right = dest->right;
				bounds.top = dest->top;
				bounds.bottom = dest->bottom;

				if (bounds.left < cr->left)
				{
					bounds.left = cr->left;
				}
				if (bounds.right > cr->right)
				{
					bounds.right = cr->right;
				}
				if (bounds.top < cr->top)
				{
					bounds.top = cr->top;
				}
				if (bounds.bottom > cr->bottom)
				{
					bounds.bottom = cr->bottom;
				}

				if ((bounds.right - bounds.left) <= 0 || (bounds.bottom - bounds.top) <= 0)
				{
					continue;
				}

				AddChange(cb, &bounds);
			}
		} while (overflow);

		break;
	}
}

}

Are you sure that’s being drawn through DrvBitBlt? In the early days, at least, when GDI wanted to fill a rectangular region quickly, it called DrvTextOut with an opaquing rectangle but no text.

Thanks Tim! It turned out that it wasn’t DrvTextOut that was responsible for these missing parts, but DrvAlphaBlend. For those stuck on this issue, performing the same clipping (if any) as you would in DrvBitBlt provided the correct dirty regions. I assume (not tested as yet), that Windows 8+ doesn’t use DrvAlphaBlend for similar rendering in order to be compliant with the remote display driver specification.

Jamie