diff --git a/src/Files.App/NativeMethods.txt b/src/Files.App/NativeMethods.txt
index 283bbe917cda..39a4df749a6d 100644
--- a/src/Files.App/NativeMethods.txt
+++ b/src/Files.App/NativeMethods.txt
@@ -60,3 +60,13 @@ ResizePseudoConsole
ClosePseudoConsole
CreatePipe
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
+STARTUPINFOEXW
+STARTUPINFOW
+PROCESS_CREATION_FLAGS
+PROCESS_INFORMATION
+SECURITY_ATTRIBUTES
+CloseHandle
+DeleteProcThreadAttributeList
+UpdateProcThreadAttribute
+InitializeProcThreadAttributeList
+CreateProcess
\ No newline at end of file
diff --git a/src/Files.App/Utils/Terminal/ConPTY/Native/ProcessApi.cs b/src/Files.App/Utils/Terminal/ConPTY/Native/ProcessApi.cs
deleted file mode 100644
index abbb241d3ed9..000000000000
--- a/src/Files.App/Utils/Terminal/ConPTY/Native/ProcessApi.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Files.App.Utils.Terminal.ConPTY
-{
- ///
- /// PInvoke signatures for win32 process api
- ///
- static class ProcessApi
- {
- internal const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- internal struct STARTUPINFOEX
- {
- public STARTUPINFO StartupInfo;
- public nint lpAttributeList;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- internal struct STARTUPINFO
- {
- public int cb;
- public string lpReserved;
- public string lpDesktop;
- public string lpTitle;
- public int dwX;
- public int dwY;
- public int dwXSize;
- public int dwYSize;
- public int dwXCountChars;
- public int dwYCountChars;
- public int dwFillAttribute;
- public int dwFlags;
- public short wShowWindow;
- public short cbReserved2;
- public nint lpReserved2;
- public nint hStdInput;
- public nint hStdOutput;
- public nint hStdError;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct PROCESS_INFORMATION
- {
- public nint hProcess;
- public nint hThread;
- public int dwProcessId;
- public int dwThreadId;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct SECURITY_ATTRIBUTES
- {
- public int nLength;
- public nint lpSecurityDescriptor;
- public int bInheritHandle;
- }
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool InitializeProcThreadAttributeList(
- nint lpAttributeList, int dwAttributeCount, int dwFlags, ref nint lpSize);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool UpdateProcThreadAttribute(
- nint lpAttributeList, uint dwFlags, nint attribute, nint lpValue,
- nint cbSize, nint lpPreviousValue, nint lpReturnSize);
-
- [DllImport("kernel32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CreateProcess(
- string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
- ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
- nint lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
- out PROCESS_INFORMATION lpProcessInformation);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool DeleteProcThreadAttributeList(nint lpAttributeList);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- internal static extern bool CloseHandle(nint hObject);
- }
-}
diff --git a/src/Files.App/Utils/Terminal/ConPTY/Processes/Process.cs b/src/Files.App/Utils/Terminal/ConPTY/Processes/Process.cs
index 652aaa703d4a..5d7cf5ec0edb 100644
--- a/src/Files.App/Utils/Terminal/ConPTY/Processes/Process.cs
+++ b/src/Files.App/Utils/Terminal/ConPTY/Processes/Process.cs
@@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
-using static Files.App.Utils.Terminal.ConPTY.ProcessApi;
+using Windows.Win32;
+using Windows.Win32.System.Threading;
namespace Files.App.Utils.Terminal.ConPTY
{
@@ -9,13 +10,13 @@ namespace Files.App.Utils.Terminal.ConPTY
///
internal sealed class Process : IDisposable
{
- public Process(STARTUPINFOEX startupInfo, PROCESS_INFORMATION processInfo)
+ public Process(STARTUPINFOEXW startupInfo, PROCESS_INFORMATION processInfo)
{
StartupInfo = startupInfo;
ProcessInfo = processInfo;
}
- public STARTUPINFOEX StartupInfo { get; }
+ public STARTUPINFOEXW StartupInfo { get; }
public PROCESS_INFORMATION ProcessInfo { get; }
#region IDisposable Support
@@ -34,20 +35,23 @@ void Dispose(bool disposing)
// dispose unmanaged state
// Free the attribute list
- if (StartupInfo.lpAttributeList != nint.Zero)
+ unsafe
{
- DeleteProcThreadAttributeList(StartupInfo.lpAttributeList);
- Marshal.FreeHGlobal(StartupInfo.lpAttributeList);
+ if ((void*)StartupInfo.lpAttributeList != null)
+ {
+ PInvoke.DeleteProcThreadAttributeList(StartupInfo.lpAttributeList);
+ Marshal.FreeHGlobal((nint)(void*)StartupInfo.lpAttributeList);
+ }
}
// Close process and thread handles
if (ProcessInfo.hProcess != nint.Zero)
{
- CloseHandle(ProcessInfo.hProcess);
+ PInvoke.CloseHandle(ProcessInfo.hProcess);
}
if (ProcessInfo.hThread != nint.Zero)
{
- CloseHandle(ProcessInfo.hThread);
+ PInvoke.CloseHandle(ProcessInfo.hThread);
}
disposedValue = true;
diff --git a/src/Files.App/Utils/Terminal/ConPTY/Processes/ProcessFactory.cs b/src/Files.App/Utils/Terminal/ConPTY/Processes/ProcessFactory.cs
index 4966a9a31402..f66624cefb8f 100644
--- a/src/Files.App/Utils/Terminal/ConPTY/Processes/ProcessFactory.cs
+++ b/src/Files.App/Utils/Terminal/ConPTY/Processes/ProcessFactory.cs
@@ -1,6 +1,9 @@
using System;
using System.Runtime.InteropServices;
-using static Files.App.Utils.Terminal.ConPTY.ProcessApi;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.Security;
+using Windows.Win32.System.Threading;
namespace Files.App.Utils.Terminal.ConPTY
{
@@ -22,77 +25,95 @@ internal static Process Start(string command, string directory, nint attributes,
return new Process(startupInfo, processInfo);
}
- private static STARTUPINFOEX ConfigureProcessThread(nint hPC, nint attributes)
+ private static STARTUPINFOEXW ConfigureProcessThread(nint hPC, nint attributes)
{
// this method implements the behavior described in https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session#preparing-for-creation-of-the-child-process
-
- var lpSize = nint.Zero;
- var success = InitializeProcThreadAttributeList(
- lpAttributeList: nint.Zero,
- dwAttributeCount: 1,
- dwFlags: 0,
- lpSize: ref lpSize
- );
- if (success || lpSize == nint.Zero) // we're not expecting `success` here, we just want to get the calculated lpSize
+ unsafe
{
- throw new InvalidOperationException("Could not calculate the number of bytes for the attribute list. " + Marshal.GetLastWin32Error());
- }
+ var lpSize = nuint.Zero;
+ var success = PInvoke.InitializeProcThreadAttributeList(
+ lpAttributeList: new(null),
+ dwAttributeCount: 1,
+ lpSize: ref lpSize
+ );
+ if (success || lpSize == nuint.Zero) // we're not expecting `success` here, we just want to get the calculated lpSize
+ {
+ throw new InvalidOperationException("Could not calculate the number of bytes for the attribute list. " + Marshal.GetLastWin32Error());
+ }
- var startupInfo = new STARTUPINFOEX();
- startupInfo.StartupInfo.cb = Marshal.SizeOf();
- startupInfo.lpAttributeList = Marshal.AllocHGlobal(lpSize);
+ var startupInfo = new STARTUPINFOEXW();
+ startupInfo.StartupInfo.cb = (uint)Marshal.SizeOf();
+ startupInfo.lpAttributeList = new((void*)Marshal.AllocHGlobal((int)lpSize));
- success = InitializeProcThreadAttributeList(
- lpAttributeList: startupInfo.lpAttributeList,
- dwAttributeCount: 1,
- dwFlags: 0,
- lpSize: ref lpSize
- );
- if (!success)
- {
- throw new InvalidOperationException("Could not set up attribute list. " + Marshal.GetLastWin32Error());
- }
+ success = PInvoke.InitializeProcThreadAttributeList(
+ lpAttributeList: startupInfo.lpAttributeList,
+ dwAttributeCount: 1,
+ lpSize: ref lpSize
+ );
+ if (!success)
+ {
+ throw new InvalidOperationException("Could not set up attribute list. " + Marshal.GetLastWin32Error());
+ }
- success = UpdateProcThreadAttribute(
- lpAttributeList: startupInfo.lpAttributeList,
- dwFlags: 0,
- attribute: attributes,
- lpValue: hPC,
- cbSize: nint.Size,
- lpPreviousValue: nint.Zero,
- lpReturnSize: nint.Zero
- );
- if (!success)
- {
- throw new InvalidOperationException("Could not set pseudoconsole thread attribute. " + Marshal.GetLastWin32Error());
- }
+ success = PInvoke.UpdateProcThreadAttribute(
+ lpAttributeList: startupInfo.lpAttributeList,
+ dwFlags: 0,
+ Attribute: (nuint)attributes,
+ lpValue: (void*)hPC,
+ cbSize: (nuint)nint.Size,
+ lpPreviousValue: null,
+ lpReturnSize: (nuint*)null
+ );
+ if (!success)
+ {
+ throw new InvalidOperationException("Could not set pseudoconsole thread attribute. " + Marshal.GetLastWin32Error());
+ }
- return startupInfo;
+ return startupInfo;
+ }
}
- private static PROCESS_INFORMATION RunProcess(ref STARTUPINFOEX sInfoEx, string commandLine, string directory)
+ private static PROCESS_INFORMATION RunProcess(ref STARTUPINFOEXW sInfoEx, string commandLine, string directory)
{
- int securityAttributeSize = Marshal.SizeOf();
- var pSec = new SECURITY_ATTRIBUTES { nLength = securityAttributeSize };
- var tSec = new SECURITY_ATTRIBUTES { nLength = securityAttributeSize };
- var success = CreateProcess(
- lpApplicationName: null,
- lpCommandLine: commandLine,
- lpProcessAttributes: ref pSec,
- lpThreadAttributes: ref tSec,
- bInheritHandles: false,
- dwCreationFlags: EXTENDED_STARTUPINFO_PRESENT,
- lpEnvironment: nint.Zero,
- lpCurrentDirectory: directory,
- lpStartupInfo: ref sInfoEx,
- lpProcessInformation: out PROCESS_INFORMATION pInfo
- );
- if (!success)
+ unsafe
{
- throw new InvalidOperationException("Could not create process. " + Marshal.GetLastWin32Error());
- }
+ var success = false;
+
+ int securityAttributeSize = Marshal.SizeOf();
+ var pSec = new SECURITY_ATTRIBUTES { nLength = (uint)securityAttributeSize };
+ var tSec = new SECURITY_ATTRIBUTES { nLength = (uint)securityAttributeSize };
+
+ PROCESS_INFORMATION lpProcessInformation;
- return pInfo;
+ fixed (STARTUPINFOEXW* lpStartupInfo = &sInfoEx)
+ {
+ fixed (char* lpCurrentDirectory = directory)
+ {
+ fixed (char* lpCommandLine = commandLine)
+ {
+ success = PInvoke.CreateProcess(
+ lpApplicationName: new PCWSTR(null),
+ lpCommandLine: lpCommandLine,
+ lpProcessAttributes: &pSec,
+ lpThreadAttributes: &tSec,
+ bInheritHandles: false,
+ dwCreationFlags: PROCESS_CREATION_FLAGS.EXTENDED_STARTUPINFO_PRESENT,
+ lpEnvironment: null,
+ lpCurrentDirectory: lpCurrentDirectory,
+ lpStartupInfo: (STARTUPINFOW*)lpStartupInfo,
+ lpProcessInformation: &lpProcessInformation
+ );
+ }
+ }
+ }
+
+ if (!success)
+ {
+ throw new InvalidOperationException("Could not create process. " + Marshal.GetLastWin32Error());
+ }
+
+ return lpProcessInformation;
+ }
}
}
}