Есть несколько способов, но я признаю, что ни одно из моих двух решений не является переносимым / стандартным C ++, но вы пометили Windows, поэтому я дам метод Windows.
код ниже фактически выполняет обе проверки. Первый способ - использовать именованный мьютекс. Windows имеет "Глобальный" мьютекс, который проверяет запущенные процессы любым пользователем. Если мьютекс уже существует, то он работает. Если его не существует, значит, он не работает. Есть некоторые состояния, где вещи не могут быть легко определены, поэтому он проверяет список запущенных процессов. Эта часть менее точна, поскольку различные разрешения влияют на список.
Часть с мьютексами будет работать только в том случае, если вы сможете изменить приложение, которое вы пытаетесь запустить, так, чтобы оно создавало мьютекс.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <psapi.h>
#include <TlHelp32.h>
#include <shellapi.h>
#include <advpub.h>
enum class ProcessRunningState {
YES,
NO,
ERR
};
ProcessRunningState CheckIfProcessIsAlreadyRunning( DWORD currentProcessId, const wchar_t *programName, const wchar_t *programGUID, HANDLE *mutex_handle ) noexcept {
{ // Check the mutexes first
wchar_t global_prog_name[1024] = L"Global\\";
wcsncat_s( global_prog_name, programName, wcslen( programGUID ) );
if ( mutex_handle ) {
*mutex_handle = CreateMutex( NULL, TRUE, global_prog_name );
if ( !( *mutex_handle ) ) {
const DWORD dw = GetLastError();
if ( dw == ERROR_ALREADY_EXISTS )
return ProcessRunningState::YES;
} else {
return ProcessRunningState::NO;
}
} else {
HANDLE h = OpenMutex( SYNCHRONIZE, FALSE, global_prog_name );
if ( h ) {
CloseHandle( h );
return ProcessRunningState::YES;
} else if ( GetLastError() == ERROR_FILE_NOT_FOUND ) {
return ProcessRunningState::NO;
}
}
}
{ // At this point, the state is unknown, so try running through the process list
DWORD aProcesses[2048], cProcesses;
if ( !EnumProcesses( aProcesses, sizeof( aProcesses ), &cProcesses ) ) {
return ProcessRunningState::ERR;
}
// Calculate how many process identifiers were returned.
cProcesses = cProcesses / sizeof( DWORD );
for ( unsigned int i = 0; i < cProcesses; i++ ) {
if ( aProcesses[i] != 0 && aProcesses[i] != currentProcessId ) {
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
WCHAR szProcessName[MAX_PATH] = { 0 };
if ( hProcess ) {
HMODULE hMod;
DWORD cbNeeded;
if ( EnumProcessModules( hProcess, &hMod, sizeof( hMod ), &cbNeeded ) ) {
GetModuleBaseName( hProcess, hMod, szProcessName, sizeof( szProcessName ) / sizeof( TCHAR ) ); // Can't error here, since this function "errors" on access
}/* else {
return ProcessRunningState::ERR;
}*/
CloseHandle( hProcess );
}
if ( _wcsicmp( szProcessName, programName ) == 0 ) {
return ProcessRunningState::YES;
}
}
}
}
return ProcessRunningState::NO;
}
Если он называется так, то, если возможно, будет создан мьютекс, и, в основном, он говорит: «Я хочу бежать, не так ли?» если нет, запускает приложение.
if ( CheckIfProcessIsAlreadyRunning( GetCurrentProcessId(), L"PROGRAM_NAME", programGUID, nullptr ) == ProcessRunningState::NO ) {
std::wstring programInstallLocation = L"path";
std::wstring programName = programInstallLocation + L"\\PROGRAM_NAME";
ShellExecute( NULL, L"open", programName.c_str(), NULL, NULL, SW_SHOW );
}
И где-то в вашем коде вы бы указали, что такое programGUID
. Например:
WCHAR programGUID[] = L"ba2e95a0-9168-4b6e-bcd6-57309748df21";