我通过平台调用创建和控制进程,因为C#仍然不允许创建挂起进程等等。以这种方式创建流程,如果需要,我可以创建Process .Net类的实例。但我需要重定向子进程的输出。使用Diagnostics命名空间实现创建过程很容易,但如果已创建过程,则无法执行。它也可以用纯C ++做。但是要创建管道,重定向子进程输出以及使用p / invoke进行异步I / O似乎很疯狂。这个问题是否存在更简单的解决方案?
答案 0 :(得分:0)
1天后...... 现在,我的项目中有下一个气味类,用于使用输出重定向生成进程。我已经决定将重定向仅用于文件以便开始。
public class Program
{
public static void Main(string[] args)
{
using (var mp = ProcessManipulator.Start("test1.exe", null,
ProcessCreationFlags.CREATE_BREAKAWAY_FROM_JOB |
ProcessCreationFlags.CREATE_SUSPENDED, null, "5.txt"))
{
mp.Resume();
}
}
}
[Flags]
public enum ProcessCreationFlags : uint
{
ZERO_FLAG = 0x00000000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_NO_WINDOW = 0x08000000,
CREATE_PROTECTED_PROCESS = 0x00040000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_SEPARATE_WOW_VDM = 0x00001000,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_SUSPENDED = 0x00000004,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
DEBUG_PROCESS = 0x00000001,
DETACHED_PROCESS = 0x00000008,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
INHERIT_PARENT_AFFINITY = 0x00010000
}
public class ProcessManipulator : IDisposable
{
private IntPtr _primaryThread;
private bool _disposed = false;
private ProcessManipulator(IntPtr primaryThread)
{
_primaryThread = primaryThread;
}
public Process ManipulatedProcess { get; private set; }
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public Int32 bInheritHandle;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private 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;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
/// <summary>
/// Decrements a thread's suspend count. When the suspend count is decremented to zero, the execution of the thread is resumed.
/// </summary>
/// <param name="hThread">A handle to the thread to be restarted.</param>
/// <returns>If the function succeeds, the return value is the thread's previous suspend count. If the function fails, the return value is -1.</returns>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int ResumeThread(IntPtr hThread);
public void Resume()
{
if (ResumeThread(_primaryThread) == -1)
throw new Exception(string.Format("Unable to resume the thread. Error: {0}", Marshal.GetLastWin32Error()));
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
private const int GENERIC_WRITE = 0x40000000;
private const int FILE_SHARE_READ = 0x00000001;
private const int FILE_SHARE_WRITE = 2;
private const int CREATE_NEW = 1;
private const int FILE_ATTRIBUTE_NORMAL = 128;
private static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private static IntPtr PrepareLogFile(string fileName)
{
var length = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
var securityAttributes = new SECURITY_ATTRIBUTES()
{
nLength = (uint)length,
lpSecurityDescriptor = IntPtr.Zero,
bInheritHandle = 1
};
var securityAttributesPtr = Marshal.AllocHGlobal(length);
try
{
Marshal.StructureToPtr(securityAttributes, securityAttributesPtr, false);
var hLogFile = CreateFile(fileName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
securityAttributesPtr,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if (hLogFile == INVALID_HANDLE_VALUE)
throw new Exception(string.Format("Unable to create a log file. Error: {0}", Marshal.GetLastWin32Error()));
return hLogFile;
}
finally
{
Marshal.FreeHGlobal(securityAttributesPtr);
}
}
[Flags]
private enum STARTF : uint
{
STARTF_USESHOWWINDOW = 0x00000001,
STARTF_USESIZE = 0x00000002,
STARTF_USEPOSITION = 0x00000004,
STARTF_USECOUNTCHARS = 0x00000008,
STARTF_USEFILLATTRIBUTE = 0x00000010,
STARTF_RUNFULLSCREEN = 0x00000020, // ignored for non-x86 platforms
STARTF_FORCEONFEEDBACK = 0x00000040,
STARTF_FORCEOFFFEEDBACK = 0x00000080,
STARTF_USESTDHANDLES = 0x00000100,
}
/// <summary>
/// Allows to create child process specifing creation flags.
/// </summary>
/// <param name="fileName">Path to the executable module</param>
/// <param name="args">Arguments</param>
/// <param name="creationFlags">Process creation flags</param>
/// <param name="currentDirectory">Current directory</param>
/// <param name="logFileName">File for output redirection</param>
public static ProcessManipulator Start(string fileName, string args, ProcessCreationFlags creationFlags,
string currentDirectory, string logFileName)
{
var hLogFile = PrepareLogFile(logFileName);
try
{
return Start(fileName, args, creationFlags, currentDirectory, hLogFile);
}
finally
{
CloseHandle(hLogFile);
}
}
private static ProcessManipulator Start(string fileName, string args, ProcessCreationFlags creationFlags, string currentDirectory, IntPtr hOutRedirection)
{
var startupInfo = new STARTUPINFO
{
cb = Marshal.SizeOf(typeof(STARTUPINFO)),
hStdError = hOutRedirection,
hStdOutput = hOutRedirection,
dwFlags = hOutRedirection != IntPtr.Zero ? (int)STARTF.STARTF_USESTDHANDLES : 0
};
var processInfo = new PROCESS_INFORMATION();
if (!CreateProcess(fileName,
String.Format("{0} {1}", Path.GetFileName(fileName), args),
IntPtr.Zero,
IntPtr.Zero,
hOutRedirection != IntPtr.Zero,
(uint)creationFlags,
IntPtr.Zero,
currentDirectory,
ref startupInfo,
out processInfo))
throw new Exception(string.Format("Unable to create a process. Error: {0}", Marshal.GetLastWin32Error()));
//GetProcessById() open new handle for the process so current must be closed as useless
if (!CloseHandle(processInfo.hProcess))
throw new Exception(string.Format("Unable to close the process handle. Error: {0}", Marshal.GetLastWin32Error()));
return new ProcessManipulator(processInfo.hThread)
{
ManipulatedProcess = Process.GetProcessById(processInfo.dwProcessId)
};
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
//dispose managed disposable resources
ManipulatedProcess.Dispose();
}
var result = CloseHandle(_primaryThread);
_primaryThread = IntPtr.Zero;
//if (!result)
// throw new Exception(string.Format("Unable to close the job object handle. Error: {0}", Marshal.GetLastWin32Error()));
_disposed = true;
}
~ProcessManipulator()
{
Dispose(false);
}
}
测试代码&#34;孩子&#34;应用程式:
public static void Main(string[] args)
{
Console.WriteLine("Test");
}
创建文件并包含字符串&#34;测试&#34;。