5

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].

jw_
  • 1,663
  • 18
  • 32
  • C# is base 0. What's the error message when you `printf("%s\n",argv[0])`? – Jeremy Thompson May 01 '19 at 03:25
  • @Jeremy Thompson ? Can't understand what you said. – jw_ May 01 '19 at 03:26
  • If you want the path of the Assembly can you try: `var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location.Replace("bin\\Debug", string.Empty));` – Jeremy Thompson May 01 '19 at 03:28
  • `Assembly.GetExecutingAssembly().Location` will give you the full path to the assembly. In `.Net Core` this will be the DLL, for a `.Net Framework` console application this will be the `.exe` – Simply Ged May 01 '19 at 03:30
  • 1
    Please read the question, I don't want to get the assembly which many API can provide. I need to get argv[0] exactly in a C/C++ program. which is often different than assembly name There should be a property of Program that just provide this. – jw_ May 01 '19 at 03:32

2 Answers2

7

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

kalimag
  • 1,139
  • 2
  • 6
  • 11
  • Ha, is that all he/she wanted. – Jeremy Thompson May 01 '19 at 03:34
  • Tested on Ubuntu, works for most case, but still not working for relative command line, it get transfered to absolute command line, maybe this is considered to be a limitation/bug of the runtime? – jw_ May 01 '19 at 03:40
  • A work around for this(if there is really no solution) is to wrap the C# wrapper within another wrapper written in language that support exact argv[0] such as C/C++ (or bash?) which pass argv[0] as argv[1] and so on and the C# program treat argv[1] as argv[0] and so on. – jw_ May 01 '19 at 03:47
  • Huh, it works as expected on .NET Framework, but not on .NET Core. I'm guessing it's getting mangled to hide the `dotnet`/self-contained launcher executable. You may have to refer to platform-native APIs to obtain the original command line, if possible. – kalimag May 01 '19 at 03:58
  • @kalimag Do you know how to pass exact argv[0] down to the started process with ProcessStartInfo? I don't like to ask another question just for this. – jw_ May 01 '19 at 06:57
  • @jw_ That is a different question and should be asked as a different question ;-) (sorry if you already have, it just looks like your comment hasn’t been addressed). – binki Nov 18 '19 at 01:03
0

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
shroudednight
  • 605
  • 4
  • 16