I am using this code for print with windows print pictures...
string fileName = #"C:\Images\12.jpg";
var p = new Process();
p.StartInfo.FileName = fileName;
p.StartInfo.Verb = "Print";
p.Start();
I want to open multiple images from directory into this, how can i do it?
I tried this code, but does not work:
var p = new Process();
DirectoryInfo d = new DirectoryInfo(#"Directory address");
FileInfo[] Files = d.GetFiles("*.jpg");
foreach (FileInfo file in Files)
{
p.StartInfo.FileName += file.FullName.ToList();
p.StartInfo.Verb = "Print";
p.Start();
}
From your code example, it appears you want to simply invoke separate "print" verb commands for each file. If so, then you should be able to accomplish that by simply assigning the file name in your loop, instead of enumerating the characters of the file name and appending that to the FileName property:
DirectoryInfo d = new DirectoryInfo(#"Directory address");
FileInfo[] Files = d.GetFiles("*.jpg");
ProcessStartInfo psi = new ProcessStartInfo();
psi.Verb = "Print";
foreach (FileInfo file in Files)
{
psi.FileName = file.FullName;
Process.Start(psi);
}
Note that you can't reuse a single Process object for this purpose. Once a given Process object has been started, it can't be started again. But you can reuse a ProcessStartInfo object, starting a new process with each iteration of the loop.
EDIT:
From your comment:
I do not want to simply invoke separate "print" verb commands for each file...I want to add all files in one "print" verb command
This is not possible using the Process class. By definition, the DDE "print" verb (i.e. "command") handles only a single document. If you are willing to do a lot of extra work, you can write your own DDE client that attempts to use DDEEXEC to iteratively interact with a DDE server that knows how to print your image files. But a) this is a lot more work, and b) it still will only work if you happen to have a program installed that handles printing of image files via DDEEXEC (the Windows built-in support for printing images does not).
I recommend you stick with the above.
(And for future reference, if you only want to call Process.Start() once, putting it inside a loop is definitely not the way to go. Your question would have been more clear if your example code bore any resemblance at all to what you were actually trying to do. :) )
Related
I'm trying to solve a problem i got. My job is to make little app, that will show text which is inside of .txt file in the app window, but for some reason they told me that i have to use # ShellExecute(use Process.Start).
Is there even a way to do it? Because when i use ShellExecute, that file opens in notepad after button press, which is, I guess, point of using Shell.
There is little code of what i tried to do, but without success.
Thanks in advice!
string filePath = #"C:\Folder\file.txt";
ProcessStartInfo psi = new ProcessStartInfo(filePath);
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
var proc = Process.Start(psi);
string s = proc.StandardOutput.ReadToEnd();
textBox1.Text = s;
Instead of using ProcessStartInfo, try StreamReader like this :
string filePath = #"C:\Folder\file.txt";
StreamReader sr = new StreamReader(filePath);
string s = sr.ReadToEndAsync().GetAwaiter().GetResult();
Console.WriteLine(s);
Use Async method to read all text without blocking.
If you absolutely need to do that, you can create a second application TxtToTextBox, which you can run from your first application using Process.Start (initialize ProcessStartInfo with the path to that application instead of the txt file).
Then you can give that process an argument pointing to the file using psi.Arguments = $"\"{filePath}\"; (this also adds quotation marks around your path, so spaces are escaped).
Then in your second application you can do the sane thing, and simply read the file with File.ReadAllLines(args[0]) and print that into your text box.
If possible, I would recommend talking to whoever told you to use Process.Start and asking them for more reasons as to why you should use is, as this is one of the most roundabout ways to do this I could think of.
I'm writing a native exe stored as an embedded resource to the file returned by Path.GetTempFileName. That function is desirable since it lets me ignore the implementation details that avoid the race condition. The only downside is that it returns a filename with the extension .tmp.
Process.Start opens the tmp-named-exe file in Notepad, on my system. Apparently you can specify the class and verb manually using p/invoke (see https://stackoverflow.com/a/12681219/521757). Before I do that, is there any way to accomplish the same thing using the .NET framework?
I think it is possible.. set the Process.StartInfo.UseShellExecute property to False prior to starting the process, e.g.:
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = #"c:\tmp\a123.tmp";
p.StartInfo.UseShellExecute = false;
p.Start();
This will start the process directly and the file should be considered to be executable itself. Does it work for you?
Why don't you use Path.GetRandomFileName() in conjunction with Path.GetTempPath()?
This way you still have a unique temporary file and path name and you can append '.exe', eliminating the current problem that you have with executing a file with a '.tmp' extension.
As a sideline, I hope that you remember to delete the temporary files after you have used them, especially when using Path.GetTempFileName(), since it can cause issues when you reach 65535 temporary files. Which is very possible and frustrating to debug when that actually happens on production code.
this should work for you
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = //your filename .tmp
proc.StartInfo.UseShellExecute = false;
proc.Start();
Why "1.bat" can't run successfully? Any help will be appreciate. "1.bat" was created successfully.It can run without error, but can't rename the files.
private void button1_Click(object sender, EventArgs e)
{
string str = System.Environment.CurrentDirectory;
str += "\\1.bat";
string txt = "";
txt = "ren *.mp3 *.wav";
StreamWriter sw = new StreamWriter(str,false, Encoding.UTF8);
sw.Write(txt);
sw.Close();
Process p = new Process();
p.StartInfo.FileName = str;
p.StartInfo.Arguments = "";
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.Start();
}
One problem is that your file is being written with a UTF-8 BOM. Try passing Encoding.Default to test this out. Or pass new UTF8Encoding(false) as the encoding to pass a UTF-8 encoding that omits the BOM.
Another problem (which you just added in an edit) is that you set UseShellExecute to false. That requires the file you pass to be an executable file. Your file isn't. You need UseShellExecute to be true to allow the shell to work out how to process your .bat file.
And yet another possible problem is that the current directory may not be what you think it is.
When faced with problems like this there is no need at all to be helpless. Do some debugging. Add a pause at the end of your batch file and make sure that you can see the console. You'll find out immediately what the problem is. Learning how to debug is just as important as learning how to program. You won't be able to do the latter until you can do the former.
If I were having to do it this way, with an external process, I would:
Set UseShellExecute to false.
Pass cmd.exe as the executable file.
Pass the command to be executed as the command line.
However, it would be much easier to do this directly using C# and so avoid having to spin up external processes.
My scenario in C# project is user will pass path like "c:\homedir\mydir" to batch file then batch file should accept this path and create directory at the specified path.
I don't know how to pass string to batch file through c# and how batch file will accept string and process it.
Create a process and pass your argument(s) through the StartInfo.Arguments property.
Process proc = new Process();
proc.StartInfo.FileName = //path to your BAT file
proc.StartInfo.Arguments = String.Format("{0}", #"C:\homedir\mydir");
//set the rest of the process settings
proc.Start();
That will load your BAT file and pass whichever arguments you've added. Your BAT file can access the arguments using %1 for the first argument, %2 for the second one etc...
Since you didn't gave us any information, I just give an example of these subjects.
First of all, you need to use Process class include System.Diagnostics namespace.
Provides access to local and remote processes and enables you to start
and stop local system processes.
An example with a batch file:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "yourbatchfile.bat";
p.Start();
For passing arguments, you can use ProcessStartInfo.Arguments property.
Gets or sets the set of command-line arguments to use when starting
the application.
I am creating a File copy program which will copy large number of files(~100,000) with size ~50 KB using ROBOCOPY command.
For each file, I am creating a new process and passing the ROBOCOPY command and arguments as follow:
using (Process p = new Process)
{
p.StartInfo.Arguments = string.Format("/C ROBOCOPY {0} {1} {2}",
sourceDir, destinationDir, fileName);
p.StartInfo.FileName = "CMD.EXE";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.WaitForExit();
}
Instead of creating a process for each file, I am looking for a better approach, which will be good in terms of performance and design. Can someone suggest a better method?
This question is a bit old but I thought I would answer to help anyone who still land on it. I wrote a library called RoboSharp (https://github.com/tjscience/RoboSharp) that brings all of the goodness in Robocopy to c#. Take a look if you require the power of Robocopy in c#.
Process p = new Process();
p.StartInfo.Arguments = string.Format("/C Robocopy /S {0} {1}", "C:\\source", "C:\\destination");
p.StartInfo.FileName = "CMD.EXE";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.WaitForExit();
/C Robocopy -> this is a command to run robocopy
/S -> This will help to copy sub folders as well as Files
I would just use System.IO. Should be plenty fast enough, and your filename could be a wildcard.
using System.IO;
// snip your code... providing fileName, sourceDir, destinationDir
DirectoryInfo dirInfo = new DirectoryInfo(sourceDir);
FileInfo[] fileInfos = dirInfo.GetFiles(fileName);
foreach (FileInfo file in fileInfos)
{
File.Copy(file.FullName, Path.Combine(destinationDir, file.Name), true); // overwrites existing
}
You should call File.Copy in a loop.
Robocopy can use up to 128 thread by itself. It makes a huge difference. By default it uses 8.
See https://pureinfotech.com/robocopy-multithreaded-file-copy-windows-10/
.cmd has following lines
Start ROBOCOY src dest a* b* c* /z /w:1 r:1
Start ROBOCOY src dest d* e* f* g* /z /w:1 r:1
Start ROBOCOY src dest h* K* P* Y* /z /w:1 r:1
Start ROBOCOY src dest xry* srp* /z /w:1 r:1
When I run > Robocopy sample.cmd
I starts with 4 multiple windows copying files simultaneously as per above commands, it waits
for another file, as it has wait time, if file is being used by another process. Is is more
faster as it do job simultaneously.
Now I am developing GUI using C# windows to run the process instead going to command console and
start
main()
{
process.start( "path of sample.cmd" )
process.waitforexit()
label.text=" sucessful copy"
}
However, if it takes control of one process, i.e. cmd.exe and and there are 4 robocopy processes in
taskmanager. when cmd.exe process completes, it returns the cursor to label.text "Sucesssfully
completed". While there are robocopy processes still running. you can see the robocopy windows
doing the copying process.
Here is the question: I want to take control of all the processes (cmd.exe and robocopy.exe)
programatically in C#, so that when the label.text should display "successfully completed" only
when all commands are successfully completed", if one fails, then there is no point in the GUI.
option 2 (similar to Biju has written above): is it better to remove robocopy command scripts from
sample.cmd(batch file) file and write code to run the 4 robocopy lines in C#, but how to run the
robocooy script line written .cmd file, as they have arguments as well. I code runs each robocopy
process then each will return to the next line of code and if it fails, we can catch the error and
display in the message box.
Hope this will help... However, I am looking for more better way, if somebody can improve on the same.