Using GDI to Print in C#

One reason for using GDI maybe speed and familiarity with GDI or having more control over the printer.
 
Until now we have been selecting objects such as fonts and lines and then drawing on a page, which is then printed out. Keep in mind that all the fonts you can use within the .NET environment have to be TrueType fonts. Before TrueType came along, there was something called PCL (Printer Control Language), also known as bitmap fonts. So what's the difference? you may ask. It's simple: A PCL or bitmap font is made up of patterns of dots that represent each letter.
 
The problem is that a different PCL font was required for every size of the letter needed, such as 12, 14, and so on. Different PCL, fonts were needed even for italic and bold versions! As you can imagine, it was necessary to have lots of PCL fonts to maintain the flexibility we take for granted today.
 
TrueType fonts, on the other hand, are a lot more flexible. The reason is that the fonts are mathematical representations of each letter rather than a pattern of dots. If I decide I need a Times New Roman font at size 20, the font is simply recalculated rather than just a different pattern of dots being loaded.
 
What happens if your printer does not support the TrueType font you have selected? The only way to print it is to send what you want to print to the printers as graphics, which can be time-consuming if you're creating large printouts.
 
The code in Listing 14.3, you would be able to create detailed pages consisting of multiple fonts and graphics. The nice thing is that they can all be created by just sending text to the printer rather than using graphics command.
 
You may want to change the printer before you rest this code. The following line of code specifies the printer:
 
PrintDirect.OpenPrinter (\\\\192.168.1.101\\hpl,ref lhPrinter, 0);
 
LISTING 14.3: Using GDI print functionality in a managed application

 

  1. //PrintDirect.cs  
  2. //shows how to write data directly to the  
  3. //printer using Win32 APIs.  
  4. //this code sends Hewlett-Packard PCL5 codes  
  5. //to the printer to print  
  6. //out a rectangle in the middle of the page.  
  7. using System;  
  8. using System.Text;  
  9. using System.Runtime.InteropServices;  
  10.   
  11. [StructLayout(LayoutKind.Sequential)]  
  12. public struct DOCINFO {  
  13.  [MarshalAs(UnmangedType.LPWStr)]  
  14.  public string pDocName;  
  15.  [MarshalAs(UnmangedType.LPWStr)]  
  16.  public string pOutputFile;  
  17.  [MarshalAs(UnmangedType.LPWStr)]  
  18.  public string pDataType;  
  19. }  
  20.   
  21. public class PrintDirect {  
  22.  [DllImport("winspool.drv",  
  23.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  24.   CallingConvention = CallingConvention.StdCall)]  
  25.  public static extern long OpenPrinter(String pPrinterName,  
  26.   ref IntPtr phPrinter, int pDefault);  
  27.   
  28.  [DllImport("winspool.drv",  
  29.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  30.   CallingConvention = CallingConvention.StdCall)]  
  31.  public static extern long StartDocPrinter(Int hPrinter,  
  32.   int Level, ref DOCINFO pDocInfo);  
  33.   
  34.  [DllImport("winspool.drv",  
  35.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  36.   CallingConvention = CallingConvention.StdCall)]  
  37.  public static extern long StartPagePrinter(  
  38.   IntPtr hPrinter);  
  39.   
  40.  [DllImport("winspool.drv",  
  41.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  42.   CallingConvention = CallingConvention.StdCall)]  
  43.  public static extern long WritePrinter(IntPtr hPrinter,  
  44.   string data, int buf, ref int pcWrittern);  
  45.   
  46.  [DllImport("winspool.drv",  
  47.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  48.   CallingConvention = CallingConvention.StdCall)]  
  49.  public static extern long EndPrinter(IntPtr hPrinter);  
  50.   
  51.  [DllImport("winspool.drv",  
  52.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  53.   CallingConvention = CallingConvention.StdCall)]  
  54.  public static extern long EndDocPrinter(IntPtr hPrinter);  
  55.   
  56.  [DllImport("winspool.drv",  
  57.   CharSet = CharSet.Unicode, ExactSpelling = false,  
  58.   CallingConvention = CallingConvention.StdCall)]  
  59.  public static extern long ClosePrinter(IntPtr hPrinter);  
  60. }  
  61.   
  62. public static void Main() {  
  63.  System.IntPtr lhPrinter =  
  64.   new System.IntPtr();  
  65.  DOCINFO di = new DOCINFO();  
  66.  int pcWritten = 0;  
  67.  string st1;  
  68.   
  69.  //Text to print with a form-feed character  
  70.  st1 = "This is an example of printing " +  
  71.   "directory to a printer\f";  
  72.  di.pDocName = "my test document";  
  73.  di.pDataType = "RAW";  
  74.   
  75.  //The "\xlb" means an ASCII  escape character  
  76.  st1 = "\xlb*c600a6b0P\f";  
  77.  //lhPrinter contains the handle for the printer opened  
  78.  //IF lhPrinter is 0, then an error has occurred.  
  79.  PrintDirect.OpenPrinter(\\\\192.168 .1 .101\\ hp1,  
  80.   ref lhPrinter, 0);  
  81.  PrintDirect.StartDocPrinter(lhPrinter, 1, ref di);  
  82.  PrintDirect.StartPagePrinter(lhPrinter);  
  83.   
  84.  try {  
  85.   //Moves the cursor 900 dots (3 inches at  
  86.   //300 dpi) in from the left margin, and  
  87.   //600 dots (2 inches at 300 dpi) down   
  88.   //from the top margin  
  89.   st1 = "\xlb*p900x600Y";  
  90.   PrintDirect.WritePrinter(lhPrinter,  
  91.    st1, st1.Length, ref pcWritten);  
  92.   
  93.   //Using the print model commands for rectangle  
  94.   //dimensions, "600a" specifies a rectangle  
  95.   //with a horizontal size, or width, of 600 dots,  
  96.   //and "6b" specifies a vertical  
  97.   //size, or height, of 6 dots. "0P" selects the  
  98.   //solid black rectangle area fill  
  99.   st1 = "\xlb*c600a6b0P";  
  100.   PrintDirect.WritePrinter(lhPrinter,  
  101.    st1, st1.Length, ref pcWritten);  
  102.   
  103.   //Specifies a rectangle with width of  
  104.   //6 dots, height of 600 dots, and a  
  105.   //Fill pattern of solid black  
  106.   st1 = "\xlb*c6a600b0P";  
  107.   PrintDirect.WritePrinter(lhPrinter,  
  108.    st1, st1.Length, ref pcWritten);  
  109.   
  110.   //Moves the current cursor position to  
  111.   //900 dots from the left margin and  
  112.   //1200 dots down from the top margin  
  113.   
  114.   st1 = "\xlb*p900x1200Y";  
  115.   PrintDirect.WritePrinter(lhPrinter,  
  116.    st1, st1.Length, ref pcWritten);  
  117.   
  118.   //Specifies a rectangle with a width  
  119.   //of 606 dots, a height of 6 dots, and a  
  120.   //fill patter of solid balck  
  121.   st1 = "\xlb*c606a6b0P";  
  122.   PrintDirect.WritePrinter(lhPrinter,  
  123.    st1, st1.Length, ref pcWritter);  
  124.   //Move the current cursor position to 1500  
  125.   //dots in from the left margin and  
  126.   //600 dots down from the top margin  
  127.   st1 = "\xlb*p1500x600Y";  
  128.   PrintDirect.WritePrinter(lhPrinter,  
  129.    st1, st1.Length, ref pcWritten);  
  130.   
  131.   //Specifies a rectangle with a width of 6 dots,  
  132.   //a height of 600 dots, and a   
  133.   //fill patter of solid black  
  134.   st1 = "\xlb*c6a600b0P";  
  135.   PrintDirect.WritePrinter(lhPrinter,  
  136.    st1, st1.Length, ref pcWritter);  
  137.   
  138.   //Send a from-feed character to the printer  
  139.   st1 = "\f";  
  140.   PrintDirect.WritePrinter(lhPrinter,  
  141.    st1, st1.Length, ref pcWritten);  
  142.  } catch (Exception e) {  
  143.   Console.WriteLine(e.Message);  
  144.  }  
  145.   
  146.  PrintDirect.EndPagePrinter(lhPrinter);  
  147.  PrintDirect.EndDocPrinter(lhPrinter);  
  148.  PrintDirect.ClosePrinter(lhPrinter);  
  149. }  
  150. }
Using this code will enable us to drive a printer at its maximum output rate.