-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API Proposal: get full path of current process executable #40862
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
I usually do it via |
(also tagging IO, b/c it seems relevant) |
For example, if you run |
In what environments would it return null? |
Wasm? |
Interesting. Is this discrepancy desirable? It seems for a .NET developer, the virtualized output would generally make more sense, no? |
We can describe the API by what it returns. It is the current proposal. The process executable path is non-ambiguous definition. Or we can describe the value by what it is meant to be used for. It leads to some kind of policy to compute or configure the path. The existing |
As I was looking into this, I have found that there is API that returns policy-free process executable in WinForms: |
Would it make sense to expose both the native and virtual paths: public class Environment
{
// existing; new in .NET 5. returns cached value of Process.GetCurrentProcess().Id
public static int ProcessId { get; }
+ // file containing native entrypoint, which ProcessId refers to
+ // (e.g. abs. path to `dotnet` in `dotnet myapp.dll`)
+ public static string? ProcessExecutablePath { get; }
+ // file containing managed entrypoint
+ // (e.g. abs. path to `myapp.dll` in `dotnet myapp.dll`)
+ public static string ProcessMainModulePath { get; }
} |
I am not sure sure what the difference between |
Results would be hosting-dependent:
This will make it explicit whether we are interested in the file, strictly containing the dotnet application entrypoint, or the native entrypoint (latter of which corresponds to |
If |
|
I was thinking that in cases where assembly with managed entrypoint does not physically exist, the second API will return the same value as |
Extremely often developers also want to get the directory path instead. Yes I know this is a one liner from the new executable path propery but since we're discussing this proposal. Would it make sense to add a property for this as well considering how often it is going to be used? (FYI: On Winforms there is namespace System
{
public class Environment {
// Returns null in environments where the current executable path is not available
public static string? ProcessExecutablePath { get; }
++ // Returns null in environments where the current executable directory is not available
++ public static string? ProcessDirectoryPath { get; }
}
} Usage Example:
|
|
I would like to use this for forking the current process - I've use that a couple of times for console applications. |
To start second instance of the current process, you need both |
It seems there are three concepts:
The current proposal would represent them as follows:
I don't mind having all three concepts, but I am concerned that there are three different ways to acquire them, some non-intuitive. Since the differences are nuanced and we know that the developers will usually pick the thing that is easiest to discover, which is likely going to be I think it would be better if we were to expose these three choices on the same type with well-picked names and IntelliSense documentation explaining how to choose among them. My proposal is: namespace System
{
public partial class Environment
{
// Returns the path to the file that launched the process. For framework dependent apps
// this will return the path to dotnet.exe. For environment where this concept doesn't
// exist, for example WebAssebmly, the method will return null.
public string? ApplicationProcessPath => Process.GetCurrentProcess().MainModule.FileName;
// Returns the path to the file that contains the `Main` method.
public string ApplicationEntryPointPath => GetCommandLineArgs()[0];
// Returns the directory path of your application. Same as AppContext.BaseDirectory.
public string ApplicationBaseDirectory => AppContext.BaseDirectory;
}
} |
The resources were unzipped into the %TEMP% directory as well in the .NET 3.x single-file, in some cases at last. We made AppContext.BaseDirectory to return the %TEMP% directory in .NET 3 because we believed that it makes more cases work than it breaks. |
My uber point is - if we introduce the new API We should not say "it does the same thing as AppContext.BaseDirectory" - that is wrong. They are 2 different intended use cases. |
Agree that this would need to be documented and that writing a good prescriptive documentation for the APIs like |
Unrelated: I keep wondering whether |
I think something that was strong in the API review was that each member should have the |
They may return the same path in most cases, but the intention of these APIs is different, which makes them different.
/// <summary>
/// Gets the path for the executable file that started the application.
/// </summary>
public static string StartupPath Today, it is implemented as calling So when we add the above So we will have 4 APIs, but 2 sets of "duplicated" behaviors:
I think I agree with you. In the API review, the intention of appending an Given this discussion, I think we should push this back to API Review as I think we should get some clarity on the 2 new APIs here. |
For
|
I'd also add scenarios for iOS/Android where the native process executable isn't necessarily next to the assemblies. |
namespace System
{
public partial class Environment
{
public static string? ProcessPath { get; }
}
} |
Fixes #40862 Co-authored-by: Stephen Toub <stoub@microsoft.com> Co-authored-by: Ryan Lucia <ryan@luciaonline.net>
Background and Motivation
The path of the current process executable is often needed for logging or to find more files next to the current process executable.
This API is needed more than before now that we support single-file publishing and assemblies do not have physical file paths anymore. See https://github.com/dotnet/designs/blob/master/accepted/2020/form-factors.md#single-file for details.
We have internal APIs to get current process executable path in this repo that return current executable path, e.g. here: https://github.com/dotnet/runtime/search?q=GetExePath&unscoped_q=GetExePath
Proposed API
Usage Examples
Examples of equivalent APIs in other environments:
os.Executable
in https://golang.org/pkg/os/#ExecutableAlternative Designs
The current cross-platform way to get full path of current process is
Process.GetCurrentProcess().MainModule.FileName
. This workaround is very inefficient because of it does a lot more than what is required to get the current process path. More discussion on this issue is in #13051 .The text was updated successfully, but these errors were encountered: