检查特定进程是否正在运行的快速方法

Fast way to check for a specific process running

本文关键字:运行 方法 进程 是否 检查      更新时间:2023-10-16

要检查进程是否正在运行,可以使用"CreateToolHelp32SnapShot"Windows API函数并枚举正在运行的进程。示例C/C++代码在回答问题中给出:检查是否有一个特定进程在带有C++的窗口上运行

我的问题是,如果你知道你在寻找一个特定的流程,是否有一种更快的方法可以找到答案,而不必依次检查每个流程?我们需要定期检查我们的远程支持工具TeamViewer.exe是否正在运行。请注意,TeamViewer是由第三方编写的,我们无法控制它,也不知道EXE的内部结构。

编辑:

TeamViewer提供了一些关于其流程内部的信息,这些信息可用于在本例中加快速度(请参阅公认的答案)。答案还显示了如何加快对任何进程的检查(通过保存进程ID)。

您必须采取的第一步是枚举进程。使用工具帮助或EnumProcesses执行此操作。如果找到您的进程,请将PID传递给OpenProcess以获取进程句柄。然后等待进程发出信号。这样就不需要在最初的枚举之外进行轮询。

如果初始枚举找不到进程,则必须重复枚举。使用工具帮助或EnumProcesses中的任何一个都会更有效。也许可以限制投票。您也可以选择使用WMI来获得新进程创建的通知,这样可以完全避免轮询的需要。

经过大量研究(以及TeamViewer支持部门的回应),我发布了一个明确的答案,希望对其他人有所帮助。代码是用Delphi编写的,但可以很容易地翻译成C++。

*如果您没有关于流程内部的信息*

function IsRemoteSupportRunning() : Boolean;
var
    hSnapShot, hProcess: THandle;
    process: TProcessEntry32;
    bFound: Boolean;
begin
    bFound := False;
    if (cache.dwTeamViewerID = 0) then
        begin
        // TeamViewer not running...is it running now?
        try
            hSnapShot := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
            process.dwSize := Sizeof(TProcessEntry32);
            if (Process32First(hSnapShot, process)) then
                bFound := (AnsiCompareText(REMOTE_SUPPORT_EXE, process.szExeFile) = 0);
            if (not bFound) then
                begin
                while (Process32Next(hSnapShot, process)) do
                    begin
                    bFound := (AnsiCompareText(REMOTE_SUPPORT_EXE, process.szExeFile) = 0);
                    if (bFound) then
                        break;
                    end;
                end;
            CloseHandle(hSnapShot);
        except
        end;
        // If found, save the process ID
        if (bFound) then
            cache.dwTeamViewerID := process.th32ProcessID;
        end
    else
        begin
        // In a previous call to this function, TeamViewer was running...
        hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, cache.dwTeamViewerID);
        if (hProcess > 0) then
            begin
            // Still running!
            bFound := True;
            CloseHandle(hProcess);
            end
        else
            begin
            // Process is no longer running
            cache.dwTeamViewerID := 0;
            end;
        end;
    Result := bFound;
end;

在我的机器上,如果TeamViewer.exe没有运行,这将消耗约1.5毫秒。一旦运行并且已知PID,该值将降至约6.8µs。

*如果您有关于的一些信息,或者可以控制该过程*

这里有很多可能性。例如,进程可以使用以下代码创建(或者您对进程进行编码以创建)共享内存对象:

CreateFileMapping(HWND($FFFFFFFF), nil, PAGE_READONLY, 0, 32, 'MyProcess');

您现在可以使用以下方法检查运行的进程:

var
    hMapping: HWND;
hMapping := CreateFileMapping(HWND($FFFFFFFF), nil, PAGE_READONLY, 0, 32, 'MyProcess');
if (hMapping <> 0) then
    begin
    if (GetLastError() = ERROR_ALREADY_EXISTS) then
        bRunning := True;
    CloseHandle(hMapping);
    end;

最后,TeamViewer支持告诉我一个命名的互斥对象,您将在下面的代码中看到它。请注意,这是TeamViewer特有的,但如果您可以控制进程,则可以创建一个互斥并使用此技术。在我的系统上,这会消耗约2.6µs!

function IsRemoteSupportRunning() : Boolean;
var
    hProcess: THandle;
begin
    // Use OpenMutex to see if TeamViewer.exe is running...
    Result := False;
    hProcess := OpenMutex(MUTEX_ALL_ACCESS, False, PChar('TeamViewer_Win32_Instance_Mutex'));
    if (hProcess > 0) then
        begin
        bFound := True;
        CloseHandle(hProcess);
        end;
end;

TeamViewer告诉我一个强大的工具WinObj可以调查系统中的对象,https://technet.microsoft.com/de-de/sysinternals/bb896657.aspx.检出BaseNamedObjects。Mutex显示为"突变体"。

在Windows上,您可以利用system()_wsystem()快速确定进程是否按名称运行。如果要发送包含.exe的整个进程名称,只需从函数的第一行中删除字符.exe即可。

static bool process_exists(std::wstring token)
{
    std::wstring cmd_query(std::wstring(L"tasklist|findstr /i "") + token + L".exe">nul 2>&1");
    return (_wsystem(cmd_query.data()) == 0) ? (true) : (false);
}

使用Mutex检查进程运行情况。

在检查进程中创建一个具有特定名称的互斥体,并检查该互斥体是否存在于其他进程中。

流程1:

        using var mutex = new Mutex(true, LockId, out var created);

LockId是一个特定的名称。

    public const string LockId = "5742D257-CCCC-4F7A-8191-6362609C458D";

进程2可以使用Mutex.TryOpenExisting来检查互斥是否存在。