Search code examples
c#appdomain

Is it possible to override Environment.GetCommandLineArgs() at runtime?


I am working on a "debug dispatcher" C# program that is a debug assistance tool. This is not a new application; it has been a part of this project and invaluable to debugging it for some time. However, it has some limitations, which I have been trying to address to enable a more complete debugging experience.

This debug dispatcher takes the place of a system service that accepts requests to launch applications, and its purpose is to permit an attached debugger to automatically interact with code that would ordinarily be launched in a child process. The child processes are themselves .NET applications.

When this tool was made (years ago), the first thing that was investigated was whether there might be any way to launch a child process with the current debugger already attached to it. None was found, and so instead the tool creates an independent AppDomain within which to launch each process, then loads the application as an assembly and calls its entry method. This is almost working perfectly, but the problem I'm running into is that if those child processes call Environment.GetCommandLineArgs, they get the debug dispatcher tool's command-line instead of the command-line intended to be passed into a child process.

I have been trying to find a way to override Environment.GetCommandLineArgs.

  • Based on the publicly-available source code, it looks like if my application were .NET Core, there would in fact be an internal method SetCommandLineArgs I could invoke via reflection. The fact that this is internal isn't particularly troubling to me as this tool is specifically a debug assistant; if it happens to break down the road because the implementation changed, so be it. It serves no purpose whatsoever outside of a debugging context and won't ever be on a non-dev machine. But... .NET Core and .NET 5 don't support AppDomains at all, and never will, so that's a non-starter.

  • I have tried using Ryder to redirect Environment.GetCommandLineArgs to my own implementation, but it doesn't seem to work, even with a .ini file specifying a [.NET Framework Debugging Control] section with AllowOptimize=0. It almost looks as though the JIT has special handling for this specific method, because even though the reference source shows it making an icall into a native method, when I request disassembly of the JIT output in the debugger, it shows no calls at all, simply loading a value directly from an inlined memory address.

  • I searched for ways to change the current process's command-line at the Win32 level, but that appears to be unmodifiable.

In the context of supporting multiple concurrent applications inside the same process by means of AppDomains (solely for assisting debugging), is there any way to intercept and/or override the return value of Environment.GetCommandLineArgs, so that I can support hosting applications that obtain their command-line arguments exclusively via that method?


Solution

  • Okay, well, I'm not sure what I did that changed it, but at some point redirecting Environment.GetCommandLineArgs using Ryder seemed to go from being unreliable (some calls would redirect, others wouldn't -- in some debug sessions, Ryder seemed to have no effect at all) to reliable (every call gets redirected). Ryder's redirection apparently doesn't automatically apply in all AppDomains, so I have to reinstall it each time I create an AppDomain, after which my experience has been that the process dies a messy death if I try to unload the AppDomain. But, for debug purposes... I think it's adequate.