Помощь - Поиск - Пользователи - Календарь
Полная версия: Отслеживание двойного запуска
Форум «Всё о Паскале» > Delphi, Assembler и другие языки. > Delphi
Unconnected
Нужно встроить в программу проверку, не запущена ли уже эта её копия. В гугле это есть, но.. осложняется тем, что теоретический дабл-запуск будет как бы фор-кликом, то есть мгновенно после первого запуска. И видимой формы тоже нет..
IUnknown
Цитата
осложняется тем, что теоретический дабл-запуск будет как бы фор-кликом, то есть мгновенно после первого запуска.
И что? CreateMutex - атомарная операция. Первый из тех, кто вызовет эту функцию получит хэндл мьютекса, второй (пускай даже на следующем такте процессора) - уже поймает ERROR_ALREADY_EXISTS.
Unconnected
var

f_m: THandle; // mutex
begin
f_m := CreateMutex(nil, true, srMutexName);
if ( (ERROR_ALREADY_EXISTS = GetLastError()) or (ERROR_ACCESS_DENIED = GetLastError()) ) then begin
if (0 <> f_m) then CloseHandle(f_m);
MessageBox('Another instance is already running');
end
else try
Application.Initialize;
...
Application.Run;
finally
CloseHandle(f_m);
end;
end.


Нашёл такой код (это в .dpr), нормальный? Мессадж что-то не вылетает.
IUnknown
Цитата
Мессадж что-то не вылетает.


program Project1;

{$APPTYPE CONSOLE}

uses
Windows, SysUtils;

const
srMutexName = 'VOLVO_APP_VERY_LONG_ID_STRING'; // Тут на самом деле была еще пара десятков цифр

var
f_m: THandle; // mutex
begin
f_m := CreateMutex(nil, true, srMutexName);
if ( (ERROR_ALREADY_EXISTS = GetLastError()) or (ERROR_ACCESS_DENIED = GetLastError()) ) then begin
if (0 <> f_m) then CloseHandle(f_m);
MessageBox(0, 'Another instance is already running', 'Error', MB_OK);
end
else try
MessageBox(0, 'test', 'test', MB_OK);
//Application.Initialize;
// ...
//Application.Run;
finally
CloseHandle(f_m);
end;
end.

Вылетает сообщение о том, что приложение уже запущено, при Quad-клике... А вот насчет необходимости ERROR_ACCESS_DENIED я бы поспорил... Если у тебя нет доступа к мьютексу - значит, у тебя и на его установку нет доступа, ты можешь и при запуске первой копии нарваться на сообщение, что "уже запущено"...
IUnknown
Кстати, тут у тебя еще есть неприятные мелочи, которые могут сильно осложнить тебе жизнь:

1)
  f_m := CreateMutex(nil, true, srMutexName);
if ( (ERROR_ALREADY_EXISTS = GetLastError()) or (ERROR_ACCESS_DENIED = GetLastError()) ) then begin
Я бы поменял проверки местами: то есть, сначала убедись, что CreateMutex вернула не NULL, и только потом проверяй, а что за ошибка? Если ERROR_ALREADY_EXISTS (ну, и ERROR_ACCESS_DENIED тоже можешь сюда включить) - то все нормально, мьютекс просто уже существует... Кстати, зачем ты его при этом удаляешь - не понятно. Если он есть - то удалить его может только владелец, кто ж тебе даст другому приложению удалить объект ядра? Проблемы что-ли нужны? 64-битные ОСи таких ошибок не прощают smile.gif Это тебе не старая добрая WinXP 32 bit...

2) даже если и даст - мьютекс не удаляется через CloseHandle... Специально была придумана ReleaseMutex... То есть, во втором чтении код принимает вид:

uses
Windows, SysUtils;
const
srMutexName = 'VOLVO_APP_VERY_LONG_ID_STRING'; // Тут на самом деле была еще пара десятков цифр
var
f_m: THandle; // mutex
begin
f_m := CreateMutex(nil, true, srMutexName);

if (f_m <> 0) then
begin
if (GetLastError() = ERROR_ALREADY_EXISTS) or (GetLastError() = ERROR_ACCESS_DENIED) then
begin
MessageBox(0, 'Another instance is already running', 'Error', MB_OK);
end
else
try
MessageBox(0, 'test', 'test', MB_OK);
//Application.Initialize;
// ...
//Application.Run;
finally
ReleaseMutex(f_m);
end;
end
else
MessageBox(0, 'CreateMutex = NULL', 'Error', MB_OK); // А вот это уже странно...
end.

(не надо этих Сишных заморочек с константой слева/именем функции справа. Это в случае Дельфи бесполезно)
Unconnected
Угу, спасибо, все сделал по рекомендациям, работает) Правда, не в .dpr, а прямо в коде, там такая специфика.. А что за заморочка с константой\именем? Я сначала думал, что у автора стиль такой написания, да и f_m не константа вовсе..
Блин, меня постоянно пугает, что на одной машине прога работает, а на другой с такой же осью - не будет, или будет как-то непонятно, и непонятно что с исключениями делать зачастую..(
IUnknown
Цитата
А что за заморочка с константой\именем? Я сначала думал, что у автора стиль такой написания
Этот "стиль" пришел из Си... Ибо если напишешь так:

if (f_m = 0)
{
//
}
(пропустишь второй знак равенства), то присвоишь f_m значение ноль, и этим дело закончится. Программа будет компилироваться (кто ж на предупреждения внимание обращает, да они и отключены у многих, стоит ли после этого удивляться, что "90% кода в интернете - ...", ну, ты помнишь), но работать не будет, разумеется. Поэтому пишут так:

if (0 == f_m)
{
//
}
. если здесь упустить один из знаков равенства - то ты уже нарушаешь синтаксис: присвоить значение числовой константе нельзя, компилятор сразу "встанет на дыбы". В языках с Паскалевским синтаксисом это лишено смысла: компилятор так или иначе поднимет тревогу, если ты вместо "=" где-нибудь напишешь ":=", или наоборот...

Цитата
Блин, меня постоянно пугает, что на одной машине прога работает, а на другой с такой же осью - не будет, или будет как-то непонятно
Еще раз: для того, чтобы программа работала одинаково на разных компьютерах (возможно даже с разными ОСями) - нужно очень немного: всего-навсего программа должна быть написана корректно. Особенно это касается IA64. Если какие-то шероховатости на i386 тебе прощались - то 64 битная архитектура за них жестоко наказывает: Неинициализированный мусор на ia64 может быть смертелен как пример...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.