|
|
- using Microsoft.Win32.SafeHandles;
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
-
- namespace TrustedUninstaller.Shared
- {
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SECURITY_ATTRIBUTES
- {
- public int nLength;
- public IntPtr lpSecurityDescriptor;
- public int bInheritHandle;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct PROCESS_INFORMATION
- {
- public IntPtr hProcess;
- public IntPtr hThread;
- public int dwProcessId;
- public int dwThreadId;
- }
-
- // This also works with CharSet.Ansi as long as the calling function uses the same character set.
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct STARTUPINFO
- {
- public Int32 cb;
- public string lpReserved;
- public string lpDesktop;
- public string lpTitle;
- public Int32 dwX;
- public Int32 dwY;
- public Int32 dwXSize;
- public Int32 dwYSize;
- public Int32 dwXCountChars;
- public Int32 dwYCountChars;
- public Int32 dwFillAttribute;
- public Int32 dwFlags;
- public Int16 wShowWindow;
- public Int16 cbReserved2;
- public IntPtr lpReserved2;
- public IntPtr hStdInput;
- public IntPtr hStdOutput;
- public IntPtr hStdError;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- public struct STARTUPINFOEX
- {
- public STARTUPINFO StartupInfo;
- public IntPtr lpAttributeList;
- }
-
- public class NativeProcess
- {
-
- [DllImport("kernel32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CreateProcess(
- string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
- ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
- IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
- out PROCESS_INFORMATION lpProcessInformation);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool UpdateProcThreadAttribute(
- IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
- IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool InitializeProcThreadAttributeList(
- IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- private static extern bool CloseHandle(IntPtr hObject);
-
- private const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
- private const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
- private const int CREATE_NO_WINDOW = 0x08000000;
- private const int CREATE_NEW_CONSOLE = 0x00000010;
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
- const UInt32 INFINITE = 0xFFFFFFFF;
- const UInt32 WAIT_ABANDONED = 0x00000080;
- const UInt32 WAIT_OBJECT_0 = 0x00000000;
- const UInt32 WAIT_TIMEOUT = 0x00000102;
-
- public static Process? Process;
- public static bool StartProcess(string path, int parent, string playbookDir)
- {
- Process = null;
-
- // Create a new process with a different parent process
- // https://stackoverflow.com/questions/10554913/how-to-call-createprocess-with-startupinfoex-from-c-sharp-and-re-parent-the-ch
- var pInfo = new PROCESS_INFORMATION();
- var sInfoEx = new STARTUPINFOEX();
- sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
- var lpValue = IntPtr.Zero;
-
- try
- {
- var lpSize = IntPtr.Zero;
- var success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
- if (success || lpSize == IntPtr.Zero)
- {
- return false;
- }
-
- sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
- success = InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize);
- if (!success)
- {
- return false;
- }
-
- var parentHandle = Process.GetProcessById(parent).Handle;
- // This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function
- lpValue = Marshal.AllocHGlobal(IntPtr.Size);
- Marshal.WriteIntPtr(lpValue, parentHandle);
-
- success = UpdateProcThreadAttribute(
- sInfoEx.lpAttributeList,
- 0,
- (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
- lpValue,
- (IntPtr)IntPtr.Size,
- IntPtr.Zero,
- IntPtr.Zero);
- if (!success)
- {
- return false;
- }
-
-
- var pSec = new SECURITY_ATTRIBUTES();
- var tSec = new SECURITY_ATTRIBUTES();
- pSec.nLength = Marshal.SizeOf(pSec);
- tSec.nLength = Marshal.SizeOf(tSec);
-
- CreateProcess(null,
- $"\"{path}\" \"{playbookDir}\"",
- ref pSec,
- ref tSec,
- false,
- EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW,
- IntPtr.Zero,
- null,
- ref sInfoEx,
- out pInfo);
-
- //WaitForSingleObject(pInfo.hProcess, INFINITE);
- Process = Process.GetProcessById(pInfo.dwProcessId);
-
- return true;
- }
- finally
- {
- // Free the attribute list
- if (sInfoEx.lpAttributeList != IntPtr.Zero)
- {
- DeleteProcThreadAttributeList(sInfoEx.lpAttributeList);
- Marshal.FreeHGlobal(sInfoEx.lpAttributeList);
- }
- Marshal.FreeHGlobal(lpValue);
-
- // Close process and thread handles
- if (pInfo.hProcess != IntPtr.Zero)
- {
- CloseHandle(pInfo.hProcess);
- }
- if (pInfo.hThread != IntPtr.Zero)
- {
- CloseHandle(pInfo.hThread);
- }
- }
- }
- }
- }
|