Как определить, что приложение уже запущено или нет в windows с использованием C ++? - PullRequest
0 голосов
/ 29 января 2020

Я запускаю настольное приложение windows с помощью CATStartProcess (const char * comPath, char * const argv [], int wait, int * pid, int * exitStatus); Аргументы передаются ему. Если приложение уже запущено, мне не нужно создавать новый экземпляр для этого. Как я могу проверить, работает ли это приложение уже в фоновом режиме или нет?

    int wait = 0;   
    int pid;
    int exitStatus;
    char *CommandArgs[9] = { 0 };
    CommandArgs[0] = (char*)usComposerExePath.ConvertToChar();
    CommandArgs[1] = (char*)usOpen.ConvertToChar();
    CommandArgs[2] = (char*)usComposerProjectDocPath.ConvertToChar();
    CommandArgs[3] = (char*)strInfiniteTicket.ConvertToChar();
    CommandArgs[4] = (char*)strDocName.ConvertToChar();
    CommandArgs[5] = (char*)strSecurityContext.ConvertToChar();     
    CommandArgs[6] = (char*)usBusID.ConvertToChar();
    CommandArgs[7] = (char*)usUserID.ConvertToChar();
    CommandArgs[8] = NULL;

    CATLibStatus startComposerBatchStatus = CATStartProcess((char*)usComposerExePath.ConvertToChar(), CommandArgs, wait, &pid, &exitStatus);

1 Ответ

1 голос
/ 29 января 2020

Есть несколько способов, но я признаю, что ни одно из моих двух решений не является переносимым / стандартным 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";
...