创建一个不是创建进程子进程的新进程
Posted
技术标签:
【中文标题】创建一个不是创建进程子进程的新进程【英文标题】:Creating a new process that's not a child of the creating process 【发布时间】:2012-08-22 07:56:50 【问题描述】:我正在开发一个应用程序,其中进程 A 的多个实例依赖于进程 B 的单个实例。想法是进程 A 的一个实例启动进程 B,以便所有实例的A可以使用它。 A 的实例托管在第 3 方进程中,并且可以在不可预测的时间点被拆除(通过杀死进程树)。因此,进程 B 不是进程 A 的任何实例的子进程至关重要。
我曾尝试使用 PInvoke 调用 CreateProcess,在创建标志中指定 DetachedProcess (0x08),但这不起作用(请参阅下面的代码)。
[DllImport("kernel32.dll")]
private static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation);
public Process LaunchProcess(Path executablePath, string args)
StartupInfo sInfo = new StartupInfo();
const uint creationFlags = (uint)(CreationFlags.CreateNoWindow | CreationFlags.DetachedProcess);
ProcessInformation pInfo;
bool success = CreateProcess(executablePath.ToString(), args, IntPtr.Zero, IntPtr.Zero, false, creationFlags, IntPtr.Zero, executablePath.GetFolderPath().ToString(), ref sInfo, out pInfo);
if (!success)
throw new Win32Exception();
return Process.GetProcessById(pInfo.dwProcessId);
我还阅读了How to create a process that is not a child of it's creating process? 上的文章,该文章建议使用临时进程来启动新进程,但我不喜欢这种方法,因为它会使同步变得复杂,以确保只有进程 B 的单个实例已启动。
有谁知道实现这一目标的更好方法?
【问题讨论】:
【参考方案1】:您可以尝试使用ManagementClass
来启动一个进程并传递一些CreateFlags
,更具体地说,是DETACHED_PROCESS
标志。 (您需要引用System.Management
。)
private static void Main()
using (var managementClass = new ManagementClass("Win32_Process"))
var processInfo = new ManagementClass("Win32_ProcessStartup");
processInfo.Properties["CreateFlags"].Value = 0x00000008;
var inParameters = managementClass.GetMethodParameters("Create");
inParameters["CommandLine"] = "notepad.exe";
inParameters["ProcessStartupInformation"] = processInfo;
var result = managementClass.InvokeMethod("Create", inParameters, null);
if ((result != null) && ((uint)result.Properties["ReturnValue"].Value != 0))
Console.WriteLine("Process ID: 0", result.Properties["ProcessId"].Value);
Console.ReadKey();
至少在我的机器记事本上不被视为我的控制台测试应用程序的子进程。
【讨论】:
您好 Jensen,感谢您的回答。我曾考虑使用 WMI,但希望有人知道使用 CreateProcess 或类似方法的更简单方法。按照您的建议使用 ManagementClass 实际上会将新进程的创建推迟到 WMI。结果是新进程是 wmiprvse.exe 的子进程,而不是创建进程。 DETACHED_PROCESS 标志对此结果没有影响。它的使用,与 PInvoke / CreateProcess 中的等效标志一样,实际上会导致新进程在没有控制台的情况下被初始化;它不控制新进程的父状态。 我想补充一点,您的建议无疑会解决我的问题,因为通过破坏进程 A 和进程 B 的实例之间的父子关系,杀死进程 A 的实例的进程树不会杀死进程 B。 这正是我所需要的!帮我省了很多麻烦。 这个解决方案解决了父子关系问题,允许用户从任务管理器中结束进程树以结束所有子进程。这样,就没有办法从父进程结束子进程,反之亦然(显然)【参考方案2】:您可以使用进程属性指定不同的父级。这是一个可以做到这一点的函数。虽然它是用 C++ 编写的,但它展示了它的工作原理。
bool CreateProcessWithParent(DWORD parentId, PWSTR commandline)
auto hProcess = ::OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parentId);
if (!hProcess)
return false;
SIZE_T size;
//
// call InitializeProcThreadAttributeList twice
// first, get required size
//
::InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
//
// now allocate a buffer with the required size and call again
//
auto buffer = std::make_unique<BYTE[]>(size);
auto attributes = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(buffer.get());
::InitializeProcThreadAttributeList(attributes, 1, 0, &size);
//
// add the parent attribute
//
::UpdateProcThreadAttribute(attributes, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&hProcess, sizeof(hProcess), nullptr, nullptr);
STARTUPINFOEX si = sizeof(si) ;
//
// set the attribute list
//
si.lpAttributeList = attributes;
PROCESS_INFORMATION pi;
//
// create the process
//
BOOL created = ::CreateProcess(nullptr, commandline, nullptr, nullptr,
FALSE, EXTENDED_STARTUPINFO_PRESENT, nullptr, nullptr,
(STARTUPINFO*)&si, &pi);
//
// cleanup
//
::CloseHandle(hProcess);
::DeleteProcThreadAttributeList(attributes);
return created;
源码取自https://scorpiosoftware.net/2021/01/10/parent-process-vs-creator-process/
【讨论】:
以上是关于创建一个不是创建进程子进程的新进程的主要内容,如果未能解决你的问题,请参考以下文章
MPI C 将矩阵逐行发送到所有进程子进程 (MPI_COMM_SPAWN)