PrintPreview margins not displaying

  • Thread starter Thread starter emorgoch
  • Start date Start date
E

emorgoch

I have a .NET 1.1 windows form ap from which I'm trying to allow the
user to print out the form. I use the bitblt function in gdi32.dll to
capture the image of the form and turn it into a bitmap for printing.
The problem that I'm currently having is that the print preview dialog
on the form does not show the page margins when it displays the
preview. Relevent code is attached.

As well, if someone know how I can properly scale the image to fin on
to the page if it's too big, that would be a great help too.


Thanks,
Evan

Bitmap formImage;
private PrintDocument pd = new PrintDocument ();
private PrintPreviewDialog printPreviewDialog = new
PrintPreviewDialog();
private System.Windows.Forms.PageSetupDialog pageSetupDialog;
printPreviewDialog.Document = this.pd;

private void printMenuItem_Click(object sender, System.EventArgs e) {
this.GetFormImage();
pd.Print();
}


private void pd_PrintPage (object sender,
System.Drawing.Printing.PrintPageEventArgs e) {
e.Graphics.DrawImage (this.formImage, 0, 0);
}


private void GetFormImage() {
Graphics mygraphics = this.CreateGraphics();
this.formImage = new Bitmap (this.Size.Width, this.Size.Height,
mygraphics);
Graphics memoryGraphics = Graphics.FromImage(this.formImage);

int bordersize = (this.Width - this.ClientRectangle.Width) / 2;
int titlebarHeight = (this.Height - this.ClientRectangle.Height) -
bordersize;

IntPtr sourceHandle = mygraphics.GetHdc();
IntPtr destinationHandle = memoryGraphics.GetHdc();
BitBlt(destinationHandle, pd.DefaultPageSettings.Bounds.X,
pd.DefaultPageSettings.Bounds.Y,
this.Width, this.Height, sourceHandle, 0 - bordersize, 0 -
titlebarHeight, 13369376);
mygraphics.ReleaseHdc(sourceHandle);
memoryGraphics.ReleaseHdc(destinationHandle);
}

[DllImport("gdi32.dll")]
static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int
nWidth,
int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);


private void printPreviewMenuItem_Click(object sender,
System.EventArgs e) {
this.GetFormImage();
printPreviewDialog.ShowDialog();
}

private void pageSetupMenuItem_Click(object sender, System.EventArgs
e) {
this.GetFormImage();
this.pageSetupDialog.ShowDialog();
}
 
Thanks for you attemped answer Ciaran, but I don't think you understand
my problem. The problem is that in the print preview dialog, the user
defined margins (set in the Page setup dialog) are not displayed, and
the image of the form appears in very upper left corner of the preivew
page. But when printed, the image is moved according to the margins.

The full code for an example application is included below. As for your
suggestions, they are not applicable, as this is for a .NET 1.1 Windows
form application, and the items you suggest are only available in .NET
2.0. Thank you for your suggestions though. On a side note, a nearly
identical sample application built in VS2005 on .NET 2.0 does not show
the same behavior.

Thanks
Evan

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace SimplePrintApp
{

public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button1;
private System.Drawing.Printing.PrintDocument printDocument1;
private System.Windows.Forms.PageSetupDialog pageSetupDialog1;
private System.Windows.Forms.PrintPreviewDialog printPreviewDialog1;
private System.Drawing.Bitmap formImage;
private System.ComponentModel.Container components = null;

public Form1() {
InitializeComponent();
}

[DllImport("gdi32.dll")]
static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int
nWidth,
int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);

public void GetFormImage() {
Graphics mygraphics = this.CreateGraphics();
Bitmap tempImage = new Bitmap(this.Size.Width, this.Size.Height,
mygraphics);
Graphics memGraphics = Graphics.FromImage(tempImage);
IntPtr dc1 = mygraphics.GetHdc();
IntPtr dc2 = memGraphics.GetHdc();
BitBlt (dc2, 0, 0, this.ClientRectangle.Width,
this.ClientRectangle.Height, dc1, 0, 0, 13369376);
mygraphics.ReleaseHdc(dc1);
memGraphics.ReleaseHdc(dc2);

this.formImage = tempImage;
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new
System.Resources.ResourceManager(typeof(Form1));
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.printDocument1 = new System.Drawing.Printing.PrintDocument();
this.pageSetupDialog1 = new System.Windows.Forms.PageSetupDialog();
this.printPreviewDialog1 = new
System.Windows.Forms.PrintPreviewDialog();
this.SuspendLayout();
//
// button2
//
this.button2.Location = new System.Drawing.Point(72, 80);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(120, 23);
this.button2.TabIndex = 0;
this.button2.Text = "Print Preview";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(72, 128);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(120, 23);
this.button3.TabIndex = 1;
this.button3.Text = "Print";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button1
//
this.button1.Location = new System.Drawing.Point(72, 32);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(120, 23);
this.button1.TabIndex = 2;
this.button1.Text = "Page Setup";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// printDocument1
//
this.printDocument1.OriginAtMargins = true;
this.printDocument1.PrintPage += new
System.Drawing.Printing.PrintPageEventHandler(this.printDocument1_PrintPage);
//
// pageSetupDialog1
//
this.pageSetupDialog1.Document = this.printDocument1;
//
// printPreviewDialog1
//
this.printPreviewDialog1.AutoScrollMargin = new
System.Drawing.Size(0, 0);
this.printPreviewDialog1.AutoScrollMinSize = new
System.Drawing.Size(0, 0);
this.printPreviewDialog1.ClientSize = new System.Drawing.Size(400,
300);
this.printPreviewDialog1.Document = this.printDocument1;
this.printPreviewDialog1.Enabled = true;
this.printPreviewDialog1.Icon =
((System.Drawing.Icon)(resources.GetObject("printPreviewDialog1.Icon")));
this.printPreviewDialog1.Location = new System.Drawing.Point(290,
17);
this.printPreviewDialog1.MinimumSize = new System.Drawing.Size(375,
250);
this.printPreviewDialog1.Name = "printPreviewDialog1";
this.printPreviewDialog1.TransparencyKey =
System.Drawing.Color.Empty;
this.printPreviewDialog1.Visible = false;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button1);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void printDocument1_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e) {
e.Graphics.DrawImage (this.formImage, 0, 0);
}

private void button1_Click(object sender, System.EventArgs e) {
this.GetFormImage();
this.pageSetupDialog1.ShowDialog();
}

private void button2_Click(object sender, System.EventArgs e) {
this.GetFormImage();
this.printPreviewDialog1.ShowDialog();
}

private void button3_Click(object sender, System.EventArgs e) {
this.printDocument1.Print();
}
}
}
 
emorgoch said:
Thanks for you attemped answer Ciaran, but I don't think you understand
my problem. The problem is that in the print preview dialog, the user
defined margins (set in the Page setup dialog) are not displayed, and
the image of the form appears in very upper left corner of the preivew
page. But when printed, the image is moved according to the margins.

The full code for an example application is included below. As for your
suggestions, they are not applicable, as this is for a .NET 1.1 Windows
form application, and the items you suggest are only available in .NET
2.0. Thank you for your suggestions though. On a side note, a nearly
identical sample application built in VS2005 on .NET 2.0 does not show
the same behavior.

Two points of interest.

First, when printing to either print preview or the printer, it is up
to _you_ to respect the page margins. If you draw the graphic at point
0,0 as you're doing, then Windows will put the graphic at point 0,0,
margins or no margins. You need to use e.MarginBounds and do the
appropriate hundredths-of-inch-to-pixels math to figure out where the
drawing rectangle is on your Graphics object. There's probably a quick
and easy way to do it, but in .NET 1.1 I found that I had to dive into
calling GDI32 routines.

Second, it's not that easy. (It never is with Windows, is it?) When you
print to a real printer (as opposed to print preview), the printer uses
the top corner of its _printable area_ as point 0,0. In other words, if
the printer can't print the left 0.5 inch and top 0.5 inch of the page,
then 0,0 becomes the point a half inch in from the left and a half inch
down from the top. All of your careful margin calculations are now too
large on the left and top by a half inch. So, as Ciaran pointed out,
you have to subtract the printer's hard margins from your soft margins
to know where your top, left page corner should be. Again, I had to
call GDI32 routines to get the printer's hard margins, and put code in
my printing routine to decide whether I was printing to print preview
(use user margins as stated), or to a printer (use user margines less
hard margins). It's all rather ugly, isn't it?

Here is a bit of my code where I do this, although the GDI32 calls are
elsewhere:

private bool PrintAPage(PrintPageEventArgs ev, bool reallyPrint)
{
float yPos = 0.0F;
int count;
Graphics g = ev.Graphics;

// The following is a trick to discover whether we're
// printing to a real printer or to print preview,
// courtesy of Kevin Yu of Microsoft, via the UseNet.
// It relies on the fact that printers clip the visible
// area of the page to the page size or less because
// of unprintable area, whereas print preview does not.
// We need to know this because the printer metrics we
// have are for the final destination printer, not for
// print preview, which has no edges of the page where
// it cannot draw. If we just use the print metrics that
// we have from the graphics object to determine margins,
// then the margins will be too small in print preview,
// but correct on the printer.
bool isToPrintPreview;
if (g.VisibleClipBounds.Width > ev.PageBounds.Width)
{
isToPrintPreview = true;
}
else
{
isToPrintPreview = false;
}
Rectangle printArea;
try
{
this.docProperties.PrintMetrics =
Agama.GDI32.GDI32.GetPrinterMetrics(g);
if (isToPrintPreview)
{
printArea = this.docProperties.ActualMarginsRectangle;
}
else
{
printArea = this.docProperties.PrintingRectangle;
}
}
catch (Agama.GDI32.InvalidPrinterMetricsException)
{
// Margins as given are invalid for this printer /
// paper combination. Use margins of zero instead
printArea = Agama.GDI32.GDI32.PrintAreaForPrinter(g, new
Margins(0, 0, 0, 0));
}

...
}
 
Back
Top