简体   繁体   English

Windows 10上不成功的TerminateProcess

[英]TerminateProcess not suceeding on Windows 10

Our C++ app launches a separate .exe ( which may start its own sub-processes) using CreateProcess as below. 我们的C ++应用程序使用CreateProcess如下启动一个单独的.exe(它可以启动自己的子进程)。

BOOL started = ::CreateProcess(NULL,      // application
                p,         // parameters
                NULL,        // process security
                NULL,        // thread security
                TRUE,        // inherit handles flag
                0,           // flags
                NULL,        // inherit environment
                dirLP,      // inherit directory
                &startup,    // STARTUPINFO
                &procinfo);  // PROCESS_INFORMATIO

In case we need cancel the "job" we use CreateToolhelp32Snapshot to iterate through the process list to find any child processes of the one we launched. 如果需要取消“作业”,我们使用CreateToolhelp32Snapshot遍历进程列表以查找我们启动的进程的任何子进程。

static BOOL TerminateProcessTree (HANDLE parentProcess,UINT exitCode) 
{ 
    BOOL            result=TRUE;
    HANDLE         hProcessSnap = NULL; 
    PROCESSENTRY32 pe32      = {0}; 
    //  Take a snapshot of all processes in the system. 

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

    if (hProcessSnap == INVALID_HANDLE_VALUE) 
        return (FALSE); 
     pe32.dwSize = sizeof(PROCESSENTRY32); 

    //  Walk the snapshot of the processes
    DWORD parentID=GetProcessId(parentProcess);
    if(parentID==0){
        PrintLastError("GetProcessId");
        return FALSE;
    }
   if (Process32First(hProcessSnap, &pe32)) { 
        do{ 
            if(pe32.th32ParentProcessID==parentID){

               HANDLE hProcess = OpenProcess (PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); 
               if(hProcess!=NULL){
                    BOOL terminateChildren=TerminateProcessTree(hProcess,exitCode);
                    BOOL terminatedChild = TerminateProcess(hProcess, exitCode);
                    if (!terminatedChild){
                        PrintLastError("TerminateProcess");
                    }
                    CloseHandle(hProcess);
                    if(!terminatedChild || !terminateChildren){
                        result=FALSE;
                        break;
                    }
               } else{
                   PrintLastError("OpenProcess");
               }
            }

        }while (Process32Next(hProcessSnap, &pe32)); 
    }
    CloseHandle (hProcessSnap); 
    DWORD checkCode=0;
    BOOL terminated;
    if(GetExitCodeProcess(parentProcess,&checkCode) && checkCode==STILL_ACTIVE){
        terminated=TerminateProcess(parentProcess,exitCode);
        if (!terminated){
            PrintLastError("TerminateProcess");
            result= FALSE;
        }
    }
    return result;
}

As noted, this works fine on Windows 7. Windows 10 fails with "Access Denied" on the first call "TerminateProcess". 如前所述,这在Windows 7上可以正常工作。Windows 10失败,第一个调用“ TerminateProcess”出现“访问被拒绝”。 Clearly something has changed in the Windows security model when it comes to processes. 显然,Windows安全模型在流程方面已发生了变化。

The robust way to deal with controlling a process tree of objects is to use Job objects as noted in the comment threads. 处理对象的进程树的有效方法是使用注释线程中指出的Job对象。

The one thing to keep in mind is that a process can only belong to a single job, and by default any EXE that the OS determines needs appcompat help is put into a job object automatically managed by the "Program Compatibility Assistant". 要记住的一件事是,一个进程只能属于一个作业,默认情况下,操作系统确定需要应用程序帮助的任何EXE都会放入由“程序兼容性助手”自动管理的作业对象中。 This makes using a Job object to manage arbitrary 3rd party EXEs a little bit more complicated (ie AssignProcessToJobObject fails for these processes). 这使得使用Job对象来管理任意第三方EXE更加复杂(即, AssignProcessToJobObject对于这些进程失败)。

If you are using CreateProcess you can make use of the flag CREATE_BREAKAWAY_FROM_JOB . 如果使用的是CreateProcess ,则可以使用标志CREATE_BREAKAWAY_FROM_JOB See this blog post . 请参阅此博客文章 This works fine as long as the target EXE has the same rights as the calling object. 只要目标EXE具有与调用对象相同的权限,此方法就可以正常工作。

For a Standard User EXE to run an EXE that might need Administrator rights (ie they contain a manifest which marks it as requireAdministrator ), you have to use ShellExecute or ShellExecuteEx as calling CreateProcess in this case will fail. 为了使标准用户EXE运行可能需要管理员权限的EXE(即它们包含将其标记为requireAdministrator的清单),您必须使用ShellExecuteShellExecuteEx因为在这种情况下调用CreateProcess将失败。 If your target EXEs are all using the proper manifest elements then it won't be put into a PCA Job object.. You can use the trick of passing SEE_MASK_FLAG_NO_UI which will have the side-effect of avoiding the PCA job behavior. 如果目标EXE都使用了正确的清单元素,则不会将其放入PCA作业对象中。您可以使用传递SEE_MASK_FLAG_NO_UI的技巧,从而避免PCA作业行为。 If you are launching arbitrary 3rd party EXEs, you should use ShellExecuteEx and not CreateProcess . 如果要启动任意的第三方EXE,则应使用ShellExecuteEx而不是CreateProcess

bool SpawnProcess( const WCHAR* szExePath, const WCHAR* szExeArgs )
{
    if( !szExePath )
        return false;

    // NOTE: szExeArgs can be nullptr.

    // Get working directory from executable path.    
    WCHAR szDirectory[MAX_PATH] = {0};
    wcscpy_s( szDirectory, szExePath );
    PathRemoveFileSpec( szDirectory );

    // ShellExecute or ShellExecuteEx must be used instead of CreateProcess
    // to permit the shell to display a UAC prompt asking for consent to
    // elevate when the target executable's manifest specifies a run level
    // of "requireAdministrator".
    //
    // You can only use CreateProcess if you know that the application you
    // are spawning will be at the same run level as the current process.
    // Otherwise, you will receive ERROR_ACCESS_DENIED if the elevation
    // consent could not be obtained.
    SHELLEXECUTEINFO info = {};
    info.cbSize = sizeof( info );
    info.lpVerb = L"open";
    info.fMask = SEE_MASK_FLAG_NO_UI;
    info.lpFile = szExePath;
    info.lpParameters = szExeArgs;
    info.lpDirectory = szDirectory;
    info.nShow = SW_SHOW;
    if( !ShellExecuteEx( &info ) )
        return false;

    return true;
}

Note that if you want to wait until this process exits, you can use: 请注意,如果要等到该过程退出,可以使用:

bool SpawnProcessAndWait( const WCHAR *szExePath, const WCHAR *szExeArgs, DWORD *pdwExitCode )
{
    if( !szExePath )
        return false;

    // NOTE: szExeArgs and pExitCode can be nullptr.

    // Get working directory from executable path.    
    WCHAR szDirectory[MAX_PATH] = {0};
    wcscpy_s( szDirectory, szExePath );
    PathRemoveFileSpec( szDirectory );

    // See SpawnProcess for information why ShellExecute or ShellExecuteEx
    // must be used instead of CreateProcess.
    SHELLEXECUTEINFO info = {};
    info.cbSize = sizeof( info );
    info.lpVerb = L"open";
    info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
    info.lpFile = szExePath;
    info.lpParameters = szExeArgs;
    info.lpDirectory = szDirectory;
    info.nShow = SW_SHOW;
    if( !ShellExecuteEx( &info ) )
        return false;

    // Wait for process to finish.
    WaitForSingleObject( info.hProcess, INFINITE );

    // Return exit code from process, if requested by caller.
    if( pdwExitCode )
        GetExitCodeProcess( info.hProcess, pdwExitCode );

    CloseHandle( info.hProcess );
    return true;
}

You haven't noted if your "master" application here is using administrator or Standard User rights. 您尚未注意到此处的“主”应用程序是否正在使用管理员或标准用户权限。 Ideally it is using Standard User rights per the User Account Control guidelines dating back to Windows Vista. 理想情况下,它使用可追溯到Windows Vista的“ 用户帐户控制”准则的“标准用户”权限。 If your app is running as Standard User, then it's likely that your code no longer works due to security improvements to keep non-Administrator malware from doing this kind of thing to other processes. 如果您的应用程序以“标准用户”身份运行,则由于安全性得到了改进,以防止非管理员恶意软件对其他进程执行此类操作,因此您的代码可能不再起作用。

For general appcompat questions about Windows 10, be sure to read the Windows and Windows Server compatibility cookbook and look back at the Windows 8.0 and Windows 8.1 material if you are jumping directly from Windows 7 to Windows 10. 对于与Windows 10有关的一般appcompat问题,如果直接从Windows 7跳至Windows 10,请务必阅读Windows和Windows Server兼容性手册并回顾Windows 8.0和Windows 8.1资料。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM