![]() |
:: Главная :: Решения :: Статьи :: Проект "Русский help" :: Файловый архив :: Фотоальбом :: Ссылки :: | ![]() |
![]() |
Л и с о в о д ы в с е х с т р а н, о б ъ е д и н я й т е с ь !!! |
Как предотвратить повторный запуск приложения | ||
---|---|---|
Вопрос:
Как предотвратить повторный запуск приложения? Ответ: Это один из тех вопросов, которые легко задать, но трудно ответить. Трудно не потому, что он очень уж сложный, а потому, что ответ на него требует некоторых пояснений того, что именно и почему необходимо сделать. Для начала, следует определиться с тем, что именно Вы вкладываете в понятие "повторный запуск приложения". Например: И это далеко не полный перечень самых разных ситуаций, которые могут подразумеваться под термином "повторный запуск приложения". Собственно, вопрос сводится к набору признаков, по которому Вы хотите идентифицировать приложение. Причем эти признаки должны быть такими, которые однозначно определяются в момент открытия приложения и не могут быть изменены в процессе работы приложения. Именно поэтому, наиболее распространенный способ определения приложения по его заголовку не может служить таким уникальным идентификатором. По крайней мере, сам по себе. Без каких-либо дополнительных признаков. Просто потому, что заголовок окна приложения легко может быть изменен в процессе работы приложения или же один и тот же заголовок могут иметь разные приложения. Разные в том смысле, который Вы вкладываете в это понятие. Уникальными идентификаторами могут являться: Вам могут понадобиться и другие идентификаторы, формируемые либо внутри Вашего приложения, либо самой операционной системой для того, чтобы однозначно определить уникальный экземпляр приложения. Какие именно – решайте сами исходя из Вашей задачи.
Теперь, когда Вы определились с набором признаков, идентифицирующих Ваше приложение, встает следующий вопрос: как и где, хранить этот набор, чтобы он был доступен из другого приложения? Это "хранилище" реквизитов должно удовлетворять следующим требованиям: 1. Формироваться в момент открытия приложения 2. Быть недоступным для изменения из другого приложения в процессе работы приложения, его создавшего. Однако должно быть доступным на чтение. 3. Очищаться при закрытии приложения. Даже если закрытие приложения произошло в аварийном режиме (сбой питания) Ну, очевидно, идеальным вариантом такого хранилища является само приложение. Точнее, набор переменных памяти, которые создает само приложение. Однако использовать напрямую приложение затруднительно. По ряду причин. Например, при таком подходе необходимо будет просканировать вообще все открытые приложения. Ведь заранее неизвестно, какое именно приложение нам нужно найти. Есть и другие причины. Но, тем не менее, существует довольно простое решение данной проблемы. Это использование так называемых, объектов-семафоров. Эти объекты создаются при помощи специальных API-функций и их можно "увидеть" извне приложения. Т.е. любое другое приложение может сразу определить, существует ли искомый объект или нет. Поскольку в данном случае необходимо определить существование одного и только одного экземпляра приложения, то лучше всего использовать объект Mutex. Свое название он получил от выражения "mutually exclusive", что означает "взаимно исключающий".
Полное описание способов использования объекта Mutex смотрите в библиотеке MSDN на сайте Microsoft. В данном случае будет описан один единственный способ, реализующий необходимую функциональность. Прежде, чем использовать объект Mutex в приложении, необходимо объявить API-функцию для его создания с именем CreateMutex.
lpMutexAttributes – атрибуты защиты. В данном случае не используются, поэтому значение этого параметра устанавливается в 0. bInitialOwner – начальное состояние объекта в момент инициализации. Значение 1 означает, что приложение создавшее объект становится владельцем этого объекта. Значение 0 означает, что приложение только создает объект, но не владеет им. В данном случае всегда следует использовать значение 1. lpName – имя объекта. Не должно содержать символа "\" и общая длина не должна превышать 260 символов (MAX_PATH). Регистр букв (большие или маленькие) имеет значение. Т.е для объекта Mutex большие и маленькие буквы – это разные буквы. Именно имя и будет являться тем уникальным идентификатором, по значению которого и будет определяться факт существования приложения с определенными значениями реквизитов. Само имя – это символьная строка "сложенная" из значений необходимых идентификаторов. Исключая символ "\" и длиной не более 260 символов.
Функция CreateMutex возвращает так называемый, "хендл" или идентификатор объекта. Целое число. Однако данная функция может, как создать объект, так и вернуть ссылку на уже существующий объект созданный ранее другим приложением. Чтобы определить, был ли объект Mutex действительно создан или Вы получили ссылку на ранее созданный объект, следует использовать другую API-функцию с именем GetLastError. Если эта функция вернет значение 183 (ERROR_ALREADY_EXISTS), то это и будет означать тот факт, что объект Mutex с тем же именем уже был ранее создан. Т.е. было ранее запущено приложение с теми же реквизитами. В принципе, объект Mutex и все ссылки на него автоматически удаляются при закрытии приложения. Поэтому можно и не давать специальные команды по удалению этого объекта из памяти. Но уборка за собой является хорошим тоном в программировании. Поэтому, лучше все-таки выполнить удаление объекта Mutex при закрытии приложения. Простейший код использования объекта Mutex для проверки факта существования ранее запущенного приложения будет выглядеть примерно так.
Однако, несмотря на все достоинства использования объекта Mutex, его использование имеет и недостатки. Дело в том, что данный объект существует только и исключительно в памяти того компьютера, в котором он был создан. В большинстве случаев это не является проблемой, поскольку требуется проконтролировать факт повторного запуска приложения на одном и том же компьютере. Но если Вам надо контролировать факт запуска приложения, например, одного и того же пользователя, но с разных компьютеров, то использование объекта Mutex не решает проблему. Возвращаясь к требованиям, предъявляемым к "хранилищу" реквизитов приложения по которым определяется факт запуска приложения, дополняем его еще одним требованием. 4. Оно должно быть доступным для чтения с разных компьютеров. В принципе, можно реализовать и это требование при помощи объекта Mutex, если создавать его всегда только на том компьютере, где хранятся общие данные приложения. Т.е. создавать этот объект на сервере. Это можно реализовать, создав специальную библиотеку Com+. Но описание данной технологии выходит за рамки данной стать. Кроме того, есть другой способ. Дело в том, что в самой среде FoxPro есть механизм взаимодействия нескольких пользователей одного приложения. Это блокировки. Ведь запись, заблокированную одним пользователем невозможно изменить другим пользователем, хотя можно прочитать из нее информацию. Это значит, что если создать специальную таблицу, включенную в базу данных, записи которой будут содержать информацию о факте запуска приложения, то, наложив блокировку на соответствующую запись, можно дать знать другим экземплярам приложения кто уже работает с приложением. Чтобы операции с этой служебной таблицей не мешали основной работе приложения, лучше открывать ее в отдельной сессии данных. Это можно сделать, например, используя объект Session, введенный в Visual FoxPro 6.0 Service Pack 3. Для младших версий FoxPro придется очень аккуратно следить за установкой и снятием блокировок с таблиц. Т.е. за командами UNLOCK, RLOCK(), LOCK(), SET MULTILOCKS. Хотя, можно использовать невидимую форму. Итак, в базе данных создается еще одна таблица. Это обычная таблица, принадлежащая базе данных. Т.е. таблица, лежащая на сервере, а не на локальном компьютере пользователя. Список полей этой таблицы является набором идентификаторов, по которым в Вашей задаче надо отделять процессы друг от друга. Это может быть, например: Теперь, при входе в Ваше приложение, первым делом открываете эту служебную таблицу и ищете запись с полным набором идентификаторов, однозначно определяющих данный процесс. Если такой записи нет, то создаете ее. После того, как запись найдена (или создана) предпринимаете попытку ее заблокировать. Если это не удалось, то значит приложение уже запущено. В коде это будет выглядеть примерно так. Служебная таблица имеет примерно такую структуру
Здесь CurProcID - это код записи. В данном случае использовано тип данных Integer-Autoincrement, который был введен только в версии Visual FoxPro 8.0. Для младших версий FoxPro можно формировать код записи при помощи специальной функции NewId() или любым удобным для Вас способом. Идентификатором процесса выступает сетевое имя компьютера SYS(0) Тогда собственно код функции будет таким
Снимать блокировку записи не надо до окончания работы приложения. В случае аварийного завершения приложения (сбой питания) снятие блокировки произойдет автоматически. Если при закрытии приложения удалять (или очищать) созданную запись, то по факту наличия не заблокированной записи можно сделать вывод о том, что приложение было закрыто аварийно. И определить кем именно. Запись времени нужна для того, чтобы не накапливался мусор. Например, уже нет компьютера со значением SYS(0), но запись с таким значением все еще существует. Вот по времени последнего обращения можно оценить: оставлять такую запись или уже пора удалять. Также эту таблицу можно использовать для получения сведений о том, кто в данный момент работает с приложением Смотрите также Как вывести приложение на передний план Заметки на сайте Юрия Шутенко Kernel Object Namespaces Исправлено 9 раз(а). Последнее : Владимир Максимов, 08.06.10 21:01 ![]() |
||
Тема | Просмотров | Написано | Написано |
---|---|---|---|
![]() |
4736 | Владимир Максимов | 29.10.05 22:56 |
![]() ![]() |
14218 | Владимир Максимов | 30.10.05 02:30 |
![]() ![]() |
9830 | Владимир Максимов | 30.10.05 15:08 |
© 2006 Fox Club  |