Запрет работы нескольких копий программы
Программа работает в скрытом режиме (никаких окон, иконок в трее, только процесс в диспетчере задач). А когда запускаешь ее снова, то вместо запуска второй копии программы, скрытая показывает окно с которым и можно работать.
Т.е. нужно запретить запуск нескольких копий программы и обеспечить взаимодействие "запускаемой" и работающей.
Хочу так: :)
Программа работает в скрытом режиме (никаких окон, иконок в трее, только процесс в диспетчере задач). А когда запускаешь ее снова, то вместо запуска второй копии программы, скрытая показывает окно с которым и можно работать.
Т.е. нужно запретить запуск нескольких копий программы и обеспечить взаимодействие "запускаемой" и работающей.
Ну, хочешь. И что? Ты просто решил об этом рассказать?=)
{
HANDLE Test_Present = CreateMutex(NULL,false,"My_Program_Already_Present");
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(0,"Программа уже запущена",NULL,MB_OK);
return 0;
};
CloseHandle(Test_Present);
return 0;
}
Ну, хочешь. И что? Ты просто решил об этом рассказать?=)
гы. Да вот решил поделиться :)
Спасибо. А я все думал, для чего эти мутексы?
А как работающий процесс узнает том, что другую копию пытались запустить?
гы. Да вот решил поделиться :)
Спасибо. А я все думал, для чего эти мутексы?
А как работающий процесс узнает том, что другую копию пытались запустить?
Mutex объявляется глобально, два одинаковых создать нельзя. Вот так. Если приглядеться к коду, то ты увидишь что если последняя ошибка ОШИБКА_УЖЕ_ЕСТЬ, то выдается сообщение, что программв уже запущена.
Mutex объявляется глобально, два одинаковых создать нельзя. Вот так. Если приглядеться к коду, то ты увидишь что если последняя ошибка ОШИБКА_УЖЕ_ЕСТЬ, то выдается сообщение, что программв уже запущена.
То-ли я чего-то не понял, то-ли ты меня непонял.
Повторно запускаемая копия узнает, что приложение уже запущено. Это ясно. А наоборот как? Т.е. сделать, чтобы уже находящийся в памяти и работающий процесс узнал о попытке повторного запуска.
Т.е. сделать, чтобы уже находящийся в памяти и работающий процесс узнал о попытке повторного запуска.
Можно использовать событие.
Программа при запуске могла бы попытаться открыть конкретное событие, если оно есть, значит это вторая копия. Совсем упрощенно
BOOL bRun = TRUE;
DWORD WINAPI myFunc(LPVOID)
{
while(bRun==TRUE)
{
WaitForSingleObject(hEvent, INFINITE);
AfxMessageBox("Event fired!");
ResetEvent(hEvent);
}
return 0;
}
//при запуске
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("My_Event"));
if(hEvent==NULL) //первая копия
{
hEvent = CreateEvent(NULL, FALSE, FALSE, _T("My_Event"));
DWORD threadID;
CreateThread(NULL, 0, myFunc, NULL, 0, &threadID);
}
else // запуск второй копии
{
SetEvent(hEvent); // сообщение
CloseHandle(hEvent);
return 0;
}
И еще такая просьба. Не мог бы ты описать значения параметров CreateMutex. Потому как я понял только значение третьего :) У меня есть MSDN, но туго с английским.
LPSECURITY_ATTRIBUTES lpMutexAttributes, // указатель на структуру с атрибутами безопасности
BOOL bInitialOwner, // кажется, наличие зозяина у мутекса
LPCTSTR lpName // указатель на имя.
);
Если у твоей программы есть окно - находишь его (при повторном запуске) FindWindow и посылаешь (SendMessage) экзотическое сообщение с экзотическими параметрами. Если программа его ловит - выскакивает на передний план, скажем. Вот.
Если у твоей программы есть окно - находишь его (при повторном запуске) FindWindow и посылаешь (SendMessage) экзотическое сообщение с экзотическими параметрами. Если программа его ловит - выскакивает на передний план, скажем. Вот.
Блин. Спасибо. Сам бы не догнал :)
Блин. Спасибо. Сам бы не догнал :)
Оффтоп: Ты это сказал с иронией?
Оффтоп: Ты это сказал с иронией?
Роль mutex гораздо больше в многозадачном/многопоточном программировании.
И вообще, насколько помню, в Win3.1 второй параметр WinMain передавал HINSTANCE предыдущей копии процесса. Может, оно как-то и работает еще (хотя, где-то опять же читал, что параметр устарел, но это относилось к win95).
Оффтоп: Ты это сказал с иронией?
Ничего не понял. Вообще-то я смеюсь над собой :)
Можно использовать событие.
Программа при запуске могла бы попытаться открыть конкретное событие, если оно есть, значит это вторая копия. Совсем упрощенно
BOOL bRun = TRUE;
DWORD WINAPI myFunc(LPVOID)
{
while(bRun==TRUE)
{
WaitForSingleObject(hEvent, INFINITE);
AfxMessageBox("Event fired!");
ResetEvent(hEvent);
}
return 0;
}
//при запуске
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("My_Event"));
if(hEvent==NULL) //первая копия
{
hEvent = CreateEvent(NULL, FALSE, FALSE, _T("My_Event"));
DWORD threadID;
CreateThread(NULL, 0, myFunc, NULL, 0, &threadID);
}
else // запуск второй копии
{
SetEvent(hEvent); // сообщение
CloseHandle(hEvent);
return 0;
}
Как я понял созданый поток, в данном примере, будет ждать события и выводить окошко. А можно-ли вместо вывода MessageBox вызвать функцию CreateWindow из основного потока? Как все это будет работать?
Как я понял созданый поток, в данном примере, будет ждать события и выводить окошко. А можно-ли вместо вывода MessageBox вызвать функцию CreateWindow из основного потока? Как все это будет работать?
А почему нет?
Thread - это такой-же фрагмент кода в твоей программе как и MainThread. Сидят они в одном адресном пространстве и используют одни и те-же библиотеки и.т.п. Единственные грабли - на которые можно наступить при разработке Multithread приложений - некорректная обработка доступа нескольких потоков к одним и тем-же участкам памяти.
То-ли я чего-то не понял, то-ли ты меня непонял.
Повторно запускаемая копия узнает, что приложение уже запущено. Это ясно. А наоборот как? Т.е. сделать, чтобы уже находящийся в памяти и работающий процесс узнал о попытке повторного запуска.
Попробуй через зашареные секции.
Типа:
#pragma data_seg("Shared")
volatile int CountApp=0;
#pragma data_seg()
#pragma comment(linker,"/Selection:Shared,RWS")
Переменная CountApp - доступна из любого екземпляра приложения. Увеличивай её при запуске приложения и уменьшай при закрытии, будешь знать количество приложений. Только грабли: нужно её инициализировать; и в строке #pragma comment... в кавычках не поставь пробела.
По-моему так...
Чтобы не допустить
запуск других экземпляров программы,
нужно создать ИМЕННОВАНЫЙ mutex
(если НЕИМЕННОВАННЫЙ, то не сработает GetLastError).
Но любое заранее определенное имя
может уже использоваться.
Таким образом, я рискую,
что ни один экземпляр не запустится.
Вопрос такой - как гарантировать,
что первый экземплят точно запустится,
а второй - точно не запустится?
Вообще, хотелось бы иметь что-то вроде FindProcess ().
А всякие левые способы типа FindWindow ()
мне не нравятся.
В последнем случае нужно искать окно
определенного класса с определенным заголовком.
А вдруг у чужой программы класс и заголовок такие же,
как и у моей?
Хочу ГАРАНТИРОВАННОЙ работы программ!
А Microsoft на каждом шагу предлагает
ПОЛАГАТЬСЯ НА "АВОСЬ".
..
Но любое заранее определенное имя
может уже использоваться.
..
С чего ты взял?? Просто не создавай имена типа "Hallo", "Test" или "Mutex":D.. Если уж ты настолько 'озабочен' этой "проблемой", используй генераторы уникальных идентификаторов. Их в Интернете полно. Я использую UUID, когда нужно. В VS 2005, насколько я помню, есть встроенный генератор.
..
Таким образом, я рискую,
что ни один экземпляр не запустится.
..
Определенный риск при использовании Mutex конечно есть. К примеру, если твоя программа экстренно завершилась - не всегда можно предположить, что случилось с Mutex. Есть несколько способов обеспечения запуска единственной копии приложения(где-то валялась статья по этому поводу), к примеру, создание временного файла на время работы программы и т.д..
ИМХО: Использование Mutex наиболее уместно в данном случае!
..
Вопрос такой - как гарантировать,
что первый экземплят точно запустится,
а второй - точно не запустится?
..
Очень просто - грамотно написать рабочую прорамму, чтобы у тебя хотя бы первая копия запустилась:D
А вдруг у чужой программы класс и заголовок такие же,
как и у моей?
У тебя прям мания какая-то!!:D Для этого существуют области имен!
Хочу ГАРАНТИРОВАННОЙ работы программ!
А Microsoft на каждом шагу предлагает
ПОЛАГАТЬСЯ НА "АВОСЬ".
Блин, еще один!! Тогда чо ты лезешь в программирование под Windows - программируй под другие ОС!! И где это интересно она в официальных источниках 'такое' предлагала?!
Он что, все Mutexы в системе проверит?
Про временный файл - хорошая идея, я уже думал.
Тем более есть какая-то функция
для поиска уникального имени файла.
(Правда, можно опасаться,
что второй экземпляр стартует раньше,
чем первый экземпляр создаст файл.
Но это действительно уже на невроз тянет).
Насчет грамотной рабочей программы.
С этим-то проблем нет.
Проблема, чтобы моя защита против второго экземпляра
не сработала против первого.
Насчет области имен - опять же, не понял.
Я всегда думал,
что имена классов главных окон приложений
хранятся в какой-то общесистемной области.
Разве нет?
Не заявляла Microsoft ОФИЦИАЛЬНО,
что надо полагаться на "авось"?
Еще бы она заявляла.
Официально-то у нее все безоблачно...
Вообще-то я не люблю брюзжать про "плохую Microsoft".
Во-первых, я пользователь многих ее продуктов,
а во-вторых -
они не слабые специалисты по маркетингу.
Их среднего качества продукты
успешно борятся с более качественными.
Это надо уметь.
Он что, все Mutexы в системе проверит?
Ничего он проверять не будет. Но GUID тебе даст уникальный (почитай что это такое).
P.S. Mutex'а вполне достаточно для контроля запуска одной копии программы. Ставь мьютекс и не заморачивай голову. Все будет работать.
[COLOR=#808080][SIZE=2][COLOR=black]if(m_hMutex == INVALID_HANDLE_VALUE)[/COLOR][/SIZE]
[SIZE=2][COLOR=black] return -1;[/COLOR][/SIZE]
[SIZE=2][COLOR=black]int res = WaitForSingleObject(m_hMutex, 0);[/COLOR][/SIZE]
[SIZE=2][COLOR=black]if(res == WAIT_TIMEOUT)[/COLOR][/SIZE]
[SIZE=2][COLOR=black] return -1;[/COLOR][/SIZE]
[/COLOR]
Это конечно мало вероятно что они повторятся :)
Но GUID был специально придуман для уникальности. Так что его и надо юзать
В начале функции WinMain поместил 2 строчки:
CreateMutex (NULL,FALSE,MUTEX_NAME);
if (GetLastError ()==ERROR_ALREADY_EXISTS) return 0;
Все работает как надо, а в качестве идентификатора
я взял более или менее заковыристую строку.
Что касается GUID, то слабоваты познания
(ни разу не приходилось использовать).
Я посмотрел документацию (ole.hlp):
"CoCreateGuid. Creates a GUID, a unique 128-bit integer...
Use the CoCreateGuid function when you need an absolutely unique number...
To a very high degree of certainty, this function returns a unique value..."
Т.е. функция CoCreateGuid
создает 128-битовое целое значение,
которое с большой вероятностью уникально.
Судя по всему,
просто создается случайная последовательность
из 128 битов.
Количество вариантов - 2 в степени 128.
Это примерно 10 в 38-ой.
Вероятность повтора - 10 в минус 38-ой (очень мала).
Так вот.
По-моему, с таким же точно успехом
можно использовать в Mutexе
строку из 128 случайных символов.
Впрочем, с GUID удобнее - не надо forов и randomов.
Точно параметров не знаю;), но то, что на уникальность можно рассчитывать - 101%. Видимо по этому вероятность совпадения GUID и не оговорена в help'е:D
Лучше использовать FileMapping, поскольку, с его помощью можно не только ограничить экземпляры приложения, но и размещать в примаппированной области дополнительную информацию (например хендл окна уже запущенного приложения).
А для передачи данных между экземплярами оконного приложения лучше всего подходит сообщение WM_COPYDATA.
Если будет нужно приведу пример на C++ или Delphi.
------------------------------
sprintf(g_szEventName,"event_%u", _getpid());
g_tpsMain.m_hEvent = bthread::newsignal(FALSE, FALSE, g_szEventName);
-------------------------------
Хотя если нужкн один уникальный для всех процессов, а не уникальный в каждом процессе, то не катит.
(хотел создать новую тему, ну думаю здесь будет тоже втему).
Вобщем я использую mutex-ы для синхронизации процессов, которые делают записи в один и тот же файл.
Допустим стандартная ситуация:
Один процесс(поток процесса) занял под себя Mutex, а другой соответствено ждёт используя WaitForSingleObject и если первый процесс отработал корректно он вызовёт ReleaseMutex, и тогда во втором процессе WaitForSingleObject вернёт WAIT_OBJECT_0 - но вот интересуют две ситуации:
1. что будет если первый процесс завершится из-за какой либо ошибки - по идее mutex object тоже тогда освободится, но что тогда вернёт функция - WaitForSingleObject?
2. Допустим Mutex ждут много процессов, тогда кто первый из них его получит - тот кто первый вызвал WaitForSingleObject?
-------------------
Данные вопросы связаны с моим фиговым знанием англ. языка - я вижу
в MSDN что там какая то засада описана с некорректным завершением потока, который занимает Mutex, но чёт не очень врубаюсь какая...
Будто Mutex'ы - это ответ на все проблемы!
Копай в сторону CreateSemaphore - семафоры!
+ CreateEvent - события!