Как я могу узнать, запущен ли другой экземпляр моей программы?

Попробуйте выставить некоторую часть палитры как свойство метки, а затем ее анимировать:

Q_PROPERTY(QColor color READ color WRITE setColor)

void MyLabel::setColor(const QColor &value) {
    QPalette palette;
    palette.setBrush(QPalette::WindowText, value);
    setPalette(palette);
}

QColor MyLabel::color() {
    return palette(QPalette::Normal, QPalette::Window).
}

void MyLabel::startFadeOutAnimation() {
    QPropertyAnimation *animation = new QPropertyAnimation(label, "color", this);
    QColor c = label->color();
    animation->setKeyValueAt(0, c);
    c.setAlpha(0);
    animation->setKeyValueAt(1, c);
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->setDuration(1000);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

Вы можете попытаться избежать подкласса путем определения и регистрации нового интерполятора, который будет обрабатывать QPalette qRegisterAnimationInterpolator , но это немного сложно.

29
задан Toby Allen 21 January 2013 в 23:41
поделиться

12 ответов

Вы можете создать семафор и остановить выполнение (поместить код в файл * .dpr) и вывести на экран запущенное приложение.

var
  Semafor: THandle;

begin
  { Don't start twice ... if already running bring this instance to front }
  Semafor := CreateSemaphore(nil, 0, 1, 'MY_APPLICATION_IS_RUNNING');
  if ((Semafor <> 0) and { application is already running }
     (GetLastError = ERROR_ALREADY_EXISTS)) then 
  begin
    RestoreWindow('TMyApplication');
    CloseHandle(Semafor);
    Halt;
  end;

  Application.CreateForm(....);    
  Application.Initialize;
  Application.Run;
  CloseHandle(Semafor);
end;

РЕДАКТИРОВАТЬ (добавлен метод RestoreWindow):

aFormName - это имя вашего основного класса формы в вашем приложении.

procedure RestoreWindow(aFormName: string);
var
  Wnd,
  App: HWND;    
begin
  Wnd := FindWindow(PChar(aFormName), nil);
  if (Wnd <> 0) then 
  begin { Set Window to foreground }
    App := GetWindowLong(Wnd, GWL_HWNDPARENT);
    if IsIconic(App) then 
      ShowWindow(App, SW_RESTORE);

    SetForegroundwindow(App);
  end;
end;
18
ответ дан kobik 21 January 2013 в 23:41
поделиться

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

-1
ответ дан ahanson 21 January 2013 в 23:41
поделиться

Если вы хотите остановить выполнение вашего приложения более одного раза в в одно и то же время (поместите код в файл *. Dpr ] проекта). отобразит сообщение после запуска второго приложения и мгновенно остановит его.

Forms,
  Unit1 in 'Unit1.pas' {Form1},
// add this units ....
TlHelp32,SysUtils,Windows,Dialogs;

{$R *.res}


function ProcessCount(const ExeName: String): Integer;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize:= SizeOf(FProcessEntry32);
  ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
  Result:= 0;
  while Integer(ContinueLoop) <> 0 do begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeName)) or (UpperCase(FProcessEntry32.szExeFile) =
      UpperCase(ExeName))) then Inc(Result);
    ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;


begin
  if ProcessCount(ExtractFileName(Application.ExeName)) > 1 then begin
    MessageDlg('Application is already running!', mtError, [mbOK], 0);
    Application.Terminate;
  end else begin

  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
  end;

end.
0
ответ дан Hamo Redone 21 January 2013 в 23:41
поделиться

См. Этот блок (с помощью CreateMutex): UiApp

Кроме того, на этой странице вы можете прочитать о преимуществах и недостатках этой работы с различными методами (mutex, FindWindows, ..). .).

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

С уважением и извините за мой плохой английский.


Нефтали-Герман Эстевес-

0
ответ дан Germán Estévez -Neftalí- 21 January 2013 в 23:41
поделиться

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

Однако, при использовании этой стратегии у вас есть другая проблема, что произойдет, если ваша программа потерпит крах? Файл блокировки все еще остается, и этот конкретный случай должен быть обработан.

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

Тем не менее, эта стратегия зависит от платформы, и реализация будет отличаться от платформы к платформе.

1
ответ дан 21 January 2013 в 23:41
поделиться

Управление количеством экземпляров приложения:

http://delphi.about.com/od/windowsshellapi/l/aa100703a.htm

1
ответ дан g2mk 21 January 2013 в 23:41
поделиться

Я хотел бы добавить один момент к превосходному ответу Роба Кеннеди (кроме того факта, что было бы лучше сделать функцию из его кода, а не копировать все в файл DPR Вам нужны только два параметра, имя мьютекса и логическое значение, должен ли мьютекст быть индивидуальным или общесистемным).

Ответ не уделяет особого внимания наименованию мьютекса. Если вы ожидаете, что ваша программа будет установлена ​​с помощью Inno Setup (и, возможно, других инструментов настройки), вы должны тщательно выбрать имя, так как мьютекс можно использовать, чтобы программа установки проверила, запущено ли приложение в данный момент, и предупредила они должны закрыть все экземпляры приложения. Если вы решите разрешить один экземпляр программы для каждого пользователя, вам может потребоваться также создать второй общесистемный мьютекс, поскольку для установки может не потребоваться никаких запущенных экземпляров приложения вообще , чтобы в состоянии заменить файлы. Имя, которое будет использоваться для синхронизации с установщиком InnoSetup, должно быть жестко запрограммировано.

2
ответ дан Community 21 January 2013 в 23:41
поделиться

Всемогущий JVCL имеет компонент для этой цели. Смотрите "TJvAppInstances".

17
ответ дан utku_karatas 21 January 2013 в 23:41
поделиться

Вы можете просто использовать функцию API окон FindWindow. В delphi имя класса окна совпадает с именем класса, вы можете переопределить имя класса, переопределив функцию CreateParams. Чтобы проверить, существует ли окно, добавьте код перед созданием главного окна, перед Application.Initialize;

Program test
var 
  handle :HWND;
begin
  handle := FindWindow('TMySuperApp', nil);

  if IsWindow(handle) then
  begin 
       //app is running
       exit;
  end.

  Application.Initialize;
  Application.CreateForm(TMySuperApp, SuperApp);
  Application.Run;
end;
1
ответ дан Edin Omeragic 21 January 2013 в 23:41
поделиться

Вы создаете систему мьютекс .

У меня нет кода Delphi, но вот код C ++:

HANDLE Mutex;

const char MutexName[] = "MyUniqueProgramName";

Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, MutexName);

if (Mutex)
     throw Exception("Program is already running.");
else
     Mutex = CreateMutex(NULL, true, MutexName);
6
ответ дан menjaraz 21 January 2013 в 23:41
поделиться

Нормальным решением является создание именованного общесистемного мьютекса .

  • Если вам удастся создать его, то вы одно из запущенных приложений.
  • Если нет, то знаешь, что есть другой.

РЕДАКТИРОВАТЬ:

Я не предоставил код, поскольку я не знаю Delphi. Я могу предоставить код C #, если это будет полезно.

5
ответ дан menjaraz 21 January 2013 в 23:41
поделиться

Как впервые предположил Джон, вы можете попробовать создать мьютекс. Звоните CreateMutex . Если вы получите ненулевой дескриптор, позвоните GetLastError . Он скажет вам, был ли вы тем, кто создал мьютекс, или мьютекс уже был открыт ранее (Error_Already_Exists). Обратите внимание, что не необходимо приобретать право собственности на мьютекс. Мьютекс не используется для взаимного исключения. Он используется, потому что это именованный объект ядра. Событие или семафор тоже могут сработать.

Техника мьютекса дает логический ответ: да, есть другой экземпляр, или нет, нет.

Вы часто хотите знать больше, чем просто это. Например, вы можете захотеть узнать дескриптор главного окна другого экземпляра, чтобы вы могли указать, чтобы он вышел на передний план вместо вашего другого экземпляра. Вот где файл с отображением в памяти может пригодиться; он может содержать информацию о первом экземпляре, чтобы более поздние экземпляры могли ссылаться на него.

Будьте осторожны при выборе названия мьютекса. Внимательно прочитайте документацию и помните, что некоторые символы (например, обратная косая черта) недопустимы в некоторых версиях ОС, но необходимы для определенных функций в других версиях ОС.

Также помните о проблеме других пользователей. Если ваша программа может быть запущена через удаленный рабочий стол или с помощью быстрого переключения пользователей, то могут быть другие пользователи, уже запускающие вашу программу, и вы, возможно, не захотите ограничивать текущий запуск программы вашим пользователем. В этом случае не используйте глобальное имя. Если вы действительно хотите ограничить доступ для всех пользователей, то убедитесь, что атрибуты безопасности объекта мьютекса таковы, что каждый сможет открыть для него дескриптор. Использование нулевого указателя для параметра lpSecurityAttributes недостаточно для этого; «дескриптор безопасности по умолчанию», который упоминает MSDN, предоставляет полный доступ текущему пользователю и не дает доступа другим.

Вам разрешено редактировать файл DPR вашей программы. Обычно это хорошее место для подобных вещей. Если вы подождете до события OnCreate одной из ваших форм, то ваша программа уже наберет импульс для нормального запуска, поэтому неуместно пытаться завершить программу в этот момент. Лучше прекратить работу до того, как будет выполнена слишком большая работа с пользовательским интерфейсом Например:

var
  mutex: THandle;
  mutexName: string;
begin
  mutexName := ConstructMutexName();

  mutex := CreateMutex(nil, False, PChar(mutexName));

  if mutex = 0 then
    RaiseLastOSError; // Couldn't open handle at all.

  if GetLastError = Error_Already_Exists then begin
    // We are not the first instance.
    SendDataToPreviousInstance(...);
    exit;
  end;
  // We are the first instance.

  // Do NOT close the mutex handle here. It must
  // remain open for the duration of your program,
  // or else later instances won't be able to
  // detect this instance.

  Application.Initialize;
  Application.CreateForm(...);
  Application.Run;
end.

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

Но вы все равно можете закрыть ручку. Предположим, вы решили реализовать функцию SendDataToPreviousInstance, о которой я упоминал в коде. Если вы хотите стать модным, то вы можете учесть, что предыдущий экземпляр уже закрывается и не может принять новые данные. Тогда вам не захочется закрывать второй экземпляр. Первый экземпляр может закрыть дескриптор мьютекса, как только узнает, что завершает работу, и фактически становится экземпляром «хромой утки». Второй экземпляр попытается создать дескриптор мьютекса, преуспеть и считать себя настоящим первым экземпляром. Предыдущий экземпляр будет закрыт непрерывно. Используйте CloseHandle, чтобы закрыть мьютекс; вызывайте его из обработчика событий вашей основной формы OnClose или откуда угодно, например, Application.Terminate.

39
ответ дан menjaraz 21 January 2013 в 23:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: