Mirror driver - icons aren't getting print in multi-monitor environment

Hi,

this thread relates to http://www.osronline.com/showThread.cfm?link=160595
Currently I’m working on the (unfortunately) still existing problem with the invisible icons again. I have done a lot of research on the internet but I did not find anything helpful. So I decided to re-implement a simple version of the driver.

In a first version the driver supports the following DrvXxx functions:

  • DrvAssertMode
  • DrvEnablePDEV, DrvCompletePDEV, DrvDisablePDEV
  • DrvEnableSurface, DrvDisableSurface
  • DrvEscape
  • DrvDisableDriver
  • DrvTextOut, DrvBitBlt, DrvCopyBits, DrvStrokePath, DrvAlphaBlend

In DrvEnablePDEV() the DEVINFO-struct is initialized with:
flGraphicsCaps = GCAPS_LAYERED
flGraphicsCaps2 = GCAPS2_ALPHACURSOR

In DrvEnableSurface() two surfaces are created. One engine managed surface EngCreateBitmap, EngAssociateSurface(no hooks)) and one device managed surface (EngCreateDeviceSurface, EngModifySurface(lDelta=0,pvScan0=NULL)). The hooks for the device managed surface are HOOK_BITBLT|HOOK_COPYBITS|HOOK_STROKEPATH|HOOK_TEXTOUT|HOOK_ALPHABLEND. DrvEnableSurface returns the handle to the device managed surface.

If the driver gets called to render something on the device managed surface (DrvTextOut, DrvBitBlt, DrvCopyBits, DrvStrokePath, DrvAlphaBlend) the driver just punts the call back to GDI with the surface(s) modified pointing to the engine managed surface.

I have also created a little user mode test-application which calls ExtEscape() to get a copy of the engine managed surface every 50 ms. The application blits a part of the surface to its client area.

Some more information about the test-machine:

  • Intel Celeron M 1Ghz with 2GB of RAM (also tested with Core Duo 2Ghz - same problems)
  • Windows XP SP 2
  • Intel 855 Embedded Graphics Controller (Dual Head)

As long as the second output of the graphics card is disabled, everything works as expected. The test-application gets a perfect copy of the primary display (including the mouse pointer). After enabling the second output of the graphics card, some desktop icons on the mirror surface disappear (as described in the preceding postings).

The second version of the driver:
More or less by chance I implemented DrvSetPointerShape() and DrvMovePointer() with the GCAPS_PANNING-flag set. DrvSetPointerShape() just returns SPS_ACCEPT_NOEXCLUDE without doing anything.
DrvMovePointer() does nothing, too. In this combination all icons get print on the mirror surface, even if the second output of the graphics card is enabled! As expected in this combination there is no mouse pointer visible on the mirror surface. So, in the next step, I let the driver call EngSetPointerShape() from within DrvSetPointerShape() to ask GDI to simulate the pointer. This ends in the problem with the invisible icons again. ;-(

Have you any ideas or suggestions? Am I missing somthing?

Markus

Hello,

first, you should hook and implement DrvTransparentBlt (null function pointer dereference will occur otherwise), even though the documentation states that it is optional.

second, I also found some new problems arisng when second display became active. I had hard time processing clipping regions (pitfalls in the API) as well as finding out how to exactly manage the surfaces (not to expose an engine-managed surface to the GDI all the time).

Make sure you trace your hooks well.

Hi and thank you for your answer,

in DrvTextOut, DrvBitBlt, DrvCopyBits, DrvStrokePath and DrvAlphaBlend I check the dhsurf member of the SURFOBJs. As long as I did not support DrvCreateDeviceBitmap/DrvDeleteDeviceBitmap the dhsurf member should only be non-NULL for my driver managed surface, right? In such cases I pass down the engine mananged surface to the EngXxx function.

Markus

Hi,

I said “not to expose an engine-managed surface to the GDI all the time” – it’s not precise. What I had in mind is that one must not expose a surface to the GDI where the GDI knows how to draw on. Because if it does know, then it tends to bypass hooks (no matter how thorough hooks are set) under certain circumstances.
So I ended up with two surfaces of different kinds: a “device-managed” that the GDI cannot draw on (nothing is being drawn there, it’s just a “shield”) and a DIB-surface where it does. Hooks are being called with the first one, then the second one is locked, drawn on and unlocked. I think that this is even described in detail somewhere in the WDK docs.

I see these scenarios:
1.) the icons get drawn on the surface (but you don’t notice)
2.) you fail to draw the icons (in your hooks)
3.) GDI does not even try drawing the icons

You’ll need to know which is the case before looking further.

Note: icons might be drawn with transparency effects. If you don’t hook TransparentBlt, then the GDI would call copybits from your surface to its internal, draw on the internal, do copybits from internal to yours back. If you fail to implement copybits correctly and one of the steps fails then you will lose stuff.

BTW, as a direct competitor (some call us “the big S”) I shouldn’t be giving these hints to you :). The best tip when it comes to mirror drivers is to go and buy the dfMirage sources and save yourself time and money.

Hi,

sorry for the late response, but I was busy with other tasks…

As decribed I create two surfaces, too. One device managed (DrvEnableSurface() returns the handle to this surface) and one engine managed onto which the drawings are done within the hooked (for the device managed surface) DrvXxx functions. As long as no other graphics device is attached to the desktop, everythings works fine. The problems only occur if one or more other devices expand the windows desktop. I have no idea what caused it. Maybe you have any idea?

Today I’ve tried something different. I’ve done it the other way round:
In DrvEnableSurface() I create only a engine managed surface ( EngCreateBitmap() followed by EngAssocisateSuface(no hooks) ). DrvEnableSurface() returns the handle to this engine managed surface. The driver does not support any (drawing-)DrvXxx function. This means, that GDI will do all the drawing by itself and render directly to the engine managed surface. My test-application calls ExtEscape() to get a copy of the engine managed surface.
In this scenario the driver shows exactly the same behavior: with only the primary graphics device enabled, everything is ok. With a additional graphics device enabled, the icons aren’t on the surface, too! It seams as if the GDI does not draw the icons in an multimonitor environment. Why so?
Is there anything special to do in DrvEnablePDEV()? Shouldn’t this problem have catched somebody’s eye?

Any help would be appreciated.

Markus

Well, then it’s apparently the third case, the GDI cannot draw the icons. It did not happen to me yet AFAIK. Reason for this is most likely that there is something wrong with your surface, maybe one of the many flags is not quite right, maybe the completely missing hooks (I don’t remember this being legal), maybe a required function is missing.

Have you tried other mirror drivers already, do they have similar issues on your system?

Hi,

depending on the type of surface the driver has to support a varying set of DrvXxx() functions (http://msdn.microsoft.com/en-us/library/ms797858.aspx). When DrvEnableSurface() returns a engine-managed surface with no hooks (this means that GDI does all the drawing by itself) the driver isn’t responsible for any drawing operation. If the driver manages its own surface the driver must also, at a minimum, support the following drawing functions:
DrvCopyBits(), DrvBitBlt(), DrvStrokePath(), DrvTextOut().

For the engine-managed surface (EngCreateBitmap() followed by EngAssociateSurface()) there aren’t so many flags to be set. Do you have special flags in mind?

Kind regards,

Markus

Hello,

what I had in mind were the GDIINFO flags that must be set in DrvEnablePDEV.
You say that behavior is different depending on how you handle cursor drawing. So apparently the non-hook functions are the reason of your problems.

I’m afraid I will not be a big help here because IIRC when I took over the mirror driver part the icon problems were already solved (rather accidentally I guess). FUY: we don’t draw the cursor on our surface.

Hi and thank you for your answer,

I don’t know how often I’ve checked any flags in the mirror driver. However, I will check this flags again… :wink:

I can’t imagine hat the non-hooked functions are the reason for the problems. Hooking all possible functions results in the same behavior. The key point is that the behavior changes depending on if there is another graphics device attached to the desktop or not.

Markus

Have you tried running a checked image already? Can you reproduce the behavior in a VM? How many bits per pixel do you have?
Get IDA and the decompiler and see how far you can go with the checked Windows DLLs and the according PDBs. You will need to know how the icons are drawn when it succeeds and see what’s wrong when it fails. That’s the hard way, but I don’t see any easier options at the moment.