Trouble Starting Selenium Process from a Console Application - c#

Let me be clear:
- I have Java.exe in my path environment variable
- So if I want to run a "selenium-server" I will do :
1. Start cmd.exe
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.
C:\Documents and Settings\cnguyen>
2. Then:
C:\Documents and Settings\cnguyen>cd C:\Selenium RC 0.9.2\selenium-server-0.9.2
3. Next, I'm in the directory that I want so I run:
C:\Documents and Settings\cnguyen>cd C:\Selenium RC 0.9.2\selenium-server-0.9.2
C:\Selenium RC 0.9.2\selenium-server-0.9.2>java -jar selenium-server.jar
09:26:18.586 INFO - Java: Sun Microsystems Inc. 16.3-b01
09:26:18.586 INFO - OS: Windows 2003 5.2 x86
09:26:18.586 INFO - v0.9.2 [2006], with Core v0.8.3 [1879]
09:26:18.633 INFO - Version Jetty/5.1.x
09:26:18.633 INFO - Started HttpContext[/selenium-server/driver,/selenium-server
/driver]
09:26:18.633 INFO - Started HttpContext[/selenium-server,/selenium-server]
09:26:18.633 INFO - Started HttpContext[/,/]
09:26:18.648 INFO - Started SocketListener on 0.0.0.0:4444
09:26:18.648 INFO - Started org.mortbay.jetty.Server#16a55fa
And here is what I got so far, it compiled but not showing anything :(
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace SeleniumProcessExample
{
public class SeleniumProcess
{
private Process pro;
public SeleniumProcess()
{
pro = new Process();
Directory.SetCurrentDirectory( #"C:\Selenium RC 0.9.2\selenium-server-0.9.2" );
pro.StartInfo.FileName = "java";
pro.StartInfo.Arguments = " -jar selenium-server.jar";
pro.StartInfo.RedirectStandardOutput = true;
pro.StartInfo.RedirectStandardError = true;
pro.StartInfo.UseShellExecute = false;
pro.Start();
string strOutput = pro.StandardOutput.ReadToEnd();
string strError = pro.StandardError.ReadToEnd();
Console.WriteLine( strOutput );
Console.WriteLine( strError );
Console.Out.Flush();
pro.CloseMainWindow();
}
}
}
EDIT: if you intent is to hide the
selenium-server output window, you're
going to have to make some
asynchronous calls. I can go into the
details if this is indeed your intent.
I would love to see this. Would you mind showing me how to do this? Thanks a lot for your suggestion ;)

This works for me...
/// <summary>
/// Creates new process to run and executable file, and return the output
/// </summary>
/// <param name="program">The name of the executable to run</param>
/// <param name="arguments">Any parameters that are required by the executable</param>
/// <param name="silent">Determines whether or not we output execution details</param>
/// <param name="workingDirectory">The directory to run the application process from</param>
/// <param name="standardErr">The standard error from the executable. String.Empty if none returned.</param>
/// <param name="standardOut">The standard output from the executable. String.Empty if none returned, or silent = true</param>
/// <returns>The application's exit code.</returns>
public static int Execute(string program, string arguments, bool silent, string workingDirectory, out string standardOut, out string standardErr)
{
standardErr = String.Empty;
standardOut = String.Empty;
//sometimes it is not advisable to output the arguments e.g. passwords etc
if (!silent)
{
Console.WriteLine(program + " " + arguments);
}
Process proc = Process.GetCurrentProcess();
if (!string.IsNullOrEmpty(workingDirectory))
{
//execute from the specific working directory if specified
proc.StartInfo.WorkingDirectory = workingDirectory;
}
proc.EnableRaisingEvents = true;
proc.StartInfo.FileName = program;
proc.StartInfo.Arguments = arguments;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.Start();
proc.WaitForExit();
//only display the console output if not operating silently
if (!silent)
{
if (proc.StandardOutput != null)
{
standardOut = proc.StandardOutput.ReadToEnd();
Console.WriteLine(standardOut);
}
}
if (proc.StandardError != null)
{
standardErr = proc.StandardError.ReadToEnd();
Console.WriteLine(standardErr);
}
proc.StandardOutput.Close();
proc.StandardError.Close();
return proc.ExitCode;
}

Your pro.StandardOutput.ReadToEnd() call will block until the executable terminates. Since you're starting a server that will launch and wait for output, you'll never get anything.
If you just want to see the output of the server, set UseShellExecute to true and RedirectStandardOutput and RedirectStandardError to false. (or just delete those three lines) This will cause a new console window to open and show the output from selenium-server.
EDIT: if you intent is to hide the selenium-server output window, you're going to have to make some asynchronous calls. I can go into the details if this is indeed your intent.

I would start by changing the code for the process to this to see if it starts java.exe
pro = new Process();
pro.StartInfo.FileName = #"C:\Selenium RC 0.9.2\selenium-server-0.9.2\java.exe";
pro.StartInfo.Arguments = " -jar selenium-server.jar";
pro.StartInfo.RedirectStandardOutput = true;
pro.StartInfo.RedirectStandardError = true;
pro.StartInfo.UseShellExecute = false;
pro.Start();

Chances are that your program is blocking on the call to pro.StandardOutput.ReadToEnd(). Consider using the non-blocking BeginOutputReadLine() method (more at http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspx and http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx).

class LaunchJava
{
private static Process myProcessProcess;
private static StreamWriter myProcessStandardInput;
private static Thread thist = Thread.CurrentThread;
public static void DoJava()
{
// Initialize the process and its StartInfo properties.
// The sort command is a console application that
// reads and sorts text input.
myProcess= new Process();
myProcess.StartInfo.Arguments = "-jar selenium-server.jar";
myProcess.StartInfo.FileName = #"C:\Documents and Settings\cnguyen\java.exe";
// Set UseShellExecute to false for redirection.
myProcess.StartInfo.UseShellExecute = false;
// Redirect the standard output of the sort command.
// This stream is read asynchronously using an event handler.
myProcess.StartInfo.RedirectStandardOutput = true;
myProcessOutput = new StringBuilder("");
// Set our event handler to asynchronously read the sort output.
myProcess.OutputDataReceived += new DataReceivedEventHandler(myProcessOutputHandler);
// Redirect standard input as well. This stream
// is used synchronously.
myProcess.StartInfo.RedirectStandardInput = true;
Console.WriteLine("Start.");
// Start the process.
myProcess.Start();
// Use a stream writer to synchronously write the sort input.
myProcessStandardInput = myProcess.StandardInput;
// Start the asynchronous read of the sort output stream.
myProcess.BeginOutputReadLine();
// Wait for the process to end on its own.
// as an alternative issue some kind of quit command in myProcessOutputHandler
myProcess.WaitForExit();
// End the input stream to the sort command.
myProcessInput.Close();
myProcessProcess.Close();
}
private static void myProcessOutputHandler(object sendingProcess, DataReceivedEventArgs Output)
{
// do interactive work here if needed...
if (!String.IsNullOrEmpty(Output.Data))
{ myProcess.StandardInput.BaseStream.Write(bytee,0,bytee.GetLength);
}
}

Related

Executed vbscript with C# returns wrong exit code

I have a big issue with executing vbscript with C#.
I have this generic process execution function:
/// <summary>
/// Runs a process silent (Without DOS window) with the given arguments and returns the process' exit code.
/// </summary>
/// <param name="output">Recieves the output of either std/err or std/out</param>
/// <param name="exe">The executable to run, may be unqualified or contain environment variables</param>
/// <param name="args">The list of unescaped arguments to provide to the executable</param>
/// <returns>Returns process' exit code after the program exits</returns>
/// <exception cref="System.IO.FileNotFoundException">Raised when the exe was not found</exception>
/// <exception cref="System.ArgumentNullException">Raised when one of the arguments is null</exception>
/// <exception cref="System.ArgumentOutOfRangeException">Raised if an argument contains '\0', '\r', or '\n'</exception>
public static int Run(Action<string> output, string exe, params string[] args)
{
if (String.IsNullOrEmpty(exe))
throw new FileNotFoundException();
if (output == null)
throw new ArgumentNullException("output");
ProcessStartInfo psi = new ProcessStartInfo();
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.WorkingDirectory = Environment.CurrentDirectory;
psi.FileName = FindExePath(exe);
psi.Arguments = args[0];
using (Process process = Process.Start(psi))
using (ManualResetEvent mreOut = new ManualResetEvent(false),
mreErr = new ManualResetEvent(false))
{
process.OutputDataReceived += (o, e) => { if (e.Data == null) mreOut.Set(); else output(e.Data); };
process.BeginOutputReadLine();
process.ErrorDataReceived += (o, e) => { if (e.Data == null) mreErr.Set(); else output(e.Data); };
process.BeginErrorReadLine();
process.WaitForExit();
mreOut.WaitOne();
mreErr.WaitOne();
return process.ExitCode;
}
}
Works like charme.
Now I want to execute a vbscript with this function.
I call it like this:
int exit_code = ProcessUtility.Run(output_action, "cscript.exe", "//Nologo" + save_parameter_string);
This also runs very well, but my problem is, it runs a littlebit to good.
If I execute an vbscript which contains an error, the exit code is also "0" ;(
The output contains the correct "exception" from vbscript, in my case:
"...\test.vbs(145, 12) Runtime error in Microsoft VBScript: Object neccesarry"
but the exit code is 0.
Does anyone have an idea, why?
Alternatively, you can use On Error Resume Next technics as described in VBScript -- Using error handling.
Briefly, wrap your original script in an 'exception handler' of such sort:
On Error Resume Next
YourOriginalUnsafeCode()
' This would make cscript return non-zero in case of error'
if err.number <> 0 then WScript.quit err.number
Sub YourOriginalUnsafeCode()
' Your original code goes into this function'
a = 1 / 0
a = 2
End Sub
I put this in a BAT file to generate a runtime error:
echo x = 1/0 > foo.vbs
cscript foo.vbs
echo %ERRORLEVEL%
Output:
C:\null\foo.vbs(1, 1) Microsoft VBScript runtime error: Division by zero
0
The exit code is 0 so you cannot detect runtime errors using the exit code.
(%ERRORLEVEL% is 1 only for syntactic errors (echo x = ?1/0 > foo.vbs))
You will need to parse the output or determine the behaviour of StdErr or you can run VBScript from .Net via the ScriptControl which would generate standard exceptions: How to execute VBScript command within textbox from C# application?

Interactive c# System.Process not Echoing input

Given the following code running in Mono on Linux, I can successfully run ssh from C# and get a shell prompt on a remote box. I can type commands and get output. However I can't figure out how to get what I type into that shell to echo back. When I type ls and hit enter you don't see the ls or the newline from hitting the enter key, you only see it's output. I've verified ssh is assigning a tty. The destination shell is bash in interactive mode so readline is enabled there. The problem has to be in how C# is wiring up the STDIN and STDOUT up to the Console. Google is no help so I'm hoping someone on here can help.
var process_info = new ProcessStartInfo("/usr/bin/ssh");
process_info.Arguments = "-ttt hostname";
Console.Out.WriteLine("Arguments: [" + process_info.Arguments + "]");
process_info.CreateNoWindow = true;
process_info.UseShellExecute = true;
var process = new Process();
process.StartInfo = process_info;
try {
process.Start();
process.WaitForExit();
exitCode = process.ExitCode;
}
catch (Exception e)
{
exitCode = this.ExitCode == 0 ? 255 : exitCode;
Console.WriteLine(e.ToString());
}
Console.Out.WriteLine("ExitCode: " + exitCode);
Maybe this is what you're trying to do:
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace Echo
{
class Program
{
private static void Read(StreamReader reader)
{
new Thread(() =>
{
while (true)
{
int current;
while ((current = reader.Read()) >= 0)
Console.Write((char)current);
}
}).Start();
}
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"/usr/bin/ssh");
startInfo.Arguments = "-ttty localhost";
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(15000); //time to login
Read(process.StandardOutput);
Read(process.StandardError);
process.StandardInput.WriteLine("echoing your input now");
while (!process.HasExited)
try { process.StandardInput.WriteLine(Console.ReadLine()); }
catch {}
Console.WriteLine(process.ExitCode.ToString());
}
}
}
EDIT 1
You need to redirect the StandardInput in order to echo it, but then the cmd in windows will elaborate it line by line (even if you use Console.ReadKey() => process.StandardInput.Write), so you can't have shell support while typing (look at this question/answer if you want to dig in).
But mono with linux ssh behaves differently from windows cmd, so the following could be acceptable maybe:
commands are echoed and even the tab while typing a dir is managed (look at my screenshot below)! Finally please notice that the tty is correctly set.
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
namespace Echo
{
class Program
{
private static Process process;
private static void Read(StreamReader reader)
{
new Thread(() =>
{
while (!process.HasExited)
{
int current;
while ((current = reader.Read()) >= 0)
Console.Write((char)current);
}
}).Start();
}
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"/usr/bin/ssh");
startInfo.Arguments = "-ttty localhost";
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
process = new Process();
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(15000); //time to login
Read(process.StandardOutput);
Read(process.StandardError);
process.StandardInput.WriteLine("echo echoing your input now");
//Console.ReadLine();
string theLine = "\n";
while (!process.HasExited)
try {
ConsoleKeyInfo kinfo = Console.ReadKey(true);
char theKey = kinfo.KeyChar;
theLine += theKey;
process.StandardInput.Write(theKey) ;
process.StandardInput.Flush();
if (theKey.Equals('\n'))
{
Console.WriteLine(theLine);
theLine = "\n";
}
}
catch { }
Console.WriteLine(process.ExitCode.ToString());
}
}
}
EDIT 2
If you want to also manage the terminal escape sequences for the UpArrow/DownArrow, here is the code (tested on my Ubuntu terminal)
string theLine = "\n";
string theEsc = ((char)27).ToString();
while (!process.HasExited)
try {
//byte[] bytes = new byte[1];
ConsoleKeyInfo kinfo = Console.ReadKey(true);
char theKey = kinfo.KeyChar;
theLine += theKey;
switch (kinfo.Key)
{
case ConsoleKey.DownArrow:
process.StandardInput.Write(theEsc+"[B");
break;
case ConsoleKey.UpArrow:
process.StandardInput.Write(theEsc+"[A");
break;
default:
process.StandardInput.Write(theKey);
break;
}
process.StandardInput.Flush();
if (theKey.Equals('\n'))
{
Console.Write(theLine);
theLine = "\n";
}
}
EDIT 3
Just a follow up to my comments with a suggested command to restore echo (reference here).
This is the change to the code:
process.StandardInput.WriteLine("stty -a");
process.StandardInput.WriteLine("stty echo"); // or "reset" insted of "stty echo"
process.StandardInput.WriteLine("echo echoing your input now");
Back to your original code (since you're not redirecting the standard input), you could do something like the following
process_info.Arguments = "-ttt hostname 'stty echo; '$SHELL' -i'"; // or reset insted of stty echo
Look at this answer too.
In conclusion the source you're showing - and more specifically c# System.Process - is not supposed to echo anything (unless one intentionally redirects the standard I/O, as I've done here in my first example and in edit 1&2).
Echoing is a behavior of the shell, in Linux as well as in Windows: that can be managed as shown in edit 3.
I stumbled upon the same problem and the analysis of user4569980 helped a lot.
The root cause of this behavior is that mono disables the echo functionality of the currently used tty.
See http://www.linusakesson.net/programming/tty/ and https://github.com/mono/mono/blob/master/mcs/class/corlib/System/TermInfoDriver.cs#L204
I used the following workaround:
// mono sets echo off for some reason, therefore interactive mode
// doesn't work as expected this enables this tty feature which
// makes the interactive mode work as expected
let private setEcho (b:bool) =
// See https://github.com/mono/mono/blob/master/mcs/class/corlib/System/ConsoleDriver.cs#L289
let t = System.Type.GetType("System.ConsoleDriver")
if Env.isMono then
let flags = System.Reflection.BindingFlags.Static ||| System.Reflection.BindingFlags.NonPublic
if isNull t then
eprintfn "Expected to find System.ConsoleDriver.SetEcho"
false
else
let setEchoMethod = t.GetMethod("SetEcho", flags)
if isNull setEchoMethod then
eprintfn "Expected to find System.ConsoleDriver.SetEcho"
false
else
setEchoMethod.Invoke(null, [| b :> obj |]) :?> bool
else false
I'l leave it to the interested reader to convert this F# code to C#. It's basically simple reflection to bool System.ConsoleDriver.SetEcho(bool enable).
Now use the following pseudo code:
setEcho(true)
var p = startProcess ()
p.WaitForExit()
setEcho(false)
https://msdn.microsoft.com/de-de/library/system.diagnostics.processstartinfo.redirectstandardinput%28v=vs.110%29.aspx
Just capture and duplicate STDIN.
process.Start();
StreamWriter processInputStream = process.StandardInput;
do {
String inputText = Console.ReadLine():
processInputStream.write(inputText);
while(!process.HasExited)
process.WaitForExit();
Now the SSH process is no longer capturing your input, so it should be displayed locally. If it doesn't, just add Console.writeLine(inputText) to the loop, and done.
If you want better control, consider reading and writing byte wise. Just beware that TAB and other control characters might not be that easy to handle.
If you really need these as well, use ReadKey() instead and pass along whatever control characters you need. Remember to set Console.TreatControlCAsInput = true; or you won't be able to send CMD + c at all without killing your application.
Oh, but sending control sequences (keys with CMD or ALT modifier) from .NET outside of Windows?
Uh... I think that one is actually of limits. That is part of System.Window.Forms and I have no clue how to replicate that behavior with pure C# outside of Windows.
As for the other, and probably much easier option:
Just don't invoke the naked ssh executable. Open a shell instead and run SSH inside of that thing. /usr/bin/bash and "-c 'ssh -ttt hostname'". Your problem is TTY emulation, so just let the shell handle that for you. Console.TreatControlCAsInput = true; still applies though, at least if you want to be able to pass through Ctrl+C as a command sequence.

How to run multiple SSIS packages programmatically by C#?

guy, I used this code snippet, I execute multiple SSIS packages, when the first one finished, it takes a so long time to execute the another one, but I run the script command line on the CMD, it execute quickly. So I think it's the problem of code, do you know why? This is my code below:
SSISHelper.ExecuteSSISPackage("/F \"C:\\Users\\v-nashi\\Documents\\visual studio 2010\\projects\\ImportExcel\\ImportExcel\\LYO_DailyLogin.dtsx\"");
SSISHelper.ExecuteSSISPackage("/F \"C:\\Users\\v-nashi\\Documents\\visual studio 2010\\projects\\ImportExcel\\ImportExcel\\LYO_COSMOS_Activities.dtsx\"");
/// <summary>
/// Excuete SQL Server Integration Services packages with parameter.
/// </summary>
/// <param name="para">parameter</param>
/// <returns>bool</returns>
public static bool ExecutePackage(string parameter)
{
if (File.Exists(DTExec_Path) == false)
throw new Exception("The file DTExec.exe is not found, or the file is not exist.");
Process process = new Process();
process.StartInfo.FileName = DTExec_Path;
process.StartInfo.Arguments = parameter;
// True if the shell should be used when starting the process; false if the process should be created directly
// from the executable file.
process.StartInfo.UseShellExecute = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
Console.WriteLine("{0} {1}", DTExec_Path, parameter);
process.Start();
process.WaitForExit();
string[] results = process.StandardOutput.ReadToEnd().Split('\n');
foreach (string item in results)
{
if (item.Contains("DTExec: The package execution returned DTSER_SUCCESS (0)."))
return true;
}
return false;
}
I just want to run the SSIS package programmatically, or the better way?
Another way can be like this.
Microsoft.SqlServer.Dts.Runtime.Application app = new Microsoft.SqlServer.Dts.Runtime.Application();
string packagePath = "Path of your SSIS package";
Package package = app.LoadPackage(packagePath, null);
//Assign your variables here.
Variables vars = package.Variables;
vars["FileName"].Value = variables.FileName;
Microsoft.SqlServer.Dts.Runtime.DTSExecResult results = package.Execute();
if (results == DTSExecResult.Success)
{
//Do what u want after success.
}
For this U have to use this Microsoft.SqlServer.ManagedDTS library from microsoft. Try to find it in GAC or Something else site.
This is for single SSIS service in same way U can execute multiple one by one.

Command line program/app + C# class method

When working with a command line program, via a c# class method.
How do you determine if the commandline program was successfully executed and the operation it has performed is ok or has failed?
Also how do you get the screen commandline output into the c# class method?
You can use the Process class to execute a command line command.
The following code captures the standard output to output, and assigns the processes exit code to exitCode.
using (Process p = new Process())
{
p.StartInfo.FileName = exeName;
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
int exitCode = p.ExitCode;
}
Something like:
Process mycommand = new Process();
mycommand.StartInfo.FileName = "myexe.exe";
mycommand.StartInfo.Arguments = "param1";
mycommand.StartInfo.UseShellExecute = false;
mycommand.StartInfo.RedirectStandardOutput = true;
mycommand.Start();
Console.WriteLine(mycommand.StandardOutput.ReadToEnd());
mycommand.WaitForExit();
You usually determine an exe's state wether the exit code is 0, but that is arguably down to the writer of the exe
I assume you're using the Process class to call the command line app.
You can find the exit code of the process using Process.ExitCode. You can redirect its standard output by setting ProcessStartInfo.RedirectStandardOutput before starting it, and then either using Process.StandardOutput or the Process.OutputDataReceived event.
Take a look at this questionenter link description here.
The additional information you might need is process.ExitCode to see if it was sucessful. Of course, the Main method of the console app must return an exit code when it is unsuccessful, which many do not.
For this, you use the Process.Start method. You can control how the process runs with the passed in ProcessStartInfo:
var myProcess = Process.Start(new ProcessStartInfo {
FileName = "process.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
});
if (!myProcess.WaitForExit(5000)) { // give it 5 seconds to exit
myProcess.Kill();
}
if (myProcess.ExitCode != 0) {
// error!
}
var output = myProcess.StandardOutput.ReadToEnd(); // access output

Run Command Prompt Commands

Is there any way to run command prompt commands from within a C# application? If so how would I do the following:
copy /b Image1.jpg + Archive.rar Image2.jpg
This basically embeds an RAR file within JPG image. I was just wondering if there was a way to do this automatically in C#.
this is all you have to do run shell commands from C#
string strCmdText;
strCmdText= "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);
EDIT:
This is to hide the cmd window.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
process.StartInfo = startInfo;
process.Start();
EDIT 2:
It is important that the argument begins with /C, otherwise it won't work. As #scott-ferguson said: /C carries out the command specified by the string and then terminates.
Tried RameshVel's solution but I could not pass arguments in my console application. If anyone experiences the same problem here is a solution:
using System.Diagnostics;
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine("echo Oscar");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
var proc1 = new ProcessStartInfo();
string anyCommand;
proc1.UseShellExecute = true;
proc1.WorkingDirectory = #"C:\Windows\System32";
proc1.FileName = #"C:\Windows\System32\cmd.exe";
proc1.Verb = "runas";
proc1.Arguments = "/c "+anyCommand;
proc1.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(proc1);
None of the above answers helped for some reason, it seems like they sweep errors under the rug and make troubleshooting one's command difficult. So I ended up going with something like this, maybe it will help someone else:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\Program Files\Microsoft Visual Studio 14.0\Common7\IDE\tf.exe",
Arguments = "checkout AndroidManifest.xml",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
WorkingDirectory = #"C:\MyAndroidApp\"
}
};
proc.Start();
Though technically this doesn't directly answer question posed, it does answer the question of how to do what the original poster wanted to do: combine files. If anything, this is a post to help newbies understand what Instance Hunter and Konstantin are talking about.
This is the method I use to combine files (in this case a jpg and a zip). Note that I create a buffer that gets filled with the content of the zip file (in small chunks rather than in one big read operation), and then the buffer gets written to the back of the jpg file until the end of the zip file is reached:
private void CombineFiles(string jpgFileName, string zipFileName)
{
using (Stream original = new FileStream(jpgFileName, FileMode.Append))
{
using (Stream extra = new FileStream(zipFileName, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[32 * 1024];
int blockSize;
while ((blockSize = extra.Read(buffer, 0, buffer.Length)) > 0)
{
original.Write(buffer, 0, blockSize);
}
}
}
}
if you want to run the command in async mode - and print the results. you can you this class:
public static class ExecuteCmd
{
/// <summary>
/// Executes a shell command synchronously.
/// </summary>
/// <param name="command">string command</param>
/// <returns>string, as output of the command.</returns>
public static void ExecuteCommandSync(object command)
{
try
{
// create the ProcessStartInfo using "cmd" as the program to be run, and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows, and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
// The following commands are needed to redirect the standard output.
//This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
// Log the exception
Console.WriteLine("ExecuteCommandSync failed" + objException.Message);
}
}
/// <summary>
/// Execute the command Asynchronously.
/// </summary>
/// <param name="command">string command.</param>
public static void ExecuteCommandAsync(string command)
{
try
{
//Asynchronously start the Thread to process the Execute command request.
Thread objThread = new Thread(new ParameterizedThreadStart(ExecuteCommandSync));
//Make the thread as background thread.
objThread.IsBackground = true;
//Set the Priority of the thread.
objThread.Priority = ThreadPriority.AboveNormal;
//Start the thread.
objThread.Start(command);
}
catch (ThreadStartException )
{
// Log the exception
}
catch (ThreadAbortException )
{
// Log the exception
}
catch (Exception )
{
// Log the exception
}
}
}
if you want to keep the cmd window open or want to use it in winform/wpf then use it like this
string strCmdText;
//For Testing
strCmdText= "/K ipconfig";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);
/K
Will keep the cmd window open
Yes, there is (see link in Matt Hamilton's comment), but it would be easier and better to use .NET's IO classes. You can use File.ReadAllBytes to read the files and then File.WriteAllBytes to write the "embedded" version.
with a reference to Microsoft.VisualBasic
Interaction.Shell("copy /b Image1.jpg + Archive.rar Image2.jpg", AppWinStyle.Hide);
This can also be done by P/Invoking the C standard library's system function.
using System.Runtime.InteropServices;
[DllImport("msvcrt.dll")]
public static extern int system(string format);
system("copy Test.txt Test2.txt");
Output:
1 file(s) copied.
Here is little simple and less code version. It will hide the console window too-
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
process.Start();
I have the following method, which I use to run the command prompt commands from C#
In first parameter pass the command you want to run
public static string RunCommand(string arguments, bool readOutput)
{
var output = string.Empty;
try
{
var startInfo = new ProcessStartInfo
{
Verb = "runas",
FileName = "cmd.exe",
Arguments = "/C "+arguments,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = false
};
var proc = Process.Start(startInfo);
if (readOutput)
{
output = proc.StandardOutput.ReadToEnd();
}
proc.WaitForExit(60000);
return output;
}
catch (Exception)
{
return output;
}
}
You can achieve this by using the following method (as mentioned in other answers):
strCmdText = "'/C some command";
Process.Start("CMD.exe", strCmdText);
When I tried the methods listed above I found that my custom command did not work using the syntax of some of the answers above.
I found out more complex commands need to be encapsulated in quotes to work:
string strCmdText;
strCmdText = "'/C cd " + path + " && composer update && composer install -o'";
Process.Start("CMD.exe", strCmdText);
you can use simply write the code in a .bat format extension ,the code of the batch file :
c:/ copy /b Image1.jpg + Archive.rar Image2.jpg
use this c# code :
Process.Start("file_name.bat")
You can use RunProcessAsTask pacakge and run your process async and easily like this:
var processResults = await ProcessEx.RunAsync("git.exe", "pull");
//get process result
foreach (var output in processResults.StandardOutput)
{
Console.WriteLine("Output line: " + output);
}
This may be a bit of a read so im sorry in advance. And this is my tried and tested way of doing this, there may be a simpler way but this is from me throwing code at a wall and seeing what stuck
If it can be done with a batch file then the maybe over complicated work around is have c# write a .bat file and run it. If you want user input you could place the input into a variable and have c# write it into the file. it will take trial and error with this way because its like controlling a puppet with another puppet.
here is an example, In this case the function is for a push button in windows forum app that clears the print queue.
using System.IO;
using System;
public static void ClearPrintQueue()
{
//this is the path the document or in our case batch file will be placed
string docPath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//this is the path process.start usues
string path1 = docPath + "\\Test.bat";
// these are the batch commands
// remember its "", the comma separates the lines
string[] lines =
{
"#echo off",
"net stop spooler",
"del %systemroot%\\System32\\spool\\Printers\\* /Q",
"net start spooler",
//this deletes the file
"del \"%~f0\"" //do not put a comma on the last line
};
//this writes the string to the file
using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "test.bat")))
{
//This writes the file line by line
foreach (string line in lines)
outputFile.WriteLine(line);
}
System.Diagnostics.Process.Start(path1);
}
IF you want user input then you could try something like this.
This is for setting the computer IP as static but asking the user what the IP, gateway, and dns server is.
you will need this for it to work
public static void SetIPStatic()
{
//These open pop up boxes which ask for user input
string STATIC = Microsoft.VisualBasic.Interaction.InputBox("Whats the static IP?", "", "", 100, 100);
string SUBNET = Microsoft.VisualBasic.Interaction.InputBox("Whats the Subnet?(Press enter for default)", "255.255.255.0", "", 100, 100);
string DEFAULTGATEWAY = Microsoft.VisualBasic.Interaction.InputBox("Whats the Default gateway?", "", "", 100, 100);
string DNS = Microsoft.VisualBasic.Interaction.InputBox("Whats the DNS server IP?(Input required, 8.8.4.4 has already been set as secondary)", "", "", 100, 100);
//this is the path the document or in our case batch file will be placed
string docPath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
//this is the path process.start usues
string path1 = docPath + "\\Test.bat";
// these are the batch commands
// remember its "", the comma separates the lines
string[] lines =
{
"SETLOCAL EnableDelayedExpansion",
"SET adapterName=",
"FOR /F \"tokens=* delims=:\" %%a IN ('IPCONFIG ^| FIND /I \"ETHERNET ADAPTER\"') DO (",
"SET adapterName=%%a",
"REM Removes \"Ethernet adapter\" from the front of the adapter name",
"SET adapterName=!adapterName:~17!",
"REM Removes the colon from the end of the adapter name",
"SET adapterName=!adapterName:~0,-1!",
//the variables that were set before are used here
"netsh interface ipv4 set address name=\"!adapterName!\" static " + STATIC + " " + STATIC + " " + DEFAULTGATEWAY,
"netsh interface ipv4 set dns name=\"!adapterName!\" static " + DNS + " primary",
"netsh interface ipv4 add dns name=\"!adapterName!\" 8.8.4.4 index=2",
")",
"ipconfig /flushdns",
"ipconfig /registerdns",
":EOF",
"DEL \"%~f0\"",
""
};
//this writes the string to the file
using (StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "test.bat")))
{
//This writes the file line by line
foreach (string line in lines)
outputFile.WriteLine(line);
}
System.Diagnostics.Process.Start(path1);
}
Like I said. It may be a little overcomplicated but it never fails unless I write the batch commands wrong.

Categories

Resources