Нужно встроить в программу проверку, не запущена ли уже эта её копия. В гугле это есть, но.. осложняется тем, что теоретический дабл-запуск будет как бы фор-кликом, то есть мгновенно после первого запуска. И видимой формы тоже нет..
IUnknown
25.06.2011 14:49
Цитата
осложняется тем, что теоретический дабл-запуск будет как бы фор-кликом, то есть мгновенно после первого запуска.
И что? CreateMutex - атомарная операция. Первый из тех, кто вызовет эту функцию получит хэндл мьютекса, второй (пускай даже на следующем такте процессора) - уже поймает ERROR_ALREADY_EXISTS.
Unconnected
26.06.2011 3:13
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
26.06.2011 3:37
Цитата
Мессадж что-то не вылетает.
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
26.06.2011 5:17
Кстати, тут у тебя еще есть неприятные мелочи, которые могут сильно осложнить тебе жизнь:
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-битные ОСи таких ошибок не прощают Это тебе не старая добрая 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
26.06.2011 7:14
Угу, спасибо, все сделал по рекомендациям, работает) Правда, не в .dpr, а прямо в коде, там такая специфика.. А что за заморочка с константой\именем? Я сначала думал, что у автора стиль такой написания, да и f_m не константа вовсе.. Блин, меня постоянно пугает, что на одной машине прога работает, а на другой с такой же осью - не будет, или будет как-то непонятно, и непонятно что с исключениями делать зачастую..(
IUnknown
26.06.2011 12:34
Цитата
А что за заморочка с константой\именем? Я сначала думал, что у автора стиль такой написания
Этот "стиль" пришел из Си... Ибо если напишешь так:
if (f_m = 0) { // }
(пропустишь второй знак равенства), то присвоишь f_m значение ноль, и этим дело закончится. Программа будет компилироваться (кто ж на предупреждения внимание обращает, да они и отключены у многих, стоит ли после этого удивляться, что "90% кода в интернете - ...", ну, ты помнишь), но работать не будет, разумеется. Поэтому пишут так:
if (0 == f_m) { // }
. если здесь упустить один из знаков равенства - то ты уже нарушаешь синтаксис: присвоить значение числовой константе нельзя, компилятор сразу "встанет на дыбы". В языках с Паскалевским синтаксисом это лишено смысла: компилятор так или иначе поднимет тревогу, если ты вместо "=" где-нибудь напишешь ":=", или наоборот...
Цитата
Блин, меня постоянно пугает, что на одной машине прога работает, а на другой с такой же осью - не будет, или будет как-то непонятно
Еще раз: для того, чтобы программа работала одинаково на разных компьютерах (возможно даже с разными ОСями) - нужно очень немного: всего-навсего программа должна быть написана корректно. Особенно это касается IA64. Если какие-то шероховатости на i386 тебе прощались - то 64 битная архитектура за них жестоко наказывает: Неинициализированный мусор на ia64 может быть смертелен как пример...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.