Remote printing issues with Delphi and ExtEscape on Zebra printer - delphi

Our app prints directly to a Zebra UPS printer (Zebra GK420d). The list of printing commands are formatted as expected by the ExtEscape (Zebra Printer direct communication).
Printing works as expected on the local machine with the USB printer attached however nothing gets printed when using the app from a remote machine via remote desktop. All computers are running Windows 10 with latest updates.
A test was done sending the following commands from the local and remote machine while the printer is paused:
^FX
^XA
^LH30,30
^FO20,10
^ADN,18,20
^FDTest^FS
^XZ
It is possible to print the above commands correctly from the remote machine if saving it to a file and copying the file to \\printer_name.
The following is the method used to print the commands that are passed as a string argument:
procedure SendCommandsToPrinter(ACommands: string);
var
FmtLabel: AnsiString;
begin
FmtLabel := '00' + AnsiString(ACommands);
PWord(FmtLabel)^ := Length(FmtLabel) - 2; // store the length
Printer.BeginDoc;
if ExtEscape(Printer.Canvas.Handle, PASSTHROUGH, Length(FmtLabel), Pointer(FmtLabel), 0, nil) <= 0 then
raise Exception.Create('Printer error');
Printer.EndDoc;
end;
The spooled files generated on C:\Windows\System32\spool\PRINTERS folder have different content, the file generated running the app on the local machine has the exact same commands that were sent to the printer while the file generated while running the app on a remote machine have the following content:
CT~~CD,~CC^~CT~
^XA
^PW812
^POI^PQ1,0,1,Y^XZ
Anyone having similar issues with Zebra printers when printing remotelly? Any ideas on how to solve this issue?
Thanks in advance.

Related

After printer restart, settings are lost

I am using GX430t Zebra printer.
My problem is that after printer restart, printer is no longer printing special characters for Slovenia.
(example file for printing is below).
Example:
Printer is restarted and then we print example file from our application (we have our own app for printing labels). Slovenian characters are not printed:
Next step is to send that same file into printer via printer settings:
File is printed correctly:
What is even more interesting is that every file printed from our application is OK, after that step is done.
My question is: where does printer stores info about that? What I would like to do is include (if possible) this information into every file that I am printing, so regardless if printer was restarted or not, Slovenian characters will be printed correctly. Otherwise, we must use printer settings and sending example file to printer each time printer is restarted.
Example file with zebra language:
^XA^LH300,10^FO10,10^A0,20,20^FD Šazoćeđa gostinstvo d.o.o.^FS^FO10,20 ^A0,20,20^FDIme polizdelka: ^FS^FO10,40 ^A0,35,35^FDŠABAN ŠAULIĆ^FS^FO10,80 ^A0,30,30^FDDatum predpriprave: 25.04.2018^FS^FO10,120 ^A0,30,30^FDUporabno najmanj do: 25.04.2018^FS^FO10,160 ^A0,20,20^FDOddelek predpriprave: Centralna predpriprava^FS^FO10,190 ^A0,30,30^FDOddelek finalizacije: HKJ_topla kuhinja^FS^FO10,230 ^A0,30,30^FDKoličina: 7 (nar.); 0 (dos.); 7 (ned.); kg^FS^FO10,265 ^FB650,12,, ^A0,20,20^FDSestavine: MOKA PSENICNA T500 1KG (aler.: Gluten; psenica;); SOL KAMENA ; JAJCNI MELANZ (aler.: Jajca;); MLEKO SVEZE 10L (aler.: Mleko;)^FS^FO10,560 ^A0,20,20^FDPripravil: Šaban Šaulić^FS^XZ
Thanks to #banno - solution was to put proper encoding into .ZPL file. In my case, taken from this it was enough to add ^CI28 after ^XA

How to send text file to printer

As i read in some fingerprint manual we can send text file to the printer. Means we can write the program in the text editor and send the whole program as a text file to the printer using the communication program using some transfer commands.
for in my host there is a file called myfile.txt in D:/ with the fallowing data
10 PRPOS 200,200
20 DIR 3
30 ALIGN 5
40 PRIMAGE “GLOBE.1”
50 PRINTFEED
RUN
How can i send this file to printer and execute the instrucations to print the image.
Please give me some code reference.
There are several ways to do this from the command line. For example:
type foo.txt > lpt1:
Or
copy foo.txt lpt1:
Or
print foo.txt
Or
notepad /p foo.txt
If you need to do it programmatically, you can execute any of those commands using the system() function or CreateProcess().
If you're on an Intermec handheld and you're connected to a Bluetooth printer, you should be able to open a serial port to COM6 and send your file over. What programming language? There should be plenty of Serial Port communication code examples out there.
My experience with Intermec PM4i label printer was a roller coaster but know I have a working app.
I tried Windows printer pipeline through generictext driver. It does work from Notepad but with few corner cases.
Printing directly from Notepad works fine until I tried QRCODE image with a very long text line. Image did not print out. Made qrcode text a short few characters and same script worked fine.
INPUT OFF
NASC 1252
BF OFF
FT "Swiss 721 Bold BT",12,0,100
PP 50,500:PT "Text line goes here"
PP 400,400:AN 7:BARSET "QRCODE",1,1,7,2,4
PB "ABC123 aabbcc....very long text goes here...I mean about 200 chars or more"
PRINTFEED
It was like Notepad cut text to a right side border and command string was broken. I made a printing preferences A3-landscape and it accepted longer text but still was not enough for all use cases.
All printers have a physical max printing width but it should not be considered in a fingerprint/directprotocol script files. After all we are not printing this text as-is but submitting commands to the printer.
My solution was to create Java application which opens a raw TCP socket to 11.22.33.44:9100 address and writes text lines, lines terminated by NL(#10). Works fine. Another helper tool I did was Delphi app.exe to read IP address from Windows printer object. I can submit label printouts "directly" from Excel application.
End users edit Excel data rows and click PRINT LABELS button
vba macro parses a fingerprint template file with ${FIELD1} find-and-replace substitutes
file is written to %wintemp%/intermec_script.txt folder
call app.exe to read IP address of user chosen printer
call java app to submit intermec_script.txt to IP:PORT socket
I should create same socket submit app in Delphi to drop javavm dependency but this solution was faster for my use case. I am more familiar with Java than my Delphi skill level.

who/what deletes the print job?

Having a strange problem where a print occasionally is not being printed
The scenario is that we print barcode labels with a barcode printer (Zebra LP2844).
Printer is plugged into the TerminalPC and then shared.
Printer->TerminalPC -> Terminal Server.
Session on TerminalServer is using Printer as \TerminalPC\Printer
When logging print Events we see the following:
Print OK:
1) Print OK (Event 10, User myUser)
2) Print deleted (Event 13, User NT-AUTHORITY\SYSTEM)
Print not OK => only Event 2) appears in the event log
Anybody having a clue about what is happening here?
More information:
This problems occurs about 2 out of 10 times. Only difference is an increasing ID being printed as part af the barcode.
The barcode is the only object being printed. It saves to file (*.emf) every time - and looks fine on file.
The application is developed using Delphi 2010 and works fine in all other ways.
Print jobs are removed from the print spooler by the port monitor. The port monitor "EndDocPort" function calls "SetJob" with JOB_CONTROL_SENT_TO_PRINTER to indicate the the job has finished, and this removes it from the spooler.
If the printer uses a custom port monitor, the problem could be in the printer driver or custom port monitor. If it uses a standard port such as LPT or USB, it's more likely a problem with the application not calling "EndDoc" consistently, or not checking return codes from EndDoc.

Print to remote Comm Port in VB6

I have a software that prints out to a thermal printer connected to the comm port, the code below works well.
Open "COM3:" For Output Access Write As #1
Print #1, Space(8) & "FRAKAS LTD"
Print #1, Space(7) & "P.O. Box 7678 SHIMONI"
...
...
Close #1
Now I want to print on the same comm port but from a different computer on the network, is it possible?
You can redirect the serial port across the network by running software at each end. There is some info on Wikipedia here about some solutions - I haven't tried any.
We have used ethernet to serial converters from Moxa - these redirect a local COM port to a remote one without any PC at the remote end. One example is here
if the printer is availabe then you can use the following to prepare text to be printed :
printer.print "text"
to start the actual printing you use the following :
printer.enddoc

Setting correct printer in MS Word through automation

I have the following automation code:
lPrintSetup := fWordObject.Application.Dialogs.Item(wdDialogFilePrintSetup);
lPrintSetup.Printer := 'MyPrinter';
lPrintSetup.DoNotSetAsSysDefault := True;
lPrintSetup.Execute;
lPrintSetup := Null;
The Printer property is giving me some problems, sometimes Execute crashes with an EOleException (0x800A1460 (error code 5216): There is a printer error) because of a wrong printername.
I have printer information of all printers in a _PRINTER_INFO_2 record which I obtained by a EnumPrinters API-call. How can I compose the right printername for Word given the information in a _PRINTER_INFO_2 record? It has work with at least Windows 2000, Word 2000 and Citrix.
Some background info:
Our application first filled the Printername with a self constructed printername. This gave problems with Citrix clients, so for Citrix clients we took the _PRINTER_INFO_2.pPortName and deleted the Client:#: part.
This is working for the majority of our customers, but sometimes still the printer error shows up.
What I have tried so far (on Windows XP SP3, Word 2007):
Just take the _PRINTER_INFO_2.pPrinterName. Problem is that when you modify printernames on purpose (renaming 'PDFCreator' to 'HP DESKJET 520 on MYPC') it crashes on the latter (while selecting this printer in Word works).
Composing a printername like this: lPrintSetup.Printer := PRINTER_INFO_2.pPrinterName + ' on ' + PRINTER_INFO_2.pPortname. Seems to work always! But googling around showed that ' on ' is localized, so I'm not sure if that's going to work on non-english Windows versions. Edit: does not work always :(
Another solution I found on the web:
When reading the printername from Word it has the form of "Printername on Ne01:", where Ne01 is ranged from Ne00: to Ne99:. The solution suggested taking the printername and just try to set it while looping from Ne00: to Ne99:. When .Execute doesn't crash, you've got the right one. I'm not very fond of this 'trail and error' method.
I'm not sure if you've tried this, or if its of any use, but you can get a list of all the printers on the system from the Printer.Printers object make sure you add Printers to the Uses clause of your unit.
This should then list the actual names on the system and you may be able to use this information to do what you want.
As stated you can get a list of printer names using the Printer.Printers which is a TStringList with the name of the printer on each item.
This code gives the default printer name
Printer.Printers[Printer.PrinterIndex]
Some minutes ago I learned, that word2k not only wants Printernames like "Printername on Ne01:" it only wants the port (NEnn) uppercase "Printername on NE01:"
I figured it out. Word has the printername in the form of "Printername on NE01:". Ne01: is the printerport as specified in the devices section of win.ini. So now I compose the printername as _PRINTER_INFO_2.pPrinterName + ' on ' + <PrinterPort from win.ini> and set that name for the printer property of the FilePrintSetup dialog.
This is much better than to resort to the trail-and-error method mentioned in my question.

Resources