views:

509

answers:

5

I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.

The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.

Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.

How would I do it?

Example code: http://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c

A: 

This is difficult to do correctly.

It will be far easier, and more reliable, to make your own borderless form instead.

SLaks
+3  A: 

When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.

There are a couple of options, depending upon what you want to achieve:

  1. create a borderless, possibly non-rectangular window. (Use SetWindowRgn to make a window non-rectangular.) You can make this a child of the desktop window.
  2. subclass the desktop window. This is not straightforward, and involves injecting a DLL into the Explorer.exe process.
mdma
A: 

You can create the appearance of drawing to the desktop by taking a screenshot, displaying the bitmap in your own, maximized app and using standard .NET drawing over a "desktop background."

I have seen a number of apps such as screen savers use this kind of technique when they want to make it look like your own desktop is being altered.

Paul Sasik
A: 

To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.

As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).

As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).

Alex K.
+1  A: 

I posted two solutions for a similar requirement here

Basically you have two options.

1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.

Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates 

using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) 
{         
  g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20); 
}

2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.

For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.

BackColor = Color.LightGreen; 
TransparencyKey = Color.LightGreen; 
Chris Taylor