string appPath = Path.GetDirectoryName(Path.GetDirectoryName(System.IO.Directory.GetCurrentDirectory()));
Process p = new Process();
p.StartInfo = new ProcessStartInfo("cmd.exe", #"/c opencvproject.exe " + #appPath + #"\\bin\\Debug\\center\\centerilluminate.jpg");
p.Start();
I tried this at my other computer and it works , however when I tried it in my new computer this doesn't work somehow. Anyone knows how to solve this? The program I am using is c# and im calling cmd to call c++ program which is opencvproject.exe
There are still multiple instances where I use cmd to trigger other c++ program and python scripts to run and those are not working too. I am not sure what am I doing wrong..
Hold the path between double quotation.
p.StartInfo = new ProcessStartInfo("cmd.exe", "/c opencvproject.exe \"" + appPath + "\\bin\\Debug\\center\\centerilluminate.jpg\"");
Explanation
Character combinations consisting of a backslash () followed by a letter or by a combination of digits are called "escape sequences."
http://msdn.microsoft.com/ja-jp/library/h21280bw.aspx
# makes escape sequence no effect, so..
var s1 = #"\\bin\\Debug\\"; // This contains wrong path \\bin\\Debug\\
var s2 = "\\bin\\Debug\\"; // This contains right path \bin\Debug\
And need using escape sequence to hold the double quotation between double quotation.
var s3 = "\"\\bin\\Debug\\\""; // This contains "\bin\Debug\"
var s4 = #"\"\\bin\\Debug\\\""; // compile error
The # character automatically escapes characters in the string behind it, so you shouldn't double backslash your path.
Eg, where you have:
#"\\bin\\debug\\.."
it should either be:
#"\bin\debug\..."
or:
"\\bin\\debug\\.." (without the #)
Also, if your apppath contains spaces, then you should surround the entire string with " characters
Related
my code is
a.exe
string programName = AppDomain.CurrentDomain.FriendlyName;
ProcessStartInfo proc = new ProcessStartInfo();
proc.FileName = "b.exe"
proc.Arguments = programName + " \"" + AppDomain.CurrentDomain.BaseDirectory + "\"";
Process.Start(proc)
and check the value another program
b.exe
MessageBox.Show(args[0]);
MessageBox.Show(args[1]);
i predict value is
args[0] = a.exe
args[1] = D:\my test\with space\Folder\
but the value is
args[0] = a.exe
args[1] = D:\my test\with space\Folder"
QUESTION
BaseDirectory : C:\my test\with space\Folder\
so i cover BaseDirectory with " because has space.
as a result i want
b.exe a.exe "C:\my test\with space\Folder\"
but at b.exe check args[1] value is
D:\my test\with space\Folder"
where is my backslash and why appear "
help me please...
As Kayndarr already pointed out correctly in the comments, you are escaping " in your path.
There are certain characters which the compiler will not interpret as part of the string, due to their special meaning.
In order to let the compiler know, you want those characters interpreted as part of the string instead, you have to write them in a so called "escape-sequence".
I.e. that means putting a backslash in front of them.
Since the backslash itself has therefor also a special meaning as escape-character - you have to escape the slash, if you want it to be interpreted as part of the string.
"\\"
Will generate a literal string with one backslash in it, since the first backslash is used to escape the second.
The fix in your example would therefor look as follows:
string programName = AppDomain.CurrentDomain.FriendlyName;
ProcessStartInfo proc = new ProcessStartInfo();
proc.FileName = "b.exe"
proc.Arguments = programName + "\\" + AppDomain.CurrentDomain.BaseDirectory + "\\";
Process.Start(proc);
I am working on a project that involves having to manipulate a bat file based on certain user produced parameters. The bat files themselves are created manually, with a static format. A basic example of a bat file would be:
cd \some\predefined\bat
start run_some_script "user_generated_argument" [other pre-defined arguments]
The "user_generated_argument" bit of the bat file is manipulated in C# by the following code:
string bat_text = File.ReadAllText(bat_path);
Regex regex = new Regex("(.*?)\".*\"(.*)");
string new_argument = "A new argument";
string new_bat = regex.Replace(bat_text , "$1\"" + new_argument + "\"$2", 1);
And that would produce the following:
cd \some\predefined\bat
start run_some_script "A new argument" [other pre-defined arguments]
which is the expected output.
However, the problem lies when one of the other pre-defined arguments after the first quoted argument is also in quotes when that is the case, it seems that the second quoted argument disappears. For example, if the bat file looks like:
cd \some\predefined\bat
start run_some_script "user_generated_argument" "a_predefined_quoted_argument" [other pre-defined arguments]
Running the same C# code from above would produce the following:
cd \some\predefined\bat
start run_some_script "A new argument" [other pre-defined arguments]
The "a_predefined_quoted_argument" would no longer be in the string.
I may be doing this completely wrong. How would I make the predefined quoted argument not disappear?
the problem is that your expression
\".*\"
is eager or greedy, taking everything between the first quote and the last quote it finds. To make it lazy or reluctant, put a ? after the *
like so (I used VB, which escapes double quotes by double double quotes)
Dim batfile As String = "cd \some\predefined\bat" & vbCrLf & "start run_some_script ""user_generated_argument"" ""a_predefined_quoted_argument"" [other pre-defined arguments]"
Dim regex As Regex = New Regex("(.*?)"".*?""(.*)")
Dim new_argument As String = "A new argument"
Dim new_bat As String = regex.Replace(batfile, "$1""" + new_argument + """ $2", 1)
It will now take everything between the first quote, and the next quote.
Instead of using Regex you could also read the lines with File.ReadAllLines(), take the desired line and split it with string.Split() and replace them in that way.
Something like:
string[] lines = File.ReadAllLines(fileName);
string commandLine = lines.Where(d => d.StartsWith("start")).Single();
string[] arguments = commandLine.Split(' ');
foreach (var argument in arguments)
{
if (argument.StartsWith("\""))
{
// do your stuff and reassemble
}
}
This is my code. The input command line is var1 val1 var2 val2:
var rawCmd = Environment.CommandLine;
// Environment.CommandLine adds the .exe info that I don't want in my command line:
// rawCmd = "path\to\ProjectName.vshost.exe" var1 val1 var2 val2
// A. This correction makes it work, although it is pretty ugly:
var cleanCmd = rawCmd.Split(new string[] { ".exe\" " }, StringSplitOptions.None)[1];
// B. This alternative should be cleaner, but I can't make it work:
var exePath = System.Reflection.Assembly.GetCallingAssembly().Location;
cleanCmd = rawCmd.Replace(string.Format($"\"{exePath}\" "), "");
So to make B work, I should be able to find the .vhost.exe info (which I am not able to find).
But also I would like to know if there is a cleaner way to do all this.
As for the reason why I want to achieve this, here is the explanation (tl;dr: parsing a json from the command line): https://stackoverflow.com/a/36203572/831138
Instead of using
var rawCmd = Environment.CommandLine;
You can use:
var rawCmd = Environment.CommandLine;
var argsOnly = rawCmd.Replace("\"" + Environment.GetCommandLineArgs()[0] + "\"", "");
This will return "var1 val1 var2 val2" in your example. And it should work with the JSON example in the other post.
This only strips the command invocation part, no matter you write it as program, program.exe, .\program, c:program, "c:\Program Files\program", "\Program Files\program.exe", etc. or your path separator.
var exe = Environment.GetCommandLineArgs()[0]; // Command invocation part
var rawCmd = Environment.CommandLine; // Complete command
var argsOnly = rawCmd.Remove(rawCmd.IndexOf(exe),exe.Length).TrimStart('"').Substring(1);
It will leave double quotes, carets, and spaces between arguments untouched, even spaces at the beginning i.e., just after program name. Note there's an extra space at the beginning, don't ask me why. If that bothers you, remove first character, it should be easy. Hence the final .Substring(1). I define the two variables to make it more readable.
Edit:
Takes account of quoted invocation and the case where the program name string happens to appear as part of an argument (e.g., if your program is me.exe and you run me "Call me Ishmael", .Replace would trim the second me too). Now I also take out that extra space.
This is a very old question, but as of Windows 10 20H2 and .NET Framework 4.8, all of the above solutions appear to be broken in one way or another (eg. double-quote delimited exe paths).
I needed to remove the exe from Environment.CommandLine in a more generally robust way, so I decided to try a regex based approach. (Then I had 2 problems, lol.) Hope this helps somebody!
internal static string GetRawCommandLineArgs( )
{
// Separate the args from the exe path.. incl handling of dquote-delimited full/relative paths.
Regex fullCommandLinePattern = new Regex(#"
^ #anchor match to start of string
(?<exe> #capture the executable name; can be dquote-delimited or not
(\x22[^\x22]+\x22) #case: dquote-delimited
| #or
([^\s]+) #case: no dquotes
)
\s* #chomp zero or more whitespace chars, after <exe>
(?<args>.*) #capture the remainder of the command line
$ #match all the way to end of string
",
RegexOptions.IgnorePatternWhitespace|
RegexOptions.ExplicitCapture|
RegexOptions.CultureInvariant
);
Match m = fullCommandLinePattern.Match(Environment.CommandLine);
if (!m.Success) throw new ApplicationException("Failed to extract command line.");
// Note: will return empty-string if no args after exe name.
string commandLineArgs = m.Groups["args"].Value;
return commandLineArgs;
}
Testing done:
exe paths with/without doublequote
args containing doublequotes and also referencing the exe name
invoking exe with no args returns empty string
[Edit] Testing NOT done:
.NET 5 or any other runtime or OS
I have found a way to get the vhost path:
var exePath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, System.AppDomain.CurrentDomain.FriendlyName);
...although I am afraid it could lead to inconsistencies depending on where the code is executed (Debug / production ...). I hope not, I'll have to keep testing.
If the number of spaces between elements is not important, you can just Join the argument array, which is split on unquoted space characters, and doesn't contain the executable:
void Main(string[] args)
{
var cleanCmd = string.Join(" ", args);
// etc
}
Actually, the command invocation part is always enclosed in double quotes, even if the path doesn't contain any spaces. And it is always followed by a space character, even if no command line params are specified. So this should be enough in any case:
string args = Environment.CommandLine
.Substring(Environment.GetCommandLineArgs()[0].Length + 3);
But if you're like me and want to make it 100% waterproof, you can use:
string args = Environment.CommandLine
.TrimStart('"')
.Substring(Environment.GetCommandLineArgs()[0].Length)
.TrimStart('"')
.TrimStart(' ');
In the app.config file, I have:
add key="DataFileLocation" value="E:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\"/>
In the code I have:
Process P2 = new Process();
P2.StartInfo.FileName = "restore.bat";
P2.StartInfo.Arguments = + "\"" + DataFileLocation.ToString() + "\"";
P2.StartInfo.UseShellExecute = false;
P2.StartInfo.RedirectStandardOutput = true;
P2.StartInfo.CreateNoWindow = true;
P2.Start();
The output to 'restore.bat' is:
-v dataloc=\"E:\\Program Files\\Microsoft SQL Server\\MSSQL12.MSSQLSERVER\\MSSQL\\DATA\\\"
As you can see, there's an extra "\" at the beginning which is breaking the bat/sql statement...
Andrew
In your case it seems like you are already adding a extra \, so is the output according to your logic.
The best way to combine path is that you should use the Path.Combine method provided by static Path class, it takes care of all the extra \
Try this
var finalPath = Path.Combine(DataFileLocation.ToString(), "what_ever_path_you_want_to_combine");
i would like to run a process with the parameter: filename.
string parms = filechooser.Filename ;
psi = new ProcessStartInfo("timidity", parms);
The problem occur when user choose a filename with some spaces.
Ho can i pass the parameter with the " " ?
Thanks
You could wrap the value in double quotes:
string parameters = string.Format("\"{0}\"", filechooser.Filename);
psi = new ProcessStartInfo("timidity", parameters);
That should work just fine, the spaces will be passed too.
However if you want to escape the filename (which depends on the app being started, i.e. timidity), do this:
string parms = string.Format("\"{0}\"", filechooser.Filename);
psi = new ProcessStartInfo("timidity", parms);
This will create a string based on the format \"{0}\". \" becomes a quote (") and {0} will be replaced with the first parameter after the format string, i.e. the filename.
You can try this out using the Start, Run feature or command prompt (cmd.exe). Enter timidity then your full filename, with spaces, in quotes and see if that works:
timidity "my filename"
Try this.
string parms = filechooser.Filename ;
psi = new ProcessStartInfo("timidity", "\"" + parms + "\"");
Backslash is your friend:
"\"timidity\""