internal static int ResizePseudoConsole(SafePseudoConsoleHandle consoleHandle, Coord coord) { if (Environment.Is64BitOperatingSystem) { return(ResizePseudoConsole64(consoleHandle, coord)); } else { return(ResizePseudoConsole86(consoleHandle, coord)); } }
/// <summary> /// Initializes the specified startup info struct with the required properties and /// updates its thread attribute list with the specified ConPTY handle. /// </summary> /// <param name="handle">Pseudo console handle.</param> internal void InitAttributeListAttachedToConPTY(SafePseudoConsoleHandle handle) { this.StartupInfo.cb = Marshal.SizeOf <STARTUPINFOEX>(); this.StartupInfo.dwFlags = STARTF_USESTDHANDLES; const int AttributeCount = 1; var size = IntPtr.Zero; // Create the appropriately sized thread attribute list bool wasInitialized = InitializeProcThreadAttributeList(IntPtr.Zero, AttributeCount, 0, ref size); if (wasInitialized || size == IntPtr.Zero) { throw new InvalidOperationException( $"Couldn't get the size of the process attribute list for {AttributeCount} attributes", new Win32Exception()); } this.lpAttributeList = Marshal.AllocHGlobal(size); if (this.lpAttributeList == IntPtr.Zero) { throw new OutOfMemoryException("Couldn't reserve space for a new process attribute list"); } // Set startup info's attribute list & initialize it wasInitialized = InitializeProcThreadAttributeList(this.lpAttributeList, AttributeCount, 0, ref size); if (!wasInitialized) { throw new InvalidOperationException("Couldn't create new process attribute list", new Win32Exception()); } // Set thread attribute list's Pseudo Console to the specified ConPTY wasInitialized = UpdateProcThreadAttribute( this.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, handle.Handle, (IntPtr)Marshal.SizeOf <IntPtr>(), IntPtr.Zero, IntPtr.Zero); if (!wasInitialized) { throw new InvalidOperationException("Couldn't update process attribute list", new Win32Exception()); } }
/// <summary> /// Initializes a new instance of the <see cref="PseudoConsoleConnectionHandles"/> class. /// </summary> /// <param name="inPipePseudoConsoleSide">the input pipe on the pseudoconsole side.</param> /// <param name="outPipePseudoConsoleSide">the output pipe on the pseudoconsole side.</param> /// <param name="inPipeOurSide"> the input pipe on the local side.</param> /// <param name="outPipeOurSide"> the output pipe on the local side.</param> /// <param name="pseudoConsoleHandle">the handle to the pseudoconsole.</param> /// <param name="processHandle">the handle to the spawned process.</param> /// <param name="pid">the process ID.</param> /// <param name="mainThreadHandle">the handle to the main thread.</param> public PseudoConsoleConnectionHandles( SafePipeHandle inPipePseudoConsoleSide, SafePipeHandle outPipePseudoConsoleSide, SafePipeHandle inPipeOurSide, SafePipeHandle outPipeOurSide, SafePseudoConsoleHandle pseudoConsoleHandle, SafeProcessHandle processHandle, int pid, SafeThreadHandle mainThreadHandle) { this.InPipePseudoConsoleSide = inPipePseudoConsoleSide; this.OutPipePseudoConsoleSide = outPipePseudoConsoleSide; this.InPipeOurSide = inPipeOurSide; this.OutPipeOurSide = outPipeOurSide; this.PseudoConsoleHandle = pseudoConsoleHandle; this.ProcessHandle = processHandle; this.Pid = pid; this.MainThreadHandle = mainThreadHandle; }
private Task <IPtyConnection> StartPseudoConsoleAsync( PtyOptions options, TraceSource trace, CancellationToken cancellationToken) { // Create the in/out pipes if (!CreatePipe(out SafePipeHandle inPipePseudoConsoleSide, out SafePipeHandle inPipeOurSide, null, 0)) { throw new InvalidOperationException("Could not create an anonymous pipe", new Win32Exception()); } if (!CreatePipe(out SafePipeHandle outPipeOurSide, out SafePipeHandle outPipePseudoConsoleSide, null, 0)) { throw new InvalidOperationException("Could not create an anonymous pipe", new Win32Exception()); } var coord = new Coord(options.Cols, options.Rows); var pseudoConsoleHandle = new SafePseudoConsoleHandle(); int hr; RuntimeHelpers.PrepareConstrainedRegions(); try { // Run CreatePseudoConsole* in a CER to make sure we don't leak handles. // MSDN suggest to put all CER code in a finally block // See http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx } finally { // Create the Pseudo Console, using the pipes hr = CreatePseudoConsole(coord, inPipePseudoConsoleSide.Handle, outPipePseudoConsoleSide.Handle, 0, out IntPtr hPC); // Remember the handle inside the CER to prevent leakage if (hPC != IntPtr.Zero && hPC != INVALID_HANDLE_VALUE) { pseudoConsoleHandle.InitialSetHandle(hPC); } } if (hr != S_OK) { Marshal.ThrowExceptionForHR(hr); } // Prepare the StartupInfoEx structure attached to the ConPTY. var startupInfo = default(STARTUPINFOEX); startupInfo.InitAttributeListAttachedToConPTY(pseudoConsoleHandle); IntPtr lpEnvironment = Marshal.StringToHGlobalUni(GetEnvironmentString(options.Environment)); try { string app = GetAppOnPath(options.App, options.Cwd, options.Environment); string arguments = options.VerbatimCommandLine ? WindowsArguments.FormatVerbatim(options.CommandLine) : WindowsArguments.Format(options.CommandLine); var commandLine = new StringBuilder(app.Length + arguments.Length + 4); bool quoteApp = app.Contains(" ") && !app.StartsWith("\"") && !app.EndsWith("\""); if (quoteApp) { commandLine.Append('"').Append(app).Append('"'); } else { commandLine.Append(app); } if (!string.IsNullOrWhiteSpace(arguments)) { commandLine.Append(' '); commandLine.Append(arguments); } bool success; int errorCode = 0; var processInfo = default(PROCESS_INFORMATION); var processHandle = new SafeProcessHandle(); var mainThreadHandle = new SafeThreadHandle(); RuntimeHelpers.PrepareConstrainedRegions(); try { // Run CreateProcess* in a CER to make sure we don't leak handles. } finally { success = CreateProcess( null, // lpApplicationName commandLine.ToString(), null, // lpProcessAttributes null, // lpThreadAttributes false, // bInheritHandles VERY IMPORTANT that this is false EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags lpEnvironment, options.Cwd, ref startupInfo, out processInfo); if (!success) { errorCode = Marshal.GetLastWin32Error(); } // Remember the handles inside the CER to prevent leakage if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != INVALID_HANDLE_VALUE) { processHandle.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != INVALID_HANDLE_VALUE) { mainThreadHandle.InitialSetHandle(processInfo.hThread); } } if (!success) { var exception = new Win32Exception(errorCode); throw new InvalidOperationException($"Could not start terminal process {commandLine.ToString()}: {exception.Message}", exception); } var connectionOptions = new PseudoConsoleConnection.PseudoConsoleConnectionHandles( inPipePseudoConsoleSide, outPipePseudoConsoleSide, inPipeOurSide, outPipeOurSide, pseudoConsoleHandle, processHandle, processInfo.dwProcessId, mainThreadHandle); var result = new PseudoConsoleConnection(connectionOptions); return(Task.FromResult <IPtyConnection>(result)); } finally { startupInfo.FreeAttributeList(); if (lpEnvironment != IntPtr.Zero) { Marshal.FreeHGlobal(lpEnvironment); } } }
private static extern int ResizePseudoConsole86(SafePseudoConsoleHandle consoleHandle, Coord coord);