Как узнать, является ли данное приложение одним экземпляром или нет? - PullRequest
2 голосов
/ 29 июня 2011

Я ищу эффективный способ узнать, является ли данное приложение (скажем, app.exe) единичным экземпляром или нет? Я думал об этих следующих золях:

  1. Выполните ли дважды CreateProcess () и проверьте, запущены ли два или более экземпляра этого приложения? Если нет, то это приложение с одним экземпляром. Но это не эффективно.
  2. Сделайте CreateProcess () и подождите 1-2 секунды. Если этот экземпляр уничтожен (поскольку для него уже запущен экземпляр), это будет приложение с одним экземпляром.

Но я не убежден в обоих вышеупомянутых золях. Есть ли другой эффективный способ сделать это в Windows?

Обратите внимание, что я не убиваю и не изменяю уже запущенный (если есть) экземпляр этого приложения.

Ответы [ 6 ]

7 голосов
/ 12 ноября 2011

Подумайте об этом по-другому: когда вы пишете программу, как вы определяете, является ли она единичным или множественным экземпляром?Есть ли способ, чтобы какая-то другая программа могла получить эту информацию из вашей программы без ее запуска?(После того, как вы ответите на этот вопрос, у вас будет ответ на ваш вопрос.)

Эта проблема, в общем, не решаема, поскольку один экземпляр / несколько экземпляров определяется во время выполнения и может основываться на времени выполненияусловия.Например, некоторые приложения «иногда несколько экземпляров, иногда одиночные»: если вы запустите приложение, чтобы открыть документ X, а затем документ Y, вы получите два экземпляра.Но если вы откроете документ X, а затем снова документ X, эти два экземпляра сложатся в один.Другие приложения могут иметь переключатель конфигурации, который позволяет вам выбирать, являются ли они одним экземпляром или несколькими.Или, может быть, они решают подбросить монету и решают быть одним экземпляром, если хвосты, и несколькими экземплярами, если голова.

1 голос
/ 12 ноября 2011

Нет никакого способа сделать это вообще. Что произойдет, если приложение проверит мьютекс, а затем создаст окно сообщения, чтобы сообщить пользователю, что экземпляр уже запущен, и только когда пользователь отклоняет его, он убивает приложение? Есть много разных способов обеспечить взаимное исключение через некоторый общий ресурс, мьютекс, общий файл, даже, возможно, установив какой-то раздел реестра, методы не ограничены.

1 голос
/ 12 ноября 2011

Лучший способ - использовать объект синхронизации, называемый Mutex (взаимоисключающий).Вы можете погуглить это.Я думаю, что следующий код может помочь.

//---------------------------------------------------------------------------
WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
    try
    {
        HANDLE hMutex=OpenMutex(MUTEX_ALL_ACCESS,0,"SIns");
        if (!hMutex) {
            //Mutex doesn’t exist. This is the first instance so create the mutex.
            //in this case app name is SIns (Single Instance)
            hMutex=CreateMutex(0,0,"SIns");
            Application->Initialize();
            Application->MainFormOnTaskBar = true;
            Application->CreateForm(__classid(TfMain), &fMain);
            Application->Run();
            ReleaseMutex(hMutex);
        }
        else{
            //This is not single. The prev instance is already running 
            //so informing about it 
            //remember that if it finds prev instance we're activating it here
            //you may do whatsoever here ...... e.g. you may kill process or stuff like this:)
            ShowMessage("The program is already running. Switching to ...");
            HWND hWnd=FindWindow(0,"SIns");
            SetForegroundWindow(hWnd);
        }

    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    catch (...)
    {
        try
        {
            throw Exception("");
        }
        catch (Exception &exception)
        {
            Application->ShowException(&exception);
        }
    }
    return 0;
}
//---------------------------------------------------------------------------
0 голосов
/ 29 июня 2011

Проблема в том, что в обычных средах нет явных статических данных, определяющих, является ли приложение единичным экземпляром. У вас есть только поведение, но вы не можете полностью проверить поведение.

Что, если у вас есть приложение, которое имеет несколько экземпляров, но не сможет открыть файл, который уже открыт? Если вы дважды протестируете его с одним и тем же допустимым именем файла, это создаст только один процесс, но любой другой аргумент командной строки вызовет существование двух процессов. Это программа для одного экземпляра?

По этой причине вы даже можете утверждать, что «один экземпляр» не является четко определенной категорией программ.

0 голосов
/ 29 июня 2011

Вы можете использовать мьютексы ... Я делаю такую ​​проверку с помощью следующего кода:

bool insureApplicationUniqueness(HANDLE& mutexHandle)
{
    mutexHandle=CreateMutexW(NULL,true,UNIQUE_INSTANCE_MUTEX_NAME);
    if( mutexHandle&&(ERROR_ALREADY_EXISTS==GetLastError()))
    {
        CloseHandle(mutexHandle);
        return false;
    }
    return true;
}

но это для приложения, исходный код которого принадлежит вам, и который проверяет другой запущенный экземпляр.

0 голосов
/ 29 июня 2011

Обычное решение - использовать какой-нибудь файл блокировки.Например, в традиционном Unix приложение запустится, создав файл (который удастся выполнить, даже если файл существует), затем попытается создать ссылку на него (атомарное действие);если это не удастся, приложение немедленно убьет себя.В Windows режим общего доступа CreateFile можно использовать для того же эффекта: открыть файл с режимом общего доступа 0 и, если это не удастся, выйти.(Решение Unix оставит блокировку в случае сбоя процесса, что потребует его очистки вручную. Решение Windows удалит блокировку в случае сбоя системы.)

...