Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
Implement SafeProcessHandle.Open/TryOpen and Process.TryGetProcessById#126705
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
bad944e2ed39abe2bc39da114b09b63ecec90cff12a3bf1ae9fd4c3386ce237e0c5ebf0199f40aff5970534460d3fd0d5ccc672e4007b2cbd039b6ef1ec54d2063cc4bb5959a5c5598ea543c723dbf34281abf1cf799bc473875240e5bfb4000a148e105eecFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -23,6 +23,14 @@ public void Kill() { } | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] | ||
| [System.Runtime.Versioning.SupportedOSPlatformAttribute("maccatalyst")] | ||
| public static Microsoft.Win32.SafeHandles.SafeProcessHandle Open(int processId) { throw null; } | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] | ||
| [System.Runtime.Versioning.SupportedOSPlatformAttribute("maccatalyst")] | ||
| public static bool TryOpen(int processId, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out Microsoft.Win32.SafeHandles.SafeProcessHandle? processHandle) { throw null; } | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] | ||
| [System.Runtime.Versioning.SupportedOSPlatformAttribute("maccatalyst")] | ||
| public static Microsoft.Win32.SafeHandles.SafeProcessHandle Start(System.Diagnostics.ProcessStartInfo startInfo) { throw null; } | ||
| public bool TryWaitForExit(System.TimeSpan timeout, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Diagnostics.ProcessExitStatus? exitStatus) { throw null; } | ||
| public System.Diagnostics.ProcessExitStatus WaitForExit() { throw null; } | ||
| @@ -242,6 +250,10 @@ public void Refresh() { } | ||
| [System.Runtime.Versioning.SupportedOSPlatformAttribute("maccatalyst")] // this needs to come after the ios attribute due to limitations in the platform analyzer | ||
| public static int StartAndForget(string fileName, System.Collections.Generic.IList<string>? arguments = null) { throw null; } | ||
| public override string ToString() { throw null; } | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] | ||
| [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] | ||
| [System.Runtime.Versioning.SupportedOSPlatformAttribute("maccatalyst")] | ||
| public static bool TryGetProcessById(int processId, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Diagnostics.Process? process) { throw null; } | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| public void WaitForExit() { } | ||
| public bool WaitForExit(int milliseconds) { throw null; } | ||
| public bool WaitForExit(System.TimeSpan timeout) { throw null; } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -71,10 +71,41 @@ protected override bool ReleaseHandle() | ||
| Debug.Assert(_handle != null); | ||
| _handle.DangerousRelease(); | ||
| } | ||
| _waitStateHolder?.Dispose(); | ||
| return true; | ||
| } | ||
| private static bool TryOpenCore(int processId, [NotNullWhen(true)] out SafeProcessHandle? processHandle, out int lastError) | ||
| { | ||
| int result = Interop.Sys.Kill(processId, 0); | ||
| if (result != 0) | ||
| { | ||
| Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); | ||
| if (errorInfo.Error == Interop.Error.EPERM) | ||
| { | ||
| ThrowOpenProcessAccessDeniedException(processId); | ||
| } | ||
| if (errorInfo.Error == Interop.Error.ESRCH || errorInfo.Error == Interop.Error.EINVAL) | ||
| { | ||
| lastError = errorInfo.RawErrno; | ||
| processHandle = null; | ||
| return false; | ||
| } | ||
| throw new Win32Exception(errorInfo.RawErrno); | ||
| } | ||
| lastError = 0; | ||
| ProcessWaitState.Holder waitStateHolder = new(processId); | ||
| processHandle = new SafeProcessHandle(waitStateHolder); | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return true; | ||
| } | ||
| private bool SignalCore(PosixSignal signal) | ||
| { | ||
| if (!ProcessUtils.PlatformSupportsProcessStartAndKill) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -56,6 +56,91 @@ public SafeProcessHandle(IntPtr existingHandle, bool ownsHandle) | ||
| SetHandle(existingHandle); | ||
| } | ||
| /// <summary> | ||
| /// Opens an existing process by its process ID. | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// </summary> | ||
| /// <param name="processId">The process ID of the process to open.</param> | ||
| /// <returns>A <see cref="SafeProcessHandle"/> that represents the opened process.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="processId"/> is negative or zero.</exception> | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// <exception cref="Win32Exception">Thrown when the process could not be opened.</exception> | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// <exception cref="UnauthorizedAccessException">Thrown when the process exists but the caller does not have permissions to open it.</exception> | ||
| /// <remarks> | ||
| /// <para> | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// This API opens the handle immediately. In contrast, <see cref="Process.GetProcessById(int)"/> only checks whether | ||
| /// the process is currently running; opening the process handle is deferred until <see cref="Process.SafeHandle"/> is accessed. | ||
| /// </para> | ||
| /// <para> | ||
| /// On Windows, this API requests query/synchronize/terminate rights, while <see cref="Process.SafeHandle"/> requests | ||
| /// broader rights for interop scenarios. | ||
| /// </para> | ||
| /// <para> | ||
| /// On Windows, if the process has already exited, the method may still succeed and return a valid handle representing the terminated process. | ||
| /// </para> | ||
| /// <para> | ||
| /// On Unix, if the process has already exited and been reaped, a <see cref="Win32Exception"/> is thrown. | ||
| /// </para> | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// </remarks> | ||
| [UnsupportedOSPlatform("ios")] | ||
| [UnsupportedOSPlatform("tvos")] | ||
| [SupportedOSPlatform("maccatalyst")] | ||
| public static SafeProcessHandle Open(int processId) | ||
| { | ||
| ValidateOpenArguments(processId); | ||
| if (!TryOpenCore(processId, out SafeProcessHandle? handle, out int lastError)) | ||
| { | ||
| throw new Win32Exception(lastError); | ||
| } | ||
| return handle; | ||
| } | ||
| /// <summary> | ||
| /// Attempts to open an existing process by its process ID. | ||
| /// </summary> | ||
| /// <param name="processId">The process ID of the process to open.</param> | ||
| /// <param name="processHandle">When this method returns <see langword="true"/>, contains the <see cref="SafeProcessHandle"/> for the opened process; otherwise, <see langword="null"/>.</param> | ||
| /// <returns><see langword="true"/> if the process was successfully opened; otherwise, <see langword="false"/>.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="processId"/> is negative or zero.</exception> | ||
| /// <exception cref="UnauthorizedAccessException">Thrown when the process exists but the caller does not have permissions to open it.</exception> | ||
| /// <remarks> | ||
| /// <para> | ||
| /// This method does not throw when the process does not exist. Instead, it returns <see langword="false"/>. | ||
| /// </para> | ||
| /// <para> | ||
| /// This API opens the handle immediately. In contrast, <see cref="Process.TryGetProcessById(int, out Process)"/> only checks | ||
| /// whether the process is currently running; opening the process handle is deferred until <see cref="Process.SafeHandle"/> is accessed. | ||
| /// </para> | ||
| /// <para> | ||
| /// On Windows, this API requests query/synchronize/terminate rights, while <see cref="Process.SafeHandle"/> requests | ||
| /// broader rights for interop scenarios. | ||
| /// </para> | ||
| /// <para> | ||
| /// On Windows, if the process has already exited, the method may still succeed and return a valid handle representing the terminated process. | ||
| /// </para> | ||
| /// </remarks> | ||
| [UnsupportedOSPlatform("ios")] | ||
| [UnsupportedOSPlatform("tvos")] | ||
| [SupportedOSPlatform("maccatalyst")] | ||
| public static bool TryOpen(int processId, [NotNullWhen(true)] out SafeProcessHandle? processHandle) | ||
| { | ||
| ValidateOpenArguments(processId); | ||
| return TryOpenCore(processId, out processHandle, out _); | ||
| } | ||
| private static void ValidateOpenArguments(int processId) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(processId, 0); | ||
| if (!ProcessUtils.PlatformSupportsProcessStartAndKill) | ||
| { | ||
| throw new PlatformNotSupportedException(); | ||
| } | ||
| } | ||
| private static void ThrowOpenProcessAccessDeniedException(int processId) => | ||
| throw new UnauthorizedAccessException(SR.Format(SR.OpenProcessAccessDenied, processId)); | ||
| /// <summary> | ||
| /// Starts a process using the specified <see cref="ProcessStartInfo"/>. | ||
| /// </summary> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -936,6 +936,31 @@ public static Process GetProcessById(int processId) | ||
| return new Process(".", false, processId, null); | ||
| } | ||
| /// <summary> | ||
| /// Attempts to get a <see cref="Process"/> instance for an existing process with the specified process ID. | ||
| /// </summary> | ||
| /// <param name="processId">The process ID of the process to open.</param> | ||
| /// <param name="process">When this method returns <see langword="true"/>, contains a <see cref="Process"/> representing the opened process; otherwise, <see langword="null"/>.</param> | ||
| /// <returns><see langword="true"/> if the process was found and opened successfully; otherwise, <see langword="false"/>.</returns> | ||
| /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="processId"/> is negative or zero.</exception> | ||
| [UnsupportedOSPlatform("ios")] | ||
| [UnsupportedOSPlatform("tvos")] | ||
| [SupportedOSPlatform("maccatalyst")] | ||
| public static bool TryGetProcessById(int processId, [NotNullWhen(true)] out Process? process) | ||
| { | ||
| ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(processId, 0); | ||
| if (ProcessManager.IsProcessRunning(processId)) | ||
| { | ||
| process = new Process(".", false, processId, null); | ||
| return true; | ||
| } | ||
| process = null; | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return false; | ||
adamsitnik marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| /// <devdoc> | ||
| /// <para> | ||
| /// Creates an array of <see cref='System.Diagnostics.Process'/> components that are | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.