Click here to Skip to main content
15,885,951 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
My cash drawer is connected to the receipt printer, how to send a command to printer to open the drawer?

I been told that I need to send the string to printer in order to open the drawer. Below is the sample code how i print a document.

C#
System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument();

       private void Form3_Load(object sender, EventArgs e)
       {

           pd.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage);
           pd.BeginPrint += new System.Drawing.Printing.PrintEventHandler(pd_BeginPrint);
           pd.EndPrint += new System.Drawing.Printing.PrintEventHandler(pd_EndPrint);
           pd.Print();
       }
       void pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
       {
           e.Graphics.DrawString("Hello", new Font("Arial", 20f), new SolidBrush(Color.Red), new PointF(20, 20));

       }
       void pd_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
       {

       }

       void pd_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
       {

       }


This is the ASCII code for the receipt printer to open drawer:

27, 112, 0, 100, 250
Posted
Comments
Rob Branaghan 9-Dec-11 12:23pm    
Why do you want to open the drawer from the printer? Shouldn't you open the drawer from code rather than the printer?
melvintcs 9-Dec-11 22:06pm    
my drawer is connected with the printer, i did some research and they said that we need to send the code to the printer in order to open the drawer. thats why i use send string to the printer.

or u have a better idea?

do not know if you solved this but here goes.

had a similar problem myself, solution was to use the printer driver to talk direct, that way it handles the talking to the printer on any port, and send lines with escape codes embedded. the other advantage of this is that using the windows drivers to print usually does not let you get at the full functionality of the printer (barcodes etc.).

there is an article on MS on using RawPrinterHelper to get a handle on the printer and write text direct. in the MS example it processes the write as a single document, which is slow if you write line by line as it opens and closes the printer each time so you would have to build a page. made a few modifications as (for me) a receipt printer is more of line oriented device there is no page size.

here is the MS link for the original: http://support.microsoft.com/kb/322091

this is not perfect, still testing and more error trapping needed, if it does not open the printer it just consumes write no output.

here is the modified class for raw printing:

VB
Imports System
Imports System.Drawing
Imports System.Drawing.Printing
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Imports System.IO

Public Class RawPrinterHelper
    ' Structure and API declarions:
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Public Class DOCINFOA
        <MarshalAs(UnmanagedType.LPStr)> _
        Public pDocName As String
        <MarshalAs(UnmanagedType.LPStr)> _
        Public pOutputFile As String
        <MarshalAs(UnmanagedType.LPStr)> _
        Public pDataType As String
    End Class
    <DllImport("winspool.Drv", EntryPoint:="OpenPrinterA", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function OpenPrinter(<MarshalAs(UnmanagedType.LPStr)> szPrinter As String, ByRef hPrinter As IntPtr, pd As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function ClosePrinter(hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="StartDocPrinterA", SetLastError:=True, CharSet:=CharSet.Ansi, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartDocPrinter(hPrinter As IntPtr, level As Int32, <[In](), MarshalAs(UnmanagedType.LPStruct)> di As DOCINFOA) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndDocPrinter(hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartPagePrinter(hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndPagePrinter(hPrinter As IntPtr) As Boolean
    End Function

    <DllImport("winspool.Drv", EntryPoint:="WritePrinter", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function WritePrinter(hPrinter As IntPtr, pBytes As IntPtr, dwCount As Int32, ByRef dwWritten As Int32) As Boolean
    End Function

    ' SendBytesToPrinter()
    ' When the function is given a printer name and an unmanaged array
    ' of bytes, the function sends those bytes to the print queue.
    ' Returns true on success, false on failure.
    Private hPrinter As New IntPtr(0)
    Private di As New DOCINFOA()
    Private PrinterOpen As Boolean = False
    Public Sub OpenPrint(szPrinterName As String)
        If PrinterOpen = False Then
            di.pDocName = ".NET RAW Document"
            di.pDataType = "RAW"

            If OpenPrinter(szPrinterName.Normalize(), hPrinter, IntPtr.Zero) Then
                ' Start a document.
                If StartDocPrinter(hPrinter, 1, di) Then
                    If StartPagePrinter(hPrinter) Then
                        PrinterOpen = True
                    End If
                End If
            End If
        End If
    End Sub
    Public Sub ClosePrint()
        If PrinterOpen Then
            EndPagePrinter(hPrinter)
            EndDocPrinter(hPrinter)
            ClosePrinter(hPrinter)
            PrinterOpen = False
        End If
    End Sub
    Public Function SendStringToPrinter(szPrinterName As String, szString As String) As Boolean
        If PrinterOpen Then
            Dim pBytes As IntPtr
            Dim dwCount As Int32
            Dim dwWritten As Int32 = 0

            dwCount = szString.Length

            pBytes = Marshal.StringToCoTaskMemAnsi(szString)

            SendStringToPrinter = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)

            Marshal.FreeCoTaskMem(pBytes)
        Else
            SendStringToPrinter = False
        End If
    End Function
End Class


And an example usage my printers are all Epson so uses Epson escape sequences :

VB
Public Class Form1
    Public Const eClear As String = Chr(27) + "@"
    Public Const eCentre As String = Chr(27) + Chr(97) + "1"
    Public Const eLeft As String = Chr(27) + Chr(97) + "0"
    Public Const eRight As String = Chr(27) + Chr(97) + "2"
    Public Const eDrawer As String = eClear + Chr(27) + "p" + Chr(0) + ".}"
    Public Const eCut As String = Chr(27) + "i" + vbCrLf
    Public Const eSmlText As String = Chr(27) + "!" + Chr(1)
    Public Const eNmlText As String = Chr(27) + "!" + Chr(0)
    Public Const eInit As String = eNmlText + Chr(13) + Chr(27) + "c6" + Chr(1) + Chr(27) + "R3" + vbCrLf
    Public Const eBigCharOn As String = Chr(27) + "!" + Chr(56)
    Public Const eBigCharOff As String = Chr(27) + "!" + Chr(0)

    Private prn As New RawPrinterHelper

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        StartPrint()

        Print(eInit + eCentre + "Shop")
        Print("Telephone")
        Print("Web Address")
        Print("Email Address")
        Print("VAT Reg No:123 4567 89" + eLeft)
        PrintDashes()
        Print(eSmlText + "Tea                                          T1   6.00")
        PrintDashes()
        Print(eSmlText + "                                         Total:   6.00")
        Print("                                     Paid Cash:   6.00")
        Print(eCentre + "Thank You For Your Support!" + eLeft)
        Print(vbLf + vbLf + vbLf + vbLf + vbLf + eCut + eDrawer)

        EndPrint()

        StartPrint()
        Print(eCentre + "Thank You For Your Support!" + eLeft)
        Print(vbLf + vbLf + vbLf + vbLf + vbLf + eCut)
        EndPrint()
    End Sub

    Private PrintBuffer As String
    Public Sub StartPrint()
        PrintBuffer = ""
        prn.OpenPrint("EPSON TM-T20 Receipt")
    End Sub
    Public Sub Print(Line As String)
        prn.SendStringToPrinter("EPSON TM-T20 Receipt", Line + vbLf)
    End Sub
    Public Sub PrintDashes()
        Print(eLeft + eNmlText + "-".PadRight(42, "-"))
    End Sub
    Public Sub EndPrint()
        prn.ClosePrint()
    End Sub
End Class


means you format strings manually, pad item names out with spaces to position cash values but i find that easier...

code block lang changed fom xml to vb
 
Share this answer
 
v5
Comments
SoMad 1-Jan-14 17:14pm    
Your solution is a little late to the party, but since it is a question I see being asked every once in a while and you have provided a comprehensive and working solution, I think it is ok for you to post this answer. :thumbsup:

Soren Madsen
thatraja 2-Jan-14 2:54am    
5!
Using the printer port to fire the cash drawer is a long standing retail industry standard, stemming from the days when all printers used parallel ports. Since ASCII doesn't use bit7, this bit was used to fire the solenoid latch holding the spring loaded drawer closed. Once printers became serial devices, special codes were introduced which are ignored by the printer and passed through to the cash drawer via an RJ-45 connector. Yours is probably a Toshiba TEC-series drawer.

Having never really explored using the Windows device context approach to printing, I can't really suggest in detail how to solve the problem in your code, but a brute force method might be to instantiate a serial port corresponding to the USB port attached to the printer, then writing a serial byte array containing your control codes to that port after you finish printing the receipt. Looking at my own Windows 7 Device Manager, I see that Ports have disappeared, but there are addresses for each connected USB device that should be usable for sending serial data.
 
Share this answer
 
This may or may not help you. I developed this little DLL to act as an interface between .NET and a vendor-supplied DLL for sending commands to their POS device via USB.

PartnerTech CD-7220 POS Customer Display - .NET Class [^]
 
Share this answer
 

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900