Solved

Print international charaters in Epson Tm-T70

Posted on 2013-05-16
9
2,509 Views
Last Modified: 2013-05-17
When I print international characters on Epson POS Tm-T20 i have no problem using the class RawPrinterHelper. However when printing on Epson Tm-T70 does not print international characters. But using eg. Chr(128) prints the "Ç" character on TM-T70, correctly.
0
Comment
Question by:rflorencio
  • 4
  • 3
  • 2
9 Comments
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 39171562
Can you show us code you use to send strings to printer?
0
 

Author Comment

by:rflorencio
ID: 39171625
This is the code:

In Dim b1 As String = "ÇÇÇÇÇÇÇÇÇ" & Chr(128) code, "ÇÇÇÇÇÇÇÇÇ" prints a odd character  and Chr(128) prints correctly.


Call RawPrinterClass

      Dim b As Integer = 50

        Dim b1 As String = "ÇÇÇÇÇÇÇÇÇ" & Chr(128)

        Dim s As String
        ''-------------------------------------------------
        s = sess_PT_CHAR1
        s &= "  .: Example :. " & vbCrLf
        s &= "================================" & vbCrLf
        s &= "   EXAMPLE    " & vbCrLf
        s &= b1 & Space(1) & b.ToString & vbCrLf
        s &= sess_EPSON_BOLD_ON
        s &= "* * * END * * *"
        s &= sess_EPSON_BOLD_OFF
        s &= "" & vbCrLf
        s &= "" & vbCrLf
        s &= "" & vbCrLf
        s &= "" & vbCrLf
        s &= "" & vbCrLf
        s &= "" & vbCrLf
        s &= sess_CUT_PAPER
        s &= sess_OPEN_CASH
        Dim xPrintText As New RawPrinterHelper(s)

'-----------------------------------------------------------------------------------


RawPrinterClass
'-----------------------------------------------------------------------------------
Imports System.IO
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices

Public Class RawPrinterHelper
    Public Shared ESC As String = Convert.ToString(ChrW(27))
    Public Shared sess_ESC As String = ChrW(27) + "!"
    Public Shared sess_EPSON_BOLD_ON As String = sess_ESC + Chr(16) + sess_ESC + Chr(32)
    Public Shared sess_EPSON_BOLD_OFF As String = sess_ESC + Chr(0) + sess_ESC + Chr(0)
    Public Shared sess_CUT_PAPER As String = ESC & "@" & ChrW(29) & "V" & ChrW(1)
    Public Shared sess_OPEN_CASH As String = Chr(27) & Chr(112) & Chr(48) & Chr(64) & Chr(64)

Public Shared sess_PT_CHAR As String = Chr(27) & Chr(116) & Chr(0)
'--------------------------------------------------



    ' Structure and API declarions:
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    Structure DOCINFOW
        <MarshalAs(UnmanagedType.LPWStr)> Public pDocName As String
        <MarshalAs(UnmanagedType.LPWStr)> Public pOutputFile As String
        <MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
    End Structure
    <DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function OpenPrinter(ByVal src As String, ByRef hPrinter As Integer, ByVal pd As Integer) As Boolean
    End Function
    ' Este código estava a dar um erro foi actualizado nas na framework 4.0 e posterior
    'Public Shared Function OpenPrinter(ByVal src As String, ByRef hPrinter As Integer, ByVal pd As Long) As Boolean
    'End Function
    <DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, ByRef pDI As DOCINFOW) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
    End Function
    <DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
    SetLastError:=True, CharSet:=CharSet.Unicode, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal 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 or False on failure.
    Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As IntPtr, ByVal dwCount As Int32) As Boolean
        Dim hPrinter As IntPtr      ' The printer handle.
        Dim dwError As Int32        ' Last error - in case there was trouble.
        Dim di As DOCINFOW          ' Describes your document (name, port, data type).
        Dim dwWritten As Int32      ' The number of bytes written by WritePrinter().
        Dim bSuccess As Boolean     ' Your success code.

        ' Set up the DOCINFO structure.
        With di
            .pDocName = "My Visual Basic .NET RAW Document"
            .pDataType = "RAW"
        End With
        ' Assume failure unless you specifically succeed.
        bSuccess = False
        If OpenPrinter(szPrinterName, hPrinter, 0) Then
            If StartDocPrinter(hPrinter, 1, di) Then
                If StartPagePrinter(hPrinter) Then
                    ' Write your printer-specific bytes to the printer.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
                    EndPagePrinter(hPrinter)
                End If
                EndDocPrinter(hPrinter)
            End If
            ClosePrinter(hPrinter)
        End If
        ' If you did not succeed, GetLastError may give more information
        ' about why not.
        If bSuccess = False Then
            dwError = Marshal.GetLastWin32Error()
        End If
        Return bSuccess
    End Function ' SendBytesToPrinter()

    ' SendFileToPrinter()
    ' When the function is given a file name and a printer name,
    ' the function reads the contents of the file and sends the
    ' contents to the printer.
    ' Presumes that the file contains printer-ready data.
    ' Shows how to use the SendBytesToPrinter function.
    ' Returns True on success or False on failure.
    Public Shared Function SendFileToPrinter(ByVal szPrinterName As String, ByVal szFileName As String) As Boolean
        ' Open the file.
        Dim fs As New FileStream(szFileName, FileMode.Open)
        ' Create a BinaryReader on the file.
        Dim br As New BinaryReader(fs)
        ' Dim an array of bytes large enough to hold the file's contents.
        Dim bytes(fs.Length) As Byte
        Dim bSuccess As Boolean
        ' Your unmanaged pointer.
        Dim pUnmanagedBytes As IntPtr

        ' Read the contents of the file into the array.
        bytes = br.ReadBytes(fs.Length)
        ' Allocate some unmanaged memory for those bytes.
        pUnmanagedBytes = Marshal.AllocCoTaskMem(fs.Length)
        ' Copy the managed byte array into the unmanaged array.
        Marshal.Copy(bytes, 0, pUnmanagedBytes, fs.Length)
        ' Send the unmanaged bytes to the printer.
        bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, fs.Length)
        ' Free the unmanaged memory that you allocated earlier.
        Marshal.FreeCoTaskMem(pUnmanagedBytes)
        Return bSuccess
    End Function ' SendFileToPrinter()

    ' When the function is given a string and a printer name,
    ' the function sends the string to the printer as raw bytes.
    Public Shared Function SendStringToPrinter(ByVal szPrinterName As String, ByVal szString As String)
        Dim pBytes As IntPtr
        Dim dwCount As Int32
        ' How many characters are in the string?
        dwCount = szString.Length()
        ' Assume that the printer is expecting ANSI text, and then convert
        ' the string to ANSI text.
        pBytes = Marshal.StringToCoTaskMemAnsi(szString)
        ' Send the converted ANSI string to the printer.
        SendBytesToPrinter(szPrinterName, pBytes, dwCount)
        Marshal.FreeCoTaskMem(pBytes)
    End Function
    Public Sub New(TextToPrint As String)
        ' TextToPrint - Sequencia de Escape a enviar para impressora ou texto a imprimir
        Dim pd As New PrintDialog()
        ' Open the printer dialog box, and then allow the user to select a printer.
        pd.PrinterSettings = New PrinterSettings()
        If (pd.ShowDialog() = DialogResult.OK) Then
            RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, TextToPrint)
        End If
    End Sub
End Class

Open in new window

0
 
LVL 16

Expert Comment

by:DansDadUK
ID: 39174051
The "Ç" (capital C with cedilla accent) character is defined at Unicode code-point U+00C7.
Unicode is used on most modern operating systems as the "internal" character coding mechanism.

Most printers do not use Unicode directly (since it requires 16-bit character codes), but instead map various 8-bit coded character sets to different sets of (up to 256) glyphs.

The 8-bit coded character set which corresponds directly to the first 256 Unicode code-points is the ISO-8859-1 Latin-1 set, so in this set, the "Ç" character is represented by character-code (hexadecimal) 0xC7, or decimal 199.

The fact that you get the required character printed with a character-code of (decimal) 128 implies that the printer is assuming a coded-character set other than ISO-8859-1.

I'm not familiar with either VB or the Epson printer language, so I don't know how to advise you to select a different coded-character-set on the printer, but I think that this is what you need to do.
0
 
LVL 16

Expert Comment

by:DansDadUK
ID: 39174066
The Tm-T70 manual (see http://www.juta-soft.hu/pdf/egyeb%20eszkozok/epson%20tm-t70%20felhasznaloi%20kezikonyv.pdf ) refers to use of different character code tables.

Appendix C.1 Page 0 (PC437: USA, Standard Europe (International character set: when “America” is selected)) maps 0x80 (decimal 128) to the "Ç" glyph.

Appendix C.7 Page 16 (WPC1252) maps 0xC7 (decimal 199) to the "Ç" glyph.

This 'code page' appears to be the equivalent of the Windows Latin-1 (codepage 1252) coded character set (which is a superset of ISO-8859-1 (in that graphic characters are assigned to code-points in the range 0x80-0x9F which (in ISO-8859-1) are assigned to the (rarely used) C1 control-code characters).
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 83

Expert Comment

by:CodeCruiser
ID: 39174358
What happens if you change

pBytes = Marshal.StringToCoTaskMemAnsi(szString)

to

pBytes = Marshal.StringToCoTaskMemUni(szString)

Or

pBytes = Marshal.StringToCoTaskMemAuto(szString)
0
 

Author Comment

by:rflorencio
ID: 39174682
CodeCruiser,
If change code only first line is printed.

My problem is that I can do almost everything cut paper, put into expanded, etc.. I can not "say" to printer which is the character table to use. Do not accept this escape sequence
Chr(27) & Chr(116) & Chr(0).
0
 
LVL 16

Accepted Solution

by:
DansDadUK earned 500 total points
ID: 39174768
Surely you need to send the Esc/Pos escape sequence:
Chr(27) & Chr(116) & Chr(16)
to select table 16 (cp1252); selecting table 0 (as per your sequence) will just reselect the American table, which appears to be the default.
0
 

Author Comment

by:rflorencio
ID: 39174931
DansDadUK one more thing,

In fact your sequence works in perfection. However if I put Chr(27) & Chr(116) & Chr(3), also should work with accented characters (or not)?
0
 
LVL 16

Expert Comment

by:DansDadUK
ID: 39175244
Table 3 appears to be code page 860 (Portuguese), which is one of the old National Language Variant sets; it does indeed contain a number of accented characters, but:

- C-cedilla is represented by 0x80 (so your back to the same problem as with the default table 0 character set.

- Code page 1252 (as represented by table 16) matches the 8-bit coded character set used by Windows systems and (apart from the C1 control-code range) that used by *n*x systems as well.
I.e. it matches the character encoding used on your workstation, so it doesn't really make sense to use any other 8-bit set if you want to use characters which are not in the 7-bit ASCII subset.
Of course, if you want to use non-Western languages (e.g. Cyrillic or Thai) then you'd need a different character set or (more likely these days) use Unicode (either UCS-2 or UTF-8 representations), but not all printers support Unicode directly (the Tm-T70 certainly doesn't appear to).
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Check my code out(2) 1 35
VB.Net - For Loop Error 5 26
Round up to 100% in .NET 10 46
Printer recommendation 7 21
This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now