设置ProcessStartInfo为c#进程从CreateProcessAsUser与CREATE_SUSPENDED



在我的c#程序中,我需要(1)创建一个处于挂起状态的进程,(2)修改令牌。我这样做是为了将它注册到JobObject因此,如果父进程在子进程仍在运行时意外死亡,则子进程将被杀死。我需要根据业务需求修改令牌。

我发现不可能添加一个未启动的c#进程to aJobObject,或者创建一个进程处于挂起状态,或修改其令牌。所以,我使用c++CreateProcessAsUser完成这些事情。到目前为止,一切顺利:

[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
String lpApplicationName,
String lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
public static uint CreateSuspendedProcess(string appPath, string cmdLine = null, bool visible = false)
result = CreateProcessAsUser(
hUserToken, // Modified token - working great
appPath, // Application Name - doesn't end up in Process.ProcessStartInfo?
cmdLine, // is null
IntPtr.Zero,
IntPtr.Zero,
false,
dwCreationFlags, // contains CREATE_SUSPENDED
pEnv,
null, // working directory
ref startInfo, // not related to C# ProcessStartInfo?
out procInfo);
// does other stuff, and then returns the Process ID

我遇到问题的地方实际上是启动进程。

从调用者(参见下面的代码片段),我尝试从我用CreateProcessAsUser创建的进程的ID中获取进程。由CreateProcessAsUser创建的进程没有包含文件名的StartInfo。我期望appPath的功能与StartInfo相同。文件名,但有一些我不明白这里,因为过程。StartInfo似乎是虚拟信息,根据我在这里读到的文档,GetProcesses等不会返回StartInfo,一旦进程启动,StartInfo就不能修改。我认为创建一个处于挂起状态的进程算作启动。

我是一名新手开发人员,在尝试蒙混过关之前从未使用过c++,但我能够学到的是,也许我不应该尝试使用Process。启动-但我还没有找到任何替代方案来满足将进程注册到JobObject的需要.

var processId = CreateSuspendedProcess(startInfo.FileName, startInfo.Arguments);
IntPtr hProcess = IntPtr.Zero;
using (var job = new Job())
using (var process = Process.GetProcessById((int)processId)) // use the suspended process
{
var jobSuccess = job.AddProcess(process.Id); // this works
if (!jobSuccess)
{
// do not proceed if process cannot be run in job object; dispose of both
throw new Exception("Failed to add process to job object.");
}
// === I want the start info to have the filename, but can't except in Debug
//process.StartInfo.FileName = startInfo.FileName;
// other code here
Process.Start(); // Get a no FileName error

是的,答案是避免使用c# Process类方法,而是手动打开并恢复进程中的所有线程。

[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);

相关内容