有人可以告诉我如何强制终止调用(父)进程时杀死子进程吗?顺便说一句,我无法更改子应用程序的源代码。
我已经检查了StackOverflow中的现有线程,看起来JobObject是正确的方法。但是当我测试它时(使用控制台应用程序来调用notepad.exe),我发现当控制台应用程序退出时,记事本没有。
我使用CreateProcess
来生成新进程。
我也看到有人说在父进程和子进程之间建立管道就可以了,但我还没有尝试过。
如果有人能给我一些提示,我会非常感激。
更新:如果AssignProcessToJobObject
中没有| CREATE_BREAKAWAY_FROM_JOB
,则WINAPI CreatProcess
无效。现在它有效!
谢谢大家。
再次更新:
这真的很棘手。我总是对Windows API感到困惑。
第1组:
处理标记:CREATE_SUSPENDED
JobObject标志:JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_SECURITY_RESTRICTED_TOKEN or JOB_OBJECT_SECURITY_NO_ADMIN or JOB_OBJECT_LIMIT_BREAKAWAY_OK
结果:AssingProcessToJobObject
失败,错误代码为5拒绝访问
第2组:
处理标记:CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB
JobObject标志:JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_SECURITY_RESTRICTED_TOKEN or JOB_OBJECT_SECURITY_NO_ADMIN
结果:AssingProcessToJobObject
成功,但是当父项被杀死时,子进程无法被杀死。
第3组:
处理标记:CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB
JobObject标志:JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
结果:AssingProcessToJobObject
成功,子进程在父进程被杀死时自动终止。
第4组:
处理标记:CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB
JobObject标志:JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_BREAKAWAY_OK
结果:与第3组相同。
以下代码使用我从http://cboard.cprogramming.com/windows-programming/60561-program-termination.html#post430075
复制的JobObeject#define _WIN32_WINNT 0x0500
#include <windows.h>
int main(void)
{
HANDLE hJob;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
/*
* Create a job object.
*/
hJob = CreateJobObject(NULL, NULL);
/*
* Causes all processes associated with the job to terminate when the
* last handle to the job is closed.
*/
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
/*
* Create the process suspended.
*/
si.cb = sizeof(si);
CreateProcess(TEXT("C:\\Windows\\System32\\Notepad.exe"), NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB /*Important*/, NULL, NULL, &si, &pi);
/*
* Add the process to our job object.
*/
AssignProcessToJobObject(hJob, pi.hProcess); // Does not work if without CREATE_BREAKAWAY_FROM_JOB
/*
* Start our suspended process.
*/
ResumeThread(pi.hThread);
/*
* At this point, if we are closed, windows will automatically clean up
* by closing any handles we have open. When the handle to the job object
* is closed, any processes belonging to the job will be terminated.
* Note: Grandchild processes automatically become part of the job and
* will also be terminated. This behaviour can be avoided by using the
* JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK limit flag.
*/
/*
* Do what you like here. For demonstration purposes we will just wait
* for the child process to complete. Click our close button to see
* everything in action.
*/
WaitForSingleObject(pi.hProcess, 3000);
/*
* Cleanup. As mentioned, Windows does this automagically when our process
* exits, but it is good style to do it explicitly.
*/
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hJob);
return 0;
}
答案 0 :(得分:8)
不要在Visual Studio中通过F5或Ctrl + F5进行测试。当Visual Studio启动您的程序时,它本身使用Job来管理事物,并且与您的代码交互不良。
打开控制台并“手动”启动exe。你的代码是正确的(“在这里工作”,VS2010在七上)
编辑:您可以添加错误检查,不要假设所有API始终成功。
编辑:您可以使用IsProcessInJob API来了解您的流程在启动时是否已经在工作中。如果是这种情况,默认情况下,子进程是在该先前存在的作业中创建的,然后您必须使用CREATE_BREAKAWAY_FROM_JOB
(如果不这样做,则不能使用AssignProcessToJobObject
)
从Visual Studio启动流程或在资源管理器中双击时,该流程将在作业中启动。
添加,我的代码基于你的代码,可以在VS或Explorer中使用。
#include <Windows.h>
#include <stdio.h>
int main( void ) {
BOOL bIsProcessInJob;
BOOL bSuccess = IsProcessInJob( GetCurrentProcess(), NULL, &bIsProcessInJob );
if ( bSuccess == 0 ) {
printf( "IsProcessInJob failed: error %d\n", GetLastError() );
return 0;
}
if ( bIsProcessInJob ) {
MessageBox( NULL, L"Process is already in Job", L"Job Test", 0 );
}
HANDLE hJob = CreateJobObject( NULL, NULL );
if ( hJob == NULL ) {
printf( "CreateJobObject failed: error %d\n", GetLastError() );
return 0;
}
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
bSuccess = SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, &jeli, sizeof( jeli ) );
if ( bSuccess == 0 ) {
printf( "SetInformationJobObject failed: error %d\n", GetLastError() );
return 0;
}
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
si.cb = sizeof( si );
DWORD dwCreationFlags = bIsProcessInJob ? CREATE_BREAKAWAY_FROM_JOB : 0;
bSuccess = CreateProcess( L"C:\\Windows\\System32\\Notepad.exe", NULL, NULL, NULL, FALSE,
dwCreationFlags, NULL, NULL, &si, &pi);
if ( bSuccess == 0 ) {
printf( "CreateProcess failed: error %d\n", GetLastError() );
return 0;
}
bSuccess = AssignProcessToJobObject( hJob, pi.hProcess );
if ( bSuccess == 0 ) {
printf( "AssignProcessToJobObject failed: error %d\n", GetLastError() );
return 0;
}
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
printf( "Type a key to exit..." );
getchar();
CloseHandle( hJob );
return 0;
}
答案 1 :(得分:1)
总结我的评论:
生成孩子的过程必须创建作业,并且是唯一具有打开句柄的作业。然后,所有被淹没的子进程都是工作的一部分。
hJob = CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {
0, 0, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, 0
};
SetInformationJobObject(hJob, &jeli);
if (AssignProcessToJobObject(hJob, GetCurrentProcess()) == FALSE) {
DWORD Error = GetLastError();
}
如果上述分配失败,请尝试使用JOB_OBJECT_SECURITY_NO_ADMIN
或JOB_OBJECT_SECURITY_RESTRICTED_TOKEN
等安全标记。
关于AssignProcessToJobObject
的MSDN:
如果进程已在运行且作业具有安全性 限制,AssignProcessToJobObject可能会失败。例如,如果 进程的主令牌包含本地管理员组, 但是作业对象具有安全限制 JOB_OBJECT_SECURITY_NO_ADMIN,函数失败。如果工作有 安全限制JOB_OBJECT_SECURITY_ONLY_TOKEN,进程必须 被创建暂停。要创建暂停的进程,请调用 带有CREATE_SUSPENDED标志的CreateProcess函数。
流程只能与单个作业相关联。进程继承 与其相关的工作限制并添加其会计 工作的信息。如果进程与作业相关联,则全部 默认情况下,它创建的进程与该作业关联。至 创建一个不属于同一工作的流程,调用 带有CREATE_BREAKAWAY_FROM_JOB标志的CreateProcess函数。
因此,在这种情况下,子进程自动成为作业的一部分。但是,为了创建作业,可能需要以更高的权限启动控制台应用程序。调用AssignProcessToJobObject(hJob, GetCurrentProcess())
后返回的错误代码是什么?
关于CREATE_BREAKAWAY_FROM_JOB
的MSDN:
与作业关联的进程的子进程不是 与工作相关联。
如果调用进程未与作业关联,则此常量具有 没有效果。如果调用进程与作业相关联,则该作业 必须设置JOB_OBJECT_LIMIT_BREAKAWAY_OK限制。
标志CREATE_BREAKAWAY_FROM_JOB
应该防止子进程成为作业的一部分。但这仅适用于为作业设置JOB_OBJECT_LIMIT_BREAKAWAY_OK
的情况。
答案 2 :(得分:0)
只是想一想,如果故意只是在杀死父进程时杀死子进程:
如果在父进程的OnClose(或任何需要)期间保留子进程句柄并终止它们,该怎么办?像这样:
// Creating
UINT u = 0;
HANDLE* pH = new HANDLE[2];
for (int i =0 ; i< 2; i++)
{
STARTUPINFO si ;
ZeroMemory(&si, sizeof(si));
si.wShowWindow = SW_SHOW;
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(TEXT("C:\\Windows\\System32\\Notepad.exe"), NULL, NULL, NULL, FALSE,
NULL, NULL, NULL, &si, &pi))
OutputDebugString(_T("Failed"));
else
OutputDebugString(_T("Success"));
pH[i] = pi.hProcess;
}
// Killing children
i = 0;
while (i<2)
{
::TerminateProcess(pH[i], u);
i++;
}
在枚举窗口句柄之后,也可以发送消息,而不是终止进程。如果我遗失了任何东西,请告诉我。
答案 3 :(得分:0)
我的情况有点类似。我的主应用程序创建一个用于记录“事件”的子进程。子进程保留其父进程的记录(它可以有很多)。在子进程中使用计时器,我能够检查父进程是否已崩溃,或者是否已关闭。检测到此情况后,子进程将完全关闭。