Reputation: 6597
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).
Upvotes: 0
Views: 3395
Reputation: 4327
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.
Upvotes: 0
Reputation: 6958
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);
}
Upvotes: 1
Reputation: 6597
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".
Upvotes: 1
Reputation: 612884
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.
Upvotes: 3