我真的希望能够通过共享管道进行文件重定向,并将继承的句柄列表过滤为仅那些 stdout/stderr/stdin 句柄,据我所知,STARTUPINFOEX 和扩展属性是这样做的方法。我还需要能够以其他用户身份启动。
- CreateProcess 在使用 STARTUPINFOEX 时为我工作,并且要么不传递任何属性,要么传递单个属性(要么更改父级,要么过滤继承的句柄)。
- CreateProcessWithLogonW 在使用 STARTUPINFOEX 时有效,但前提是我从创建标志中删除 EXTENDED_STARTUPINFO_PRESENT(基本上将 STARTUPINFOEX 视为 STARTUPINFO,即使 startupinfo.cb 是完整结构)。
- 如果我添加 EXTENDED_STARTUPINFO_PRESENT,我会得到有用的“参数不正确”,即使不使用任何属性(适用于 CreateProcess)
以下内容有效,直到您取消注释 // | NativeMethods.EXTENDED_STARTUPINFO_PRESENT,
public static void CreateProcessExtended(
string userName,
SecureString password)
{
var startupInfoEx = new NativeMethods.STARTUPINFOEX { StartupInfo = new NativeMethods.STARTUPINFO() };
startupInfoEx.StartupInfo.dwFlags = NativeMethods.STARTF_USESHOWWINDOW;
startupInfoEx.StartupInfo.wShowWindow = 0; // SW_HIDE
NativeMethods.PROCESS_INFORMATION processInfo;
startupInfoEx.StartupInfo.cb = Marshal.SizeOf(startupInfoEx);
IntPtr passwordPtr = Marshal.SecureStringToCoTaskMemUnicode(password);
bool retVal = NativeMethods.CreateProcessWithLogonW(
userName,
null,
passwordPtr,
NativeMethods.LogonFlags.LOGON_WITH_PROFILE,
null,
@"C:\windows\system32\notepad.exe",
(uint)NativeMethods.CREATE_NO_WINDOW | NativeMethods.CREATE_SUSPENDED,// | NativeMethods.EXTENDED_STARTUPINFO_PRESENT,
IntPtr.Zero,
null,
ref startupInfoEx,
out processInfo);
if (!retVal)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
[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;
}
[return: MarshalAs(UnmanagedType.Bool)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("Advapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
public static extern bool CreateProcessWithLogonW(
string userName,
string domain,
IntPtr password,
LogonFlags logonFlags,
string lpApplicationName,
string lpCommandLine,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
[In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
Edit.1 在过滤的句柄属性列表中发送,以防合同差异需要扩展属性不是 IntPtr.Zero。还是失败了。同样,在 CreateProcess 中工作,在 CreateProcessWithLogonW 中使用这些新信号失败:
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, uint dwFlags, uint Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);