/// <summary> /// Gets the file name (path) for the given module handle in the given process. /// </summary> /// <param name="process">The process for the given module or null for the current process.</param> /// <remarks>External process handles must be opened with PROCESS_QUERY_INFORMATION|PROCESS_VM_READ</remarks> public static unsafe string GetModuleFileName(ModuleInstance module, SafeProcessHandle?process = null) { if (process == null) { return(PlatformInvoke.GrowableBufferInvoke( (ref ValueBuffer <char> buffer) => { fixed(char *b = buffer) { return Imports.GetModuleFileNameW(module, b, buffer.Length); } }, ReturnSizeSemantics.BufferTruncates | ReturnSizeSemantics.LastErrorInsufficientBuffer | ReturnSizeSemantics.SizeIncludesNullWhenTruncated)); } else { return(PlatformInvoke.GrowableBufferInvoke( (ref ValueBuffer <char> buffer) => { fixed(char *b = buffer) { return Imports.K32GetModuleFileNameExW(process, module, b, buffer.Length); } }, ReturnSizeSemantics.BufferTruncates)); } }
/// <summary> /// Instructs the Process component to wait the specified number of milliseconds for the associated process to exit. /// </summary> private bool WaitForExitCore(int milliseconds) { SafeProcessHandle?handle = null; try { handle = GetProcessHandle(Interop.Advapi32.ProcessOptions.SYNCHRONIZE, false); if (handle.IsInvalid) { return(true); } using (Interop.Kernel32.ProcessWaitHandle processWaitHandle = new Interop.Kernel32.ProcessWaitHandle(handle)) { return(_signaled = processWaitHandle.WaitOne(milliseconds)); } } finally { // If we have a hard timeout, we cannot wait for the streams if (_output != null && milliseconds == Timeout.Infinite) { _output.WaitUtilEOF(); } if (_error != null && milliseconds == Timeout.Infinite) { _error.WaitUtilEOF(); } handle?.Dispose(); } }
/// <summary> /// Gets info for the given module in the given process. /// </summary> /// <param name="process">The process for the given module or null for the current process.</param> /// <remarks>External process handles must be opened with PROCESS_QUERY_INFORMATION|PROCESS_VM_READ</remarks> public static unsafe ModuleInfo GetModuleInfo(ModuleInstance module, SafeProcessHandle?process = null) { Error.ThrowLastErrorIfFalse( Imports.K32GetModuleInformation(process ?? Processes.GetCurrentProcess(), module, out var info, (uint)sizeof(ModuleInfo))); return(info); }
/// <devdoc> /// Helper to associate a process handle with this component. /// </devdoc> /// <internalonly/> private void SetProcessHandle(SafeProcessHandle processHandle) { _processHandle = processHandle; _haveProcessHandle = true; if (_watchForExit) { EnsureWatchingForExit(); } }
/// <summary> /// Gets the specified process memory counters. /// </summary> /// <param name="process">The process to get memory info for for or null for the current process.</param> public static unsafe ProcessMemoryCountersExtended GetProcessMemoryInfo(SafeProcessHandle?process = null) { if (process == null) { process = GetCurrentProcess(); } Error.ThrowLastErrorIfFalse( Imports.K32GetProcessMemoryInfo(process, out var info, (uint)sizeof(ProcessMemoryCountersExtended))); return(info); }
/// <summary> /// Gets the module handles for the given process. /// </summary> /// <remarks>External process handles must be opened with PROCESS_QUERY_INFORMATION|PROCESS_VM_READ</remarks> /// <param name="process">The process to get modules for or null for the current process.</param> public static unsafe IEnumerable <ModuleInstance> GetProcessModules(SafeProcessHandle?process = null) { if (process == null) process = Processes.GetCurrentProcess(); }
public unsafe IChildProcessStateHolder SpawnProcess( ref ChildProcessStartInfoInternal startInfo, string resolvedPath, SafeHandle stdIn, SafeHandle stdOut, SafeHandle stdErr) { var arguments = startInfo.Arguments; var environmentVariables = startInfo.EnvironmentVariables; var workingDirectory = startInfo.WorkingDirectory; var flags = startInfo.Flags; Debug.Assert(startInfo.CreateNewConsole || ConsolePal.HasConsoleWindow()); var commandLine = WindowsCommandLineUtil.MakeCommandLine(resolvedPath, arguments ?? Array.Empty <string>(), !flags.HasDisableArgumentQuoting()); var environmentBlock = startInfo.UseCustomEnvironmentVariables ? WindowsEnvironmentBlockUtil.MakeEnvironmentBlock(environmentVariables.Span) : null; // Objects that need cleanup InputWriterOnlyPseudoConsole?pseudoConsole = null; SafeJobObjectHandle? jobObjectHandle = null; SafeProcessHandle? processHandle = null; SafeThreadHandle? threadHandle = null; try { pseudoConsole = startInfo.CreateNewConsole ? InputWriterOnlyPseudoConsole.Create() : null; if (pseudoConsole is not null && flags.HasUseCustomCodePage()) { ChangeCodePage(pseudoConsole, startInfo.CodePage, workingDirectory); } bool killOnClose = startInfo.AllowSignal && WindowsVersion.NeedsWorkaroundForWindows1809; jobObjectHandle = CreateJobObject(killOnClose, startInfo.DisableWindowsErrorReportingDialog); using var inheritableHandleStore = new InheritableHandleStore(3); var childStdIn = stdIn != null?inheritableHandleStore.Add(stdIn) : null; var childStdOut = stdOut != null?inheritableHandleStore.Add(stdOut) : null; var childStdErr = stdErr != null?inheritableHandleStore.Add(stdErr) : null; IntPtr jobObjectHandles = jobObjectHandle.DangerousGetHandle(); Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count]; inheritableHandleStore.DangerousGetHandles(inheritableHandles); fixed(IntPtr *pInheritableHandles = inheritableHandles) { using var attr = new ProcThreadAttributeList(3); if (pseudoConsole is not null) { attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle()); } attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length); attr.UpdateJobList(&jobObjectHandles, 1); const int CreationFlags = Kernel32.CREATE_UNICODE_ENVIRONMENT | Kernel32.EXTENDED_STARTUPINFO_PRESENT; int processId; (processId, processHandle, threadHandle) = InvokeCreateProcess( commandLine, CreationFlags, environmentBlock, workingDirectory, childStdIn, childStdOut, childStdErr, attr); return(new WindowsChildProcessState(processId, processHandle, jobObjectHandle, pseudoConsole, startInfo.AllowSignal)); } } catch { if (processHandle is not null) { Kernel32.TerminateProcess(processHandle, -1); processHandle.Dispose(); } pseudoConsole?.Dispose(); jobObjectHandle?.Dispose(); throw; } finally { threadHandle?.Dispose(); } }
// Change the code page of the specified pseudo console by invoking chcp.com on it. private static unsafe void ChangeCodePage( InputWriterOnlyPseudoConsole pseudoConsole, int codePage, string?workingDirectory) { var commandLine = new StringBuilder(ChcpPath.Length + 5); WindowsCommandLineUtil.AppendStringQuoted(commandLine, ChcpPath); commandLine.Append(' '); commandLine.Append(codePage.ToString(CultureInfo.InvariantCulture)); using var inheritableHandleStore = new InheritableHandleStore(3); using var nullDevice = FilePal.OpenNullDevice(FileAccess.ReadWrite); var childStdIn = inheritableHandleStore.Add(nullDevice); var childStdOut = inheritableHandleStore.Add(nullDevice); var childStdErr = inheritableHandleStore.Add(nullDevice); SafeProcessHandle?processHandle = null; try { Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count]; inheritableHandleStore.DangerousGetHandles(inheritableHandles); fixed(IntPtr *pInheritableHandles = inheritableHandles) { using var attr = new ProcThreadAttributeList(2); attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle()); attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length); const int CreationFlags = Kernel32.CREATE_UNICODE_ENVIRONMENT | Kernel32.EXTENDED_STARTUPINFO_PRESENT; SafeThreadHandle threadHandle; (_, processHandle, threadHandle) = InvokeCreateProcess( commandLine, CreationFlags, null, workingDirectory, childStdIn, childStdOut, childStdErr, attr); threadHandle.Dispose(); } using var waitHandle = new WindowsProcessWaitHandle(processHandle); waitHandle.WaitOne(); if (!Kernel32.GetExitCodeProcess(processHandle, out var exitCode)) { throw new Win32Exception(); } if (exitCode != 0) { ThrowHelper.ThrowChcpFailedException(codePage, exitCode, nameof(codePage)); } } finally { processHandle?.Dispose(); } }
/// <devdoc> /// <para> /// Frees any resources associated with this component. /// </para> /// </devdoc> public void Close() { if (Associated) { // We need to lock to ensure we don't run concurrently with CompletionCallback. // Without this lock we could reset _raisedOnExited which causes CompletionCallback to // raise the Exited event a second time for the same process. lock (this) { // This sets _waitHandle to null which causes CompletionCallback to not emit events. StopWatchingForExit(); } if (_haveProcessHandle) { _processHandle !.Dispose(); _processHandle = null; _haveProcessHandle = false; } _haveProcessId = false; _isRemoteMachine = false; _machineName = "."; _raisedOnExited = false; // Only call close on the streams if the user cannot have a reference on them. // If they are referenced it is the user's responsibility to dispose of them. try { if (_standardOutput != null && (_outputStreamReadMode == StreamReadMode.AsyncMode || _outputStreamReadMode == StreamReadMode.Undefined)) { if (_outputStreamReadMode == StreamReadMode.AsyncMode) { _output?.CancelOperation(); _output?.Dispose(); } _standardOutput.Close(); } if (_standardError != null && (_errorStreamReadMode == StreamReadMode.AsyncMode || _errorStreamReadMode == StreamReadMode.Undefined)) { if (_errorStreamReadMode == StreamReadMode.AsyncMode) { _error?.CancelOperation(); _error?.Dispose(); } _standardError.Close(); } if (_standardInput != null && !_standardInputAccessed) { _standardInput.Close(); } } finally { _standardOutput = null; _standardInput = null; _standardError = null; _output = null; _error = null; CloseCore(); Refresh(); } } }