I need to print multiple PDF-files from the hard-drive. I have found this beautiful solution of how to send a file to the printer. The problem with this solution is that if you want to print multiple files you have to wait for each file for the process to finish.
in the command shell it is possible to use the same command with multiple filenames: print /D:printerName file1.pdf file2.pdf
and one call would print them all.
unfortunately simply just to put all the filenames into the ProcessStartInfo doesn't work
string filenames = #"file1.pdf file2.pdf file3.pdf"
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = filenames;
neither does it to put the filenames as Arguments of the Process
info.Arguments = filename;
I always get the error: Cannot find the file!
How can I print a multitude of files with one process call?
Here is an example of how I use it now:
public void printWithPrinter(string filename, string printerName)
{
var procInfo = new ProcessStartInfo();
// the file name is a string of multiple filenames separated by space
procInfo.FileName = filename;
procInfo.Verb = "printto";
procInfo.WindowStyle = ProcessWindowStyle.Hidden;
procInfo.CreateNoWindow = true;
// select the printer
procInfo.Arguments = "\"" + printerName + "\"";
// doesn't work
//procInfo.Arguments = "\"" + printerName + "\"" + " " + filename;
Process p = new Process();
p.StartInfo = procInfo;
p.Start();
p.WaitForInputIdle();
//Thread.Sleep(3000;)
if (!p.CloseMainWindow()) p.Kill();
}
Following should work:
public void PrintFiles(string printerName, params string[] fileNames)
{
var files = String.Join(" ", fileNames);
var command = String.Format("/C print /D:{0} {1}", printerName, files);
var process = new Process();
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = command
};
process.StartInfo = startInfo;
process.Start();
}
//CALL
PrintFiles("YourPrinterName", "file1.pdf", "file2.pdf", "file3.pdf");
It's not necessarily a simple solution, but you could merge the pdfs first and then send then to acrobat.
For example, use PdfMerge
Example overload to your initial method:
public void printWithPrinter(string[] fileNames, string printerName)
{
var fileStreams = fileNames
.Select(fileName => (Stream)File.OpenRead(fileName)).ToList();
var bundleFileName = Path.GetTempPath();
try
{
try
{
var bundleBytes = new PdfMerge.PdfMerge().MergeFiles(fileStreams);
using (var bundleStream = File.OpenWrite(bundleFileName))
{
bundleStream.Write(bundleBytes, 0, bundleBytes.Length);
}
}
finally
{
fileStreams.ForEach(s => s.Dispose());
}
printWithPrinter(bundleFileName, printerName);
}
finally
{
if (File.Exists(bundleFileName))
File.Delete(bundleFileName);
}
}
Related
I am working on a C# .net core project.I created a process to run "xdotool windowactivate $windowpid".I should store the windowID which process run on it.The solution could be any property of xdotool which i couldn't find,or Is there any way to take windowId of a process when it is created?
Another Try is that:
I created my pages with this method. I tried to take mainwindowtitle of process;because of single process,i couldn't take the titles.
static List<string> chromeTitles = new List<string>();
public static Process StartChrome(string filePath)
{
string dataDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Chrome-UserData");
filePath += " --user-data-dir=" + dataDirectory;
var Chrome = new Process
{
StartInfo =
{
FileName = "C:/Program/chrome.exe",
Arguments = filePath,
UseShellExecute = false,
CreateNoWindow=true,
WindowStyle = ProcessWindowStyle.Maximized,
}
};
Chrome.Start();
string title = Chrome.MainWindowTitle;
chromeTitles.Add(title);
}
Then I call it :
StartChrome("https://tr.wikipedia.org/wiki/Anasayfa");
Thread.Sleep(2000);
StartChrome("https://tureng.com/");
You can use the Process class for accessing more capabilities.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = "xdotool.exe";
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = $"windowactivate $windowpid";
process.StartInfo = startInfo;
process.Start();
To get the PID of the process that got run by the code, you can use Process.ID property:
process.Id;
if you want to read the output, you can add this code:
string output = process.StandardOutput.ReadToEnd();
To get Output, startInfo.RedirectStandardOutput should be True.
I've been messing around with C# and in one moment of the code, I need to dump the output of an external .exe into a .txt. I do it by starting cmd.exe and then loading the program, with its attributes plus the > opperator. But now, when I execute the program, the file isn't even created. Meanwhile, if I input the EXACT same code that is passed to cmd in the program:
"o:\steam\steamapps\common\counter-strike global offensive\bin\demoinfogo.exe" "O:\Steam\SteamApps\common\Counter-Strike Global Offensive\csgo\testfile.dem" -gameevents -nofootsteps -deathscsv -nowarmup > "o:\steam\steamapps\common\counter-strike global offensive\demodump.txt"
directly into the Command Prompt, it does get dumped. I've been looking around, and I found A LOT of info, but sadlly nothing has helped me enough so far, so I decided to ask myself.
I attach the chunks of code that I think are relevant to this.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = true;
startInfo.FileName = "CMD.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
if (checkBox1.Checked)
{
arguments += " -gameevents";
if (checkBox2.Checked)
{
arguments += " -nofootsteps";
}
if (checkBox3.Checked)
{
arguments += " -extrainfo";
}
}
if (checkBox4.Checked)
{
arguments += " -deathscsv";
if (checkBox5.Checked)
{
arguments += " -nowarmup";
}
}
if (checkBox6.Checked)
{
arguments += " -stringtables";
}
if (checkBox7.Checked)
{
arguments += " -datatables";
}
if (checkBox8.Checked)
{
arguments += " -packetentites";
}
if (checkBox9.Checked)
{
arguments += " -netmessages";
}
if (dumpfilepath == string.Empty)
{
dumpfilepath = getCSGOInstallationPath() + #"\demodump.txt";
}
baseOptions = #"""" + demoinfogopath + #"""" + " " + #"""" + demofilepath + #"""" + arguments;
startInfo.Arguments = baseOptions + " > " + #"""" + dumpfilepath + #"""";
try
{
using (exeProcess = Process.Start(startInfo))
....a bunch of code...
The Process class that you're creating has this useful little property:
Process.StandardOutput
When a Process writes text to its standard stream, that text is normally displayed on the console. By redirecting the StandardOutput stream, you can manipulate or suppress the output of a process. For example, you can filter the text, format it differently, or write the output to both the console and a designated log file.
All you need to do is ensure you're redirecting the StandardOutput to this stream (using the RedirectStandardOutput property in the ProcessStartInfo) and then you can read the output from that stream. Here's the MSDN sample code, slightly abridged:
Process myProcess = new Process();
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(args[0], "spawn");
myProcessStartInfo.UseShellExecute = false; // important!
myProcessStartInfo.RedirectStandardOutput = true; // also important!
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
// Here we're reading the process output's first line:
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadLine();
Console.WriteLine(myString);
If you look at the help for CMD (access by typing CMD /?) you'll see the following options:
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
Without one of those switches, CMD won't interpret the string you provide it as a command to execute.
When I write a short program like the following, it successfully generates a file... but only if I use either the /C or /K options:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = true;
startInfo.FileName = "CMD.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
var command = #"echo test > c:\users\myusername\Desktop\test.txt";
var args = "/C " + command;
startInfo.Arguments = args;
using (var process = Process.Start(startInfo)) { }
//Hi you could try this to build your process like this.
public class Launcher
{
public Process CurrentProcess;
public string result = null;
public Process Start()
{
CurrentProcess = new Process
{
StartInfo =
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
WorkingDirectory = #"C:\",
FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe")
}
};
CurrentProcess.Start();
return CurrentProcess;
}
//Start the process to get the output you want to add to your .txt file:
private void writeOuput()
{
Currentprocess = new process();
Start()
CurrentProcess.StandardInput.WriteLine("Your CMD");
CurrentProcess.StandardInput.Close();
result = CurrentProcess.StandardOutput.ReadLine();
CurrentProcess.StandardOutput.Close()
//Then to put the result in a .txt file:
System.IO.File.WriteAllText (#"C:\path.txt", result);
}
}
}
UPDATED...
I want to call kdiff from Console application. So I'm building two files and want to compare they at the end of executing my program:
string diffCmd = string.Format("{0} {1}", Logging.FileNames[0], Logging.FileNames[1]);
// diffCmd = D:\vdenisenko\DbHelper\DbHelper\bin\Debug\Reports\16_Nov 06_30_46_DiscussionThreads_ORIGIN.txt D:\vdenisenko\DbHelper\DbHelper\bin\Debug\Reports\16_Nov 06_30_46_DiscussionThreads_ORIGIN.txt
System.Diagnostics.Process.Start(#"C:\Program Files (x86)\KDiff3\kdiff3.exe", diffCmd);
//specification is here http://kdiff3.sourceforge.net/doc/documentation.html
It runs kdiff3 tool, but something wrong with filenames or command... Could you please look on screenshot and say what is wrong?
You need to use Process.Start():
string kdiffPath = #"c:\Program Files\Kdiff3.exe"; // here is full path to kdiff utility
string fileName = #"d:\file1.txt";
string fileName2 = #"d:\file2.txt";
Process.Start(kdiffPath,String.Format("\"{0}\" \"{1}\"",fileName,fileName2));
Arguments as described in the docs: kdiff3 file1 file2
var args = String.Format("{0} {1}", fileName, fileName2);
Process.Start(kdiffPath, args);
string kdiffPath = #"c:\Program Files\Kdiff3.exe"; // here is full path to kdiff utility
string fileName = #"d:\file1.txt";
string fileName2 = #"d:\file2.txt";
ProcessStartInfo psi = new ProcessStartInfo(kdiffPath);
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.Arguments = fileName + " " + fileName2;
Process app = Process.Start(psi);
StreamReader reader = app.StandardOutput;
//get reponse from console app in your app
do
{
string line = reader.ReadLine();
}
while(!reader.EndOfStream);
app.WaitForExit();
This will run the program from your console app
Process p = new Process();
p.StartInfo.FileName = kdiffPath;
p.StartInfo.Arguments = "\"" + fileName + "\" \"" + fileName2 + "\"";
p.Start();
Unless you are trying to do something else, in which case you need to provide more details.
I have the following:
C:\temp\dowork.exe < input.txt
processing.......
complete
C:\
I try this:
processArguments = " < input.txt";
pathToExe = "C:\\temp\dowork.exe";
startInfo = new ProcessStartInfo
{
FileName = pathToExe,
UseShellExecute = false,
WorkingDirectory = FilepathHelper.GetFolderFromFullPath(pathToExe),
Arguments = processArguments
};
try
{
using (_proc = Process.Start(startInfo))
_proc.WaitForExit();
}
catch (Exception e)
{
Console.WriteLine(e);
}
and my dowork.exe crashes after Start() is called.
Any suggestions?
Post Question Update.
Thank you everyone for your input. I solved the problem using amit_g's answer. Extended thanks to Phil for showing likely the best way (although I didn't test it out, I can see why it is better). Below is my complete solution. Feel free to copy and modify for your own issue.
1) create a console application project, add this class
internal class DoWork
{
private static void Main(string[] args)
{
var fs = new FileStream("C:\\temp\\output.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None);
var toOutput = "Any items listed below this were passed in as args." + Environment.NewLine;
foreach (var s in args)
toOutput += s + Environment.NewLine;
Console.WriteLine("I do work. Please type any letter then the enter key.");
var letter = Console.ReadLine();
Console.WriteLine("Thank you.");
Thread.Sleep(500);
toOutput += "Anything below this line should be a single letter." + Environment.NewLine;
toOutput += letter + Environment.NewLine;
var sw = new StreamWriter(fs);
sw.Write(toOutput);
sw.Close();
fs.Close();
}
}
2) Create 1 file: C:\temp\input.txt
3) edit input.txt, type a single letter 'w' and save (that's right the file contains a single letter).
4) Create a new class library project. Add a reference to nunit (i'm using version 2.2).
5) Create a testfixture class, it should look like the following. Note: this test fixture is handling external resources, as such you cannot run the entire fixture, instead, run each test one-at-a-time. You can fix this by making sure all file streams are closed, but i didn't care to write this, feel free to extend it yourself.
using System.Diagnostics;
using System.IO;
using NUnit.Framework;
namespace Sandbox.ConsoleApplication
{
[TestFixture]
public class DoWorkTestFixture
{
// NOTE: following url explains how ms-dos performs redirection from the command line:
// http://www.febooti.com/products/command-line-email/batch-files/ms-dos-command-redirection.html
private string _workFolder = "C:\\Temp\\";
private string _inputFile = "input.txt";
private string _outputFile = "output.txt";
private string _exe = "dowork.exe";
[TearDown]
public void TearDown()
{
File.Delete(_workFolder + _outputFile);
}
[Test]
public void DoWorkWithoutRedirection()
{
var startInfo = new ProcessStartInfo
{
FileName = _workFolder + _exe,
UseShellExecute = false,
WorkingDirectory = _workFolder
};
var process = Process.Start(startInfo);
process.WaitForExit();
Assert.IsTrue(File.Exists(_workFolder + _outputFile));
}
[Test]
public void DoWorkWithoutRedirectionWithArgument()
{
var startInfo = new ProcessStartInfo
{
FileName = _workFolder + _exe,
UseShellExecute = false,
WorkingDirectory = _workFolder,
Arguments = _inputFile
};
var process = Process.Start(startInfo);
process.WaitForExit();
var outputStrings = File.ReadAllLines(_workFolder + _outputFile);
Assert.IsTrue(File.Exists(_workFolder + _outputFile));
Assert.AreEqual(_inputFile, outputStrings[1]);
}
[Test]
public void DoWorkWithRedirection()
{
var startInfo = new ProcessStartInfo
{
FileName = _workFolder + _exe,
UseShellExecute = false,
WorkingDirectory = _workFolder,
RedirectStandardInput = true
};
var myProcess = Process.Start(startInfo);
var myStreamWriter = myProcess.StandardInput;
var inputText = File.ReadAllText(_workFolder + _inputFile);
myStreamWriter.Write(inputText);
// this is usually needed, not for this easy test though:
// myProcess.WaitForExit();
var outputStrings = File.ReadAllLines(_workFolder + _outputFile);
Assert.IsTrue(File.Exists(_workFolder + _outputFile));
// input.txt contains a single letter: 'w', it will appear on line 3 of output.txt
if(outputStrings.Length >= 3) Assert.AreEqual("w", outputStrings[2]);
}
[Test]
public void DoWorkWithRedirectionAndArgument()
{
var startInfo = new ProcessStartInfo
{
FileName = _workFolder + _exe,
UseShellExecute = false,
WorkingDirectory = _workFolder,
RedirectStandardInput = true
};
var myProcess = Process.Start(startInfo);
var myStreamWriter = myProcess.StandardInput;
var inputText = File.ReadAllText(_workFolder + _inputFile);
myStreamWriter.Write(inputText);
myStreamWriter.Close();
// this is usually needed, not for this easy test though:
// myProcess.WaitForExit();
var outputStrings = File.ReadAllLines(_workFolder + _outputFile);
Assert.IsTrue(File.Exists(_workFolder + _outputFile));
// input.txt contains a single letter: 'w', it will appear on line 3 of output.txt
Assert.IsTrue(outputStrings.Length >= 3);
Assert.AreEqual("w", outputStrings[2]);
}
}
}
You have to use the STDIN redirection. Like this...
inputFilePath = "C:\\temp\input.txt";
pathToExe = "C:\\temp\dowork.exe";
startInfo = new ProcessStartInfo
{
FileName = pathToExe,
UseShellExecute = false,
WorkingDirectory = FilepathHelper.GetFolderFromFullPath(pathToExe),
RedirectStandardInput = true
};
try
{
using (_proc = Process.Start(startInfo))
{
StreamWriter myStreamWriter = myProcess.StandardInput;
// Use only if the file is very small. Use stream copy (see Phil's comment).
String inputText = File.ReadAllText(inputFilePath);
myStreamWriter.Write(inputText);
}
_proc.WaitForExit();
}
catch (Exception e)
{
Console.WriteLine(e);
}
You are going to want to do something like,
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = pathToExe,
UseShellExecute = false,
WorkingDirectory = FilepathHelper.GetFolderFromFullPath(pathToExe)
};
Process process = Process.Start(startInfo);
FileStream reader = File.OpenRead("input.txt");
reader.CopyTo(process.StandardInput.BaseStream);
This can be done, at least in a somewhat "hacky" fashion by passing arguments directly to cmd.exe. However, as I recommend emulating the "<" manually as in the other answers, this is here as a note only.
(foo.txt is contains two lines, "b" and "a", so that they will be reversed when correctly sorted)
var x = new ProcessStartInfo {
FileName = "cmd",
Arguments = "/k sort < foo.txt",
UseShellExecute = false,
};
Process.Start(x);
You can replace /k with /c to prevent cmd.exe from remaining open. (See cmd /? for the options).
Happy coding.
First, you don't need a space preceeding your args. The method does it for you. This might mess you up to begin with. So it would be:
processArguments = "< input.txt";
But if that doesn't work you can try::
process = "cmd.exe";
processArguments = "/c dowork.exe < input.txt";
I want to give command name and file path in ProcessStartInfo() method in C#.
So I have a command name("F:\AndroidProjects\AndProj3>) and file path("F:\Android\apache-ant-1.8.2-bin\apache-ant-1.8.2\bin\ant debug") just like that but it is not working and process can not be started.
Please give me a solution for starting the process because command name first execute and after that file path will be execute.
How I can pass the both argument in ProcessStartInfo() method?
public static string BuildAndroidProject()
{
string result="";
// string ProjNameNDLocation = ProjectLocation + "\\" + ProjectName + ">";
try
{
System.Diagnostics.ProcessStartInfo androidBuildProj = new System.Diagnostics.ProcessStartInfo("F:\\AndroidProjects\\AndProj3 F:\\Android\\apache-ant-1.8.2-bin\\apache-ant-1.8.2\\bin\\ant debug");//ProjNameNDLocation, Program.ANDROIDDEBUGGCMD);
androidBuildProj.RedirectStandardOutput = true;
androidBuildProj.UseShellExecute = false;
androidBuildProj.CreateNoWindow = true;
System.Diagnostics.Process androidProcess = new System.Diagnostics.Process();
androidProcess.StartInfo = androidBuildProj;
androidProcess.Start();
result = androidProcess.StandardOutput.ReadToEnd();
androidProcess.Close();
}
catch (Exception e)
{
}
return result;
}
Problem is in the ProcessInfoStart Function. How can I run this command?
Based on the question, the closest I can see is:
using (var proc = Process.Start(new ProcessStartInfo
{
WorkingDirectory = #"F:\AndroidProjects\AndProj3",
FileName = #"F:\Android\apache-ant-1.8.2-bin\apache-ant-1.8.2\bin\ant",
Arguments = "debug"
}))
{
// maybe wait and check exit-code
// proc.WaitForExit();
// int i = proc.ExitCode;
}