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!!!