Why does C# handle command line args inconsistently? - c#

In C#, getting command line arguments directly from Main() omits the exe name, contrary to the tradition of C.
Getting those same command line args via Environment.GetCommandLineArgs includes it.
Is there some good logical reason I'm missing for this apparent inconsistency?
class Program
{
static void Main(string[] args)
{
Console.WriteLine(string.Format("args.Length = {0}", args.Length));
foreach(string arg in args)
{
Console.WriteLine(string.Format("args = {0}", arg));
}
Console.WriteLine("");
string[] Eargs = Environment.GetCommandLineArgs();
Console.WriteLine(string.Format("Eargs.Length = {0}", Eargs.Length));
foreach (string arg in Eargs)
{
Console.WriteLine(string.Format("Eargs = {0}", arg));
}
}
}
Output:
C:\\ConsoleApplication1\ConsoleApplication1\bin\Debug>consoleapplication1 xx zz aa
args.Length = 3
args = xx
args = zz
args = aa
Eargs.Length = 4
Eargs = consoleapplication1
Eargs = xx
Eargs = zz
Eargs = aa

Because it isn't C and thus isn't tied to it's conventions. Needing the exe name is pretty much an edge case; the small number of times I've needed this (compared to the other args) IMO justifies the decision to omit it.
This is additionally demanded in the spec (ECMA334v4, §10.1); (snipping to relevant parts):
10. Basic concepts
10.1 Application startup
...
This entry point method is always named Main, and shall have one of the
following signatures:
static void Main() {…}
static void Main(string[] args) {…}
static int Main() {…}
static int Main(string[] args) {…}
...
• Let args be the name of the parameter. If the length of the array designated by args is greater than
zero, the array members args[0] through args[args.Length-1], inclusive, shall refer to strings,
called application parameters, which are given implementation-defined values by the host environment
prior to application startup. The intent is to supply to the application information determined prior to
application startup from elsewhere in the hosted environment. If the host environment is not capable of
supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the
strings are received in lowercase. [Note: On systems supporting a command line, application, application parameters
correspond to what are generally known as command-line arguments. end note]

[status-by-design] -- http://msdn.microsoft.com/en-us/library/acy3edy3(v=VS.100).aspx
Unlike C and C++, the name of the program is not treated as the first command-line argument.

To me, the reason the two methods return different results is due to Context.
The Environment class is used to manipulate the current environement and process, and it makes sense that Environment.GetCommandLineArgs(); returns the executable name, since it is part of the process.
As for the args array, to me it makes sense to exclude the executable name. I know that I am calling the executable and in the context of running my application I want to know what arguments were sent to it.
At the end of the day, it is powerful to have a way to get at both alternatives.

Related

C# passing array to array but still getting "cannot convert from 'string[]' to 'string'” error

(using VS Community 2019 v16.10.4 on Win 10 Pro 202H)
I'm working on a C# console/winforms desktop app which monitors some local drive properties and displays a status message. Status message display is executed via Task Scheduler (the task is programmatically defined and registered). The UI is executed from the console app using the Process method. My intention is to pass an argument from Scheduler to the console app, perform some conditional logic and then pass the result to the UI entry (Program.cs) for further processing.
I’m testing passing an argument from the console app to the UI entry point and I’m getting a “Argument 1: cannot convert from 'string[]' to 'string'” error.
Code is:
class Program_Console
{
public static void Main(string[] tsArgs)
{
// based on MSDN example
tsArgs = new string[] { "Test Pass0", "TP1", "TP2" };
Process p = new Process();
try
{
p.StartInfo.FileName = BURS_Dir;
p.Start(tsArgs); // error here
}
public class Program_UI
{
[STAThread]
public void Main(string[] tsArgs)
{
Isn’t "tsArgs" consistently an array?
EDIT:
For clarity I’m using .NET Framework 4.7.2. The problem was not with consistency of what I am passing but in the Process.Start(String, IEnumerable String) overload. I believed “IEnumerable String” included string[ ]; it obviously does not since I was able to pass a plain string (not a string variable -- that also failed – just a hardcoded string).
In case it’s useful to somebody, my work-around is saving the arguments to a SQLite table in the console app and loading them into a List in the UI app. I’m sure a more proficient programmer could do it more efficiently.
Start doesn' have a costractor with string array. if you look at msdn document youi will see that you can use something the closest to your example
public static Start (string fileName, IEnumerable<string> arguments);
so you can try
p.Start( filename,tsArgs );
and replace filename with yours
The only Start() method taking arguments as an array also needs the filename: Start(). You can't set the Filename via StartInfo and then omit that parameter in the method call.
The following should work for you:
p.Start(BURS_Dir, tsArgs);
In .Net 5.0+, and .Net Core and Standard 2.1+, you can use a ProcessStartInfo for multiple command-line arguments
tsArgs = new string[] { "Test Pass0", "TP1", "TP2" };
Process p = new Process();
try
{
p.StartInfo.FileName = BURS_Dir;
foreach (var arg in tsArgs)
p.StartInfo.ArgumentList.Add(arg);
p.Start();
}
catch
{ //
}
Alternatively, just add them directly
Process p = new Process
{
StartInfo =
{
FileName = BURS_Dir,
ArgumentList = { "Test Pass0", "TP1", "TP2" },
}
};
try
{
p.Start();
}
catch
{ //
}

Issue With a String Not Able To Concatenate

The desktop client we use with our phone system has an API which allows us to capture the telephone number of the phone as it rings.
In order to use the API you reference a DLL and specify.
using TelephonyProxy;
public class program
{
private static Commander commander;
private static Listener listener;
static void Main()
{
commander = new Commander();
listener = new Listener();
SubscribeToListener();
}
private static void SubcribeToListener()
{
Debug.WriteLine("Subscribe To Listener");
listener.Connect += OnConnect;
listener.Disconnect += OnDisconnect;
listener.Offering += OnOffering;
listener.Ringback += OnRingback;
}
private static void OnOffering(string name, string number)
{
Debug.WriteLine(number + “abc”);
}
}
The issue is the OnOffering is called correctly and the telephone number is in the number variable. However the debug only shows the number and not the “abc”. In testing it seems you can concatenate anything in front of number but anything after is ignored.
Have you any idea why that might be?
Thanks for any input you can give this.
ASCII character 0 (represented in the debugger as \0) is sometimes used to terminate strings. If you're dealing with something like a COM device, etc., this may be the case.
For example:
Debug.WriteLine("a\0b");
will only output "a". ASCII character 0 is not printed, nor are any of the subsequent characters. Naturally, appending something to such a string will mean that anything after \0 in the original string, nothing will appear.
If you're dealing with COM, look at the string in the debugger and see if \0 is on the end.
You could remove it using replace:
Debug.WriteLine(number.Replace("\0", "") + "abc");

Execute the C# console exe with command line arguments from VB Project

How to call an exe written in C# which accepts command line arguments from VB.NET application.
For Example, Let's assume the C# exe name is "SendEmail.exe" and its 4 arguments are From ,TO ,Subject and Message and If I have placed the exe in the C drive. This is how I call from the command prompt
C:\SendEmail from#email.com,to#email.com,test subject, "Email Message " & vbTab & vbTab & "After two tabs" & vbCrLf & "I am next line"
I would like to call this "SendEmail" exe from the VB.NET application and pass the command line arguments from VB (arguments will be using vb Syntax like vbCrLf, VBTab etc). This problem may look silly but I am trying to divide the complex problem into series of smaller issues and conquer it.
Because your question has the C# tag, I'll suggest a C# solution you can re-spin in your preferred language.
/// <summary>
/// This will run the EXE for the user. If arguments are passed, then arguments will be used.
/// </summary>
/// <param name="incomingShortcutItem"></param>
/// <param name="xtraArguments"></param>
public static void RunEXE(string incomingExePath, List<string> xtraArguments = null)
{
if (File.Exists(incomingExePath))
{
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo();
System.Diagnostics.Process proc = new System.Diagnostics.Process();
if (xtraArguments != null)
{
info.Arguments = " " + string.Join(" ", xtraArguments);
}
info.WorkingDirectory = System.IO.Path.GetDirectoryName(incomingExePath);
info.FileName = incomingExePath;
proc.StartInfo = info;
proc.Start();
}
else
{
//do your else thing here
}
}
You might not need to call it via the console. If it's done in C# and marked public instead of internal or private, or if it relies on a public type, you may be able to add it as a reference in your VB.Net solution and call the method you want directly.
This is so much cleaner and better because you don't have to worry about things like escaping spaces or quotes in your subject or body arguments.
If you have control over the SendMail program, you make it accessible with a few simple changes. By default, a C# Console project gives you something like this:
using ....
// several using blocks at the top
// class name
class Program
{
//static Main() method
static void Main(string[] args)
{
//...
}
}
You can make it available to use from VB.Net like this:
using ....
// several using blocks at the top
//Make sure an explicit namespace is declared
namespace Foo
{
// make the class public
public class Program
{
//make the method public
static void Main(string[] args)
{
//...
}
}
}
That's it. Again, just add the reference in your project, Import it at the top of your VB.Net file, and you can call the Main() method directly, without going through the console. It doesn't matter that's it an .exe instead of a .dll. In the .Net world, they're all just assemblies you can use.

How to write a program in C# that can take arguments

I've seen alot of command-line programs that take arguments, like ping google.com -t. How can I make a program like ping? I would like my program to take a number as an argument and then further use this number:
For example:
geturi -n 1188
Just write a generic, console application.
The main method looks like the following snippet:
class Program
{
static void Main(string[] args)
{
}
}
Your arguments are included in the args array.
With a normal Console Application, in static void Main(string[] args), simply use the args. If you want to read the first argument as a number, then you simply use:
static void Main(string[] args)
{
if (args.Length > 1)
{
int arg;
if (int.TryParse(args[0], out arg))
// use arg
else // show an error message (the input was not a number)
}
else // show an error message (there was no input)
}

How to receive an argument in console program?

So I want other users to be able to run my programm sending arguments. how to do such thing?
If you have a Main method (which you'll have with a command-line app) you can access them directly as the args string-array parameter.
public static void Main(string[] args) {
var arg1 = args[0];
var arg2 = args[1];
}
If you're some other place in your code you can access the static Environment.GetCommandLineArgs method
//somewhere in your code
var args = Environment.GetCommandLineArgs();
var arg1 = args[0];
var arg2 = args[1];
You mean args when launching? such as myapp.exe blah blah2 blah3
Make your main method look like this:
public static void Main(string[] args)
{
}
now args is an array of the arguments passed into the program. So in the example case, args[0] == "blah", args[1] == "blah2", etc
The program is run from a method with this signature
public static void Main(string[] args)
The parameter args will contain the command line arguments, split on space.
While string[] args works just fine, it's worth mentioning Environment.GetCommandLineArgs.
You can read command line arguments from Main's optional string[] parameter:
static void Main(string[] args)
{
if (args.Length >= 1)
{
string x = args[0];
// etc...
}
}
Note that the following declaration for the Main method is also valid, but then you don't have access to the command line arguments:
static void Main()
{
// ...
}
See the documentation for more details.
This is supported by default, and the arguments will appear in the args array passed to your program.
public static void Main(string[] args)
If you say
App.exe Hello World What's Up
On a command line, you will receive an args array like this:
[0] = "Hello"
[1] = "World"
[2] = "What's"
[3] = "Up"
It's just up to you to determine what arguments you want, how they will be formatted, etc.
try these:
http://sourceforge.net/projects/csharpoptparse/
http://www.codeproject.com/KB/recipes/command_line.aspx
they basically allow you to define args and parse them in an OO way rather than having to lots of string comparisons and stuff like that. i used a similar one for java and it was great

Categories