I'm using the redmon to redirect de output postcript my c# .exe to process.
The print configuration is the same as if I'd do to configure the ghostscript, but instead of the ghost path I informed my .exe path.
To convert the postscript in PDF I'm using the ghostscript, as the code bellow
Stream content = Console.OpenStandardInput();
using BinaryReader standardInputReader = new BinaryReader(content);
using (FileStream standardInputFile = new FileStream(psFile, FileMode.Create, FileAccess.ReadWrite))
{
standardInputReader.BaseStream.CopyTo(standardInputFile);
}
standardInputReader.Close();
string ghostScriptPath = #"C:\gs\gs9.52\bin\gswin64.exe";
String ars = #"-Ic:\gs\gs925\lib -dNOPAUSE -dBATCH -q -dSAFER -sDEVICE=pdfwrite -sOutputFile=teste.pdf psFile.ps";
Process proc = new Process();
proc.StartInfo.FileName = ghostScriptPath;
proc.StartInfo.Arguments = ars;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();
proc.WaitForExit();
But the ghostscript always throws the error %%[ Error: undefined; OffendingCommand: Redmon ]%%.
If I use the ghostscript instead of my program everything works fine, but if I "intercept", the error always happens. I logged the output on the two cases, but the log is the same, a piece bellow.
The full log can be seen here
%%BeginResource: file Pscript_WinNT_ErrorHandler 5.0 0
/currentpacking where{pop/oldpack currentpacking def/setpacking where{pop false
setpacking}if}if/$brkpage 64 dict def $brkpage begin/prnt{dup type/stringtype
ne{=string cvs}if dup length 6 mul/tx exch def/ty 10 def currentpoint/toy exch
def/tox exch def 1 setgray newpath tox toy 2 sub moveto 0 ty rlineto tx 0
rlineto 0 ty neg rlineto closepath fill tox toy moveto 0 setgray show}bind def
/nl{currentpoint exch pop lmargin exch moveto 0 -10 rmoveto}def/=={/cp 0 def
typeprint nl}def/typeprint{dup type exec}readonly def/lmargin 72 def/rmargin 72
def/tprint{dup length cp add rmargin gt{nl/cp 0 def}if dup length cp add/cp
exch def prnt}readonly def/cvsprint{=string cvs tprint( )tprint}readonly def
/integertype{cvsprint}readonly def/realtype{cvsprint}readonly def/booleantype
{cvsprint}readonly def/operatortype{(--)tprint =string cvs tprint(-- )tprint}
readonly def/marktype{pop(-mark- )tprint}readonly def/dicttype{pop
(-dictionary- )tprint}readonly def/nulltype{pop(-null- )tprint}readonly def
/filetype{pop(-filestream- )tprint}readonly def/savetype{pop(-savelevel- )
tprint}readonly def/fonttype{pop(-fontid- )tprint}readonly def/nametype{dup
xcheck not{(/)tprint}if cvsprint}readonly def/stringtype{dup rcheck{(\()tprint
tprint(\))tprint}{pop(-string- )tprint}ifelse}readonly def/arraytype{dup rcheck
{dup xcheck{({)tprint{typeprint}forall(})tprint}{([)tprint{typeprint}forall(])
tprint}ifelse}{pop(-array- )tprint}ifelse}readonly def/packedarraytype{dup
rcheck{dup xcheck{({)tprint{typeprint}forall(})tprint}{([)tprint{typeprint}
forall(])tprint}ifelse}{pop(-packedarray- )tprint}ifelse}readonly def/courier
/Courier findfont 10 scalefont def end errordict/handleerror{systemdict begin
$error begin $brkpage begin newerror{/newerror false store vmstatus pop pop 0
ne{grestoreall}if errorname(VMerror)ne{showpage}if initgraphics courier setfont
lmargin 720 moveto errorname(VMerror)eq{userdict/ehsave known{clear userdict
/ehsave get restore 2 vmreclaim}if vmstatus exch pop exch pop PrtVMMsg}{
(ERROR: )prnt errorname prnt nl(OFFENDING COMMAND: )prnt/command load prnt
$error/ostack known{nl nl(STACK:)prnt nl nl $error/ostack get aload length{==}
repeat}if}ifelse systemdict/showpage get exec(%%[ Error: )print errorname
=print(; OffendingCommand: )print/command load =print( ]%%)= flush}if end end
end}dup 0 systemdict put dup 4 $brkpage put bind readonly put/currentpacking
where{pop/setpacking where{pop oldpack setpacking}if}if
%%EndResource
obs: I'm using Windows 10
OK well if you look at the file you posted it begins:
RedMon - Redirection Port Monitor
Copyright (C) 1997-2012, Ghostgum Software Pty Ltd. All Rights Reserved.
2012-06-21 Version 1.9
get_filename_as_user sent: C:\Users\Marina\Desktop\teste.pdf
....
...
REDMON WritePort: about to write 4096 bytes to port.
%!PS-Adobe-3.0
Everything up to the %!PS-Adobe is not PostScript and is not being sent by the printer driver. That's all being sent by the RedMon Port Monitor. The output then ends with:
%%EOF
REDMON WritePort: OK count=2489 written=2489
REDMON EndDocPort: starting
REDMON WriteThread: ending
%%[Page: 1]%%
%%[LastPage]%%
REDMON EndDocPort: process finished after 1 second
REDMON EndDocPort: 0 bytes written to printer
REDMON EndDocPort: ending
and there everything following the %%EOF is not PostScript and is coming from the Port Monitor. Since all of that doesn't form a valid PostScript program, sending it to Ghostscript will cause an error of some kind.
You need to work out how to strip that verbiage out and only send the PostScript language program to Ghostscript.
I'm afraid I can't help you with that, I don't know how your application is receiving data from RedMon.
In any event this isn't really a Ghostscript, or PostScript, question.
Related
I am working with ffmpeg via C#'s Process class.
I have a script that runs ffmpeg to generate thumbnails from video. Initially it was called manually from command line - .\ffmpeg.exe -i .\input.mp4 -ss 00:00:01.000 -vframes:v 1 output.png, it starts ffmpeg instance, outputs some warnings/errors during the execution:
[image2 # 000001e51095ec80] The specified filename 'output.png' does not contain an image sequence pattern or a pattern is invalid.
[image2 # 000001e51095ec80] Use a pattern such as %03d for an image sequence or use the -update option (with -frames:v 1 if needed) to write a single image.
frame= 1 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.00 bitrate=N/A speed= 0x
video:73kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
but anyway exits the process and correctly generates thumbnail image at output.png.
I want to execute it from C#.
Let's see the code:
var ffmpegProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = _config.FfmpegExecutablePath,
Arguments = CreateArgumentsForFfmpegProcessToRun(videoTempFilePath, thumbnailTempFilePath),
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
},
EnableRaisingEvents = true
};
ffmpegProcess.Start();
await ffmpegProcess.WaitForExitAsync();
Method CreateArgumentsForFfmpegProcessToRun returns exactly the same arguments as in the script above -i .\input.mp4 -ss 00:00:01.000 -vframes:v 1 output.png.
However, when I run this code, it stucks/blocked at line ffmpegProcess.WaitForExitAsync() infinitely and no output written to output path.
If I omit WaitForExitAsync call and just go to the next line, then it doesn't stuck and writes the output as expected and finish the process with -1 exit code.
I am trying to figure out why block/stuck happens and what is the best way to resolve this situation? As far I know, WaitForExitAsync should return as process ends, no matter how process ends - 0 or another exit code, am I right?
Update #1:
Community advised to search if somewhere up the stack I am blocking my code. I wrote xunit-test and it still stucks.
[Theory]
[InlineData("assets/input.mp4", "assets/ffmpeg.exe")]
public async Task CreateThumbnailFromVideo(string videoFilePath, string ffmpegExePath)
{
var config = new VideoThumbnailServiceConfig
{
FfmpegExecutablePath = ffmpegExePath,
ThumbnailImageExtension = ".png"
};
var sut = new VideoThumbnailService(config);
using var fileStream = File.OpenRead(videoFilePath);
await sut.CreateThumbnailFromVideo(fileStream);
}
Inside sut.CreateThumbnailFromVideom I call process start method and awaits WaitForExitAsync().
When I use ghostscript in windows cmd with my setup.ps postscript file it prints my pdfs perfectly.
setup.ps
mark
/OutputFile (%printer%HP LaserJet 1018)
/BitsPerPixel 1
/NoCancel false
/UserSettings
<<
/DocumentName(document)
/MaxResolution 360
>>
(mswinpr2)finddevice
putdeviceprops
setdevice
<<
/BeginPage {10 -55 translate}
>>
setpagedevice
CommandLine
start /d "C:\Program Files (x86)\gs\gs9.19\bin" gswin32.exe -sOutputFile="%printer%HP LaserJet 1018" -dBATCH -dNOPAUSE -dFIXEDMEDIA setup.ps a.pdf
(I don't know why it needs sOutputFile in setup.ps and in commandline but it doesn't work otherwise)
Now when I put the same switches in my C# project which uses Ghostscript.NET wrapper.
private static void CreateSetupPsFile(string printername)
{
const string Translationstring = #"{10 -15 translate}";
string ps = $#"
mark
/OutputFile (%printer%{printername})
/BitsPerPixel 1
/NoCancel false % don't show the cancel dialog
/UserSettings
<<
/DocumentName(document) % name for the Windows spooler
/MaxResolution 360
>>
(mswinpr2)finddevice % select the Windows device driver
putdeviceprops
setdevice
<<
/PageOffset [30 -30]
>>
setpagedevice";
File.WriteAllText("setup.ps", ps);
}
private static void PrintA4(string pdfFileName, PrinterSettings printerSettings)
{
using (var processor = new GhostscriptProcessor(GsDll))
{
CreateSetupPsFile(printerSettings.PrinterName);
var switches = new List<string>
{
$"-sOutputFile=\"%printer%{printerSettings.PrinterName}\"",
#"-dBATCH",
#"-dNOPAUSE",
#"-dFixedMedia",
"setup.ps",
"-f",
pdfFileName
};
processor.StartProcessing(switches.ToArray(), null);
}
}
It totally ignores everything in the setup.ps file.
Does anyone know why ? It just ignores and doesn't say what's wrong
Thank you in advance
Update
I managed to run some poscript... Apparently the wrapper needs the postscript to be given like that:
var switches = new List<string>
{
#"-dBATCH",
#"-dNOPAUSE",
#"-sDEVICE=mswinpr2",
$#"-sOutputFile=%printer%{printerSettings.PrinterName}",
"-c",
$"<</BeginPage {translateString}>> setpagedevice",
"-f",
pdfFileName
};
processor.StartProcessing(switches.ToArray(), null);
Not like that:
var switches = new List<string>
{
#"-dBATCH",
#"-dNOPAUSE",
#"-sDEVICE=mswinpr2",
$#"-sOutputFile=%printer%{printerSettings.PrinterName}",
$"-c <</BeginPage {translateString}>> setpagedevice -f",
pdfFileName
};
processor.StartProcessing(switches.ToArray(), null);
It's just unbelievable.
How do you know its ignoring what's in setup.ps ?
Tray adding some debug into the PostScript program, eg
(Inside setup.ps) == flush
The first and most obvious thing I see is that you dealare that setup.ps contains :
<<
/BeginPage {10 -55 translate}
>>
setpagedevice
Yet your code to create setup.ps contains:
<<
/PageOffset [30 -30]
>>
setpagedevice";
Clearly those aren't the same which kind of makes me doubt that you are executing the PostScript code you think you are.
How did you get on with my answer to your previous question ?
Adding an example to do all the hacky setup.ps stuff without using setup.ps or the non-standard extensions.
Firstly you don't need to use finddevice, putdeviceprops or setdevice. Just set the device on the command line and use setpagedevice to set the properties. This is standard PostScript and the way the device is intended to be configured. Ghostscript may use its non-standard stuff behind the scenes, but you don't need to worry about that.
So something like:
gswin32 -sDEVICE=mswinpr2 -sOutputFile=%printer%PrinterName -c "<</BitsPerPixel 1 /NoCancel false /DocumentName (dummy) /MaxResolution 360 /BeginPage {10 10 translate}>> setpagedevice" -f PDF.pdf
Because you aren't using finddevice/putdeviceprops/setdevice you shouldn't need to mess about trying to set OutputFile twice. I'm assuming that you do want the BeginPage but not the PageOffset. I have no idea if you really want all those device-specific settings in there, since I don't know what printer you are using, sop I've just left them.
Obviously I can't test this, because I don't have your printer, but it ought to work. All that messing about in setup.ps is just bad news, I'd avoid it if at all possible.
I'm trying to redirect the stdout and stderr of a long process. It's an Exe that could take 40 minutes until it finished processing.
The issue is that if I run the EXE from command-line (cmd), stdout and stderr are displayed on console in a certain order,
and that's the order I'd like it to be redirected from my application, but it does not work. The order is changed when I use the following function, and can't find out what the reason is. I'd appreciate an advice.
This is the code I use:
Public numOutputLines As Integer = 0
Public sortOutput As StringBuilder = Nothing
Public Function ProcessTask3New(ByVal ExeName As String, ByVal arguments As String, ByRef stdout As String, ByRef stderr As String, ByRef ExitCode As Integer, _
Optional ByVal Filename As String = "", Optional ByVal IsDeleteTempLogFiles As Boolean = False) As Boolean
' This fucntion executes cmd commands and arguments,
' Function returns standard output and startdard error. stderr contains data if error was generated
Try
ProcessTask3New = True
Dim p As Process
Dim psi As ProcessStartInfo
Dim currentTime As System.DateTime
currentTime = System.DateTime.Now
If Filename <> "" Then Filename = Replace(Filename & ".", "\", "")
Dim tmpStdoutFilename As String = System.IO.Path.GetTempPath & "stdout." & Filename & currentTime.Ticks.ToString()
Dim tmpStderrFilename As String = System.IO.Path.GetTempPath & "stderr." & Filename & currentTime.Ticks.ToString()
netOutput = New StringBuilder
p = New Process
psi = p.StartInfo
psi.Arguments = psi.Arguments.Replace("/C " & Chr(34), "/C " & Chr(34) & Chr(34))
psi.FileName = ExeName
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Minimized
' Redirect the standard output of the sort command.
' Read the stream asynchronously using an event handler.
psi.RedirectStandardOutput = True
psi.RedirectStandardError = True
psi.CreateNoWindow = True
sortOutput = New StringBuilder()
' Set our event handler to asynchronously read the sort output.
AddHandler p.OutputDataReceived, _
AddressOf SortOutputHandler
AddHandler p.ErrorDataReceived, AddressOf SortOutputHandler
If IsDebug Then Write2Log("ProcessTask3New: " + psi.FileName.ToString + " " + psi.Arguments.ToString)
Try
Write2Log(My.Computer.FileSystem.CurrentDirectory)
p.Start()
Catch w As System.ComponentModel.Win32Exception
Write2Log("ProcessTask3New: " & w.Message)
Write2Log("ProcessTask3New: " & w.ErrorCode.ToString())
Write2Log("ProcessTask3New: " & w.NativeErrorCode.ToString())
Write2Log("ProcessTask3New: " & w.StackTrace)
Write2Log("ProcessTask3New: " & w.Source)
Dim e As New Exception()
e = w.GetBaseException()
Write2Log("ProcessTask3New: " & e.Message)
End Try
' Start the asynchronous read of the sort output stream.
p.BeginOutputReadLine()
p.BeginErrorReadLine()
p.WaitForExit()
ExitCode = p.ExitCode
p.Close()
netOutput = Nothing
Catch ex As Exception
Write2Log("error at ProcessTask3New function: " & ex.ToString & " : " + ex.StackTrace)
End Try
End Function
Private Sub SortOutputHandler(ByVal sendingProcess As Object, _
ByVal outLine As DataReceivedEventArgs)
' Collect the sort command output.
If Not String.IsNullOrEmpty(outLine.Data) Then
numOutputLines += 1
Add the text to the collected output.
sortOutput.Append(Environment.NewLine + "[" _
+ numOutputLines.ToString() + "] - " _
+ outLine.Data)
End If
End Sub
Now the output.
This is how it looks when I run it from cmd window (this is GOOD):
Processing key file: vob_db.k01(1), total of 291 nodes
Processing delete chain: 1 node on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100 %
Processing key file: vob_db.k02(2), total of 1246 nodes
Processing delete chain: 2 nodes on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100 %
Processing key file: vob_db.k03(5), total of 1 node
Processing delete chain: 0 nodes on delete chain. Processing nodes:
100%
Processing key file: vob_db.k04(6), total of 277 nodes
Processing delete chain: 7 nodes on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100 %
(the lines like this one come from stderr.)
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%++
This is how it looks when I run it from my application (this is BAD):
ProcessTask3New: cmd.exe /C ""C:\Program Files
(x86).." -a -k -R -r1
-p29000 vob_db" E:\backup2\db db_VISTA Version 3.20 Database Consistency Check Utility Copyright (C) 1985-1990 Raima
Corporation, All Rights Reserved
------------------------------------------------------------------------ Processing key file: vob_db.k01(1), total of 291 nodes
------------------------------------------------------------------------ Processing key file: vob_db.k02(2), total of 1246 nodes
------------------------------------------------------------------------ Processing key file: vob_db.k03(5), total of 1 node
------------------------------------------------------------------------ Processing key file: vob_db.k04(6), total of 277 nodes
------------------------------------------------------------------------ Processing data file: vob_db.d01(0), total of 7107 records
------------------------------------------------------------------------ Processing data file: vob_db.d02(3), total of 20516 records
------------------------------------------------------------------------ Processing data file: vob_db.d03(4), total of 1 record
------------------------------------------------------------------------ Processing data file: vob_db.d04(7), total of 0 records
------------------------------------------------------------------------ Processing data file: vob_db.d05(8), total of 39938 records Processing
delete chain: 1 node on delete chain. 0 errors were encountered in 0
records/nodes
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100% Processing delete chain: 2 nodes on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100% Processing delete chain: 0 nodes on delete chain. Processing nodes:
100%
Please advice. THANK YOU!
You have the option to "mix" the stdout and stderr, redirecting the stderr into stdout
cmd /c "commandToRun 2>&1"
Here we are asking cmd to execute some command and redirect the stream 2 (stderr) sending its output to stream 1 (stdout).
BUT, obviously you will not retrieve any data on stderr.
The reason behind different orders is that when in console, a single output stream is indeed assigned to both "standard output" and "error output", and when called by your application, there are two streams that are not synchronized, thus your SortOutputHandler events are called in any order (if there were extremely long pauses between writes to the outputs or flushes it could get ordered correctly by chance).
The only solution you have to get this well sorted is to ensure that there is a single stream. The problem is that I am not aware of a solution allowing this using the ProcessStartInfo class.
One possibility would be to start the process in "pause" mode, then redirect forcefully its standard error handle to the output handle, then let it run (as cmd.exe does)
ProcessStartInfo startInfo = new ProcessStartInfo("CMD.exe");
startInfo.Arguments = "/c " + URL;
Process p = new Process();
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.CreateNoWindow = true;
p = Process.Start(startInfo);
string original = p.StandardOutput.ReadToEnd();
string result1 = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes(original));
string result2 = Encoding.BigEndianUnicode.GetString(Encoding.BigEndianUnicode.GetBytes(original));
string result3 = Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(original));
string result4 = Encoding.UTF32.GetString(Encoding.UTF32.GetBytes(original));
string result5 = Encoding.UTF7.GetString(Encoding.UTF7.GetBytes(original));
string result6 = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(original));
cmd output contains russian letters, that can't be decoded properly with all encodings what I tried. Please help.
I tried:
startInfo.StandardOutputEncoding = Encoding."all possible encodings";
but no help.
any ideas?
Old question, but no possible correct answer.
Here it is:
process.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(850);
850 is the standard cmd-page. So the user which is using the application will get the characters just as he would expect when using the command line itself.
This one solved all symbol-problems on a german OS for me.
OEM code pages:
437 - English
708 - Arabic (ASMO)
720 - Arabic (Microsoft)
737 - Greek
775 - Baltic
850 - Western European (Multilingual Latin I)
852 - Middle European (Latin II)
855 - Cyrillic
857 - Turkish
858 - Western European (Multilingual Latin I + Euro)
860 - Portuguese
861 - Icelandic
862 - Hebrew
863 - Canadian French
864 - Arabic (IBM)
865 - Nordic
866 - Russisch
869 - Greek
1254 - Turkish
This works for me:
startInfo.StandardOutputEncoding = Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage)
First, you need to set a correct font for your console. Run the application with some pause (see the second code sample below) once, click "Properties" and change the font.
Now, you need to set the encoding for three things: in first application (to be executed as a child process), this is the console output encoding. In the parent-process application, you need to do the same if you want to see the result, you need to do the same, but you also need to set standard output encoding in System.Diagnostics.ProcessStartInfo. Also, if you use some input, you should need all three things in input.
On my system, all UTFs except UTF-8, throw an exception. Let it be: only one UTF is probably currently implemented (Windows 7 Pro, in my case).
First, let's see how can you write the application which simply outputs the Unicode text:
namespace WriteAndPresentUnicode {
using System;
class Program {
static void Main(string[] args) {
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine("Пишем по-русски..."); // "We are writing in Russian..."
} //Main
} //class Program
} //namespace WriteAndPresentUnicode
Now, let's see how to start it as a chile process with redirection of output:
namespace ReadUnicode {
using System;
using System.Diagnostics;
using System.IO;
class Program {
const string application = "WriteAndPresentUnicode.exe";
static void Main(string[] args) {
Process myProcess = new Process();
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(application);
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8; // this is the most important part, to get correct myString, see below
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadToEnd();
myProcess.WaitForExit();
myProcess.Close();
Console.InputEncoding = System.Text.Encoding.UTF8;
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine(myString);
Console.WriteLine("Press any key...");
Console.ReadKey(true);
} //Main
} //class Program
} //namespace ReadUnicode
-Tested-
The solution to use UTF8 encoding to write console is good if console application is yours. But if you using standart Windows utilites like 'netsh' it doesn't help. Standart cmd code pages is OEM. For example for Russian language:
process.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
process.StartInfo.StandardErrorEncoding = Encoding.GetEncoding(866);
OEM code pages:
437 (US)
720 (Arabic)
737 (Greek)
775 (Baltic)
850 (Multilingual Latin I)
852 (Latin II)
855 (Cyrillic)
857 (Turkish)
858 (Multilingual Latin I + Euro)
862 (Hebrew)
866 (Russian)
Try this if nothing else helps!
After a lot of trying & suffering, here's what I found out: no matter how UTF8 your output stream is, no matter how you set 65001, things will not work until you start a child process inside the child process. Sounds silly but true.
Look:
chcp 65001 && dir // nope, still 437
chcp 65001 && cmd /c dir // correct UTF8
Hope this saves you at least as much time as it took from my miserable life!
Below are my code:
PosExplorer posExplorer = new PosExplorer();
DeviceCollection receiptPrinterDevices = posExplorer.GetDevices(DeviceType.PosPrinter);
DeviceInfo receiptPrinterDevice = posExplorer.GetDevice(DeviceType.PosPrinter,"SRP2");
PosPrinter printer = (PosPrinter)posExplorer.CreateInstance(receiptPrinterDevice);
printer.Open();
printer.Claim(10000);
printer.DeviceEnabled = true;
printer.PrintNormal(PrinterStation.Receipt, "test print 1");
I debug and everything went through without exception, already confirmed also that the printer targeted is the correct one, however the printer is not printing anything. Is there any step that I did wrong? Any guidance is greatly appreciated. Thanks
If it helps, My Printer Interface via Ethernet to a specific IP.
The problem appears to be that you are not sending a new line character (\n) at the end of your PrintNormal string, without it the service object will just buffer the line data, waiting until it sees the \n before sending the data to the device.
printer.PrintNormal(PrinterStation.Receipt, "test print 1\n");
From the POS for .net Documentation on PrintNormal
Newline / Line Feed (10 Decimal)
Print any data in the line buffer, and feed to the next print line. (A carriage return is not required in order to print the line.)
This is because the printer must print one complete line at a time, so it waits until you tell it that you have completed a line before starting to print, this allows you to use 2 or more PrintNormal calls for a single line of printout to build up the line data if needed (e.g. in a loop).
I have ran the below code on a networked POS Printer (Tysso PRP-250) and with the \n it prints the line, without it it does not.
PosExplorer posExplorer = new PosExplorer();
DeviceInfo receiptPrinterDevice = posExplorer.GetDevice(DeviceType.PosPrinter, "SRP2");
PosPrinter printer = posExplorer.CreateInstance(receiptPrinterDevice) as PosPrinter;
printer.Open();
printer.Claim(10000);
if (printer.Claimed)
{
printer.DeviceEnabled = true;
printer.PrintNormal(PrinterStation.Receipt, "test print 1\n");
printer.DeviceEnabled = false;
}
printer.Release();
printer.Close();