1

通过流程,我可以执行以下操作:

int pid;
::CreateProcess(NULL, cmd, ..., &pi);
pid = pi.dwProcessId;
::CloseHandle(pi.hProcess);
// then later...
HANDLE proc = ::OpenProcess(PROCESS_TERMINATE, FALSE, pid);
::TerminateProcess(proc, 1);
::CloseHandle(proc);

以这种方式,我可以只通过 pid 来管理 windows 进程,这对于多平台代码来说很好。

我想将此模式扩展到工作对象:

HANDLE job = ::CreateJobObject(NULL, name);
::AssignProcessToJobObject(job, proc); // proc from above
::CloseHandle(job);
// then later...
job = ::OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, name);
::TerminateJobObject(job, 1);

需要明确的是,我不在工作中,但我的子进程在。MSDN 说“当它的最后一个句柄已关闭并且所有相关进程都已退出时,该作业将被销毁”。在这种情况下,我的主进程已经关闭了他的最后一个句柄,但是子进程仍在运行,并且仍然有一个句柄。IsProcessInJob(proc, NULL, &isit)确认工作仍然存在的电话。但是,我打开作业的调用返回 NULL,错误代码是 ERROR_FILE_NOT_FOUND。

所以问题是:我的主进程在关闭它后有什么办法来处理这个工作吗?

4

2 回答 2

2

这就是 NT 对象管理器的工作方式。几乎所有对象都是“临时的”,这意味着当不再存在对它们的引用(内核模式指针引用或句柄)时,它们将被删除。您应该能够通过调用NtMakePermanentObject您的作业对象来更改此行为。不过,我以前从未尝试过。

于 2012-12-19T10:25:57.870 回答
2

是的,有可能。但是,请注意:

// This example will fail to reopen and terminate the job.
// Processes cmd and ping stay running
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(PROCESS_INFORMATION));

// BEGIN BLOCK A
::CreateProcess(NULL, "cmd /c ping 127.0.0.1 -n 10 > nul",
    NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, ".", &si, &pi);
HANDLE job = ::CeateJobObject(NULL, "myjob");
::AssignProcessToJobObject(job, pi.hProcess);
// END BLOCK A

::ResumeThread(pi.hThread);
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
::CloseHandle(job);
HANDLE reopenJob = ::OpenJobObject(JOB_OBJECT_TERMINATE, FALSE, "myjob");
if(reopenJob != NULL)
    ::TerminateJobObject(reopenJob, 1);

本例中重新打开的作业为 NULL,错误代码为 ERROR_FILE_NOT_FOUND。

作业必须在进程之前创建并被继承,才能重新打开作业。

// NEW BLOCK A
HANDLE job = ::CreateJobObject(NULL, "myjob");
::SetHandleInformation(job, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
::CreateProcess(NULL, "cmd /c ping 127.0.0.1 -n 10 > nul",
    NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, ".", &si, &pi);
::AssignProcessToJobObject(job, pi.hProcess);

如果您的目标是使用 PID 命名作业,请注意此创建顺序会阻止此类约定。这仍然意味着除了 PID 之外,还必须跟踪某些信息才能重新打开作业。

于 2012-12-21T22:43:03.730 回答