Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing over all windows on multiple monitors

Tags:

c#

desktop

gdi+

I am using the following code to draw on a single monitor:

Point cursorLocation;
NativeMethods.GetCursorPos(out cursorLocation);
Screen screen = Screen.FromPoint(cursorLocation);

Point h1 = new Point(screen.Bounds.Left, cursorLocation.Y);
Point h2 = new Point(screen.Bounds.Right, cursorLocation.Y);
Point v1 = new Point(cursorLocation.X, screen.Bounds.Top);
Point v2 = new Point(cursorLocation.X, screen.Bounds.Bottom);

using (Graphics graphics = Graphics.FromHwnd(NativeMethods.GetDesktopWindow())) {
    NativeMethods.SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
    graphics.DrawLine(Pens.Red, h1, h2);
    graphics.DrawLine(Pens.Red, v1, v2);
}

Natively, this should theoretically draw on either monitor. However, it only draws on the primary. So, to fix this I am getting the DC of all the displays and trying to do it this way.

IntPtr hdc = NativeMethods.CreateDC("DISPLAY", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
Graphics graphics = Graphics.FromHdc(hdc);
graphics.DrawLine(Pens.Red, h1, h2);
graphics.DrawLine(Pens.Red, v1, v2);
graphics.Dispose();
NativeMethods.ReleaseDC(IntPtr.Zero, hdc);

Go figure, this doesn't even draw to the screen at all. I have tried various overloads for CreateDC, as well as searched SO and other resources and I'm stumped.


Once this is resolved, anyone know how to get rid of flicker by refreshing the desktop using SHCHangeNotify? I'm only drawing two lines and it flickers like mad..)

like image 220
David Anderson Avatar asked Mar 30 '09 03:03

David Anderson


Video Answer


2 Answers

this worked for me. i used EnumDisplayDevices to fetch the names.

[DllImport("gdi32.dll")]
public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);

var hdc = CreateDC(@"\\.\DISPLAY1", "", "", IntPtr.Zero);
Graphics g = Graphics.FromHdc(hdc);
var pt = Cursor.Position;
g.DrawEllipse(Pens.BlueViolet, pt.X - 100, pt.Y - 100, 200, 200);

more info here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd145179(v=vs.85).aspx

like image 184
ColacX Avatar answered Oct 01 '22 04:10

ColacX


This is not an answer to your question but if you have no problem with it, I would recomment trying using WPF to solve this. I have played with other kind of desktop interaction like transparency and WPF is lightning fast compared to the GDI alternative.

You place your wpf application and resize it to fit all the area you need to be painting on. Then set it to transparent, and make sure its clickthrough (i think that is default on 100% transparency). That way as long as you dont have anything on this big WPF canvas/form all mouse events will click through to desktop.

Then just start painting on it. (i liked it because it was very easy to add effects to lines and images). Guaranteed no flickering.

Alternatively you could use the same scheme on normal Windows Forms instead.

This way you wont have to turn to GDI to do your work.

I think the only way you would be able to do this flickerfree as you are approaching it now, would be to hook into the window messaging on the desktops WM_PAINT and do your work there.

like image 43
Wolf5 Avatar answered Oct 01 '22 04:10

Wolf5