Dot Matrix Form feed epson escape sequence not working properly

Good Afternoon,

I have developed a Cheque printing application in VB.NET which is using an “OKI Microline 390 Turbo” dot matrix printer under Windows 7 using the “Generic / Text Only” driver. The paper being used is continuous carbon paper being fed in from the rear of the printer via the tractors.

I have configured the paper size correctly within the settings on the printer to be 8.5 x 7 inches.  I have also configured the “Top Of Form (TOF)” setting in the correct position for the printer when the paper is first loaded.

Settings from the printer can be seen in below screenshot.

PrinterSettings
Upon printing the first cheque from my application, everything prints fine and the alignment is perfect for each thing that is printed on the cheque as seen in below image.

chq1
After the last bit of text is printed on the cheque, I have the application issue a “Form Feed” escape sequence, for the printer head to go to the TOF on the next cheque page to be printed. Code below:

Print(eDRef + "REF:" + txtMRef.Text + eFormFeed)

Open in new window


However, for some reason an extra line is inserted knocking my TOF off by one line, which is then pushing my alignment down for the rest of the text for the next cheque. Each time a “Form Feed” is sent to the printer it inserts an extra line, pushing the alignment further and further down the page of the cheque. Examples below of the alignment being pushed down after each form feed.

chq2
chq3
Now my understanding of the form feed is that it is supposed to advance the paper to the next TOF. But for some reason this is not working and I am not sure why.

Below is my code with all of the escape sequences being sent to the printer.

'Printer - Epson Emulation Escapes
    Public Const eClear As String = Chr(27) + "@" 'Initialize printer
    Public Const eProSpaceON As String = Chr(27) + "!" + Chr(1) 'Start Porportional Spacing 
    Public Const eProSpaceOFF As String = Chr(27) + "!" + Chr(0) 'Stop Porportional Spacing
    Public Const eTypeface As String = Chr(27) + "k" + Chr(122) 'Typeface 0 Roman, 1 Swiss, 2 Courier, 3 Prestige, 7 Orator, 122 Swiss Bold, 124 Gothic
    Public Const ePitch10 As String = Chr(27) + "P" '10 CPI Pitch
    Public Const ePitch12 As String = Chr(27) + "M" '12 CPI Pitch
    Public Const ePitch15 As String = Chr(27) + "g" '15 CPI Pitch
    Public Const eCentre As String = Chr(27) + Chr(97) + "1" 'Center Justification
    Public Const eLeft As String = Chr(27) + Chr(97) + "0" 'Left Justification
    Public Const eRight As String = Chr(27) + Chr(97) + "2" 'Right Justification
    Public Const eHTAB As String = Chr(9) 'Horizontal Tab
    Public Const eFormFeed As String = Chr(12)

'Body Specific Cheque Alignment
    Public Const eBChqNum As String = Chr(27) + "$" + Chr(81) + Chr(1) '6 inches
    Public Const eBChqDate As String = Chr(27) + "$" + Chr(40) + Chr(0) '1 inch
    Public Const eBN2W As String = Chr(27) + "$" + Chr(120) + Chr(0) '2 inches
    Public Const eBPayTo As String = Chr(27) + "$" + Chr(40) + Chr(0) '1 inch
    Public Const eBRef As String = Chr(27) + "$" + Chr(40) + Chr(0) '1 inch
    Public Const eBAmount As String = Chr(27) + "$" + Chr(81) + Chr(1) '6 inches

'Description Specific Cheque Alignment
    Public Const eDRVPosF As String = Chr(27) + "(v" + Chr(2) + Chr(0) + Chr(23) + Chr(3) 'Relative Vertical Forward Postion: DESCRIPTION START POSITION 2.3 inches
    Public Const eDPayTo As String = Chr(27) + "$" + Chr(40) + Chr(0) '1 inch
    Public Const eDSummary As String = Chr(27) + "$" + Chr(40) + Chr(0) '1 inch
    Public Const eDRef As String = Chr(27) + "$" + Chr(40) + Chr(0) '1 inch

Public Sub PrintBody()

        'Prints information for Body of Cheque
        Dim N2WResult As String

        N2WResult = AmountInWords(txtMAmt.Text)

        Print(eClear + eProSpaceON + eTypeface + ePitch12 + eBChqNum + " " + txtMChqNum.Text + vbCrLf + vbCrLf + vbCrLf)
        Print(eBChqDate + DateTimePickerM.Text + eBN2W + "     " + N2WResult + vbCrLf + vbCrLf)
        Print(eBPayTo + txtMPayTo.Text)
        Print(eBRef + "REF:" + txtMRef.Text + eBAmount + eHTAB + "*" + txtMAmt.Text + "*")

    End Sub

    Public Sub PrintFooter()

        Dim formattedDate As Date = DateTimePickerM.Text

        'Prints information for Description of Cheque
        Print(eDRVPosF + eDPayTo + txtMPayTo.Text)
        Print(eDSummary + "CK#" + txtMChqNum.Text + " " + txtMCurr.Text + "$" + txtMAmt.Text + " " + formattedDate.ToString("MMMM dd, yyyy"))
        Print(eDRef + "REF:" + txtMRef.Text + eFormFeed)

    End Sub

Open in new window



Does anyone know how I can resolve this?

Kindly advise.

Regards,
N
LVL 1
KevinAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

KevinAuthor Commented:
Just to update this posting I have attempted to use a "Reverse Line Feed" with the below additions to my code:

'Printer - Epson Emulation Escapes
....
Public Const eRevLine As String = Chr(27) + "]"

Open in new window


'Prints information for Description of Cheque
...
Print(eDRef + "REF:" + txtMRef.Text + eFormFeed + eRevLine)

Open in new window


While this addition does help it still does not resolve the problem.

Instead of the text being pushed down a full line after the form feed as I said in my initial posting, it now pushes the text down a few millimeters after each form feed.
0
hdhondtCommented:
You are using a Print command to send the formfeed. That would add an extra line feed. To suppress it, try putting a semicolon (;)  at the end of the Print statement.
1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
DansDadUKCommented:
I don't know VB (.net or otherwise), but the advice from hdhondt seems to be valid.

I'm an advocate of being able to 'capture' the output of printer drivers (or stand-alone applications) into a file, so that you can check what would otherwise be sent to the device.
Analysis of such a capture file would presumably show you the extraneous LineFeed control-code character.
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

KevinAuthor Commented:
@hdhondt, thank you, this makes perfect sense.

However the semicolon at the end of the print statement is not working as I can't compile my application with it.

I have tried inserting a semi colon (below) but cannot compile, would you know of anything else I can do?

Print(eDRef + "REF:" + txtMRef.Text + eFormFeed;)

Open in new window


Print(eDRef + "REF:" + txtMRef.Text + eFormFeed);

Open in new window


Am I putting it in the right place?

Or perhaps an alternative to form feed which will advance the paper to the TOF of the next page?

Kindly advise.

Regards,
N
0
Steven CarnahanNetwork ManagerCommented:
Is "Auto CR" set?

Form Feed FF
Causes the current line to be printed, and then advances the paper to the top of the next form. If a top
margin is set, printing will continue at the top margin. Setting “Host FF at TOF” to “No” in the interface
setup menu allows a form feed to be ignored if the paper is already at top of form. If “Auto CR” is set to
“On” in the interface menu, a carriage return will also be performed.
Control code: FF
Hexadecimal: 0C


Select Automatic Carriage Return ESC [ 20 h
Selects automatic carriage return mode. This causes the printer to automatically perform a carriage return
(CR) for each line feed (LF), vertical tab (VT), or form feed (FF) that it receives. Overrides the “Auto CR”
value in the interface setup menu.
Escape Sequence: ESC [ 2 0 h
Hexadecimal: 1B 5B 32 30 68

Cancel Automatic Carriage Return ESC [ 20 l
Cancels automatic carriage return mode. Overrides the “Auto CR” value in the interface setup menu.
Escape Sequence: ESC [ 2 0 l
Hexadecimal: 1B 5B 32 30 6C
0
DansDadUKCommented:
Several things I don't understand (may be due to my lack of knowledge of VB and Epson print languages, of course):

Even if "Auto CR" is set, surely this would just cause a trailing CarriageReturn (i.e. reposition cursor to beginning of current line) rather than a LineFeed (i.e. reposition cursor one line down)?

In VB.net, the Print function (see MSDN page) seems to be a deprecated function, but it also has a different parameter list than the one used in the posted code - so perhaps that code uses a private Print function (whose definition we don't know), which might explain why the 'trailing semi-colon' causes a compilation error.
0
Steven CarnahanNetwork ManagerCommented:
•Even if "Auto CR" is set, surely this would just cause a trailing CarriageReturn (i.e. reposition cursor to beginning of current line) rather than a LineFeed (i.e. reposition cursor one line down)?

The problem with Epson (and I think Oki as well) is that there is a setting to automatically attach a LF to any CR so that it acts like a typewriter.  This effect can also be altered but I don't have the actual settings for the OKI in front of me.  Here is the site for Epson to change that default:  https://files.support.epson.com/htmldocs/fx890_/fx890_rf/cp_3.htm#changing default settings b
0
DansDadUKCommented:
The "automatically add LineFeed" scenario is rather more believable.

I'm not familiar with Epson or Oki print languages, but there is certainly an equivalent in the standard HP PCL language:

<Esc>&k#G (#=0)       Line Termination: CR=CR, LF=LF, FF=FF
<Esc>&k#G (#=1)       Line Termination: CR=CR+LF, LF=LF, FF=FF
<Esc>&k#G (#=2)       Line Termination: CR=CR, LF=CR+LF, FF=CR+FF
<Esc>&k#G (#=3)       Line Termination: CR=CR+LF, LF=CR+LF, FF=CR+FF

Open in new window

0
KevinAuthor Commented:
@DansDadUK, yes that is correct, I am using a "Private" print function to print, code below:

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 declarations:
    <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

    Private hPrinter As New IntPtr(0)
    Private di As New DOCINFOA()
    Private PrinterOpen As Boolean = False

    Public ReadOnly Property PrinterIsOpen As Boolean
        Get
            PrinterIsOpen = PrinterOpen
        End Get
    End Property

    Public Function OpenPrint(szPrinterName As String) As Boolean
        If PrinterOpen = False Then
            di.pDocName = "Dot Matrix 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

        OpenPrint = PrinterOpen

    End Function

    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

Open in new window


Thank you all for your suggestions I will experiment with what you have provided and revert back.

Kind Regards,
N
0
hdhondtCommented:
I'm in the same position as DansDad: I know little about VB. I notice your code uses a function "WritePrinter" to send data to the printer, but I do not know how that function works.
0
DansDadUKCommented:
The latest posted code snippet still does not contain a definition of a Print function - it shows OpenPrint and SendStringToPrinter functions, and a Closeprint sub.
It appears to be based on this How to send raw data to a printer by using Visual Basic .NET Microsoft article.


... and (as @hdhondt points out) the "Send..." function uses WritePrinter, which appears to be a standard method defined in a referenced DLL.
0
KevinAuthor Commented:
Morning all,

After reviewing your suggestions, I found the culprit.

As hdhondt pointed out
You are using a Print command to send the formfeed. That would add an extra line feed.
, this was exactly the problem. The next issue was to find out how to suppress it.

@pony10us – Having a look at the Auto CR feature it looks like this sequence is only available for “IBM PPDS emulation mode”, in my case this would not be applicable as I am using “Epson Emulation Sequences” to communicate with the printer.

@DansDadUK – My apologies, I thought I copied everything in the posting. The Print function is coming from a sub that I have here:

Public Sub Print(Line As String)

        prn.SendStringToPrinter(PrinterName, Line + vbLf)
       
    End Sub

Open in new window


Which exactly is the line where the extra line feed was coming from, so each time the app was calling this sub it would do a line feed.

So I removed the line feed so it looks like this now:

Public Sub Print(Line As String)

        prn.SendStringToPrinter(PrinterName, Line)
       
    End Sub

Open in new window


Since I took the line feed out from the above sub I put a few line feeds in the PrintBody and PrintFooter subs to balance everything out.

Public Sub PrintBody()

        'Prints information for Body of Cheque
        Dim N2WResult As String

        N2WResult = AmountInWords(txtMAmt.Text)

        Print(eClear + eProSpaceON + eTypeface + ePitch12 + eBChqNum + " " + txtMChqNum.Text + vbLf + vbLf + vbLf + vbLf)
        Print(eBChqDate + DateTimePickerM.Text + eBN2W + "     " + N2WResult + vbLf + vbLf + vbLf)
        Print(eBPayTo + txtMPayTo.Text + vbLf)
        Print(eBRef + "REF:" + txtMRef.Text + eBAmount + eHTAB + "*" + txtMAmt.Text + "*" + vbLf)

    End Sub

Public Sub PrintFooter()

        'Prints information for Description of Cheque

        Dim formattedDate As Date = DateTimePickerM.Text

        Print(eDRVPosF + eDPayTo + txtMPayTo.Text + vbLf)
        Print(eDSummary + "CK#" + txtMChqNum.Text + " " + txtMCurr.Text + "$" + txtMAmt.Text + " " + formattedDate.ToString("MMMM dd, yyyy") + vbLf)
        Print(eDRef + "REF:" + txtMRef.Text + eFormFeed)

    End Sub

Open in new window


And now the formfeed is working properly.

I understood you all are not too familiar with VB, but I definitely think your suggestions pointed me in the right direction, thank you very much for your suggestions and for not giving up on helping me with my issue.

Your help was very much appreciated.

Kind Regards,
N
0
DansDadUKCommented:
>> .. Your help was very much appreciated ...

You're welcome.

Good that you eventually found the cause of the problem.
0
hdhondtCommented:
Glad it's fixed. Thanks for the points!
0
Steven CarnahanNetwork ManagerCommented:
Thank you, glad you got it figured out.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Printers and Scanners

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.