How can we get argv[0] in C#? - c#

With C/C++, we can get argv[0]:
printf("%s\n",argv[0])
In C#, args begins with argv[1].
Non of bellow API gives exactly argv[0], at least under Linux:
AppDomain.CurrentDomain.FriendlyName: only gives the name, no path
Process.GetCurrentProcess().ProcessName: gives wrong result with symbol link, and no path
Process.GetCurrentProcess().MainModule.FileName: gives wrong result with symbol link, and the path is always absolute
FYI: under Linux with the above C/C++ code (whose result is treated as the golden standard here), it prints the exact path (absolute or relative) that is used to invoke the program, and if you invoke the program through any symbol link, the symbol link's name is printed instead of the real program.
I ask this question since I try to write a wrapper program using C# under Ubuntu, which should pass argv[0] through to be fully transparent in case the wrapped program's behavior depends on argv[0].

Environment.CommandLine and Environment.GetCommandLineArgs() should contain the full and unmodified command line.

The accepted answer doesn't work for me on .NET 5 on Linux, I get $PROJECT_DIRECTORY/bin/Debug/net5.0/$PROJECT_NAME.dll. Further, this doesn't change if symlinks are used.
Instead I have to use this non-portable hack (taken from this comment):
(await File.ReadAllTextAsync("/proc/self/cmdline")).Split('\0')[0]
Result:
$ bin/Debug/net5.0/bpm
argv[0]: bin/Debug/net5.0/bpm
$ ln -s bin/Debug/net5.0/bpm foo
$ ./foo
argv[0]: ./foo

Related

How can I use System.Commandline.DragonFruit to parse options if the options are not preceded with double dash

I have an existing console app that takes option args that don't have the -- in front of them. For example:
./myapp businessDate=20230128 type=charley location=nashville
Currently I parse the args[] array tokens and split them around the "=" to get the key/value
I can't change that, because other programs already call it that way. But it appears that DragonFruit needs to have it this way instead.
./myapp --businessDate=20230128 type=charley --location=nashville
So my question is, can DragonFruit be configured to NOT use the -- prefix on options when I use the equals sign to separate the key from the value the way I currently do it in the example above? I believe the answer is "no", because of the Posix compliance. But maybe I missed something.
What I Tried
I ran the example program here Building your first app with System.CommandLine.DragonFruit And it worked fine when I ran it:
$ dotnet run --int-option=123 --bool-option=true
The value for --int-option is: 123
The value for --bool-option is: True
The value for --file-option is: null
But when I tried it without the --, this way instead, it gave me errors, and I was hoping it would work as above:
$ dotnet run int-option=123 bool-option=true
Unrecognized command or argument 'int-option=123'.
Unrecognized command or argument 'bool-option=true'.

How to pass commandline arguments to csharp-shell

I try to call the csharp shell this way:
csharp proc.cs /storage
csharp error CS2007: Unrecognized command-line option: '/storage'
The 'man' file is unclear about options - they are shown in the parameters list, but never explained, man says:
csharp [--attach PID] [-e EXPRESSION] [file1 [file2]] [options]
Even if I use:
csharp proc.cs p1 p2 /storage
the error is the same. The leading slash is not accepted, even not, if it is escaped (which I explicitely wish to prevent me to do).
This looks like bad design.
Is there probably a workaround?

Passing filepath into Main(string[] args) not working

I am trying to pass a file path into a C# Console Application but am having problems with the string being incorrect by the time it reaches the console application.
If I run my application from the command line, with a file path parameter:
MyApp "C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject\"
A windows dialogue pops up and informs me that my application has stopped working, and when I click the Debug option, I can see that the result of args[0] is:
C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject"
Note there is still a trailing quote at the end.
If I pass a second argument:
MyApp "C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject\" "any old string"
I get an error again, and after viewing in debug I see that args[0] is:
C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject" any
I am baffled as to why this is happening. My only guess is that the backslashes in the string are causing some kind of escape sequence from the string? Edit: I notice that the same is happening in the string example above! It seems \" is causing problems here.
I just want to pass in the file path of the current solution directory and am calling my app from a pre-build event using $(SolutionDir), and know that I can get the path of the current solution in other ways. But this is simplest and I am curious as to why it does not work as expected.
Yes, the rules for commandline arguments are a little murky.
The \ is the escape char and you can use it to escape quotes ("). You'll have to escape a backslash but only when it is preceding a quote. So use (note the '\\' at the end):
MyApp "C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject\\"
or, simpler but you'll have to deal with it in C# somehow:
MyApp "C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject"
Also see this question
That's why it's always better to use / in path
"C:/Users/DevDave/Documents/Visual Studio 2012/Projects/MyProject/" "any old string"
take a look: http://en.wikipedia.org/wiki/Path_(computing) , you can use both \ and / in path but if you want any shell compatibility I suggest to use /
Anything that comes after MyApp will be the first argument (args[0]). In your case, the first argument is "C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject\". Also, the quote at the end of the string seems to happen because \" means that you want to want to escape the quote and write it as a string. In this case, the quote is not closing the string. That is the reason that your args[0] is the whole thing that comes after MyApp
If you don't want to scape the quote and have a slash behind it, you should do \\"
You could try this and tell me what happens:
MyApp "C:\Users\DevDave\Documents\Visual Studio 2012\Projects\MyProject\\"
(look at the double slash)
Hope it helps.
Continuation of Henk's answer, and choose to add a \ at the end of the path, then:
If you choose to hack the bug by choosing this code in Henk's answer ("simpler but you'll have to deal with it in C# somehow:"), then you should realize some bugs that will occur:
args[0] will only be set, even if you pass multiple parameters in. The length of args will be equal to 1. So you have to split args[0] into multiple pieces for your hack.
You have to replace any " characters with a \ if they are at the end of the pieces you split.

FindWindowByClassNameAndRegex issue with special characters

For our software testing we have a test that lets us check to see if certain windows are open using the FindWindowByClassNameAndRegex P/Invoke call. The issue we're getting is when we have windows open with more than a certain number of special characters we always get IntPtr.Zero as a return. Are there any known issues with this? Here's some of the code we use to find the window: (in this case it's for a firefox window)
Regex windowTitleRegex = new Regex(Regex.Escape(fullWindowTitle).Replace("\?", "."), RegexOptions.IgnoreCase | RegexOptions.ECMAScript);
curWindowHandle = NativeMethods.FindWindowByClassNameAndRegex("MozillaUIWindowClass", windowTitleRegex);
Where the title of the window is ~`!##$%^&*()_-+={[}]|:;'<,>.?/\"àëÉùÙâÏûâÏûÊÛçîÀË«éïÂλœÇÔêôÈŒ\
(There's no actual line break it's just a formatting thing)
There is no Windows API function by that name. I'm guessing you've found some DLL that exports this function. Odds are always good that the regex this DLL uses is of some kind that doesn't quite match the syntax that .NET's Regex class uses. There are a lot of dialects.
Best thing to do is to pinvoke EnumWindows(). You can use your own Regex in the callback to filter, GetClassName() gets you the window class name. If you already know the window name then just use FindWindow().

Spaces and backslashes in Visual Studio build events

I have an application that is supposed to aid my project in terms of pre- and post-build event handling. I'm using ndesk.options for command line argument parsing. Which gave me weird results when my project path contains spaces. I thought this was the fault of ndesk.options but I guess my own application is to blame. I call my application as a post-built event like so:
build.exe --in="$(ProjectDir)" --out="c:\out\"
A simple foreach over args[] displays the following:
--in=c:\my project" --out=c:\out"
What happened is that the last " in each parameter was treated as if it was escaped. Thus the trailing backslash was removed. And the whole thing is treated as a single argument.
Now I thought I was being smart by simply escaping the first " as well, like so:
build.exe --in=\"$(ProjectDir)" --out=\"c:\out\"
In that case the resulting args[] look like this:
--path="c:\my
project"
--out="c:\out"
The trailing backslash in the parameters is still swallowed and the first parameter is now split up.
Passing this args[] to ndesk.options will then yield wrong results.
How should the right command line look so that the correct elements end up in the correct args[] slots? Alternatively, how is one supposed to parse command line arguments like these with or without ndesk.options? Any suggestion is welcome.
Thanks in advance
Did you try to escape the last backslash?
build.exe --in="$(ProjectDir)\" --out="c:\out\\"
This works probably only, as long as the ProjectDir ends in \, which should be given.
This is just an idea, but I did not give it a try
EDIT:
I found a comment which suggests to leave out the trailing "
I actually used "." to solve this same problem:
build.exe --in="$(ProjectDir)." --out="c:\out\."
primarily because otherwise it might look like you are trying to escape the second quote...which you're not, you're escaping the final \ (which is hidden).
I also added a REM in the postbuild command describing why I did that.

Categories