How to effectively kill a process in C++ (Win32)? - c++

I am currently writing a very lightweight program so I have to use C++ since it is not bound to .NET framework which drastically increases size of the program.
I need to be able to terminate process and to do that I need to get a process handle. Unfortuanately I haven't figured how to do that yet.
P.S. I know that to kill a process you have to use TerminateProcess.

The following code works:
const auto explorer = OpenProcess(PROCESS_TERMINATE, false, process_id);
TerminateProcess(explorer, 1);
CloseHandle(explorer);

The PID you need for OpenProcess() is not normally easy to get a hold of. If all you got is a process name then you need to iterate the running processes on the machine. Do so with CreateToolhelp32Snapshot, followed by Process32First and loop with Process32Next. The PROCESSENTRY32.szExeFile gives you the process name (not path!), th32ProcessID gives you the PID.
The next consideration is that the process may appear more than once. And there's a chance that the same process name is used for very different programs. Like "Setup". If you don't just want to kill them all, you'll need to try to obtain some runtime info from them. Window caption bar text, perhaps. GetProcessImageFileName() can give you the path to the .exe. It uses the native kernel format, you'd need QueryDosDevice to map a disk drive device name to a drive letter.
The next consideration is the rights you ask for in OpenProcess(). You are unlikely to get PROCESS_ALL_ACCESS, all you need is PROCESS_TERMINATE. Although that's privileged as well. Ensure the account you use to run your program can obtain that right.

Rather than going through all that pain to kill a process with a known name, why not simply call out to "system" and ask the command-line to kill it?
For example,
int retval = ::_tsystem( _T("taskkill /F /T /IM MyProcess.exe") );

To get a handle to pass to TerminateProcess, use OpenProcess in combination with some other function like EnumProcesses.

Here is the full example for Visual Studio 2010 C++ project how to kill the process by the EXE file name.
In order to check it just run Internet Explorer and after this execute following code.
#include <iostream>
#include <string>
#include<tchar.h>
#include <process.h>
#include <windows.h>
#include <tlhelp32.h>
using namespace std;
// Forward declarations:
BOOL GetProcessList();
BOOL TerminateMyProcess(DWORD dwProcessId, UINT uExitCode);
int main( void )
{
GetProcessList( );
return 0;
}
BOOL GetProcessList( )
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
return( FALSE );
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
CloseHandle( hProcessSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the snapshot of processes
do
{
string str(pe32.szExeFile);
if(str == "iexplore.exe") // put the name of your process you want to kill
{
TerminateMyProcess(pe32.th32ProcessID, 1);
}
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return( TRUE );
}
BOOL TerminateMyProcess(DWORD dwProcessId, UINT uExitCode)
{
DWORD dwDesiredAccess = PROCESS_TERMINATE;
BOOL bInheritHandle = FALSE;
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
if (hProcess == NULL)
return FALSE;
BOOL result = TerminateProcess(hProcess, uExitCode);
CloseHandle(hProcess);
return result;
}
Imagine in C# it looks like
using System;
using System.Collections.Generic;
using System.Text;
namespace MyProcessKiller
{
class Program
{
static void Main(string[] args)
{
foreach (System.Diagnostics.Process myProc in System.Diagnostics.Process.GetProcesses())
{
if (myProc.ProcessName == "iexplore")
{
myProc.Kill();
}
}
}
}
}

windows only
system("taskkill /f /im servicetokill.exe")

Here are some working sample codes to kill a process called "ShouldBeDead.exe":
// you will need these headers, and you also need to link to Psapi.lib
#include <tchar.h>
#include <psapi.h>
...
// first get all the process so that we can get the process id
DWORD processes[1024], count;
if( !EnumProcesses( processes, sizeof(processes), &count ) )
{
return false;
}
count /= sizeof(DWORD);
for(unsigned int i = 0; i < count; i++)
{
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
if(processes[i] != 0)
{
// remember to open with PROCESS_ALL_ACCESS, otherwise you will not be able to kill it
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, processes[i] );
if(NULL != hProcess)
{
HMODULE hMod;
DWORD cbNeeded;
if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
{
GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR));
// find the process and kill it
if(strcmp(szProcessName, "ShouldBeDead.exe") == 0)
{
DWORD result = WAIT_OBJECT_0;
while(result == WAIT_OBJECT_0)
{
// use WaitForSingleObject to make sure it's dead
result = WaitForSingleObject(hProcess, 100);
TerminateProcess(hProcess, 0);
}
CloseHandle(hProcess);
}
}
}
}
}

CreateProcess and OpenProcess return process handles.
Here's some sample code to find a process by asking the system to list all processes and then searching the list for the process you want.

Task Killer using Modern C++
Below is the code I've created for my Terminator Program
//_____________________________________________
// |
// TheNexGen of Terminator (inclusion version) |
// ------------------------------------------- |
// |
// Add your Programs in the 'if' check as I've |
// listed below, and compile using c++17 flag |
// or higher |
//_____________________________________________|
#include <process.h>
#include <windows.h>
#include <tlhelp32.h>
#include <string_view>
using namespace std;
int main()
{
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) return 0;
PROCESSENTRY32W pe32{ .dwSize = sizeof(PROCESSENTRY32) };
if (!Process32First(hProcessSnap, &pe32)) return CloseHandle(hProcessSnap), 0;
do
{
wstring_view str = pe32.szExeFile;
if
(
str == L"chrome.exe"
|| str == L"AAM Update Notifier.exe"
|| str == L"About.exe"
|| str == L"ActionCenterDownloader.exe"
|| str == L"adb.exe"
|| str == L"AdobeARM.exe"
)
{
if (HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, pe32.th32ProcessID))
{
TerminateProcess(hProcess, 1);
CloseHandle(hProcess);
}
}
}
while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
}
Description
Increased Execution Speed 100x of the Code provided by #DmitryBoyko.

Related

Is there a way to list every windows processes from cpp?

I'm recently looking to list every processes of a machine to do some action. But I'm struggling with processes which are not launched from my user (eg: system, administrator or an other user).
I tried some codes and some solutions but there is still anything who works.
I am working on the code proposed by microsoft to enumerate all the processes.
Here is the code :
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
// and compile with -DPSAPI_VERSION=1
void PrintProcessNameAndID( DWORD processID )
{
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
// Get a handle to the process.
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );
// Get the process name.
if (NULL != hProcess )
{
HMODULE hMod;
DWORD cbNeeded;
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod),
&cbNeeded) )
{
GetModuleBaseName( hProcess, hMod, szProcessName,
sizeof(szProcessName)/sizeof(TCHAR) );
}
}
// Print the process name and identifier.
_tprintf( TEXT("%s (PID: %u)\n"), szProcessName, processID );
// Release the handle to the process.
CloseHandle( hProcess );
}
int main( void )
{
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
{
return 1;
}
// Calculate how many process identifiers were returned.
cProcesses = cbNeeded / sizeof(DWORD);
// Print the name and process identifier for each process.
for ( i = 0; i < cProcesses; i++ )
{
if( aProcesses[i] != 0 )
{
PrintProcessNameAndID( aProcesses[i] );
}
}
return 0;
}
This code works but does not allow you to view the processes of other users. Do you have an idea?
Thanks everyone for your time.
Regards
As a normal user, you are not going to get far by using OpenProcess on processes you don't own. If you elevate your process and enable the debug privilege you might have more luck. You will probably still be denied access to DRM and AntiVirus processes. In general the PSAPI functions expect a lot of access to the process with PROCESS_VM_READ being the biggest issue, Windows is not going to grant you memory read access to all other processes. Some of the newer APIs like GetProcessImageFileName have been upgraded (in Vista+) to only require PROCESS_QUERY_LIMITED_INFORMATION which you might be able to get for more processes.
I would suggest using the Toolhelp API instead, it should provide a little more info than EnumProcesses+OpenProcess. You can also get some information from the Performance Counters and WMI.
As a side note; EnumProcesses is the most useless API ever. It uses the NT API to get information about all processes then throws away all that information except the process ids.
If you are willing to use undocumented stuff, the NT Query/Information functions will give you more information than any documented API.
The most reasonable solution I think would be to use
CreateToolhelp32Snapshot
You can do some looking up on it at https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
Heres a small example
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
std::cout << "CreateToolhelp32Snapshot (of processes) failed with error " << GetLastError() << std::endl;
return;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hProcessSnap, &pe32))
{
std::cout << "Failed getting first process" << std::endl;
CloseHandle(hProcessSnap);
return;
}
do
{
std::cout << "Process: " << pe32.szExeFile << std::endl;
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);

Thread doesn't execute the function

I have written two functions which they can kill a process by its name. You can specify the name of a process, and after the execution of the program, that process will kill.
These two functions are working fine, but when I decided to run them via threads, they didn't execute. What is the problem with the following code:
#include <iostream>
#include <string>
#include <tchar.h>
#include <process.h>
#include <windows.h>
#include <tlhelp32.h>
BOOL TerminateMyProcess(DWORD dwProcessId, UINT uExitCode)
{
DWORD dwDesiredAccess = PROCESS_TERMINATE;
BOOL bInheritHandle = FALSE;
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
if (hProcess == NULL)
return FALSE;
BOOL result = TerminateProcess(hProcess, uExitCode);
CloseHandle(hProcess);
return result;
}
DWORD GetProcessList()
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return(FALSE);
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Retrieve information about the first process,
// and exit if unsuccessful
if (!Process32First(hProcessSnap, &pe32))
{
CloseHandle(hProcessSnap); // clean the snapshot object
return(FALSE);
}
// Now walk the snapshot of processes
do
{
std::string str(pe32.szExeFile);
if (str == "notepad.exe") // put the name of your process you want to kill
{
TerminateMyProcess(pe32.th32ProcessID, 1);
}
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
return(TRUE);
}
DWORD WINAPI ThreadingOne(LPVOID arg_param) {
return GetProcessList();
}
auto main(int argc, const char* argv[]) -> decltype(0)
{
DWORD ThreadId;
HANDLE ThreadHandle = CreateThread(NULL, 0, ThreadingOne, (LPVOID)0, CREATE_SUSPENDED, &ThreadId);
ResumeThread(ThreadHandle);
return 0;
}
The thread function didn't start anyway. I didn't know what is the mistake with this threading. I should mention here, I just started multithreading earlier, so it is maybe a simple question but I am a newbie in threads world.

windows EnumProcesses some process names as <unknown>

Hello I have this sample code running which uses x to print processNames and PIDS of all currently running processes. Only some of them display an actual name though, with others displaying as (as seen in my output image below)
I was wondering if this was expected behavior, and that not all processes have a name (I could see this being the case for minimal background processes), or if I was using the EnumProcesses function incorrectly.
My code is:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <tchar.h>
//https://learn.microsoft.com/en-us/windows/desktop/psapi/enumerating-all-processes
void PrintProcessNameAndID( DWORD processID ){
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
// Get a handle to the process.
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );
// Get the process name.
if (NULL != hProcess ){
HMODULE hMod;
DWORD cbNeeded;
if ( EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) ){
GetModuleBaseName( hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR) );
}
}
// Print the process name and identifier.
_tprintf( TEXT("%s (PID: %u)\n"), szProcessName, processID );
// Release the handle to the process.
CloseHandle( hProcess );
}
//https://learn.microsoft.com/en-us/windows/desktop/psapi/enumerating-all-processes
int main( void ){
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) ){
return 1;
}
// Calculate how many process identifiers were returned.
cProcesses = cbNeeded / sizeof(DWORD);
// Print the name and process identifier for each process.
//for ( i = 0; i < cProcesses; i++ ){
for ( i = 0; i < 3; i++ ){
if( aProcesses[i] != 0 ) {
_tprintf( TEXT("aProcesses[%u] = %u (process ID)\n"), i, aProcesses[i] );
PrintProcessNameAndID( aProcesses[i] );
ListProcessThreads( aProcesses[i] );
}
}
return 0;
}
As stated in documentation, OpenProcess fails for idle and CSRSS processes.
If the specified process is the Idle process or one of the CSRSS
processes, this function fails and the last error code is
ERROR_ACCESS_DENIED because their access restrictions prevent
user-level code from opening them.
You have to enable SeDebugPrivilege (and also run your application with admin privileges). Moreover, if your application is compiled as 32-bit, it cannot access 64-bit processes with OpenProcess
If you just want a list of running processes, use CreateToolhelp32Snapshot to list running processes.
#define UNICODE
#include <Windows.h>
#include <stdio.h>
#include <psapi.h>
#include <tlhelp32.h>
int main()
{
wprintf(L"Start:\n");
HANDLE hndl = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPMODULE, 0);
if(hndl)
{
PROCESSENTRY32 process = { sizeof(PROCESSENTRY32) };
Process32First(hndl, &process);
do
{
wprintf(L"%8u, %s\n", process.th32ProcessID, process.szExeFile);
} while(Process32Next(hndl, &process));
CloseHandle(hndl);
}
}
Side note, it is recommended to compile the program as Unicode. Avoid _txxx macros such as _tprintf etc.

Check whether one specific process is running on windows with C++

Is there any function in psapi or windows.h to get desired process' is running via only the process name (e.g : "chrome.exe") without getting all processes.
Edit:
If any one requires to get the desired process information via running through the list of all processes I can paste my code here. it works on a xp-machine and compiled with vs 2008.
I have found a solution for my question, too ! But according to the msdn the function runs already through the processes and checks the name without the extension. Shortly it searchs for "chrome" and returns the list of chrome.*
This function has a nice advantage it returns the process in a list, it might be an exe may run with may instances. Disadvantage CLR is required, it runs slower than the psapi functions and it has extra convertion requirements such as String^ to wchar or String (which I have not tested)
the above answer works on win 8. here it is without the wstring stuff and stripping off the path
#include <tlhelp32.h>
DWORD FindProcessId(char* processName)
{
// strip path
char* p = strrchr(processName, '\\');
if(p)
processName = p+1;
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if ( processesSnapshot == INVALID_HANDLE_VALUE )
return 0;
Process32First(processesSnapshot, &processInfo);
if ( !strcmp(processName, processInfo.szExeFile) )
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
while ( Process32Next(processesSnapshot, &processInfo) )
{
if ( !strcmp(processName, processInfo.szExeFile) )
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
}
CloseHandle(processesSnapshot);
return 0;
}
#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
using namespace std;
DWORD FindProcessId(const std::wstring& processName);
int main(int argc, char* argv[])
{
bool bAnyBrowserIsOpen = false;
if ( FindProcessId(L"chrome.exe") || FindProcessId(L"firefox.exe") || FindProcessId(L"iexplore.exe"))
{
bAnyBrowserIsOpen = true;
}
return 0;
}
DWORD FindProcessId(const std::wstring& processName)
{
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof(processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if ( processesSnapshot == INVALID_HANDLE_VALUE )
return 0;
Process32First(processesSnapshot, &processInfo);
if ( !processName.compare(processInfo.szExeFile) )
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
while ( Process32Next(processesSnapshot, &processInfo) )
{
if ( !processName.compare(processInfo.szExeFile) )
{
CloseHandle(processesSnapshot);
return processInfo.th32ProcessID;
}
}
CloseHandle(processesSnapshot);
return 0;
}
You can use CreateToolhelp32Snapshot as given above. If you need to regularly poll for the process, save the process ID once you've found it running and then check using OpenProcess. This is many times faster, but be aware that the OS recycles PIDs, so you'll have to deal with that.
If you know something about the internals of the process (or even have control over it) there are other options such as checking for:
the existence of a named memory object (using CreateFileMapping)
the existence of a named mutex (using OpenMutex)
More details are given in the answer to this question: Fast way to check for a specific process running

C++, How to determine if a Windows Process is running?

This is concerning Windows XP processes.
I have a process running, let's call it Process1. Process1 creates a new process, Process2, and saves its id.
Now, at some point Process1 wants Process2 to do something, so it first needs to make sure that Process2 is still alive and that the user has not not killed it.
How can I check that this process is still running?
Since I created it, I have the Process ID, I would think there is some library function along the lines of IsProcessIDValid( id ) but I can't find it on MSDN
You can use GetExitCodeProcess. It will return STILL_ACTIVE (259) if the process is still running (or if it happened to exit with that exit code :( ).
The process handle will be signaled if it exits.
So the following will work (error handling removed for brevity):
BOOL IsProcessRunning(DWORD pid)
{
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
DWORD ret = WaitForSingleObject(process, 0);
CloseHandle(process);
return ret == WAIT_TIMEOUT;
}
Note that process ID's can be recycled - it's better to cache the handle that is returned from the CreateProcess call.
You can also use the threadpool API's (SetThreadpoolWait on Vista+, RegisterWaitForSingleObject on older platforms) to receive a callback when the process exits.
EDIT: I missed the "want to do something to the process" part of the original question. You can use this technique if it is ok to have potentially stale data for some small window or if you want to fail an operation without even attempting it. You will still have to handle the case where the action fails because the process has exited.
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
/*!
\brief Check if a process is running
\param [in] processName Name of process to check if is running
\returns \c True if the process is running, or \c False if the process is not running
*/
bool IsProcessRunning(const wchar_t *processName)
{
bool exists = false;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry))
while (Process32Next(snapshot, &entry))
if (!wcsicmp(entry.szExeFile, processName))
exists = true;
CloseHandle(snapshot);
return exists;
}
The solution provided by #user152949, as it was noted in commentaries, skips the first process and doesn't break when "exists" is set to true. Let me provide a fixed version:
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
bool IsProcessRunning(const TCHAR* const executableName) {
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) {
CloseHandle(snapshot);
return false;
}
do {
if (!_tcsicmp(entry.szExeFile, executableName)) {
CloseHandle(snapshot);
return true;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return false;
}
I found this today, it is from 2003. It finds a process by name, you don't even need the pid.
\#include windows.h
\#include tlhelp32.h
\#include iostream.h
int FIND_PROC_BY_NAME(const char *);
int main(int argc, char *argv[])
{
// Check whether a process is currently running, or not
char szName[100]="notepad.exe"; // Name of process to find
int isRunning;
isRunning=FIND_PROC_BY_NAME(szName);
// Note: isRunning=0 means process not found, =1 means yes, it is found in memor
return isRunning;
}
int FIND_PROC_BY_NAME(const char *szToFind)
// Created: 12/29/2000 (RK)
// Last modified: 6/16/2003 (RK)
// Please report any problems or bugs to kochhar#physiology.wisc.edu
// The latest version of this routine can be found at:
// http://www.neurophys.wisc.edu/ravi/software/killproc/
// Check whether the process "szToFind" is currently running in memory
// This works for Win/95/98/ME and also Win/NT/2000/XP
// The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE"
// will both work (for szToFind)
// Return codes are as follows:
// 0 = Process was not found
// 1 = Process was found
// 605 = Unable to search for process
// 606 = Unable to identify system type
// 607 = Unsupported OS
// 632 = Process name is invalid
// Change history:
// 3/10/2002 - Fixed memory leak in some cases (hSnapShot and
// and hSnapShotm were not being closed sometimes)
// 6/13/2003 - Removed iFound (was not being used, as pointed out
// by John Emmas)
{
BOOL bResult,bResultm;
DWORD aiPID[1000],iCb=1000,iNumProc,iV2000=0;
DWORD iCbneeded,i;
char szName[MAX_PATH],szToFindUpper[MAX_PATH];
HANDLE hProc,hSnapShot,hSnapShotm;
OSVERSIONINFO osvi;
HINSTANCE hInstLib;
int iLen,iLenP,indx;
HMODULE hMod;
PROCESSENTRY32 procentry;
MODULEENTRY32 modentry;
// PSAPI Function Pointers.
BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * );
BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *,
DWORD, LPDWORD );
DWORD (WINAPI *lpfGetModuleBaseName)( HANDLE, HMODULE,
LPTSTR, DWORD );
// ToolHelp Function Pointers.
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ;
BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ;
BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ;
BOOL (WINAPI *lpfModule32First)(HANDLE,LPMODULEENTRY32) ;
BOOL (WINAPI *lpfModule32Next)(HANDLE,LPMODULEENTRY32) ;
// Transfer Process name into "szToFindUpper" and
// convert it to upper case
iLenP=strlen(szToFind);
if(iLenP<1 || iLenP>MAX_PATH) return 632;
for(indx=0;indx<iLenP;indx++)
szToFindUpper[indx]=toupper(szToFind[indx]);
szToFindUpper[iLenP]=0;
// First check what version of Windows we're in
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bResult=GetVersionEx(&osvi);
if(!bResult) // Unable to identify system version
return 606;
// At Present we only support Win/NT/2000 or Win/9x/ME
if((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) &&
(osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS))
return 607;
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT)
{
// Win/NT or 2000 or XP
// Load library and get the procedures explicitly. We do
// this so that we don't have to worry about modules using
// this code failing to load under Windows 95, because
// it can't resolve references to the PSAPI.DLL.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
return 605;
// Get procedure addresses.
lpfEnumProcesses = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))
GetProcAddress( hInstLib, "EnumProcesses" ) ;
lpfEnumProcessModules = (BOOL(WINAPI *)(HANDLE, HMODULE *,
DWORD, LPDWORD)) GetProcAddress( hInstLib,
"EnumProcessModules" ) ;
lpfGetModuleBaseName =(DWORD (WINAPI *)(HANDLE, HMODULE,
LPTSTR, DWORD )) GetProcAddress( hInstLib,
"GetModuleBaseNameA" ) ;
if( lpfEnumProcesses == NULL ||
lpfEnumProcessModules == NULL ||
lpfGetModuleBaseName == NULL)
{
FreeLibrary(hInstLib);
return 605;
}
bResult=lpfEnumProcesses(aiPID,iCb,&iCbneeded);
if(!bResult)
{
// Unable to get process list, EnumProcesses failed
FreeLibrary(hInstLib);
return 605;
}
// How many processes are there?
iNumProc=iCbneeded/sizeof(DWORD);
// Get and match the name of each process
for(i=0;i<iNumProc;i++)
{
// Get the (module) name for this process
strcpy(szName,"Unknown");
// First, get a handle to the process
hProc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
aiPID[i]);
// Now, get the process name
if(hProc)
{
if(lpfEnumProcessModules(hProc,&hMod,sizeof(hMod),&iCbneeded) )
{
iLen=lpfGetModuleBaseName(hProc,hMod,szName,MAX_PATH);
}
}
CloseHandle(hProc);
// Match regardless of lower or upper case
if(strcmp(_strupr(szName),szToFindUpper)==0)
{
// Process found
FreeLibrary(hInstLib);
return 1;
}
}
}
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
{
// Win/95 or 98 or ME
hInstLib = LoadLibraryA("Kernel32.DLL");
if( hInstLib == NULL )
return FALSE ;
// Get procedure addresses.
// We are linking to these functions of Kernel32
// explicitly, because otherwise a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in the Kernel 32.
lpfCreateToolhelp32Snapshot=
(HANDLE(WINAPI *)(DWORD,DWORD))
GetProcAddress( hInstLib,
"CreateToolhelp32Snapshot" ) ;
lpfProcess32First=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32First" ) ;
lpfProcess32Next=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32Next" ) ;
lpfModule32First=
(BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32))
GetProcAddress( hInstLib, "Module32First" ) ;
lpfModule32Next=
(BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32))
GetProcAddress( hInstLib, "Module32Next" ) ;
if( lpfProcess32Next == NULL ||
lpfProcess32First == NULL ||
lpfModule32Next == NULL ||
lpfModule32First == NULL ||
lpfCreateToolhelp32Snapshot == NULL )
{
FreeLibrary(hInstLib);
return 605;
}
// The Process32.. and Module32.. routines return names in all uppercase
// Get a handle to a Toolhelp snapshot of all the systems processes.
hSnapShot = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS, 0 ) ;
if( hSnapShot == INVALID_HANDLE_VALUE )
{
FreeLibrary(hInstLib);
return 605;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bResult=lpfProcess32First(hSnapShot,&procentry);
// While there are processes, keep looping and checking.
while(bResult)
{
// Get a handle to a Toolhelp snapshot of this process.
hSnapShotm = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPMODULE, procentry.th32ProcessID) ;
if( hSnapShotm == INVALID_HANDLE_VALUE )
{
CloseHandle(hSnapShot);
FreeLibrary(hInstLib);
return 605;
}
// Get the module list for this process
modentry.dwSize=sizeof(MODULEENTRY32);
bResultm=lpfModule32First(hSnapShotm,&modentry);
// While there are modules, keep looping and checking
while(bResultm)
{
if(strcmp(modentry.szModule,szToFindUpper)==0)
{
// Process found
CloseHandle(hSnapShotm);
CloseHandle(hSnapShot);
FreeLibrary(hInstLib);
return 1;
}
else
{ // Look for next modules for this process
modentry.dwSize=sizeof(MODULEENTRY32);
bResultm=lpfModule32Next(hSnapShotm,&modentry);
}
}
//Keep looking
CloseHandle(hSnapShotm);
procentry.dwSize = sizeof(PROCESSENTRY32);
bResult = lpfProcess32Next(hSnapShot,&procentry);
}
CloseHandle(hSnapShot);
}
FreeLibrary(hInstLib);
return 0;
}
Another way of monitoring a child-process is to create a worker thread that will :
call CreateProcess()
call WaitForSingleObject() // the worker thread will now wait till the child-process finishes execution. it's possible to grab the return code (from the main() function) too.
You can never check and see if a process is running, you can only check to see if a process was running at some point in the recent past. A process is an entity that is not controlled by your application and can exit at any moment in time. There is no way to guaranteed that a process will not exit in between the check to see if it's running and the corresponding action.
The best approach is to just do the action required and catch the exception that would be thrown if the process was not running.
call EnumProcesses() and check if the PID is in the list.
http://msdn.microsoft.com/en-us/library/ms682629%28VS.85%29.aspx
JaredPar is right in that you can't know if the process is running. You can only know if the process was running at the moment you checked. It might have died in the mean time.
You also have to be aware the PIDs can be recycled pretty quickly. So just because there's a process out there with your PID, it doesn't mean that it's your process.
Have the processes share a GUID. (Process 1 could generate the GUID and pass it to Process 2 on the command line.) Process 2 should create a named mutex with that GUID. When Process 1 wants to check, it can do a WaitForSingleObject on the mutex with a 0 timeout. If Process 2 is gone, the return code will tell you that the mutex was abandoned, otherwise you'll get a timeout.
You may find if a process (given its name or PID) is running or not by iterating over the running processes simply by taking a snapshot of running processes via CreateToolhelp32Snapshot, and by using Process32First and Process32Next calls on that snapshot.
Then you may use th32ProcessID field or szExeFile field of the resulting PROCESSENTRY32 struct depending on whether you want to search by PID or executable name. A simple implementation can be found here.
While writing a monitoring tool, i took a slightly different approach.
It felt a bit wasteful to spin up an extra thread just to use WaitForSingleObject or even the RegisterWaitForSingleObject (which does that for you). Since in my case i don't need to know the exact instant a process has closed, just that it indeed HAS closed.
I'm using the GetProcessTimes() instead:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx
GetProcessTimes() will return a FILETIME struct for the process's ExitTime only if the process has actually exited. So is just a matter of checking if the ExitTime struct is populated and if the time isn't 0;
This solution SHOULD account the case where a process has been killed but it's PID was reused by another process. GetProcessTimes needs a handle to the process, not the PID. So the OS should know that the handle is to a process that was running at some point, but not any more, and give you the exit time.
Relying on the ExitCode felt dirty :/
This is a solution that I've used in the past. Although the example here is in VB.net - I've used this technique with c and c++. It bypasses all the issues with Process IDs & Process handles, and return codes. Windows is very faithful in releasing the mutex no matter how Process2 is terminated. I hope it is helpful to someone...
**PROCESS1 :-**
Randomize()
mutexname = "myprocess" & Mid(Format(CDbl(Long.MaxValue) * Rnd(), "00000000000000000000"), 1, 16)
hnd = CreateMutex(0, False, mutexname)
' pass this name to Process2
File.WriteAllText("mutexname.txt", mutexname)
<start Process2>
<wait for Process2 to start>
pr = WaitForSingleObject(hnd, 0)
ReleaseMutex(hnd)
If pr = WAIT_OBJECT_0 Then
<Process2 not running>
Else
<Process2 is running>
End If
...
CloseHandle(hnd)
EXIT
**PROCESS2 :-**
mutexname = File.ReadAllText("mutexname.txt")
hnd = OpenMutex(MUTEX_ALL_ACCESS Or SYNCHRONIZE, True, mutexname)
...
ReleaseMutex(hnd)
CloseHandle(hnd)
EXIT
char tmp[200] = "taskkill /f /im chrome.exe && \"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\"
while (1)
{
FILE* f;
f = _popen("tasklist", "r");
char b[512];
bzero(b, 512);
while (fgets(b, 512, f) != NULL)
{
if (strncmp(b, "chrome.exe", 8) == 0)
{
printf("Chrome running!\n");
system(tmp);
}
else
{
printf("Chrome NOT running!\n");
}
}
Sleep(1000);
}