简体   繁体   中英

Fast way to check for a specific process running

To check a process is running, one can use the "CreateToolHelp32SnapShot" Windows API function and enumerate the running processes. Example C/C++ code is given in the answer question: Check whether one specific process is running on windows with C++

My question is whether there is a faster way to find the answer without having to check each process in turn if you know you're looking for a specific process? We need to regularly check that our remote support tool, TeamViewer.exe, is running. Note that TeamViewer is written by a 3rd party, we have no control over it or knowledge of the internals of the EXE.

EDIT:

TeamViewer have provided some information about the internals of their process which can be used to speed this up in this instance (see accepted answer). The answer also shows how to speed up this check for any process (by saving the process ID).

The first step you must take involves enumerating processes. Do this with either toolhelp or EnumProcesses . If you find your process, pass the PID to OpenProcess to get process handle. Then wait for the process to be signaled. This then obviates the need to poll, beyond the initial enumeration.

If your initial enumeration fails to find the process you will have to repeat the enumeration. Use whichever of toolhelp or EnumProcesses turns out to be more efficient. Perhaps throttle the polling. You may also choose to use WMI to be notified of new process creation and that way completely avoid the need for polling.

On Windows, you can leverage system() or _wsystem() to quickly determine if a process is running by name. If you want to send the whole process name, .exe included, just remove the characters .exe from the first line of the function.

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);
}

After much research (and a response from TeamViewer support) I am posting a definitive answer, hope it helpful to others. Code is in Delphi but can be translated easily to C++.

* IF YOU HAVE NO INFO ABOUT THE INTERNALS OF THE PROCESS *

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;

On my machine, this consumes ~1.5ms if TeamViewer.exe is not running. Once running and the PID is known, this drops to ~6.8µs.

* IF YOU HAVE SOME INFO ABOUT, OR HAVE CONTROL OVER, THE PROCESS *

There are a number of possibilities here. For example, the process may create (or you code the process to create) a shared memory object using this code:

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

You can now check for the process running by using this:

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;

Finally, TeamViewer support informed me about a named mutex object which you'll see in the code below. Note that this is specific to TeamViewer, but if you had control over the process, you could create a mutex and use this technique. On my system, this consumes ~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 informed me of a powerful tool WinObj to investigate objects in the system, https://technet.microsoft.com/de-de/sysinternals/bb896657.aspx . Check out the BaseNamedObjects. Mutexes appear as "Mutant".

Using Mutex to check the process running.

Creating a Mutex with specific name in the checking process and check this mutex exist in other process.

Process 1:

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

The LockId is a specific name.

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

Process 2 can use Mutex.TryOpenExisting to check the mutex exist.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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