How to write a "*.bat" file? - c#

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.

Related

Process.Start from .txt file to textbox

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.

Print multiple images using Process.StartInfo.Verb=“print” command

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. :) )

Is there a way to execute an exe stored with a temp file name?

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();

C# Pass FILE STREAM to EXE file

I have an a FILE STREAM that I want to pass to an EXE to be processed. Is this possible?
using (FileStream fs = File.Create(path))
{
Addfile(fs, fileinmemory.ToString());
}
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.Arguments = Addfile //filestream from above
p.StartInfo.FileName = "load.exe"; //used withabove argument to be passed into exe
p.Start();
p.WaitForExit();
simple :
mempry mapped files.
http://blogs.msdn.com/b/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx
I don't believe this is possible, not directly through the command line.
The arguments expected are command line arguments, normally in C# and C based applications this would be a string[].
If you were to use a file that was accessible to both processes you would need to pass the file path (or have a pre-agreed file location), then you could use that, but this is not the same as passing in a stream to an executable.
You can create the file physically and pass it's path, or you can create a memory mapped file for exchange

C# System.Diagnostics.Process redirecting Standard Out for large amounts of data

I running an exe from a .NET app and trying to redirect standard out to a streamreader. The problem is that when I do
myprocess.exe >> out.txt
out.txt is close to 14mb.
When I do the command line version it is very fast but when I run the process from my csharp app it is excruciatingly slow because I believe the default streamreader flushes every 4096 bytes.
Is there a way to change the default stream reader for the Process object?
I haven't tried, but it looks like the asynchronous methods may offer better performance. Instead of using process.StandardOutput, try this method instead:
Process process = Process
.Start(new ProcessStartInfo("a.exe"){RedirectStandardOutput = true});
if (process != null)
{
process.OutputDataReceived += ((sender, e) =>
{
string consoleLine = e.Data;
//handle data
});
process.BeginOutputReadLine();
}
Edit: Just realized I'm answering the wrong question. In my case the stdout buffer was full and WaitForExit() was blocking forever, because nothing was reading from the buffer yet. So if you have THAT problem, then here's a solution. ;)
This is my first day with C# so please understand that this might not be the best solution, and might not always work. But it works in the 2x I've tested it. ;) This is synchronous, just start start writing the redirected stdout/stderr to the file before you WaitForExit(). This way WaitForExit() won't block waiting for the stdout buffer to be emptied.
string str_MyProg = "my.exe";
string str_CommandArgs = " arg1 arg2"'
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(str_MyProg, str_CommandArgs);
procStartInfo.RedirectStandardError = true;
procStartInfo.RedirectStandardOutput = true; // Set true to redirect the process stdout to the Process.StandardOutput StreamReader
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true; // Do not create the black window
// Create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
myProcess.StartInfo = procStartInfo;
myProcess.Start();
// Dump the output to the log file
string stdOut = myProcess.StandardOutput.ReadToEnd();
StreamWriter logFile = new StreamWriter("output.txt" );
logFile.Write(stdOut);
logFile.Close();
myProcess.WaitForExit();
Yes, that's about right. There is a buffer that stores the process output, usually between 1 and 4KB in the common CRT implementations. One small detail: that buffer is located in the process you start, not the .NET program.
Nothing very special needs to happen when you redirect to a file, the CRT directly writes it. But if you redirect to your .NET program then output goes from the buffer into a pipe. Which then takes a thread switch to your program so you can empty the pipe. Back and forth a good 700 times.
Yes, not fast. Easily fixed though, call setvbuf() in the program you are running to increase the stdout and stderr output buffer sizes. Then again, that takes having the source code of that program.
Anticipating a problem with that: maybe you ought to use cmd.exe /c to get the redirection to a file, then read the file.
The Process class exposes the stdout stream directly, so you should be able to read it at whatever pace you like. It's probably best to read it in small chunks and avoid calling ReadToEnd.
For example:
using(StreamReader sr = new StreamReader(myProcess.StandardOutput))
{
string line;
while((line = sr.ReadLine()) != null)
{
// do something with line
}
}
This worked out for me:
var sb = new StringBuilder();
while (!proc.StandardOutput.EndOfStream)
{
sb.Append(proc.StandardOutput.ReadToEnd());
proc.StandardOutput.DiscardBufferedData();
}

Categories