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!
Related
I want to merge many pdf to a single one with Pdftk.
How can i make it so that whenever a pdf has an odd number of pages, a blank page is added?
I need this function for a cmd tool which i need to write in c#.
The PDF should be printed double-sided.
using System.Diagnostics;
using System.IO;
using MergePdf.Properties;
using System.Linq;
using System.Collections;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace System.Configuration
{
class Program
{
static void Main(string[] args)
{
Console.Title = "MergePDF";
// Folder from which the PDF will be pulled
string altDirIn = Settings.Default.AlternativeInputDir;
// Folder in which the merged PDF will be placed
string altDirOut = Settings.Default.AlternativeOutputDir;
// sort the files by the first name before the "_"
var rchg = new DirectoryInfo(altDirIn);
var files1 = rchg.EnumerateFiles("*.pdf").OrderBy(fi => Convert.ToInt32(fi.Name.Split('_')[0]));
var cmd1 = $"{string.Join(" ", files1.Select(fi => fi.FullName))} cat output {altDirOut}";
var evn = new DirectoryInfo(altDirIn);
var files2 = evn.EnumerateFiles("*.pdf").OrderBy(fi => Convert.ToInt32(fi.Name.Split('_')[0]));
var cmd2 = $"{string.Join(" ", files2.Select(fi => fi.FullName))} cat output {altDirOut}";
Process p = new Process();
p.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
p.StartInfo.FileName = "pdftk.exe";
p.StartInfo.Arguments = cmd1;
p.StartInfo.Arguments = cmd2;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.Start();
Console.WriteLine(p.StandardError.ReadToEnd());
Console.WriteLine("Bitte drücken Sie eine beliebige Taste, um das Programm zu beenden...");
Console.ReadKey();
p.WaitForExit();
}
}
}
When I do it this way, I have the problem that if, for example, a pdf has an odd number of pages, then on the back of the last page of the first pdf is the first page of the next pdf.
How can I proceed so that each pdf gets an even number of pages?
best regards and thanks in advance
If you can shell out to pdftk, you can shell out to cpdf and run:
cpdf -pad-multiple x in.pdf -o out.pdf
Where x here is the number of pages in the file, if even, or the number of pages in the file plus one, if odd.
You can obtain the page count with
cpdf -pages foo.pdf
Then the resulting files can be merged.
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.
I am developing an application for GSM Modems (D-Link DWM-156) in C#.Net using AT commands. I have a problem sending English SMS.
I try to send "hello", But I receive □□□□ in my phone or ...exept hello.
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.BaudRate = 9600;
serialPort1.DtrEnable = true;
serialPort1.RtsEnable = true;
serialPort1.DiscardInBuffer();
serialPort1.DiscardOutBuffer();
serialPort1.WriteLine("AT\r");
Thread.Sleep(2000);
serialPort1.WriteLine("AT+CMGF=1\r");
Thread.Sleep(1000);
serialPort1.WriteLine("AT+CMGS=\"09390149196\"\r")
Thread.Sleep(2000);
serialPort1.WriteLine("hello" + "\x1A");
Thread.Sleep(1000);
Few fixes (maybe more but I don't see full-code).
Do not use WriteLine() but Write() because for \r (alone) is the command line and result code terminator character.
SerialPort.WriteLine() by default writes a usASCII encoded string but your GSM modem expect strings encoded as specified with an AT command. Set SerialPort.Encoding property to a specific encoding and send CSCS command. You can ask supported encodings with CSCS=? AT command. Even if default GSM should apply I'd avoid to rely implicitly on this.
You do not need to wait after each command but you have to wait for modem answer (checking for OK or ERROR strings).
From docs:
A command line is made up of three elements: the prefix, the body, and the termination character. The command line prefix consists of the characters "AT" or "at" [...] The termination character may be selected by a user option (parameter S3), the default being CR.
In pseudo-code:
void SendCommand(string command) {
serialPort.Write(command + "\r");
// Do not put here an arbitrary wait, check modem's response
// Reading from serial port (use timeout).
CheckResponse();
}
serialPort.DataBits = 8;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.BaudRate = 9600;
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
serialPort.Encoding = Encoding.GetEncoding("iso-8859-1");
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
SendCommand("AT"); // "Ping"
SendCommand("AT+CMGF=1"); // Message format
SendCommand("AT+CSCS=\"PCCP437\""); // Character set
SendCommand("AT+CMGS=\"123456\"") // Phone number
SendCommand("hello" + "\x1A"); // Message
To check response (absolutely avoid arbitrary waits!) you can start with something like this (raw untested adaption so you may need some debugging, see also this post):
AutoResetEvent _receive;
string ReadResponse(int timeout)
{
string response = string.Empty;
while (true)
{
if (_receive.WaitOne(timeout, false))
{
response += _port.ReadExisting();
}
else
{
if (response.Length > 0)
throw new InvalidOperationException("Incomplete response.");
else
throw new InvalidOperationException("No response.");
}
// Pretty raw implementation, I'm not even sure it covers
// all cases, a better parsing would be appreciated here.
// Also note I am assuming verbose V1 output with both \r and \n.
if (response.EndsWith("\r\nOK\r\n"))
break;
if (response.EndsWith("\r\n> "))
break;
if (response.EndsWith("\r\nERROR\r\n"))
break;
}
return response;
}
Adding _receive.Reset() just before you send your command and of course also adding OnPortDataReceived as handler for SerialPort.DataReceived event:
void OnPortDataReceived(object sender,
SerialDataReceivedEventArgs e)
{
if (e.EventType == SerialData.Chars)
_receive.Set();
}
If you have some trouble (but you can connect) you may replace \r with \n. Some modems incorrectly (assuming <CR> has not been mapped to anything else than 13 using S3 parameter) use this character as command line terminator by default (even if it should be present in output only for V1 verbose output). Either change your code or send appropriate S3.
I'm trying create a sub-process in C# program (cmd for example) and performing read/write with process IO streams. I'm using StandardOutput.Read() method to read process output.
When I put a Thread.Sleep() method before Read(), it gives complete output but if I remove it, it displays only single line of output.
Here is the code:
string sProcess = "cmd.exe";
ProcessStartInfo psiInfo = new ProcessStartInfo();
psiInfo.FileName = sProcess;
psiInfo.CreateNoWindow = true;
psiInfo.UseShellExecute = false;
psiInfo.RedirectStandardOutput = true;
psiInfo.RedirectStandardError = true;
psiInfo.RedirectStandardInput = true;
Process pChild = new Process();
pChild.StartInfo = psiInfo;
if (pChild.Start())
{
int ch;
do
{
Thread.Sleep(50);
ch = pChild.StandardOutput.Peek();
if (ch > 0)
Console.Write((char)pChild.StandardOutput.Read());
} while (ch > 0);
Console.WriteLine("exit");
pChild.StandardInput.WriteLine("exit");
}
Output with Sleep enabled:
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
D:\ProcessDemo_001\bin\Release>exit
Output with Sleep disabled:
Microsoft Windows [Version 6.1.7601]exit
I want to know why this happens?
I want to know why this happens?
Your loop is running faster than the output is being produced. As soon as it gets through the output, it ends, so it never sees the second line.
It may happen that your Peek command is executed before pChild has output text. When that happens, ch will be 0 and the while loop quits.
I am trying to get a poster frame from a video file, using ffmpeg.
I have been following this tutorial and come up with the following code(which is taken/adapted from the link I gave):
public bool GetVideoThumbnail(string path, string saveThumbnailTo, int seconds)
{
string parameters = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", path, saveThumbnailTo, seconds);
if (File.Exists(saveThumbnailTo))
{
return true;
}
else
{
using (Process process = Process.Start(pathToConvertor, parameters))
{
process.WaitForExit();
}
return File.Exists(saveThumbnailTo);
}
}
At the moment this code is successfully creating a file in the correct destination (saveThumbnailTo) only the picture is completely black. I have tried changing the seconds value in the code to ensure that I am not just getting a blank picture from the start of the video. The path refers to where my video is stored, by the way.
I am currently calling the above code like so:
GetVideoThumbnail(videoPath, folderPath + "/poster.jpg", 100)
..and then passing it out to my view to display the picture. I just wonder whether ".jpg" is the extension I should be giving to this file as I am not entirely sure?
Edit: When I run the same command from the command line I get the following errors:
Incompatible pixel format 'yuv420p' for codec 'mjpeg', auto-selecting
format 'yuvj420p'
which appears in yellow, and
[image2 # 02S96AE0] Could not get frame filename number 2 from pattern
'poster.jpg' an_interleaved_write_frame(): Invalid argument
which appears in red.
Could anyone help me with getting this working properly as I am completely unfamiliar with the ffmpeg command line and not sure what I am doing wrong. I have tried removing the vcodec parameter and get the same error message.
Try this:
public bool GetVideoThumbnail(string path, string saveThumbnailTo, int seconds)
{
string parameters = string.Format("-ss {0} -i {1} -f image2 -vframes 1 -y {2}", seconds, path, saveThumbnailTo);
var processInfo = new ProcessStartInfo();
processInfo.FileName = pathToConvertor;
processInfo.Arguments = parameters;
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
File.Delete(saveThumbnailTo);
using(var process = new Process())
{
process.StartInfo = processInfo;
process.Start();
process.WaitForExit();
}
return File.Exists(saveThumbnailTo);
}
Short explanation:
f image2 : output is image
vframes 1 : take one frame from the input
y : overwrite output file
"processInfo.CreateNoWindow = true" : do not show the ffmpeg window
Try several times with different values for the "seconds" parameter.
Also, make sure the "pathToConvertor" is correct.
This worked for me, with recent build of ffmpeg.exe on a Windows machine.
Let me know how it goes.