in sources/Google.Solutions.Platform/Dispatch/Win32ProcessFactory.cs [151:272]
public IWin32Process CreateProcessWithPseudoConsole(
string executable,
string? arguments,
PseudoTerminalSize pseudoConsoleSize)
{
using (PlatformTraceSource.Log.TraceMethod()
.WithParameters(executable, arguments))
{
//
// Create a STARTUPINFOEX as described in
// https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
//
var size = IntPtr.Zero;
NativeMethods.InitializeProcThreadAttributeList(
IntPtr.Zero,
1,
0,
ref size);
if (size == IntPtr.Zero)
{
throw DispatchException.FromLastWin32Error(
"Calculating the number of bytes for the " +
"thread attribute list failed");
}
using (var attributeListHandle =
GlobalAllocSafeHandle.GlobalAlloc((uint)size.ToInt32()))
{
var startupInfo = new NativeMethods.STARTUPINFOEX();
startupInfo.StartupInfo.cb =
Marshal.SizeOf<NativeMethods.STARTUPINFOEX>();
startupInfo.lpAttributeList =
attributeListHandle.DangerousGetHandle();
if (!NativeMethods.InitializeProcThreadAttributeList(
startupInfo.lpAttributeList,
1,
0,
ref size))
{
throw DispatchException.FromLastWin32Error(
"Creating the thread attribute list failed");
}
var pseudoConsole = new Win32PseudoConsole(pseudoConsoleSize);
try
{
if (!NativeMethods.UpdateProcThreadAttribute(
startupInfo.lpAttributeList,
0,
(IntPtr)NativeMethods.PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
pseudoConsole.Handle.DangerousGetHandle(),
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero))
{
throw DispatchException.FromLastWin32Error(
"Attaching the pseudo-console failed");
}
var processSecurityAttributes =
new NativeMethods.SECURITY_ATTRIBUTES
{
nLength = Marshal
.SizeOf<NativeMethods.SECURITY_ATTRIBUTES>()
};
var threadSecurityAttributes =
new NativeMethods.SECURITY_ATTRIBUTES
{
nLength = Marshal
.SizeOf<NativeMethods.SECURITY_ATTRIBUTES>()
};
if (!NativeMethods.CreateProcess(
null,
$"{Quote(executable)} {arguments}",
ref processSecurityAttributes,
ref threadSecurityAttributes,
false,
NativeMethods.CREATE_SUSPENDED | NativeMethods.EXTENDED_STARTUPINFO_PRESENT,
IntPtr.Zero,
null,
ref startupInfo,
out var processInfo))
{
throw DispatchException.FromLastWin32Error(
$"Launching process for {executable} failed");
}
var process = new Win32Process(
new FileInfo(executable).Name,
processInfo.dwProcessId,
new SafeProcessHandle(processInfo.hProcess, true),
new SafeThreadHandle(processInfo.hThread, true))
{
PseudoTerminal = pseudoConsole
};
process.Exited += (_, __) =>
{
//
// Close pseudo console stream to unblock readers.
//
_ = pseudoConsole.CloseAsync();
};
InvokeOnProcessCreated(process);
return process;
}
catch
{
pseudoConsole.Dispose();
throw;
}
finally
{
NativeMethods.DeleteProcThreadAttributeList(startupInfo.lpAttributeList);
}
}
}
}