C++ How to Check if an Outlook Process is already running - c++

I am new to C++ programming but I would like to know if there is an easy way to check if an Outlook Process is already running, or in other words check if Outlook is already open.
Can anyone show me, please?
Thanks

You can check the running instance of the outlook OLE:
static const bool isOutlookRunning()
{
CLSID clsid;
HRESULT hr = CLSIDFromProgID( _T("Outlook.Application"), &clsid );
if( hr != S_OK ) return false;
IUnknown *pUnknown = NULL;
hr = GetActiveObject( clsid, 0, &pUnknown );
return ( hr == S_OK );
}
This code will not work if the app from you invoke it is running in different user security context than Outlook.
Its better to check for the process name.

//////////////////////////////////////////////////////////////////////
// IsProcessRunning
//////////////////////////////////////////////////////////////////////
bool IsProcessRunning(string &strProcessFullPathName)
{
// Get the list of process identifiers.
DWORD dwProcesses[2048];
DWORD dwSizeNeeded = 0;
DWORD dwProcessesCount = 0;
if ( !EnumProcesses( dwProcesses, sizeof(dwProcesses), &dwSizeNeeded ) )
{
_dwLastErrorCode = GetLastError();
_strLastError = "EnumProcesses";
return false;
}
dwProcessesCount = dwSizeNeeded / sizeof(DWORD);
string strToCheck = strProcessFullPathName;
transform(strToCheck.begin(), strToCheck.end(), strToCheck.begin(), tolower);
for(int i=0; i<(int)dwProcessesCount; i++ )
{
if( dwProcesses[i] != 0 )
{
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcesses[i]);
if(hProcess)
{
HMODULE hModule = NULL;
dwSizeNeeded = 0;
char cName[MAX_PATH];
if(EnumProcessModules(hProcess, &hModule, sizeof(DWORD), &dwSizeNeeded) )
{
if(GetModuleFileNameEx(hProcess, hModule, cName, MAX_PATH ) != 0)
{
string strName(cName);
// Convert to LowerCase
transform(strName.begin(), strName.end(), strName.begin(), tolower);
if(strName == strToCheck)
{
CloseHandle(hProcess);
return true;
}
}
}
CloseHandle(hProcess);
}
}
}
return false;
}

I assume that you are using Windows as platform, since Outlook normally runs under a Windows OS.
For a simple check you can use the Windows API functions EnumProcesses() and GetModuleBaseName() to determine the executable filename of the running processes and check if the executable name is "outlook.exe". A reference for the functions can be found in the MSDN.
Be aware that the this check may fail if the user runs another program that is using the same executable filename as Outlook. Another trap with the provided solution might be the access rights a user needs for the specified API calls.
Improvements might be to check the version information in the executable file too by using GetFileVersionInfo().

You can use CreateToolhelp32Snapshot and iterate through the running processes. If you need to heck for Outlook again (say you need to poll for the process), then save the process ID and use OpenProcess (many times faster). More details are given in the answer to this question:
Check whether one specific process is running on windows with C++

Related

Logoff remote system using c++

I am looking for an API to logoff current user on remote computer. Two
functions ExitWindows and InitiateSystemShutdown seem not exactly what I
want. The first one doesn't accept computer name, the second one doesn't
have logoff option.is it possible to logoff current user
on remote computer ?. Can someone tell me how to achieve this in a
C++ program?
I knew that you want to shutdown system by using exitwindows function.
However, if you want to shut down the remote system in your own process, you need to use the exitwindowsEX function and write a program that specifies the process ID.
The relevant function references are as follows:
https://learn.microsoft.com/zh-cn/windows/win32/shutdown/how-to-shut-down-the-system
The following are specific codes:
#pragma region
#include<windows.h>
#pragma warning(disable:4996)
BOOL ReSetWindows(DWORD dwFlags, BOOL bForce)
{
if (dwFlags != EWX_LOGOFF && dwFlags != EWX_REBOOT && dwFlags != EWX_SHUTDOWN)
return FALSE;
OSVERSIONINFO osvi = { 0 };
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&osvi))
{
return FALSE;
}
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
//EnableShutDownPriv();
}
dwFlags |= (bForce != FALSE) ? EWX_FORCE : EWX_FORCEIFHUNG;
return ExitWindowsEx(dwFlags, 0);
}
int main()
{
ReSetWindows(EWX_LOGOFF, false);//logoff
//ReSetWindows(EWX_REBOOT, true);//restart
//ReSetWindows(EWX_SHUTDOWN, true);//shutdown
}
=======================
Caution!!!Please save your important file before running or running in the virtual machine
WTSLogoffSession? but the concept of a current user on a remote machine does not really exist, you would have to inspect the sessions with WTSEnumerateSessions+WTSQuerySessionInformation if you want to find a specific user. This only makes sense in a environment where there is a NT domain so you can match against a domain SID. Without a domain, all you can do is match against the username which might be enough for you.
This is the program specifies the process ID:
DWORD GetProcessIDByName(LPCTSTR szProcessName)
{
STARTUPINFO st;
PROCESS_INFORMATION pi;
PROCESSENTRY32 ps;
HANDLE hSnapshot;
DWORD dwPID = 0;
ZeroMemory(&st, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
st.cb = sizeof(STARTUPINFO);
ZeroMemory(&ps, sizeof(PROCESSENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)//
{
return dwPID;
}
if (!Process32First(hSnapshot, &ps))
{
return dwPID;
}
do
{
if (lstrcmpi(ps.szExeFile, szProcessName) == 0)
{
dwPID = ps.th32ProcessID;
}
} while (Process32Next(hSnapshot, &ps));
CloseHandle(hSnapshot);
return dwPID;//
}
You need this line of code in your main function:
DWORD pId = GetProcessIDByName("\\\.exe");
Closing remote system by local machine is easy. Closing local machine by remote machine sounds like a virus. No offense, it is difficult to implement. Maybe you can try using socket to communicate local machine with virtual machine.

TerminateProcess not suceeding on Windows 10

Our C++ app launches a separate .exe ( which may start its own sub-processes) using CreateProcess as below.
BOOL started = ::CreateProcess(NULL, // application
p, // parameters
NULL, // process security
NULL, // thread security
TRUE, // inherit handles flag
0, // flags
NULL, // inherit environment
dirLP, // inherit directory
&startup, // STARTUPINFO
&procinfo); // PROCESS_INFORMATIO
In case we need cancel the "job" we use CreateToolhelp32Snapshot to iterate through the process list to find any child processes of the one we launched.
static BOOL TerminateProcessTree (HANDLE parentProcess,UINT exitCode)
{
BOOL result=TRUE;
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = {0};
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return (FALSE);
pe32.dwSize = sizeof(PROCESSENTRY32);
// Walk the snapshot of the processes
DWORD parentID=GetProcessId(parentProcess);
if(parentID==0){
PrintLastError("GetProcessId");
return FALSE;
}
if (Process32First(hProcessSnap, &pe32)) {
do{
if(pe32.th32ParentProcessID==parentID){
HANDLE hProcess = OpenProcess (PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
if(hProcess!=NULL){
BOOL terminateChildren=TerminateProcessTree(hProcess,exitCode);
BOOL terminatedChild = TerminateProcess(hProcess, exitCode);
if (!terminatedChild){
PrintLastError("TerminateProcess");
}
CloseHandle(hProcess);
if(!terminatedChild || !terminateChildren){
result=FALSE;
break;
}
} else{
PrintLastError("OpenProcess");
}
}
}while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle (hProcessSnap);
DWORD checkCode=0;
BOOL terminated;
if(GetExitCodeProcess(parentProcess,&checkCode) && checkCode==STILL_ACTIVE){
terminated=TerminateProcess(parentProcess,exitCode);
if (!terminated){
PrintLastError("TerminateProcess");
result= FALSE;
}
}
return result;
}
As noted, this works fine on Windows 7. Windows 10 fails with "Access Denied" on the first call "TerminateProcess". Clearly something has changed in the Windows security model when it comes to processes.
The robust way to deal with controlling a process tree of objects is to use Job objects as noted in the comment threads.
The one thing to keep in mind is that a process can only belong to a single job, and by default any EXE that the OS determines needs appcompat help is put into a job object automatically managed by the "Program Compatibility Assistant". This makes using a Job object to manage arbitrary 3rd party EXEs a little bit more complicated (i.e. AssignProcessToJobObject fails for these processes).
If you are using CreateProcess you can make use of the flag CREATE_BREAKAWAY_FROM_JOB. See this blog post. This works fine as long as the target EXE has the same rights as the calling object.
For a Standard User EXE to run an EXE that might need Administrator rights (i.e. they contain a manifest which marks it as requireAdministrator), you have to use ShellExecute or ShellExecuteEx as calling CreateProcess in this case will fail. If your target EXEs are all using the proper manifest elements then it won't be put into a PCA Job object.. You can use the trick of passing SEE_MASK_FLAG_NO_UI which will have the side-effect of avoiding the PCA job behavior. If you are launching arbitrary 3rd party EXEs, you should use ShellExecuteEx and not CreateProcess.
bool SpawnProcess( const WCHAR* szExePath, const WCHAR* szExeArgs )
{
if( !szExePath )
return false;
// NOTE: szExeArgs can be nullptr.
// Get working directory from executable path.
WCHAR szDirectory[MAX_PATH] = {0};
wcscpy_s( szDirectory, szExePath );
PathRemoveFileSpec( szDirectory );
// ShellExecute or ShellExecuteEx must be used instead of CreateProcess
// to permit the shell to display a UAC prompt asking for consent to
// elevate when the target executable's manifest specifies a run level
// of "requireAdministrator".
//
// You can only use CreateProcess if you know that the application you
// are spawning will be at the same run level as the current process.
// Otherwise, you will receive ERROR_ACCESS_DENIED if the elevation
// consent could not be obtained.
SHELLEXECUTEINFO info = {};
info.cbSize = sizeof( info );
info.lpVerb = L"open";
info.fMask = SEE_MASK_FLAG_NO_UI;
info.lpFile = szExePath;
info.lpParameters = szExeArgs;
info.lpDirectory = szDirectory;
info.nShow = SW_SHOW;
if( !ShellExecuteEx( &info ) )
return false;
return true;
}
Note that if you want to wait until this process exits, you can use:
bool SpawnProcessAndWait( const WCHAR *szExePath, const WCHAR *szExeArgs, DWORD *pdwExitCode )
{
if( !szExePath )
return false;
// NOTE: szExeArgs and pExitCode can be nullptr.
// Get working directory from executable path.
WCHAR szDirectory[MAX_PATH] = {0};
wcscpy_s( szDirectory, szExePath );
PathRemoveFileSpec( szDirectory );
// See SpawnProcess for information why ShellExecute or ShellExecuteEx
// must be used instead of CreateProcess.
SHELLEXECUTEINFO info = {};
info.cbSize = sizeof( info );
info.lpVerb = L"open";
info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
info.lpFile = szExePath;
info.lpParameters = szExeArgs;
info.lpDirectory = szDirectory;
info.nShow = SW_SHOW;
if( !ShellExecuteEx( &info ) )
return false;
// Wait for process to finish.
WaitForSingleObject( info.hProcess, INFINITE );
// Return exit code from process, if requested by caller.
if( pdwExitCode )
GetExitCodeProcess( info.hProcess, pdwExitCode );
CloseHandle( info.hProcess );
return true;
}
You haven't noted if your "master" application here is using administrator or Standard User rights. Ideally it is using Standard User rights per the User Account Control guidelines dating back to Windows Vista. If your app is running as Standard User, then it's likely that your code no longer works due to security improvements to keep non-Administrator malware from doing this kind of thing to other processes.
For general appcompat questions about Windows 10, be sure to read the Windows and Windows Server compatibility cookbook and look back at the Windows 8.0 and Windows 8.1 material if you are jumping directly from Windows 7 to Windows 10.

C++: check if computer is locked

I'm trying to figure out whether the computer is locked.
I've looked at LockWorkStation function, but the function that I'm hoping to find is IsWorkStationLocked.
I need to support all windows version >= XP
For windows 7 and abowe WTS API can be used:
bool IsSessionLocked() {
typedef BOOL (PASCAL * WTSQuerySessionInformation)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR* ppBuffer, DWORD* pBytesReturned);
typedef void (PASCAL * WTSFreeMemory)( PVOID pMemory);
WTSINFOEXW * pInfo = NULL;
WTS_INFO_CLASS wtsic = DW_WTSSessionInfoEx;
bool bRet = false;
LPTSTR ppBuffer = NULL;
DWORD dwBytesReturned = 0;
LONG dwFlags = 0;
WTSQuerySessionInformation pWTSQuerySessionInformation = NULL;
WTSFreeMemory pWTSFreeMemory = NULL;
HMODULE hLib = LoadLibrary( _T("wtsapi32.dll") );
if (!hLib) {
return false;
}
pWTSQuerySessionInformation = (WTSQuerySessionInformation)GetProcAddress(hLib, "WTSQuerySessionInformationW" );
if (!pWTSQuerySessionInformation) {
goto EXIT;
}
pWTSFreeMemory = (WTSFreeMemory)GetProcAddress(hLib, "WTSFreeMemory" );
if (pWTSFreeMemory == NULL) {
goto EXIT;
}
if(pWTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, g_dwSessionID, wtsic, &ppBuffer, &dwBytesReturned)) {
if(dwBytesReturned > 0) {
pInfo = (WTSINFOEXW*)ppBuffer;
if (pInfo->Level == 1) {
dwFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
}
if (dwFlags == WTS_SESSIONSTATE_LOCK) {
bRet = true;
}
}
pWTSFreeMemory(ppBuffer);
ppBuffer = NULL;
}
EXIT:
if (hLib != NULL) {
FreeLibrary(hLib);
}
return bRet;
}
Please check following article for supported platforms for WTSINFOEX structure:
https://technet.microsoft.com/ru-ru/sysinternals/ee621017
From the same MSDN link you gave, the third paragraph of "Remarks" says:
This function has the same result as pressing Ctrl+Alt+Del and clicking Lock Workstation. To unlock the workstation, the user must log in. There is no function you can call to determine whether the workstation is locked. To receive notification when the user logs in, use the WTSRegisterSessionNotification function to receive WM_WTSSESSION_CHANGE messages. You can use session notifications to track the desktop state so you know whether it is possible to interact with the user.
Alex Vershynin's version works well, with a few code changes that I had to make.
I had to: change DW_WTSSessionInfoEx to WTSSessionInfoEx (Answering user586399), define "g_dwSessionID" to WTSGetActiveConsoleSessionId(), include Wtsapi32.h. I think that's it ...
Since I can't comment, I'll paste the whole code here.
#include "Wtsapi32.h"
bool IsSessionLocked()
{
typedef BOOL( PASCAL * WTSQuerySessionInformation )( HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR* ppBuffer, DWORD* pBytesReturned );
typedef void ( PASCAL * WTSFreeMemory )( PVOID pMemory );
WTSINFOEXW * pInfo = NULL;
WTS_INFO_CLASS wtsic = WTSSessionInfoEx;
bool bRet = false;
LPTSTR ppBuffer = NULL;
DWORD dwBytesReturned = 0;
LONG dwFlags = 0;
WTSQuerySessionInformation pWTSQuerySessionInformation = NULL;
WTSFreeMemory pWTSFreeMemory = NULL;
HMODULE hLib = LoadLibrary( "wtsapi32.dll" );
if( !hLib )
{
return false;
}
pWTSQuerySessionInformation = (WTSQuerySessionInformation) GetProcAddress( hLib, "WTSQuerySessionInformationW" );
if( pWTSQuerySessionInformation )
{
pWTSFreeMemory = (WTSFreeMemory) GetProcAddress( hLib, "WTSFreeMemory" );
if( pWTSFreeMemory != NULL )
{
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if( pWTSQuerySessionInformation( WTS_CURRENT_SERVER_HANDLE, dwSessionID, wtsic, &ppBuffer, &dwBytesReturned ) )
{
if( dwBytesReturned > 0 )
{
pInfo = (WTSINFOEXW*) ppBuffer;
if( pInfo->Level == 1 )
{
dwFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
}
if( dwFlags == WTS_SESSIONSTATE_LOCK )
{
bRet = true;
}
}
pWTSFreeMemory( ppBuffer );
ppBuffer = NULL;
}
}
}
if( hLib != NULL )
{
FreeLibrary( hLib );
}
return bRet;
}
Just as a refinement to MGamsby's post: if you are targeting the Win8.1 SDK or Win10 SDK, then it's not necessary to mess around with GetProcAddress(), LoadLibrary(), and WTSGetActiveConsoleSessionId(), and the code becomes much more compact:
bool isSessionLocked()
{
WTSINFOEXW* pInfo = NULL;
WTS_INFO_CLASS wtsic = WTSSessionInfoEx;
LPTSTR ppBuffer = NULL;
DWORD dwBytesReturned = 0;
LONG sessionFlags = WTS_SESSIONSTATE_UNKNOWN; // until we know otherwise. Prevents a false positive since WTS_SESSIONSTATE_LOCK == 0
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessionID, wtsic, &ppBuffer, &dwBytesReturned))
{
if (dwBytesReturned > 0)
{
pInfo = (WTSINFOEXW*)ppBuffer;
if (pInfo->Level == 1)
{
sessionFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
}
}
WTSFreeMemory(ppBuffer);
ppBuffer = NULL;
}
return (sessionFlags == WTS_SESSIONSTATE_LOCK);
}
NOTE:
I realise that the question is about Windows 7 but you can still target Win7 using the Win8.1 SDK, and it is available for use in VS2015 onwards.
Edit: Oops. I just realised the OP asked for WinXP onwards in which case, yes, you do need to mess around with LoadLibrary() etc. Sorry about that.
I'll leave my code here in case it is useful for anyone.
Apparently there is a difference between screen lock and session lock. Here're my investigations results.
A session becomes locked when a password box is shown on the lock screen. In Windows 7 after pressing Win+L lockscreen appears with password box, so a session is locked immediately. But in Win10/11 lockscreen initially appears without password box. And nothing happens. After pressing a key or clicking a mouse button, password box appears and session becomes locked.
WTSRegisterSessionNotification(): WM_WTSSESSION_CHANGE message arrives after password box is shown.
WTSQuerySessionInformation(): sessionFlags == WTS_SESSIONSTATE_LOCK after password box is shown
SetWinEventHook() with EVENT_SYSTEM_DESKTOPSWITCH: multiple events arrives when (un)locking. Looks like two desktops are created when locking: for initial lock screen and the one with password box.
SwitchDesktop() succeeds until password box is shown.
Checking for running LogonUI.exe works, but it remains running for a while after unlock. Theoretically in the future versions it may remain running permanently. So one can't be absolutely sure the session is locked if LogonUI.exe is running.
So far I haven't found a reliable way to check if computer is locked and unlocked. But I'll try to continue my research.

C++ Check if specific process is running

I have a C++ DLL that i am writing that needs to check if a particular process is running.
the dll will be launched application will be running in:
c:\Directory\application.exe
there is a subdirectory within that that has another executable in it:
c:\Directory\SubDirectory\application2.exe
What the DLL needs to do when it runs if check that application2.exe is running, most importantly that it is running within that folder -- there will be multiple copies running, so we need to ensure that the correct one is running.
I have the following code that is working well at detecting that the application2.exe is running, but it does not take the file path into consideration:
HANDLE pss = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(pe);
if (Process32First(pss, &pe))
{
do
{
if(wcscmp(pe.szExeFile, L"application2.exe") == 0)
{
CloseHandle(pss);
return (1);
}
}
while(Process32Next(pss, &pe));
}
CloseHandle(pss);
How can I check that the path of the process matches the path of the application which called the DLL?
Use WMI for this.
From the command line you can do:
wmic process where "executablepath = 'c:\path\to\executable.exe'" get ProcessId
You can use the WMI apis from C++ to do something similar.
http://www.codeproject.com/Articles/10539/Making-WMI-Queries-In-C
I have been given a solution that works for this, in case anyone else searching here it is:
HANDLE ProcessSnap;
PROCESSENTRY32 Pe32;
unsigned int LoopCounter = 0;
Pe32.dwSize = sizeof(PROCESSENTRY32);
ProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
Process32First(ProcessSnap, &Pe32);
wchar_t TermPath[MAX_PATH];
GetModuleFileName(NULL, TermPath, MAX_PATH);
wstring WTermPath(TermPath);
int index = WTermPath.find(L"\\application.exe");
wstring Path = WTermPath.substr(0, (index));
Path = Path + L"\\SubDirectory\\Application2.exe";
do
{
HANDLE Process;
wchar_t FilePath[MAX_PATH];
Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, Pe32.th32ProcessID);
if (Process)
{
GetModuleFileNameEx(Process, 0, FilePath, MAX_PATH);
wstring WFilePath(FilePath);
if(WFilePath == Path)
{
CloseHandle(ProcessSnap);
return (1);
}
CloseHandle(Process);
}
LoopCounter++;
} while (Process32Next(ProcessSnap, &Pe32));
CloseHandle(ProcessSnap);

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