我尽可能地减少代码以保持 代码sscce这段代码的作用:
CreateProcess
TerminateProcess
在我们得到的把手上杀了记事本CreateProcess
.TerminateProcess
是异步OpenProcess
给死去的pid您可以在调试中轻松检查(在OpenProcess之前),在任务管理器或processExplorer中找不到给定的Pid.但没有其他Windows API函数似乎接受这个Pid
#include "stdafx.h"
#include <windows.h>
#include "Psapi.h"
#include <TlHelp32.h>
#include <iostream>
#include <cassert>
typedef unsigned long PID;
typedef const std::string& P_PATH;
// Launch an executable given by a path and set a few infomatives stuffs passed as ref parameters
bool launch_process(P_PATH path, STARTUPINFO& info, PROCESS_INFORMATION& processInfo, HANDLE& hProcess, PID& pid)
{
setlocale(LC_ALL, "en_US.utf8");
std::wstring widestr = std::wstring(path.begin(), path.end());
const wchar_t* widecstr = widestr.c_str();
LPTSTR szCmdline = _tcsdup(widecstr);
if (CreateProcess(szCmdline, NULL, NULL, NULL, false, NULL, NULL, NULL, &info, &processInfo))
{
hProcess = processInfo.hProcess;
pid = processInfo.dwProcessId;
return true;
}
return false;
}
int main(int argc, char* argv[])
{
// Setup
// -----
bool OK = false;
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
HANDLE hProcess;
PID pid = 0;
// launch notepad
// --------------
OK = launch_process("C:\\WINDOWS\\System32\\notepad.exe", info, processInfo, hProcess, pid);
assert(OK);
// wait a bit
// ----------
system("PAUSE");
SetLastError(0);
// get Handle on notepad
// ---------------------
hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, false, static_cast<DWORD>(pid));
std::cout << "Error: " << GetLastError() << std::endl;
// Kill notepad
// ------------
UINT exitCode = 0;
DWORD dwWaitResult = 0;
SetLastError(0);
OK = TerminateProcess(hProcess, exitCode);
std::cout << "Error: " << GetLastError() << std::endl;
// ensure everything went well ( we need to wait because TerminateProcess is asynchronous )
if (!OK || (dwWaitResult != WaitForSingleObject(hProcess, INFINITE)))
return -1;
// Cleanup
CloseHandle(hProcess);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
hProcess = nullptr;
processInfo.hProcess = nullptr;
// Ya know what let's reopen the pid I just killed
// ( you can see that notepad was started then killed, you can check the pid does not exist in either the task manager or processExplorer )
SetLastError(0);
hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, false, static_cast<DWORD>(pid));
std::cout << "Error: " << GetLastError() << std::endl;
// Yeah I can speak to the deads!
if (hProcess != nullptr)
{
LPWSTR szProcessName = L"";
GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof szProcessName);
char c_szText[MAX_PATH];
wcstombs(c_szText, szProcessName, wcslen(szProcessName) + 1);
// But the deads have no names
std::cout << "Error: " << GetLastError() << std::endl;
std::cout << "Zombie Name: " << c_szText << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它没有出现在任务管理器的进程列表中,因为它已终止.任务管理器不显示僵尸(此行为不同于例如ps -Af f
显示僵尸的Linux ).
它仍然存在并且可以访问,OpenProcess
因为进程对象尚未被破坏,即它处于僵尸状态.这将是因为另一个进程有一个开放的句柄.例如,
德:
一旦关闭句柄,不要指望过程对象被销毁,因为你的句柄不是唯一的句柄.
僵尸状态对于进程来说是完全合法的状态.如果它们已经终止,所有进程将处于僵尸状态,并且有人正在等待阅读其退出代码GetExitCodeProcess
,或者对进程状态有任何其他兴趣.通常,一旦读取了退出代码,对流程的兴趣就会减弱,句柄会被关闭,最后流程将被销毁.
一旦过程被破坏,PID就可以重复使用.(相反,在关闭所有句柄之前,不能重复使用PID).在Windows中,内核更喜欢低编号的PID,并且会很快重用它们.此行为与Linux不同,后者更喜欢递增PID,并且在达到最大值之前不会重复使用它们.
如果您想要进程的句柄,请不要关闭它.