Как определить, что приложение уже запущено?
Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду
Здравствуйте!
Не подскажете, как из Delphi-йной программы можно определить, что другая копия этой программы на данном компьютере уже запущена?
Попытался использовать функция FindWindow (как это делается в "клссических" примерах по Си). Делал вызов этой функции сразу после begin (т.е. даже ДО Application.Initialize), указав в качестве имени класса окна имя формы приложения (здесь трудностей не было, имя класса "подсмотрел" через микрософтовский Spy). Но функция "ответила", что такое окно уже существует! Откуда сделал вывод, что "где-то там, внутри" окно уже существует, и приложение нашло "само себя"...
Заранее спасибо.
Не подскажете, как из Delphi-йной программы можно определить, что другая копия этой программы на данном компьютере уже запущена?
Попытался использовать функция FindWindow (как это делается в "клссических" примерах по Си). Делал вызов этой функции сразу после begin (т.е. даже ДО Application.Initialize), указав в качестве имени класса окна имя формы приложения (здесь трудностей не было, имя класса "подсмотрел" через микрософтовский Spy). Но функция "ответила", что такое окно уже существует! Откуда сделал вывод, что "где-то там, внутри" окно уже существует, и приложение нашло "само себя"...
Заранее спасибо.
Код: Выделить всё
program Project1;
uses
Forms,
Windows,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
var
hwnd: THandle;
begin
hwnd := FindWindow('TForm1', 'Form1');
if hwnd = 0 then
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
SetForegroundWindow(hwnd)
end.
Duncon, спасибо. Но ты уверен, что ЭТО работает?
Ранее я практически именно так и делаел, лишь вторым параметром в FindWindow передавал NIL (в Си я поступал так же).
Попробовал указывать и второй параметр (как в твоем примере).
Я так понял, что туда ты передавал атрибут Caption, указанный в свойствах формы (у меня заголовок окна изменен со стандартного - в твоем примере "Form1" на другой - "Кандидаты").
Результат - тот же самый. FindWindow возвращает НЕНУЛЕВОЕ значение.
Пробовал даже вынести вызов FindWindow в отдельный unit, в инициализационную часть и подключить этот Unit в списке uses ДО Forms, предположив, что так проверка вызовется до инициализации unit-а Forms. Но не помогло. Все равно FindWindow что-то находит.
Ранее я практически именно так и делаел, лишь вторым параметром в FindWindow передавал NIL (в Си я поступал так же).
Попробовал указывать и второй параметр (как в твоем примере).
Я так понял, что туда ты передавал атрибут Caption, указанный в свойствах формы (у меня заголовок окна изменен со стандартного - в твоем примере "Form1" на другой - "Кандидаты").
Результат - тот же самый. FindWindow возвращает НЕНУЛЕВОЕ значение.
Пробовал даже вынести вызов FindWindow в отдельный unit, в инициализационную часть и подключить этот Unit в списке uses ДО Forms, предположив, что так проверка вызовется до инициализации unit-а Forms. Но не помогло. Все равно FindWindow что-то находит.

-
- Сообщения: 273
- Зарегистрирован: 30 июн 2005, 14:53
Duncon писал(а):Код: Выделить всё
program Project1][/quote] не сработает если резко запустить 2 раза
- Чем юзер похож на обезьяну?
- Он жмет на все, что жмется, дергает все, что дергается и крутит все, что крутится.
- Чем юзер отличается от обезьяны?
- У обезьяны хватает ума не воспроизводить ту последовательность, которая приводит к краху системы.
- Он жмет на все, что жмется, дергает все, что дергается и крутит все, что крутится.
- Чем юзер отличается от обезьяны?
- У обезьяны хватает ума не воспроизводить ту последовательность, которая приводит к краху системы.
Обычно для этой цели используют мьютекс или др.объекты синхронизации.
См. пример: http://www.akzhan.midi.ru/win32api/26.htm
См. пример: http://www.akzhan.midi.ru/win32api/26.htm
Вот еще вариант
Или у кого притензии может вам так проще будет....
Код: Выделить всё
begin
if HPrevInst <>0 then
begin
ActivatePreviousInstance;
Halt;
end;
end;
Код: Выделить всё
unit FirstHinstanceRunning;
interface
uses
Windows,
Forms,
StrUtils,
SysUtils;
function FirstHinstanceRunning(RunMode: Integer = 0): boolean;
implementation
function FirstHinstanceRunning(RunMode: Integer = 0): boolean;
const
MemFileSize = 127;
var
MemHnd: HWND;
MemFileName: string;
lpBaseAddress: ^HWND;
FirstAppHandle: HWND;
begin
Result := False;
MemFileName := Application.ExeName;
case RunMode of
0:
MemFileName := AnsiReplaceText(MemFileName, '\', '/');
1:
MemFileName := ExtractFileName(MemFileName);
else
Exit;
end;
//если FileMapping есть - то происходит OpenFileMapping
MemHnd := CreateFileMapping(HWND($FFFFFFFF), nil,
PAGE_READWRITE, 0, MemFileSize, PChar(MemFileName));
if GetLastError <> ERROR_ALREADY_EXISTS then
begin
if MemHnd <> 0 then
begin
lpBaseAddress := MapViewOfFile(MemHnd, FILE_MAP_WRITE, 0, 0, 0);
if lpBaseAddress <> nil then
lpBaseAddress^ := Application.Handle;
end;
end
else
begin
// MemFileHnd := OpenFileMapping(FILE_MAP_READ, False, PChar(MemFileName));
Result := True;
if MemHnd <> 0 then
begin
lpBaseAddress := MapViewOfFile(MemHnd, FILE_MAP_READ, 0, 0, 0);
if lpBaseAddress <> nil then
begin
FirstAppHandle := lpBaseAddress^;
ShowWindow(FirstAppHandle, SW_restore);
SetForegroundWindow(FirstAppHandle);
end;
end;
end;
if lpBaseAddress <> nil then
UnMapViewOfFile(lpBaseAddress);
end;
В тексте проекта * .dpr вызов функции выглядит приблизительно следующим образом
program OneHinstance;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
FirstHinstanceRunning in '..\..\FirstHinstanceRunning.pas';
{$R *.res}
begin
Application.Initialize;
if FirstHinstanceRunning(0) then
Exit;
Application.CreateForm(TForm1, Form1);
Application.Run;
// CloseHandle(MemHnd);
end.
FindWindow "всегда" находит окно, только когда приложение запущено в дизайн-тайм (под оболочкой дельфы), потому что в оболочке существует окно с тем же классом и заголовком.
Попробуй закрыть проект и запустить exe, тогда все будет работать как положено
Попробуй закрыть проект и запустить exe, тогда все будет работать как положено

С уважением, Lost Angel...
У меня такой вопрос - мне надо считать, сколько приложений запущено.
Я вижу вариант c map файлом: создавать его на 4 байта больше и в них записывать 1. В другом экземпляре при открытии мэп-файла, увеличивать счетчик на 1, а при завершении программы его уменьшать.
Вопрос такой: может есть какой-нибудь объект синхронизации, автоматически поддерживающий счет?
Я вижу вариант c map файлом: создавать его на 4 байта больше и в них записывать 1. В другом экземпляре при открытии мэп-файла, увеличивать счетчик на 1, а при завершении программы его уменьшать.
Вопрос такой: может есть какой-нибудь объект синхронизации, автоматически поддерживающий счет?
Автоматически счет поддерживают семафоры, но не в том смысле, как надо для ваших целей.
Mapping - неплохой вариант.
Mapping - неплохой вариант.