?
Solved

Line printer problems

Posted on 2009-12-29
28
Medium Priority
?
1,584 Views
Last Modified: 2013-11-23
In my Delphi 7 app, I'm trying to get a dot-matrix printer (Epson LQ590) to operate like a line printer, in other words, just to print one lie at a time without executing a form feed. Currently, the printer prints one line then form feeds so I only get one line per page.

I'm using the Printers unit and the fowing code;

 Printer.BeginDoc;
  Printer.Canvas.Pen.Color  := 0;
  Printer.Canvas.Font.Name  := 'Times New Roman';
  Printer.Canvas.Font.Size  := 12;
  //Printer.Canvas.TextOut(0, 100, #10+PrtStr+#13); // This didn't work
  Printer.Canvas.TextOut(0, 100, PrtStr);
  Printer.EndDoc;

The Epson is set up as the default system printer. Is it because I'm printing @0,100 each time? Or, Are there special control codes that I need to send with the print string? Or, do I need to modify the system printer properties?

Anybody got any suggestions?

Thanks
0
Comment
Question by:jsmitter
  • 12
  • 9
  • 3
  • +3
28 Comments
 
LVL 10

Expert Comment

by:atul_parmar
ID: 26143547
Hi, I suggest you to refer the printer manual where you will find the escape sequences. For better control open the printer port directly and print using WriteLn/Write method.

0
 
LVL 19

Expert Comment

by:MerijnB
ID: 26143840
There is an optional rs-232 module available for this printer. It's very possible that it will be very easy to achieve what you want with this module. It's more or less the same as atul_parmar says (open lpt direct), but much easier to achieve.
0
 
LVL 19

Expert Comment

by:MerijnB
ID: 26143846
Though keep in mind that if you go direct, you probably loose the ability to select a font (Times in this case) just like that, the printer will probably print in a default font.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 7

Expert Comment

by:twinsoft
ID: 26143861
Hi, the best way to print to a dot-matrix printer is to use the ESCAPE function. With this one you bypass the windows driver internal printing methods and print directly to the printer. Here is the code:

type
  TPrnBuffRec = record
  bufflength: Word;
  Buff_1: array[0..255] of Char;
end;

function DirectToPrinter(S: string; NextLine: Boolean): Boolean;
var
  Buff: TPrnBuffRec;
  TestInt: Integer;
begin
  TestInt := PassThrough;
  if Escape(Printer.Handle, QUERYESCSUPPORT, SizeOf(TESTINT), @testint, nil) > 0 then
  begin
    if NextLine then  S := S + #13 + #10;
    StrPCopy(Buff.Buff_1, S);
    Buff.bufflength := StrLen(Buff.Buff_1);
    Escape(Printer.Canvas.Handle, Passthrough, 0, @buff, nil);
    Result := True;
  end
  else
    Result := False;
end;

//  example:
printer.BeginDoc;
try
  printer.printerindex := printer.printers.IndexOf('PrinterName');
  directoprinter('This text ');
finally
  printer.EndDoc;
end;

Happy holidays...
0
 
LVL 19

Expert Comment

by:MerijnB
ID: 26143873
You know it's a good day if it starts with learning something completely new (and that's not sarcasm), thanks twinsoft :)

Please let me know if it works like you want jsmitter!
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26143892
Futhermore, if you need to change the font size, enable condessed mode etc you should use Escape Sequences and send them to the printer like this

directoprinter(#27#64);

0
 

Author Comment

by:jsmitter
ID: 26144769
Thanks for the input. If I bypass the Windows printer drivers, like Twinsoft suggests, how do I "bypass the windows driver internal printing methods and print directly to the printer". The printer connects through a USB port.
Do I still install the Epson drivers? Also, will it create a problem if the printer goes "off line", runs out of paper, how are printer errors handled, etc?
Thanks again!
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26145210
Hi again,
you do not bypass the windows driver, you bypass the internal printing methods. Yes, you install the windows driver for the printer or a Generic Text driver, if you do not have it. Everything else is working as expected, the printouts are spooled, offline and out of paper situations are handled by the windows spooler as usual. You can also select the printer port from within the driver properties (the virtual USB port in your case). All this is tested in live installations for over a decate in commercial applications that we develop...
0
 
LVL 22

Expert Comment

by:8080_Diver
ID: 26145718
One other point.  If I remember correctly from when I was messing with Epson dot matrix printers, the BEGIN DOC and END DOC functions are causing the single line to be treated as a complete document . . . which causes the form feed at the end of printing that line (or, more precisely, at the END DOC).
If you know all the lines that need to be printed, loop through them where you have the print statement for the single line.
0
 
LVL 13

Expert Comment

by:Ashok
ID: 26150928
Could you try?

var
  myFile : TextFile;
begin
  // Try to open a printer file
    AssignPrn(myFile);

    // Now prepare to write to the printer
    ReWrite(myFile);

    // Write a couple of well known words to this file -
    // they will be printed instead
    WriteLn(myFile, 'Hello');
    WriteLn(myFile, 'World');

    // Close the file
    CloseFile(myFile);
end;

HTH
Ashok
0
 
LVL 13

Expert Comment

by:Ashok
ID: 26150933
Could you try?

Note: Add Printers in uses clause.

uses Printers;

var
  myFile : TextFile;
begin
  // Try to open a printer file
    AssignPrn(myFile);

    // Now prepare to write to the printer
    ReWrite(myFile);

    // Write a couple of well known words to this file -
    // they will be printed instead
    WriteLn(myFile, 'Hello');
    WriteLn(myFile, 'World');

    // Close the file
    CloseFile(myFile);
end;

HTH
Ashok
0
 

Author Comment

by:jsmitter
ID: 26166920
I am off for New Years and will be back on the project by Tues. Looking forward to trying these recommendations. Happy New Year, everyone!
0
 

Author Comment

by:jsmitter
ID: 26318008
Hi everyone. I'm back. I lost my printer and had to go out and buy another one.
I've been playing with twinsoft's approach. I get a compile but then I get a "Debugger Exception Message - 'Printing In Progress'"  when my app tries to print. My Delphi 7 help file has nothing on the Escape Function.Therefore, I've enclosed my code to see if maybe I didn't understand something properly.
I'm not sure where the type statements go. Framing it with "Type" and "End" threw me off. Right now, I've got it placed under implentation.
implementation

type  
  TPrnBuffRec = record
  bufflength: Word;
  Buff_1: array[0..255] of Char;
end;
{$R *.dfm}
___________________________________________________________________
******* I declared the function under TForm1 Class Private left the function as it was in the twinsoft's example.
function TForm1.DirectToPrinter(S: string; NextLine: Boolean): Boolean;
var
  Buff: TPrnBuffRec;
  TestInt: Integer;
begin
  TestInt := PassThrough;
  if Escape(Printer.Handle, QUERYESCSUPPORT, SizeOf(TESTINT), @testint, nil) > 0 then
  begin
    if NextLine then  S := S + #13 + #10;
    StrPCopy(Buff.Buff_1, S);
    Buff.bufflength := StrLen(Buff.Buff_1);
    Escape(Printer.Canvas.Handle, Passthrough, 0, @buff, nil);
    Result := True;
  end
  else
    Result := False;
end;
____________________________________________________________________________
******* My implentation from within another procedure is -
  printer.BeginDoc;
try
  printer.printerindex := printer.printers.IndexOf('EPSON LQ-590 ESC/P2');
  DirectToPrinter(PrtStr,True);
finally
  printer.EndDoc;
end;
_____________________________________________________________________________
I replaced PrinterName in twinsoft's example with the WinXP printer name 'EPSON LQ-590 ESC/P2' found in "Printers and Faxes". This printer is also selected as the system default printer.
I really appreciate all the help. Thanks
0
 

Author Comment

by:jsmitter
ID: 26319817
I have one more observation to add
When the "Printer In Progress" message appears, the printer queue icon appears in the systray. When opening it, the print job is listed but the file size is 0. So, it appears that the string is not being passed to the procedure. I'll bet its got something to do with the "type" statement being in the wrong place? The only two places I could get the app to compile is placing it right above the implentaion line or below it. Either place yeilds the same result. Where is the right place for it?
Thanks again
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26321084
Hi, the problem is here:

 printer.BeginDoc;
try
 printer.printerindex := printer.printers.IndexOf('EPSON LQ-590 ESC/P2');
 DirectToPrinter(PrtStr,True);
finally
 printer.EndDoc;
end;

it should be

 printer.printerindex := printer.printers.IndexOf('EPSON LQ-590 ESC/P2');
 printer.BeginDoc;
try
 DirectToPrinter(PrtStr,True);
finally
 printer.EndDoc;
end;

You first select the printer and then start a printout to it...
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26321094
Hmm, i just saw that the mistake was mine ... (in the previous post). Sorry...
0
 

Author Comment

by:jsmitter
ID: 26322331
Thanks twinsoft,
The change worked. However, it still only prints one line per 11" page. I checked the printer settings and auto LF and auto CR are disabled and there is no auto form feed. What next?
Thanks
0
 

Author Comment

by:jsmitter
ID: 26322563

One more observation.
Interesting... Setting the boolean value from 'true' to 'false' in the 'DirectToPrinter(PrtStr,True)' statement does not change the result. It prints just like it did when it was set to 'true'. Hope this helps. Thanks
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26325477
Hi again,
  try changing the paper size in the device settings page, in the driver properties, to not available
0
 

Author Comment

by:jsmitter
ID: 26326073
No difference.
0
 

Author Comment

by:jsmitter
ID: 26327526

twinsoft,

Your routine works great and I like the versitality that it provides. However, as I stated, a FF was executed after the line was printed. I resolved this by appendinding the string with the following ESC/P codes;
 
if NextLine then  S := S + #27+#67+#1;
the 27,67,1 overrides the FF by setting the FF to one line.
The CR is necessary because the printer is a bidirectional printer. The print function now works perfectly. However, there is one last issue. The buffer fills up and the app errors out.
Last question - What is the best way to clear the buffer after the line prints? And I still need an answer to one of my earlier questions - Where should I put the type/end statement. I currently have it as the last declaration before the "implementation" section. Is that correct?
 
Many thanks,

0
 

Author Comment

by:jsmitter
ID: 26327552
Correction - the sentence where I state that the CR was necessary should have read - "The CR was not necessary..."
Sorry for the confusion
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26327647
Hi,
  1) change the length of the buffer

    Buff_1: array[0..511] of Char;

  2) The best way is to create a component that will do the job. I am sending you the declaration class of the component that i've created, to have something as a prototype (It is a comp specific to the thermal printers i use). If you don't want to use a component, the declaration must be after the first type in your unit and before the declaration of your form class. Something like this:

type
  TPrnBuffRec = record
  bufflength: Word;
  Buff_1: array[0..511] of Char;

  TForm1 = class(TForm)
  ....


  TXSPrintFormII = class(TComponent)
  private
    CurrPage: Integer;
    TotalPages: Integer;
    FPrintType: TPrintTypes;
    FTitle: string;
    FAsciiForm: string;
    FMemoryForm: TStrings;
    FCurrentPrinter: string;
    FLinesPerPage: integer;
    FIsSlipPrinter: boolean;
    FEnableCutter: boolean;
    FPrintFooter: boolean;
    FOnFieldData: TNotifyOnGetFieldData;
    FCharPitch: TCharPitch;
    FMyPrinters: TStrings;
    FOnPrintProgress: TNotifyOnPrintProgress;
    FLineSpacing: TLineSpacing;
    FHexFldNumbers: Boolean;
    FPrintToFile: Boolean;
    FPrintFileName: String;
    FHandle: TextFile;
    FooterBlock: Boolean;
    FOnPrintForm: TNotifyOnPrintForm;
    FBrcData: String;
    FPrintToMemory: Boolean;
    FUse437Greek: Boolean;
    FOnPrintDetails: TNotifyOnPrintDetails;
    FOnPrintDetailsEnd: TNotifyOnPrintDetailsEnd;
    FPrintDataset: TDataset;
    FIsLaserPrinter: boolean;
    FCurrentFont: String;
    FIs350Plus: Boolean;
    FIsTextPrinter: Boolean;
    FUseUnicode: Boolean;
    FRawPrintForm: Boolean;
    FPrintBlocks: Boolean;
    FReversePrint: Boolean;
    FEnableReverse: Boolean;

    procedure SetAsciiForm(const Value: string);
    procedure SetMemoryForm(const Value: TStrings);
    procedure SetCurrentPrinter(const Value: String);
    procedure PrepareForm(f: TStringList; DetailRecs: Variant);
    procedure SetPrintDataset(const Value: TDataset);
    procedure Print(LastPage: Boolean);
    procedure LoadPrinters;

    function SearchCode(line: string; NewCommand, IsDetail: boolean; DetailCount: Integer = 0): string;
    function DirectToPrinter(s: string; ChangeLine: boolean): Boolean;
    function PrintBarcode(Barcode: String; BrcType: TBrcType; Height: Integer; Width: TBrcWidth; HRI: THRI): String;
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure PrintForm(DetailRecs: Variant);
    procedure RefreshPrinters;
    procedure SetReverseFont(const aIsReverse: Boolean);
    function GetStandardFont(const Value: Integer): String;
    function GetFontEscSeq(aPrintType: TPrintTypes): String;
    function GetCurrFontEscSeq: TPrintTypes;
    function ConvertToDos(s: string): string;
    function SendPulse: String;
    function SendString(aString: String): Boolean;
    property Printers: TStrings read FMyPrinters;
    property CurrentFont: String read FCurrentFont;
  published
    property AsciiForm: string read FAsciiForm write SetAsciiForm;
    property CharPitch: TCharPitch read FCharPitch write FCharPitch;
    property MemoryForm: TStrings read FMemoryForm write SetMemoryForm;
    property CurrentPrinter: string read FCurrentPrinter write SetCurrentPrinter;
    property FormTitle: string read FTitle write FTitle;
    property PrintFooter: boolean read FPrintFooter write FPrintFooter;
    property PrintBlocks: boolean read FPrintBlocks write FPrintBlocks;
    property EnableCutter: boolean read FEnableCutter write FEnableCutter;
    property IsSlipPrinter: boolean read FIsSlipPrinter write FIsSlipPrinter;
    property IsLaserPrinter: boolean read FIsLaserPrinter write FIsLaserPrinter;
    property IsTextPrinter: boolean read FIsTextPrinter write FIsTextPrinter;
    property LinesPerPage: integer read FLinesPerPage write FLinesPerPage;
    property LineSpacing: TLineSpacing read FLineSpacing write FLineSpacing;
    property HexFldNumbers: Boolean read FHexFldNumbers write FHexFldNumbers;
    property PrintToFile: Boolean read FPrintToFile write FPrintToFile;
    property PrintToMemory: Boolean read FPrintToMemory write FPrintToMemory;
    property PrintFileName: String read FPrintFileName write FPrintFileName;
    property RawPrintForm: Boolean read FRawPrintForm write FRawPrintForm;
    property OnFieldData: TNotifyOnGetFieldData read FOnFieldData write FOnFieldData;
    property OnPrintProgress: TNotifyOnPrintProgress read FOnPrintProgress write FOnPrintProgress;
    property OnPrintForm: TNotifyOnPrintForm read FOnPrintForm write FOnPrintForm;
    property OnPrintDetails: TNotifyOnPrintDetails read FOnPrintDetails write FOnPrintDetails;
    property OnPrintDetailsEnd: TNotifyOnPrintDetailsEnd read FOnPrintDetailsEnd write FOnPrintDetailsEnd;
    property Use437Greek: Boolean read FUse437Greek write FUse437Greek;
    property UseUnicode: Boolean read FUseUnicode write FUseUnicode;
    property PrintDataset: TDataset read FPrintDataset write SetPrintDataset;
    property Is350Plus: Boolean read FIs350Plus write FIs350Plus;
    property EnableReverse: Boolean read FEnableReverse write FEnableReverse;
  end;

Open in new window

0
 

Author Comment

by:jsmitter
ID: 26327806
My app runs 24/7. No matter how large I make the buffer, it will evenually max out and cause the app to error out. I don't need to retain the data. Is there a way to clear or reset the buffer after I print the string?
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 26328006
Hi again,
  what you should do is create your printout in a TStringList by calling StringList.Append() for each line that you want to print. Then parse the StringList like this:

 printer.printerindex := printer.printers.IndexOf('EPSON LQ-590 ESC/P2');
 printer.BeginDoc;
try
 for i := 0 to StringList.Count -1
  DirectToPrinter(Stringlist[i],True);
finally
 printer.EndDoc;
end;

That way each buffer will only hold data for one line and you will not consume any memory. This is the way i am doing it...
0
 

Author Comment

by:jsmitter
ID: 26328709
I'm so close but yet so far!
I placed the type/end statement where you suggested - right above 'TForm1 = class(TForm)'. The interesting thing is, that the statement 'type' is not required (it would be redundant), but the statement 'end' is. This looks strange to me and I don't think its right. It's the only way that the program compiles. I would think that it would fit in with the rest of the type declarations.
______________________________________________________
type
  TPrnBuffRec = record
  bufflength: Word;
  Buff_1: array[0..511] of Char;
  end;                                       // Is this right?

  TForm1 = class(TForm)
________________________________________________________
I must be missing something fundamental here. Help!
Thanks

 
0
 
LVL 7

Accepted Solution

by:
twinsoft earned 2000 total points
ID: 26329807
Hi,
  it was late last night when i posted... Yes, you need the end; statement because it ends the record block...

type
 TPrnBuffRec = record
 bufflength: Word;
 Buff_1: array[0..511] of Char;
 end;                                       // This ends the record not the type


 TForm1 = class(TForm)
0
 

Author Closing Comment

by:jsmitter
ID: 31671036
Thanks twinsoft, The printer is now printing properly and I have complete control of it with the esc/p commands. Have a great new year!
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Sometimes clients can lose connectivity with the Lotus Notes Domino Server, but there's not always an obvious answer as to why it happens.   Read this article to follow one of the first experiences I had with Lotus Notes on a client's machine, my…
This article provides a convenient collection of links to Microsoft provided Security Patches for operating systems that have reached their End of Life support cycle. Included operating systems covered by this article are Windows XP,  Windows Server…
Windows 8 comes with a dramatically different user interface known as Metro. Notably missing from the new interface is a Start button and Start Menu. Many users do not like it, much preferring the interface of earlier versions — Windows 7, Windows X…
Windows 8 came with a dramatically different user interface known as Metro. Notably missing from that interface was a Start button and Start Menu. Microsoft responded to negative user feedback of the Metro interface, bringing back the Start button a…
Suggested Courses

807 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