views:

834

answers:

4

I need to draw a line (with the mouse) over everything with C#. I can get a Graphics object of the desktop window by using P/Invoke:

DesktopGraphics = Graphics.FromHdc(GetDC(IntPtr.Zero));

However, anything I draw using this graphics object is only showing on the left monitor, and nothing on the right monitor. It doesn't fail or anything, it just doesn't show.

After I create the Graphics object, it shows the visible clip region to be 1680 x 1050 which is the resolution of my left monitor. I can only assume that it's only getting a device context for the left monitor. Is their a way to get the device context for both (or any number) monitors?


EDIT 3/7/2009: Additional information about the fix I used.

I used the fix provided by colithium to come up with the following code for creating a graphics object for each monitor as well as a way to store the offset so that I can translate global mouse points to valid points on the graphics surface.

private void InitializeGraphics()
{
    // Create graphics for each display using compatibility mode
    CompatibilitySurfaces = Screen.AllScreens.Select(s => new CompatibilitySurface()
     {
      SurfaceGraphics = Graphics.FromHdc(CreateDC(null, s.DeviceName, null, IntPtr.Zero)),
      Offset = new Size(s.Bounds.Location)
     }).ToArray();
}

private class CompatibilitySurface : IDisposable
{
    public Graphics SurfaceGraphics = null;
    public Size Offset = default(Size);

    public PointF[] OffsetPoints(PointF[] Points)
    {
        return Points.Select(p => PointF.Subtract(p, Offset)).ToArray();
    }

    public void Dispose()
    {
        if (SurfaceGraphics != null)
         SurfaceGraphics.Dispose();
    }
}

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

Following URL to get EnumDisplayMonitor may solve your problem

MSDN

To retrieve information about all of the display monitors, use code like this:

EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0); One more URL given at MSJ

lakshmanaraj
You were also correct. I used EnumDisplayMonitors to get the device name which I then handed off to CreateDC. Thanks!
Dylan Vester
+1  A: 

Here is a link to another person that had the same problem. It was solved with a call to:

CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL)

which will return a DC to all monitors.

colithium
A: 

Hello, I don't manage to draw in my second screen using EnumDisplayMonitors and CreateDC. I've obtained the MonitorInfo struct with the EnumDisplayMonitors's callback, but how to use it with CreateDC ? I try to draw into a Graphics Object using Graphics.FromHDC and the DrawImage method.

Edit: Hi Dylan, thanks for the code sample. But it doesn't work for me ... it always draw in the main monitor :/ Here is the code I used with yours :

Graphics g = CompatibilitySurfaces[1].SurfaceGraphics; g.DrawImage(Image.FromFile(@"C:\toto.jpg"), 0, 0);

I've managed to write in my second monitor using the Bitblt Win32 Api, with the same hdc ! Unfortunately it is very complicated with the Win32 Api, and the transparent 32 bits bitmap doesn't work ..

Do you have a code working with the DrawImage method ?

Dylan, could you give me an example of your code ?
Hi there, to get it to draw on the second monitor you'll need to translate the point where you're drawing the image to include the offset of the monitor you're trying to draw on.Just run the 0,0 point through the CompatibilitySurfaces[1].OffsetPoints(new PointF[] { new PointF(0,0) });
Dylan Vester
Wait, maybe I'm confused. Try it, but it may not be what you're looking for. Here is the code I use to draw lines on the screen.foreach (CompatibilitySurface surface in CompatibilitySurfaces) surface.SurfaceGraphics.DrawLines(DrawingPen, surface.OffsetPoints(Stroke));
Dylan Vester
Hi Dylan, I tried your code with the foreach, but it doesn't work : it draws lines on the main screen once again ... It's annoying :(What I'm looking is simply draw an bitmap in my second monitor. The main monitor offset is (0,0), and the 2nd is (1280,0).
Even if I draw at (1200,0) in my 2nd monitor, the bitmap is split : left part is drawn in the main monitor while the right one is not drawn.
A: 

I've tried using Dylan's method with DrawImage and it does work in most cases, but oddly breaks when monitor1 is to the right of monitor2 and monitor1 is assigned as my main monitor and in no other combination of location or main monitor assignment. By breaks I mean the image will draw to monitor2 but not monitor1 which sounds similar to Nico's problem. Also (0, 0) seems to be the top left corner of whichever monitor I created the device context from instead of being in some fixed location relative to my desktop; meaning that I don't do any offsetting. Is anyone else seeing this behavior?