Click here to Skip to main content
6,631,889 members and growing! (17,225 online)
Email Password   helpLost your password?
Languages » C# » Utilities     Intermediate License: The Code Project Open License (CPOL)

Sending Passthrough - Commands to a Printer

By m@u

Bypassing GDI+ to send Printer-Commands
C# 1.0.NET 1.1, Win2K, WinXP, Win2003VS.NET2003, Dev
Posted:8 Jan 2007
Updated:8 May 2007
Views:17,291
Bookmarked:21 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
5 votes for this article.
Popularity: 2.84 Rating: 4.06 out of 5

1

2
1 vote, 20.0%
3
2 votes, 40.0%
4
2 votes, 40.0%
5

Introduction

I was looking for a long time to send escape-sequences to a printer while printing with the normal System.Drawing.Printing objects. This can be useful if you want to send faxes and tell the fax-drive with an escape sequence where you want to send the fax. You can also print barcodes with it. Most solutions that I found were about printing the whole page with userdefined commands. Here's a very simple solution about How to use GDI+ for printing and still have the possibility of sending userdefined PrinterCommands.

The Code

The code is very simple. There are two classes.

The first class is called EscapePrintHelper and looks like this:

public class EscapePrintHelper
{
    [DllImport("gdi32.dll", EntryPoint="Escape",
        CharSet=CharSet.Auto, SetLastError=true)]
    private static extern int Escape
        (IntPtr Hdc, int nEscape, int ncount, IntPtr inData, IntPtr outData);
    private const int PASSTHROUGH = 19;
    private IntPtr Handle;
    private Graphics graphics;
    public EscapePrintHelper(Graphics Graphics)
    {
        graphics = Graphics;
        Handle = Graphics.GetHdc();
        Graphics.ReleaseHdc(Handle);
    }
    public bool SendPassThroughExt(string PassthroughData)
    {
        return sendPassThrough(PassthroughData,Handle);
    }
    private bool sendPassThrough(string Passthroughdata, IntPtr handle)
    {
        IntPtr grp = handle;
        bool RetVal = false;
        IntPtr pData = string2Global(Passthroughdata,true);
        try
        {
            int id = Escape(grp,PASSTHROUGH,0,pData,IntPtr.Zero);
            RetVal = id > 0;
        }
        finally
        {
            Marshal.FreeHGlobal(pData);
        }
        return RetVal;
    }
    public bool SendPassThrough(string PassthroughData)
    {
        bool RetVal = false;
        IntPtr grp = graphics.GetHdc();
        try
        {
            RetVal = sendPassThrough(PassthroughData, grp);
        }
        finally
        {
            graphics.ReleaseHdc(grp);
        }
        return RetVal;
    }
    private IntPtr string2Global(string Data, bool includeSize)
    {
        int l = Data.Length;
        int offset = 0;
        if (includeSize)
        {
            l+=2;
            offset = 2;
        }
        IntPtr RetVal = Marshal.AllocHGlobal(l);
        short s = (short)Data.Length;
        byte[] buf = new byte[l];
        if (includeSize)
        {
            buf[1] = (byte)(s >> 8);
            buf[0] = (byte)s;
        }
        System.Text.Encoding.Default.GetBytes(Data,0,Data.Length,buf,offset);
        for (int i = 0; i< buf.Length; i++)
        {
            Marshal.WriteByte(RetVal,i,buf[i]);
        }
        return RetVal;
    }
} 

This class allows me to bypass the printer. So you could use this class without the second class, which is only a derived PrintDocument class that has a method called SendPassThroughCommand.

public class EscapeEventArgs:EventArgs
{
    private EscapePrintDocument doc;
    public EscapePrintDocument Doc
    {
        get
        {
            return doc;
        }
    }
    private EscapeEventArgs()
    {
    }
    public EscapeEventArgs(EscapePrintDocument Doc)
    {
        doc = Doc;
    }
}
public delegate void EscapeEventHandler(object sender, EscapeEventArgs e);
public class EscapePrintDocument:System.Drawing.Printing.PrintDocument
{
    public event EscapeEventHandler AfterPrint;
    private EscapePrintHelper commandSender;
    private bool printing;
    public void SendPassThroughCommand(string PassThroughCommand)
    {
        if (printing)
        {
            commandSender.SendPassThrough(PassThroughCommand);
        }
        else
        {
            commandSender.SendPassThroughExt(PassThroughCommand);
        }
    }
    protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e)
    {
        printing = true;
        commandSender = new EscapePrintHelper(e.Graphics);
        try
        {
            base.OnPrintPage(e);
        }
        finally
        {
            printing = false;
        }
    }
    protected virtual void onAfterPrint()
    {
        if (AfterPrint != null)
        {
            AfterPrint(this, new EscapeEventArgs(this));
        }
    }
    protected override void OnEndPrint(PrintEventArgs e)
    {
        try
        {
            onAfterPrint();
        }
        finally
        {
            base.OnEndPrint (e);
        }
    }
} 

Its usage is now really simple. Just create an EscapePrintDocument and print it. While printing, use the SendPassThroughCommand to send EscapeSequences or things like that:

private void TestPrint()
{
    PrintDialog dlg = new PrintDialog();
    EscapePrintDocument test = new EscapePrintDocument();
    dlg.Document = test;
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        test.PrintPage +=new PrintPageEventHandler(test_PrintPage);
        test.Print();
    }
}
private void test_PrintPage(object sender, PrintPageEventArgs e)
{
    EscapePrintDocument doc = sender as EscapePrintDocument;
    EscapePrintHelper hlp = new EscapePrintHelper(e.Graphics);
    SizeF pf = e.Graphics.MeasureString(textBox1.Text,new Font("Arial",12));
    RectangleF rf = new RectangleF(new PointF(30,30),pf);
    e.Graphics.DrawString("Blah!",new Font("Arial",12),Brushes.Black,rf);
    if (doc != null)
    {
        // Telling the Fax - Driver where to Send the Fax
        doc.SendPassThroughCommand
            ("\x1b[COMMAND]NUMMER YourFaxNumber\x1b[END COMMAND]");
    }
    e.HasMorePages = false;
}

This example is tested with TobitFax (if anybody knows that one:)).

If you wish to send Passthrough commands after the last page, you can add a handler to the AfterPrint event and send the command there.

Summary

I hope this example is useful for somebody. I know that the implementation is not perfect, especially for the string2Global method which I tried to implement with a struct first, but I couldn't make it work.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

m@u


Member

Occupation: Software Developer
Location: Switzerland Switzerland

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 11 of 11 (Total in Forum: 11) (Refresh)FirstPrevNext
QuestionOpen Cash Drawer Pinmemberimla5:33 7 Sep '07  
Generalstring2Global PinmemberThierry Nenin5:00 20 Jul '07  
GeneralRe: string2Global Pinmemberm@u5:42 20 Jul '07  
AnswerRe: string2Global PinmemberThierry Nenin22:18 23 Jul '07  
GeneralFax number required Pinmembersepro4:56 30 May '07  
GeneralOpen Cash Drawer Pinmemberhivo10:12 9 May '07  
GeneralRe: Open Cash Drawer Pinmemberm@u11:20 9 May '07  
GeneralVery Nice but... Pinmembergmeles21:09 7 May '07  
GeneralRe: Very Nice but... Pinmemberm@u22:13 7 May '07  
GeneralRe: Very Nice but... Pinmemberm@u4:16 8 May '07  
GeneralPerfect! Almost... PinmemberAndy Guevara11:04 8 Feb '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 8 May 2007
Editor: Deeksha Shenoy
Copyright 2007 by m@u
Everything else Copyright © CodeProject, 1999-2009
Web22 | Advertise on the Code Project