3

I'm printing my actived form (formMain) using CreateGraphics function as code below

Printing the Form (Visual C#)

Environment: windows 7 professional in classical mode, VisuaStudio 2008

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern long BitBlt (IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
private Bitmap memoryImage;
private void CaptureScreen()
{
   Graphics mygraphics = this.CreateGraphics();
   Size s = this.Size;
   memoryImage = new Bitmap(s.Width, s.Height, mygraphics);
   Graphics memoryGraphics = Graphics.FromImage(memoryImage);
   IntPtr dc1 = mygraphics.GetHdc();
   IntPtr dc2 = memoryGraphics.GetHdc();
   BitBlt(dc2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, dc1, 0, 0, 13369376);
   mygraphics.ReleaseHdc(dc1);
   memoryGraphics.ReleaseHdc(dc2);
}
private void printDocument1_PrintPage(System.Object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
   e.Graphics.DrawImage(memoryImage, 0, 0);
}
private void printButton_Click(System.Object sender, System.EventArgs e)
{
   if (MessageBox.Show("test", "test", MessageBoxButtons.YesNo) == DialogResult.Yes)
   {
        CaptureScreen();
        printDocument1.Print();
   }
}

case1: When MessageBox show by default location, formMain is can printed clearly Clearly

case 2: but, if using mouse to move messageBox out of default location, then the print's result is be dirty. It's now having messageBox (graph) include in mainForm.

Dirty

user1299527
  • 121
  • 1
  • 1
  • 5
  • This is what you get when you leak GDI handles. I doubt the snippet can really repro it, you'd have to click that button thousands of times. You'll need to describe what you are *really* doing. – Hans Passant Aug 12 '13 at 10:35
  • i do not have to click that thousands times. as Evidence. Simple using mouse to take confirm box out of default location. And then, do the print Action. You can Reproduction that – user1299527 Aug 12 '13 at 10:55
  • 1. click "print me" button, 2. when the confirm box occur, 3. using mouse to move confirm box to out of default location, 4.Click OK to confirm – user1299527 Aug 12 '13 at 10:59
  • @user1299527 I've tried this and it works OK for me. Can't reproduce your problem. BTW, do you have a `TextBox` or `RichTextBox` on your form? – King King Aug 12 '13 at 11:04
  • @user1299527 you should try displaying the `memoryImage` in a `PictureBox` instead, at least that's what I've tried and it worked like a charm. – King King Aug 12 '13 at 11:05
  • 1
    Getting the message box to *exactly* line up with the text box is a fantastic coincidence, I don't particularly believe in coincidences like that. Anyhoo, the diagnostic is that the window hasn't repainted itself yet before making the screenshot. That can happen on old Windows versions that don't have Aero, like XP. A counter-measure is to put `this.Update();` before the CaptureScreen() call. There are more things out of whack, not getting the text on the button to be anti-aliased is *very* strange as well. So is the very strange dithering of the background color. – Hans Passant Aug 12 '13 at 11:43
  • @KingKing , i'm sory about not tell you that i run my test in classical mode of windows. I just tested with windows 7 mode, and no problem. – user1299527 Aug 13 '13 at 00:37

2 Answers2

1

Instead of using the WinAPI directly (BitBlt, ...) try using this:

Bitmap bmp = new Bitmap(this.Width, this.Height);
this.DrawToBitmap(bmp, this.Bounds);
bmp.Save(@"c:\temp\test.png", System.Drawing.Imaging.ImageFormat.Png); // For testing

This should only draw the contents of your form.
I tested this with another top-most form with success.

Place it in your code:

private void CaptureScreen() {
    memoryImage = new Bitmap(this.Width, this.Height);
    this.DrawToBitmap(memoryImage, this.Bounds);
}
joe
  • 8,344
  • 9
  • 54
  • 80
  • I have tried your code with : mygraphics is from this.CreateGraphics();, S as mainform. But nothing change. Could you show me full code? – user1299527 Aug 12 '13 at 09:00
  • @user1299527: Sorry, just copied and pasted too fast. – joe Aug 12 '13 at 09:02
  • @user1299527: Leave your code as shown in your question. Then replace just the `CaptureScreen()` method with the one from my answer. (Hint: If you copy/paste code from anywhere, do not just copy it, try to understand *what* that code does and *why* its implemented like this) – joe Aug 12 '13 at 09:25
0

like XP. A counter-measure is to put this.Update();before the CaptureScreen() call.

i think my system is windows 7 , but with classical mode -> as windows xp

user1299527
  • 121
  • 1
  • 1
  • 5