Redirecting Command-line Arguments for Bootstrapping - c#

I am trying to rewrite the following program in C instead of C# (which is less portable). It is obvious that "int system ( const char * command )" will be necessary to complete the program. Starting it with "int main ( int argc, char * argv[] )" will allow getting the command-line arguments, but there is still a problem that is difficult to understand. How do you successfully escape arguments with spaces in them? In the program below, arguments with spaces in them (example: screensaver.scr "this is a test") will be passed to the script as separate arguments (example: screensaver.scr this is a test) and could easily cause problems.
namespace Boids_Screensaver
{
static class Program
{
[STAThread]
static void Main(string[] args)
{
System.Diagnostics.Process python = new System.Diagnostics.Process();
python.EnableRaisingEvents = false;
python.StartInfo.FileName = "C:\\Python31\\pythonw.exe";
python.StartInfo.Arguments = "boids.pyw";
foreach (string arg in args)
{
python.StartInfo.Arguments += " " + arg;
}
python.Start();
}
}
}

Windows is all messed up. Every program has its own rules.

The correct way to do this under windows is to use _spawnv
Its equivalent under unix like OSes is fork() followed by execv.

screensaver.scr "spaced argument" nonspaced_argument
argc = 2
argv[0] = "screensaver.scr"
argv[1] = "spaced argument"
argv[2] = "nonspaced_argument"
Sorry my English :).

Related

C# Subcommands within console application

I would like to have commands within the executable itself for example:
shorten http://stackoverflow.com/
and the url will be parsed as an argument, if I set it to return the argument, it should return me http://stackoverflow.com/
Another example is
foo bar
and it will check what is the main command which is foo and subcommands under it, which is bar and will execute the command.
This should be done within the executable and not calling the executable in the directory. I would like to have multiple custom commands within the executable and not create one for each command.
I understand how to have arguments if each command was an executable, but I would like a few commands and subcommands within 1 executable. Is this possible?
EDIT:
This is what I want:
static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "short")
{
Console.WriteLine(args[i + 1]);
}
}
Console.Read();
}
which will return me the arguments of short. So if I type short link it will return me link.
However this will only work if I call the executable through the command line like C:\Path\ConsoleApplication1.exe not if I open up the application and type short link, which will not return me anything and close.
How do I make it work when I open up the application and type it in?
You can use Console.ReadLine:
var input = Console.ReadLine();
To get command and argument(s) use String.Split :
var command = input.Split()[0];
var argument1 = input.Split()[1];
etc.

c# console: how can i read piped input from the command line

I'm a bit confused. I've been looking through previous answers to the above question and NONE of them actually work for me, so I'm not sure what i'm doing wrong.
I have a simple c# console app: (outputsomething.exe)
static void Main(string[] args) {
Console.Out.Write("This is a test");
}
And another one that takes some args and piped input from the above code, like this:
dostuffwithinput.exe some args |outputsomething.exe
First problem is that I can't work out how to "read" the piped input, as I said above none of the existing answers work for me, reading from stdin (Console.In) just doesn't capture anything.
Secondly, after piping something in I can no longer write anything out to stdout (Console.Out).
The code I have is very simple it just writes out the args to a file, together with a few console attributes and tries to read from Console.In - which it does but it only reads input that I type in.
But with piped input it just never manages to capture what is piped in and the last output is never sent to the console.
static void Main(string[] args) {
bool ior = Console.IsInputRedirected;
bool keyavail = Console.KeyAvailable;
char[] chrs = new char[4];
int chr = Console.In.ReadBlock(chrs, 0, 4);
using (StreamWriter stream = new StreamWriter("fred.txt")) {
foreach (var arg in args) {
stream.WriteLine(arg);
Console.WriteLine(arg);
}
stream.WriteLine("input = " + new string(chrs));
stream.WriteLine("io redirectirected = " + ior);
stream.WriteLine("is key available = " + keyavail);
}
Console.WriteLine("fin");
Console.Out.Flush();
}
(I'm also having serious problems with this pile-of-crap editor that keeps showing a red warning about indentation show i've have to remove a lot of examples to get it in a sendable form!)
What am I doing wrong? (this is on windows 10/9879)
TIA
Tried the same with the below example codes. It is working for me.
WriteText
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Test Line1");
Console.WriteLine("test Line2");
}
}
ProcessInput
class Program
{
static void Main(string[] args)
{
string s=Console.In.ReadToEnd();
Console.WriteLine("Redirected Text: " + s);
}
}
I invoked the app using WriteText.exe | ProcessInput.exe
It showed the output string exactly passed by the WriteText.exe
Please let me know, if this helps.
If you want to pipe from outputsomething.exe to dostuffwithinput.exe it should be
outputsomething.exe|dostuffwithinput.exe some args

Application started by Process.Start() isn't getting arguments

Using C#, I am trying to pass command-line arguments to a new process using Process.Start():
string path = #"C:\Demo\Demo.exe";
string arguments = "one two three";
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = path,
Arguments = arguments
};
var process = Process.Start(startInfo);
My C application Demo.exe just echos the command line arguments:
int main( int argc, char *argv[] )
{
int count=0;
// Display each command-line argument.
printf( "\nCommand-line arguments:\n" );
for( count = 0; count < argc; count++ )
printf( " argv[%d] %s\n", count, argv[count] );
while(1);
}
If I start my application from cmd.exe, I get reasonable output:
Command-line arguments:
argv[0] Demo.exe
argv[1] one
argv[2] two
argv[3] three
When I use the C# application, the only thing I get is the path argument at argv[0]:
Command-line arguments:
argv[0] C:
Task Manager shows command line arguments for each method of starting Demo.exe:
Why isn't my C application receiving the command-line arguments from the C# application?
Edit
#hvd suggested I use GetCommandLine(). Here is the code and result of that:
char* ar = GetCommandLine();
printf( "\nGetCommandLine arguments:\n" );
printf(" %s", ar);
Output:
GetCommandLine arguments:
"C:
Is it possible that the C app is receiving the args as one string, but ignores everything after the first \ in the path?
Edit: I've added an answer below. It is a workaround, but I'm not sure the cause of my issue.
I've gotten back to this today and have a workaround working. I don't understand why my original attempt didn't work.
Here is the difference on the command line between typing Demo.exe and “Demo.exe.”
C:\Users\me\Desktop\Work\Builds\Win32>Demo.exe one two three
There are 4 arguments.
Command-line arguments:
argv[0]: Demo.exe
argv[1]: one
argv[2]: two
argv[3]: three
C:\Users\me\Desktop\Work\Builds\Win32>"Demo.exe" one two three
There are 1 arguments.
Command-line arguments:
argv[0]: Demo.exe
The Process.Start() call seemed to be doing the “Demo.exe” variety.
Doesn’t work:
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = #"Demo.exe",
WorkingDirectory = #"C:\Users\me\Desktop\Work\Builds\Win32",
Arguments = "one two three"
};
var process = Process.Start(startInfo);
There are 1 arguments.
Command-line arguments:
argv[0]: C:
Does work:
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
WorkingDirectory = #"C:\Users\me\Desktop\Work\Builds\Win32",
Arguments = "/C Demo.exe one two three"
};
var process = Process.Start(startInfo);
There are 4 arguments.
Command-line arguments:
argv[0]: Demo.exe
argv[1]: one
argv[2]: two
argv[3]: three
Does anyone have any ideas why the first method doesn't work?
I was able to reproduce your issue. I didn't have access to C, so I used C++ in Visual Studio 2013. It appears that C# using StartInfo passes the arguments as Unicode characters, so the first byte is non-zero, while the 2nd byte is likely 0 bits resulting in displaying only the first character since that indicates the string termination character. When I used printf it did not work, I had to use _tprintf to see what is passed. And printf does not handle Unicode. Not only does printf not handle it, your C program when populating argv will not translate Unicode to a string using 1 byte characters. While TCHAR (wide char) and tprintf in C++ does, as does C# natively.
So, when you did it the other way, using "cmd.exe" to call "/C Demo.exe one two three" cmd was not passing the string as Unicode. That's my hypothesis, given the results I am getting.
Related Question on StackOverflow
Does Process.StartInfo.Arguments support a UTF-8 string?
The C++ code that displayed the Arguments correctly (tprintf) and incorrectly (printf)
#include "stdafx.h"
#include "string.h"
int _tmain(int argc, _TCHAR* argv[])
{
int count=0;
// Display each command-line argument.
printf( "\nCommand-line arguments:\n" );
for( count = 0; count < argc; count++ )
//Correct. This statement worked, displaying the arguments
//_tprintf( _T(" argv[%d] %s\n"), count, argv[count] );
//Incorrect. Displayed only the first character of each argument
//printf( " argv[%d] %s\n", count, argv[count] );
getchar();
return 0;
}
This is the C# code that called it
namespace ProcessPassArguments
{
class Program
{
static void Main(string[] args)
{
string path = #"C:\Temp\Demo.exe";
string arguments = "one two three";
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = path,
Arguments = arguments
};
var process = Process.Start(startInfo);
}
}
}
For informational purposes only, C# calling the C# also worked. Again the suspected cause is that C# is passing the arguments to your C program as Unicode Characters.
The C# code that works as the target programmed called.
namespace Demo
{
class Program
{
static void Main(string[] args)
{
int i = 0;
foreach (string arg in args)
{
i++;
Console.WriteLine("Argument {0}: {1}", i, arg);
}
Console.ReadLine();
}
}
}
Try this
Arguments = "\"arg1\" \"arg2\" \"arg3\"";

Running EXE file form CMD made with C#

I'm newbie in c# and I'm stuck on this conundrum
I've recently made a Gui Program in c# that include several tabs and some other stuff
Now I want to make one of the tabs as a exe file that i would be able to run via cmd .
the entire code i want to put in file is comprised of one class
something like that
class E2p
{
main program( take 2 arg )
{some Code
make a CSV file in appDirectory
}
I want to turn it to EXE file so I can run it from CMD like that
E2pChck.exe -i 10.0.0.127 -r RandomWord
How can I do it ??
I'm not 100% sure what you're after, but I think you mean that you want to be able to run your exe from the command line with a couple of arguments.
These arguments are passed into your application in the Main method, which you'll find in Program.cs. In a command line application the arguments parameter is provided for you, but you can add it to a Windows Forms application.
class Program
{
static void Main(string[] args)
{
string firstArgument;
string secondArgument;
const int NumberOfArgumentsRequired = 2;
// you can access the arguments using the args array,
// but we need to make sure we have enough arguments,
// otherwise we'll get an index out of range exception
// (as we're trying to access items in an array that aren't there)
if (args.Length >= NumberOfArgumentsRequired)
{
firstArgument = args[0];
secondArgument = args[1];
}
else
{
// this block will be called if there weren't enough arguments
// it's useful for setting defaults, although that could also be done
// at the point where the strings were declared
firstArgument = "This value was set because there weren't enough arguments.";
secondArgument = "So was this one. You could do this at the point of declaration instead, if you wish.";
}
string outputString = string.Format("This is the first: {0}\r\nAnd this is the second: {1}", firstArgument, secondArgument);
Console.WriteLine(outputString);
Console.ReadKey();
}
}
If you typed E2pChck.exe -i 10.0.0.127 -r RandomWord into the command line then:
args[0] would be "-i"
args[1] would be "10.0.0.127"
args[2] would be "-r"
args[3] would be "RandomWord"
I know this doesn't technically answer the question, but the OP asked for an example of starting a process.
You would put this code in your button handler (probably on a separate thread so your UI doesn't hang)
System.Diagnostics.ProcessStartInfo csvGenerationProcInfo = new System.Diagnostics.ProcessStartInfo();
csvGenerationProcInfo.Arguments = "-i 10.0.0.127 -r RandomWord";
csvGenerationProcInfo.FileName = "E2pChck.exe";
System.Diagnostics.Process csvGenerationProc = System.Diagnostics.Process.Start(csvGenerationProcInfo);
csvGenerationProc.WaitForExit();
Or, if you don't need all the features of ProcessStartInfo you can just use:
System.Diagnostics.Process.Start("E2pChck.exe", "-i 10.0.0.127 -r RandomWord");
Hope that helps!

Regular Expression to parse command lines

I need a Regular Expression to parse commands such as:
C:\Program Files\Internet Explorer\iexplore.exe https:\www.google.com
C:\Program Files\Internet Explorer\iexplore.exe http:\www.google.com
C:\Program Files\Internet Explorer\iexplore.exe www.google.com
iexplore.exe https:\www.google.com
copy C:\test.txt D:\
The point is that I want to get the first part as command and the other parts as arguments. Commands can be anything including .bat, .vbs, .exe etc.
Found a Regular Expression which is working normally if there is no space in command.
string str = #"C:\xcopy D:\test.txt D:\Test";
string pattern = #"^(?:""([^""]*)""\s*|([^""\s]+)\s*)+";
Regex parseDir = new Regex(pattern, RegexOptions.IgnoreCase);
if(parseDir.IsMatch(str))
{
Match dir = parseDir.Match(str);
var captures = dir.Groups[1].Captures.Cast<Capture>().Concat(
dir.Groups[2].Captures.Cast<Capture>()).
OrderBy(x => x.Index).
ToArray();
string cmd = captures[0].Value;
string arguments = string.Empty;
for (int i = 1; i < captures.Length; i++)
{
arguments += captures[i].Value + " ";
}
Console.WriteLine(cmd);
Console.WriteLine(arguments);
}
From your question, I'm assuming you are looking for a way to pass batch commands in a text on the Windows OS. The only way I can think of for you to do this successfully is if you have a list of all the commands or if your program can extract all the .exe files in the system, that way you can successfully check where the first exe file which is the target program of the command is and assume the others as arguments.
This way, you can do your extraction like this (Non-regex method):
var cmd = "copy this.txt C:\t.txt"
var program = getTargetProgram(cmd);
var args = cmd.Substring(cmd.IndexOf(program) + program.length).trim().split(' ');
your getTargetProgram() could go like this:
private string getTargetProgram(string cmd)
{
//first test if it's a normal executable
if(File.Exists(cmd.Substring(0, cmd.IndexOf(".exe") + 4)) //return this extract;
foreach(string s in winProgramList)
{
if(cmd.StartsWith(s)){
//voila, we can return the target
}
}
}
If you're using a standard Console application, the main entry point args[] will already have parsed this for you. There's a caveat here, because the examples you've provided won't work because of the spaces in them (C:\Program Files) but if you surround them with quotes ("C:\Program Files\Internet ...\iexplorer.exe") you'll find this works correctly.
This link walks you through creating a console application
UPDATE:
Well then, if it's not a console application but you'd like to simulate exactly what the Console Application start-up routine provides you, may I introduce to you the one and only CommandLineToArgvW native method.
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine,
out int pNumArgs);
This ridiculously simple method takes any string and converts it into an array. Here's a utility class that you can use to convert your text input into a well formed array.
/// <summary>
/// Wrapper class for Win32 API calls
/// </summary>
public class NativeMethods
{
[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
[MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);
/// <summary>
/// Parse a string into an array, including items in quotes
/// </summary>
/// <param name="commandLine"></param>
/// <returns></returns>
public static string[] CommandLineToArgs(string commandLine)
{
if (String.IsNullOrEmpty(commandLine))
return new string[] {};
int argc;
var argv = CommandLineToArgvW(commandLine, out argc);
if (argv == IntPtr.Zero)
throw new System.ComponentModel.Win32Exception();
try
{
var args = new string[argc];
for (var i = 0; i < args.Length; i++)
{
var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
args[i] = Marshal.PtrToStringUni(p);
}
return args;
}
finally
{
Marshal.FreeHGlobal(argv);
}
}
}
You either need to put quotes around the program path/name (if it has spaces in it), or write some extra code to figure out the program part of it.
One approach that comes to mind is to start with the first capture (for your iexplorer.exe example, it would be C:\Program), check if it's a valid program. If not, add the next capture with a space (e.g., C:\Program + Files\Internet => C:\Program Files\Internet) and repeat the check. Repeat until you've run out of captures or have found a valid program, and treat the rest as arguments normally.
No reason to do the parsing manually, as another answer suggested. The regexes will still work.

Categories

Resources