/// <summary> /// Asynchronously waits for the process to exit. /// </summary> public static Task WaitForExitAsync(this Process process) { if (process.HasExited) { return(Task.CompletedTask); } var safeProcessHandle = process.SafeHandle; if (safeProcessHandle.IsClosed) { throw new ObjectDisposedException("Process"); } var tcs = new TaskCompletionSource <object?>(); var waitHandle = new ProcessWaitHandle(safeProcessHandle); RegisteredWaitHandle?registeredWaitHandle = null; lock (tcs) { registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitHandle, WaitForExitAsyncCallback, null, -1, true); } return(tcs.Task); void WaitForExitAsyncCallback(object context, bool wasSignaled) { // The lock is used to ensure `registeredWaitHandle` is initialized here // even if the process terminates while `RegisterWaitForSingleObject` is returning. lock (tcs) { registeredWaitHandle !.Unregister(null); } waitHandle.Close(); tcs.SetResult(null); } }
IntPtr GetProcessHandle(Kernel32.ProcessAccessFlags access, bool throwIfExited) { if (_haveProcessHandle) { if (throwIfExited) { // Since haveProcessHandle is true, we know we have the process handle // open with at least SYNCHRONIZE access, so we can wait on it with // zero timeout to see if the process has exited. ProcessWaitHandle waitHandle = null; try { waitHandle = new ProcessWaitHandle(_processHandle); if (waitHandle.WaitOne(0, false)) { throw new InvalidOperationException("Process has exited"); } } finally { waitHandle?.Close(); } } return(_processHandle); } var handle = Kernel32.OpenProcess(access, false, _inner.Id); if (throwIfExited && (access & Kernel32.ProcessAccessFlags.QueryInformation) != 0) { if (Kernel32.GetExitCodeProcess(handle, out var exitCode) && exitCode != Kernel32.STILL_ACTIVE) { throw new InvalidOperationException("Process has exited"); } } return(handle); }
private void WaitForExitAsyncCallback(object context, bool wasSignaled) { waitForExitAsyncRegisteredWaitHandle.Unregister(null); waitForExitAsyncRegisteredWaitHandle = null; waitForExitAsyncWaitHandle.Close(); waitForExitAsyncWaitHandle = null; // Wait until the output is processed // if (standardOutputTask != null) // await standardOutputTask; // if (standardErrorTask != null) // await standardErrorTask; waitForExitTCS.SetResult(null); }
private static unsafe int ExecWaitWithCaptureUnimpersonated(SafeUserTokenHandle userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName, string trueCmdLine) { IntSecurity.UnmanagedCode.Demand(); FileStream output; FileStream error; int retValue = 0; if (outputName == null || outputName.Length == 0) { outputName = tempFiles.AddExtension("out"); } if (errorName == null || errorName.Length == 0) { errorName = tempFiles.AddExtension("err"); } // Create the files output = CreateInheritedFile(outputName); error = CreateInheritedFile(errorName); bool success = false; SafeNativeMethods.PROCESS_INFORMATION pi = new SafeNativeMethods.PROCESS_INFORMATION(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); SafeUserTokenHandle primaryToken = null; try { // Output the command line... StreamWriter sw = new StreamWriter(output, Encoding.UTF8); sw.Write(currentDir); sw.Write("> "); // 'true' command line is used in case the command line points to // a response file sw.WriteLine(trueCmdLine != null ? trueCmdLine : cmd); sw.WriteLine(); sw.WriteLine(); sw.Flush(); NativeMethods.STARTUPINFO si = new NativeMethods.STARTUPINFO(); si.cb = Marshal.SizeOf(si); #if FEATURE_PAL si.dwFlags = NativeMethods.STARTF_USESTDHANDLES; #else //!FEATURE_PAL si.dwFlags = NativeMethods.STARTF_USESTDHANDLES | NativeMethods.STARTF_USESHOWWINDOW; si.wShowWindow = NativeMethods.SW_HIDE; #endif //!FEATURE_PAL si.hStdOutput = output.SafeFileHandle; si.hStdError = error.SafeFileHandle; si.hStdInput = new SafeFileHandle(UnsafeNativeMethods.GetStdHandle(NativeMethods.STD_INPUT_HANDLE), false); // // Prepare the environment // #if PLATFORM_UNIX StringDictionary environment = new CaseSensitiveStringDictionary(); #else StringDictionary environment = new StringDictionary(); #endif // PLATFORM_UNIX // Add the current environment foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables()) { environment[(string)entry.Key] = (string)entry.Value; } // Add the flag to indicate restricted security in the process environment["_ClrRestrictSecAttributes"] = "1"; #if DEBUG environment["OANOCACHE"] = "1"; #endif // set up the environment block parameter byte[] environmentBytes = EnvironmentBlock.ToByteArray(environment, false); fixed(byte *environmentBytesPtr = environmentBytes) { IntPtr environmentPtr = new IntPtr((void *)environmentBytesPtr); if (userToken == null || userToken.IsInvalid) { RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { success = NativeMethods.CreateProcess( null, // String lpApplicationName, new StringBuilder(cmd), // String lpCommandLine, null, // SECURITY_ATTRIBUTES lpProcessAttributes, null, // SECURITY_ATTRIBUTES lpThreadAttributes, true, // bool bInheritHandles, 0, // int dwCreationFlags, environmentPtr, // IntPtr lpEnvironment, currentDir, // String lpCurrentDirectory, si, // STARTUPINFO lpStartupInfo, pi); // PROCESS_INFORMATION lpProcessInformation); if (pi.hProcess != (IntPtr)0 && pi.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(pi.hProcess); } if (pi.hThread != (IntPtr)0 && pi.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(pi.hThread); } } } else { #if FEATURE_PAL throw new NotSupportedException(); #else success = SafeUserTokenHandle.DuplicateTokenEx( userToken, NativeMethods.TOKEN_ALL_ACCESS, null, NativeMethods.IMPERSONATION_LEVEL_SecurityImpersonation, NativeMethods.TOKEN_TYPE_TokenPrimary, out primaryToken ); if (success) { RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { success = NativeMethods.CreateProcessAsUser( primaryToken, // int token, null, // String lpApplicationName, cmd, // String lpCommandLine, null, // SECURITY_ATTRIBUTES lpProcessAttributes, null, // SECURITY_ATTRIBUTES lpThreadAttributes, true, // bool bInheritHandles, 0, // int dwCreationFlags, new HandleRef(null, environmentPtr), // IntPtr lpEnvironment, currentDir, // String lpCurrentDirectory, si, // STARTUPINFO lpStartupInfo, pi); // PROCESS_INFORMATION lpProcessInformation); if (pi.hProcess != (IntPtr)0 && pi.hProcess != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(pi.hProcess); } if (pi.hThread != (IntPtr)0 && pi.hThread != (IntPtr)NativeMethods.INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(pi.hThread); } } } #endif // !FEATURE_PAL } } } finally { // Close the file handles if (!success && (primaryToken != null && !primaryToken.IsInvalid)) { primaryToken.Close(); primaryToken = null; } output.Close(); error.Close(); } if (success) { try { bool signaled; ProcessWaitHandle pwh = null; try { pwh = new ProcessWaitHandle(procSH); signaled = pwh.WaitOne(ProcessTimeOut, false); } finally { if (pwh != null) { pwh.Close(); } } // Check for timeout if (!signaled) { throw new ExternalException(SR.GetString(SR.ExecTimeout, cmd), NativeMethods.WAIT_TIMEOUT); } // Check the process's exit code int status = NativeMethods.STILL_ACTIVE; if (!NativeMethods.GetExitCodeProcess(procSH, out status)) { throw new ExternalException(SR.GetString(SR.ExecCantGetRetCode, cmd), Marshal.GetLastWin32Error()); } retValue = status; } finally { procSH.Close(); threadSH.Close(); if (primaryToken != null && !primaryToken.IsInvalid) { primaryToken.Close(); } } } else { int err = Marshal.GetLastWin32Error(); if (err == NativeMethods.ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException(); } Win32Exception win32Exception = new Win32Exception(err); ExternalException ex = new ExternalException(SR.GetString(SR.ExecCantExec, cmd), win32Exception); throw ex; } return(retValue); }
private static unsafe int ExecWaitWithCaptureUnimpersonated(SafeUserTokenHandle userToken, string cmd, string currentDir, TempFileCollection tempFiles, ref string outputName, ref string errorName, string trueCmdLine) { IntSecurity.UnmanagedCode.Demand(); if ((outputName == null) || (outputName.Length == 0)) { outputName = tempFiles.AddExtension("out"); } if ((errorName == null) || (errorName.Length == 0)) { errorName = tempFiles.AddExtension("err"); } FileStream stream = CreateInheritedFile(outputName); FileStream stream2 = CreateInheritedFile(errorName); bool flag = false; Microsoft.Win32.SafeNativeMethods.PROCESS_INFORMATION lpProcessInformation = new Microsoft.Win32.SafeNativeMethods.PROCESS_INFORMATION(); Microsoft.Win32.SafeHandles.SafeProcessHandle processHandle = new Microsoft.Win32.SafeHandles.SafeProcessHandle(); Microsoft.Win32.SafeHandles.SafeThreadHandle handle2 = new Microsoft.Win32.SafeHandles.SafeThreadHandle(); SafeUserTokenHandle hNewToken = null; try { Microsoft.Win32.NativeMethods.STARTUPINFO startupinfo; StreamWriter writer = new StreamWriter(stream, Encoding.UTF8); writer.Write(currentDir); writer.Write("> "); writer.WriteLine((trueCmdLine != null) ? trueCmdLine : cmd); writer.WriteLine(); writer.WriteLine(); writer.Flush(); startupinfo = new Microsoft.Win32.NativeMethods.STARTUPINFO { cb = Marshal.SizeOf(startupinfo), dwFlags = 0x101, wShowWindow = 0, hStdOutput = stream.SafeFileHandle, hStdError = stream2.SafeFileHandle, hStdInput = new SafeFileHandle(Microsoft.Win32.UnsafeNativeMethods.GetStdHandle(-10), false) }; StringDictionary sd = new StringDictionary(); foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables()) { sd[(string)entry.Key] = (string)entry.Value; } sd["_ClrRestrictSecAttributes"] = "1"; byte[] buffer = EnvironmentBlock.ToByteArray(sd, false); try { fixed(byte *numRef = buffer) { IntPtr lpEnvironment = new IntPtr((void *)numRef); if ((userToken == null) || userToken.IsInvalid) { RuntimeHelpers.PrepareConstrainedRegions(); try { goto Label_0325; } finally { flag = Microsoft.Win32.NativeMethods.CreateProcess(null, new StringBuilder(cmd), null, null, true, 0, lpEnvironment, currentDir, startupinfo, lpProcessInformation); if ((lpProcessInformation.hProcess != IntPtr.Zero) && (lpProcessInformation.hProcess != Microsoft.Win32.NativeMethods.INVALID_HANDLE_VALUE)) { processHandle.InitialSetHandle(lpProcessInformation.hProcess); } if ((lpProcessInformation.hThread != IntPtr.Zero) && (lpProcessInformation.hThread != Microsoft.Win32.NativeMethods.INVALID_HANDLE_VALUE)) { handle2.InitialSetHandle(lpProcessInformation.hThread); } } } flag = SafeUserTokenHandle.DuplicateTokenEx(userToken, 0xf01ff, null, 2, 1, out hNewToken); if (flag) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { flag = Microsoft.Win32.NativeMethods.CreateProcessAsUser(hNewToken, null, cmd, null, null, true, 0, new HandleRef(null, lpEnvironment), currentDir, startupinfo, lpProcessInformation); if ((lpProcessInformation.hProcess != IntPtr.Zero) && (lpProcessInformation.hProcess != Microsoft.Win32.NativeMethods.INVALID_HANDLE_VALUE)) { processHandle.InitialSetHandle(lpProcessInformation.hProcess); } if ((lpProcessInformation.hThread != IntPtr.Zero) && (lpProcessInformation.hThread != Microsoft.Win32.NativeMethods.INVALID_HANDLE_VALUE)) { handle2.InitialSetHandle(lpProcessInformation.hThread); } } } } } finally { numRef = null; } } finally { if ((!flag && (hNewToken != null)) && !hNewToken.IsInvalid) { hNewToken.Close(); hNewToken = null; } stream.Close(); stream2.Close(); } Label_0325: if (flag) { try { bool flag2; ProcessWaitHandle handle4 = null; try { handle4 = new ProcessWaitHandle(processHandle); flag2 = handle4.WaitOne(0x927c0, false); } finally { if (handle4 != null) { handle4.Close(); } } if (!flag2) { throw new ExternalException(SR.GetString("ExecTimeout", new object[] { cmd }), 0x102); } int exitCode = 0x103; if (!Microsoft.Win32.NativeMethods.GetExitCodeProcess(processHandle, out exitCode)) { throw new ExternalException(SR.GetString("ExecCantGetRetCode", new object[] { cmd }), Marshal.GetLastWin32Error()); } return(exitCode); } finally { processHandle.Close(); handle2.Close(); if ((hNewToken != null) && !hNewToken.IsInvalid) { hNewToken.Close(); } } } int error = Marshal.GetLastWin32Error(); if (error == 8) { throw new OutOfMemoryException(); } Win32Exception inner = new Win32Exception(error); ExternalException exception2 = new ExternalException(SR.GetString("ExecCantExec", new object[] { cmd }), inner); throw exception2; }
private void MonitorThread() { ProcessWaitHandle procWaitHandle = null; WaitHandle[] waitHandles; try { unsafe { // Get pointers to shared memory objects. ConsoleParams* consoleParams = (ConsoleParams*)_consoleParams.Get(); CONSOLE_SCREEN_BUFFER_INFO* consoleScreenInfo = (CONSOLE_SCREEN_BUFFER_INFO*) _consoleScreenInfo.Get(); ConsoleBufferInfo* consoleBufferInfo = (ConsoleBufferInfo*)_consoleBufferInfo.Get(); // Keep waiting for new events until process has exitted or thread is aborted. procWaitHandle = new ProcessWaitHandle(_procSafeWaitHandle); waitHandles = new WaitHandle[] { procWaitHandle, _consoleBufferInfo.RequestEvent }; // Loop until console has exitted. while (WaitHandle.WaitAny(waitHandles) > 0) { // Get current window and buffer size. int columns = consoleScreenInfo->srWindow.Right - consoleScreenInfo->srWindow.Left + 1; int rows = consoleScreenInfo->srWindow.Bottom - consoleScreenInfo->srWindow.Top + 1; int bufferColumns = consoleScreenInfo->dwSize.X; int bufferRows = consoleScreenInfo->dwSize.Y; // Check if window size has changed. if (consoleParams->Columns != columns || consoleParams->Rows != rows) { consoleParams->Columns = columns; consoleParams->Rows = rows; // Raise event, window has been resized. if (ConsoleWindowResized != null) ConsoleWindowResized(this, new EventArgs()); } // Check if buffer size has changed. if ((consoleParams->BufferColumns != 0 && consoleParams->BufferColumns != bufferColumns) || (consoleParams->BufferRows != 0 && consoleParams->BufferRows != bufferRows)) { consoleParams->BufferColumns = bufferColumns; consoleParams->BufferRows = bufferRows; // Raise event, buffer has been resized. if (ConsoleBufferResized != null) ConsoleBufferResized(this, new EventArgs()); } if (consoleBufferInfo->NewDataFound || consoleBufferInfo->CursorPositionChanged) { // Raise event, console has sent new data. if (ConsoleNewData != null) ConsoleNewData(this, new EventArgs()); // Check if new data was found. if (consoleBufferInfo->NewDataFound) { // Raise event, buffer data has changed. if (ConsoleBufferChanged != null) ConsoleBufferChanged(this, new EventArgs()); } // Check if cursor posistion has changed. if (consoleBufferInfo->CursorPositionChanged) { // Raise event, cursor position has changed. if (ConsoleCursorPositionChanged != null) ConsoleCursorPositionChanged(this, new EventArgs()); } } } } } catch (ThreadAbortException) { } finally { if (procWaitHandle != null) procWaitHandle.Close(); // Raise event. if (ConsoleClosed != null) ConsoleClosed(this, new EventArgs()); } }