Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing to screen directly on top of all window [duplicate]

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: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c

like image 343
Lazlo Avatar asked May 25 '10 14:05

Lazlo


4 Answers

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; 
like image 158
Chris Taylor Avatar answered Sep 28 '22 00:09

Chris Taylor


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.
like image 21
mdma Avatar answered Sep 28 '22 01:09

mdma


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).

like image 30
Alex K. Avatar answered Sep 28 '22 02:09

Alex K.


This is difficult to do correctly.

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

like image 45
SLaks Avatar answered Sep 28 '22 00:09

SLaks