Hace unos cuantos unos (bueno, unas semanas... que no encuentro tiempo para postear!!) necesitaba imprimir unos datos que se encontraban en un formulario y lo lógico sería usar reportes para hacerlo, pero por la falta de tiempo y por no haber trabajado reportes antes necesitaba una solución más rápida, entonces se me ocurrió imprimir el formulario y buscando por la red encontré este artículo en la knowledge base de Microsoft. Pues bien, en primer lugar lo que hice fue pasar ese código a C# y segundo hacer unas pequeñas variaciones al código para que la impresión del formulario se ajustara más a lo que deseaba. Para probarlo nos creamos un nuevo proyecto para una aplicación windows (en C#) y añadimos la siguiente clase al proyecto (extraída del articulo anterior):
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Printing;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public class Win32APICall
{
public const int DIB_RGB_COLORS = 0;
public const int BI_RGB = 0;
public const int WHITENESS = 16711778;
[DllImport("user32.dll",
EntryPoint = "PrintWindow",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern UInt32
PrintWindow(IntPtr hWnd, IntPtr hDC, int
dwFlags);
[DllImport("gdi32.dll",
EntryPoint = "CreateDIBSection",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern IntPtr
CreateDIBSection(IntPtr hdc, ref BITMAPINFOHEADER
pbmi,
Int32 iUsage, IntPtr
ppvBits, IntPtr hSection, Int32 dwOffset);
[DllImport("gdi32.dll",
EntryPoint = "PatBlt", SetLastError
= true, CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool PatBlt(IntPtr hDC, Int32
nXLeft, Int32 nYLeft, Int32
nWidth,
Int32 nHeight, Int32
dwRop);
[DllImport("gdi32.dll",
EntryPoint = "SelectObject",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern IntPtr
SelectObject(IntPtr hDC, IntPtr hObj);
[DllImport("GDI32.dll",
EntryPoint = "CreateCompatibleDC",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern IntPtr
CreateCompatibleDC(IntPtr hRefDC);
[DllImport("GDI32.dll",
EntryPoint = "DeleteDC",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("GDI32.dll",
EntryPoint = "DeleteObject",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern bool
DeleteObject(IntPtr hObj);
[DllImport("User32.dll",
EntryPoint = "ReleaseDC",
SetLastError = true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern bool
ReleaseDC(IntPtr hWnd, IntPtr
hDC);
[DllImport("User32.dll",
EntryPoint = "GetDC", SetLastError
= true,
CharSet =
CharSet.Unicode, ExactSpelling = true, CallingConvention =
CallingConvention.StdCall)]
public static extern IntPtr GetDC(IntPtr hWnd);
[StructLayout(LayoutKind.Sequential,
CharSet = CharSet.Auto)]
public struct BITMAPINFOHEADER
{
public Int32 biSize;
public Int32 biWidth;
public Int32
biHeight;
public Int16
biPlanes;
public Int16
biBitCount;
public Int32
biCompression;
public Int32
biSizeImage;
public Int32
biXPelsPerMeter;
public Int32
biYPelsPerMeter;
public Int32
biClrUsed;
public Int32
biClrImportant;
}
}
Ahora diseñamos el formulario que queremos imprimir y le añadimos un objeto PrintDocument printDocument1 y PrintDialog printDialog1, nos puede quedar algo como esto, un formulario que muestre información sobre libros (si, ya se que es feo, pero para el propósito que tiene es suficiente):

Después tendríamos que controlar el evento click del botón imprimir para que cuando pulsemos en el boton se imprima el formulario y a parte, tenemos que añadir a nuestro código el método que se encargará de imprimir el formulario (también extraído del articulo del que he hablado más arriba) llamado OnPrintPage:
private void buttonImprimir_Click(object sender, EventArgs
e)
{
printDialog1.Document = printDocument1;
if ((printDialog1.ShowDialog() == DialogResult.OK))
{
printDocument1.PrintPage += new PrintPageEventHandler(this.OnPrintPage);
printDocument1.Print();
}
}
private void OnPrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
IntPtr hwndForm;
hwndForm = this.Handle;
IntPtr hdcDIBSection;
IntPtr hdcRef;
IntPtr hbmDIBSection;
IntPtr hbmDIBSectionOld;
Win32APICall.BITMAPINFOHEADER
BMPheader;
hdcRef = Win32APICall.GetDC(IntPtr.Zero);
hdcDIBSection
= Win32APICall.CreateCompatibleDC(hdcRef);
Win32APICall.ReleaseDC(IntPtr.Zero,
hdcRef);
BMPheader.biBitCount
= 24;
BMPheader.biClrImportant = 0;
BMPheader.biClrUsed = 0;
BMPheader.biCompression
= Win32APICall.BI_RGB;
BMPheader.biSize
= 40;
BMPheader.biHeight = this.Height;
BMPheader.biPlanes
= 1;
BMPheader.biSizeImage = 0;
BMPheader.biWidth = this.Width;
BMPheader.biXPelsPerMeter
= 0;
BMPheader.biYPelsPerMeter = 0;
hbmDIBSection
= Win32APICall.CreateDIBSection(hdcDIBSection, ref BMPheader,
Win32APICall.DIB_RGB_COLORS, IntPtr.Zero,
IntPtr.Zero, 0);
hbmDIBSectionOld = Win32APICall.SelectObject(hdcDIBSection,
hbmDIBSection);
Win32APICall.PatBlt(hdcDIBSection, 0, 0, this.Width, this.Height,
Win32APICall.WHITENESS);
Win32APICall.PrintWindow(hwndForm, hdcDIBSection, 0);
Win32APICall.SelectObject(hdcDIBSection,
hbmDIBSectionOld);
Bitmap imageFrm;
imageFrm = Image.FromHbitmap(hbmDIBSection);
e.Graphics.DrawImage(imageFrm, 0, 0);
Win32APICall.DeleteDC(hdcDIBSection);
Win32APICall.DeleteObject(hbmDIBSection);
}
Bien con esto ya podemos imprimir nuestro formulario, sencillo, pero vamos a ir un poquito más allá, la verdad es que imprimir el formulario así tal cual puede quedar un poquito feo, entonces lo que podemos hacer es modificar la apariencia del formulario para que se imprima lo que nosotros queramos que se vea. Para eso solo tenemos que cambiar la apariencia antes de imprimir el formulario y después de realizar la impresión devolver al formulario su apariencia original. Para el formulario que hemos creado podríamos, por ejemplo, ocultar el botón de impresión, el marco de la ventana, eliminar el borde de los textboxs y cambiar el color de fondo. El código final para el método buttonImprimir_Click sería:
private void buttonImprimir_Click(object sender, EventArgs
e)
{
Color colorFondo = this.BackColor;
try
{
printDialog1.Document
= printDocument1;
if
((printDialog1.ShowDialog() == DialogResult.OK))
{
//
ocultamos el borde del formulario
this.FormBorderStyle
= FormBorderStyle.None;
//cambiamos
el color de fondo del formulario
this.BackColor
= Color.White;
//quitamos el
borde a los texbox
textBox1.BorderStyle = BorderStyle.None;
textBox2.BorderStyle = BorderStyle.None;
textBox3.BorderStyle
= BorderStyle.None;
textBox4.BorderStyle = BorderStyle.None;
textBox5.BorderStyle
= BorderStyle.None;
textBox6.BorderStyle = BorderStyle.None;
//ocultamos el boton de imprimir
buttonImprimir.Visible = false;
printDocument1.PrintPage += new
PrintPageEventHandler(this.OnPrintPage);
printDocument1.Print();
}
}
catch (Exception)
{
MessageBox.Show("Error
al imprimir", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
//restauramos
las propiedades de los controles
this.FormBorderStyle
= FormBorderStyle.Sizable;
this.BackColor = colorFondo;
textBox1.BorderStyle
= BorderStyle.FixedSingle;
textBox2.BorderStyle = BorderStyle.FixedSingle;
textBox3.BorderStyle
= BorderStyle.FixedSingle;
textBox4.BorderStyle = BorderStyle.FixedSingle;
textBox5.BorderStyle
= BorderStyle.FixedSingle;
textBox6.BorderStyle = BorderStyle.FixedSingle;
buttonImprimir.Visible
= true;
//refrescamos
el form
this.Refresh();
}
}
Y por si quereis trastear con el código os lo dejo adjunto más abajo, un saludo!!!