使用 CREATE_SUSPENDED 标志和 JobObject 从 CreateProcessAsUser 为 C# 进程设置 ProcessStartInfo
Posted
技术标签:
【中文标题】使用 CREATE_SUSPENDED 标志和 JobObject 从 CreateProcessAsUser 为 C# 进程设置 ProcessStartInfo【英文标题】:Setting up ProcessStartInfo for C# process from CreateProcessAsUser with CREATE_SUSPENDED flag and JobObject 【发布时间】:2021-10-26 01:41:29 【问题描述】:在我的 C# 程序中,我需要 (1) 创建一个处于挂起状态的进程并 (2) 修改令牌。我这样做是为了可以将其注册到 JobObject 以便如果父进程在子进程仍在运行时意外死亡,则子进程会被杀死。我需要根据业务需求修改令牌。
我发现不可能将未启动的 C# Process 添加到 JobObject,或在暂停状态,或修改其令牌。所以,我使用 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
我遇到问题的地方实际上是开始这个过程。
从调用者(参见下面的 sn-p)中,我尝试从使用 CreateProcessAsUser 创建的进程的 ID 中获取进程。 CreateProcessAsUser 创建的进程没有包含文件名的 StartInfo。我希望 appPath 的功能与 StartInfo.FileName 相同,但这里有一些我不明白的地方,因为 process.StartInfo 似乎是虚拟信息,per the documentation I read here 表示 GetProcesses 等,不会返回 StartInfo 并且 StartInfo 无法修改一旦一个过程开始。我想创建一个处于挂起状态的进程算作启动。
我是一名新手开发人员,在试图解决这个问题之前从未使用过 C++,但我能够学到的是,也许我不应该尝试做 Process.Start - 但我没有找到满足将流程注册到 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
【问题讨论】:
以下内容可能会有所帮助:***.com/questions/3342941/… 【参考方案1】:是的,答案是避免使用 C# Process 类方法,而是手动打开和恢复进程中的所有线程。
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
【讨论】:
以上是关于使用 CREATE_SUSPENDED 标志和 JobObject 从 CreateProcessAsUser 为 C# 进程设置 ProcessStartInfo的主要内容,如果未能解决你的问题,请参考以下文章
Java类的标志出现了一个大j,好像action找不到这个类?