Как запретить повторный запуск приложения
А если окна нет? Еще нет. уже нет. или вообще нет и не будет. ? Или есть, но создано др. приложением?
Короче говоря, этот способ корявый!
А вот мьютекс самое то! И не сложнее:
//Check if Mutex already exists
hMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME );
if(hMutex) return 0;
//It must not exist, so make Mutex
hMutex = CreateMutex( NULL, FALSE, MUTEX_NAME );
Главное задать уникальное имя MUTEX_NAME, но это, думаю, не сложно: "Mutex_for_my_application_I_Love_BEER"
:D
Хотя если приложение небольшое и имеет окно, я думаю незачем занимать память лишним мутексом .
. Хотя наверное в билдеровских пиложениях это не принципиально ;-) в использовании мютексов есть один нюанс
при некоректном завершении приложения
мютекс остается и единственный способ
удалить его это перезагрузка компьютера
так что приложение должно быть предельно безглючным Originally posted by ALI
в использовании мютексов есть один нюанс
при некоректном завершении приложения
мютекс остается и единственный способ
удалить его это перезагрузка компьютера
так что приложение должно быть предельно безглючным
Если ты пишешь приложение работающее с БД то это даже плюс.
дело в том что если твое приложение повисло и оно могло не освободить занятые им таблицы баз данных. представь что может натворить приложение если к части баз и файлов будет иметь доступ а к другим нет ?
Очень советую при зависании таких программ перезагружать компьютер.
И даже можно используя эту фишку реализовать красивый вариант , использовать оба способа обнаружения запущенности программы и поиск окна и мутекс. если мутекс найден а окно нет значит в этом случае программа до этого запускалась и повисла. можно предложить пользователю перезагрузить компьютер или провести переиндексацию БД.
И правда удобно!
Хотя если приложение небольшое и имеет окно, я думаю незачем занимать память лишним мутексом .
. Хотя наверное в билдеровских пиложениях это не принципиально ;-)
А если приложение свёрнуто в SystemTray отловит ли его FindWindow(. )?
А если приложение свёрнуто в SystemTray отловит ли его FindWindow(. )?
SystemTray тут ни при чем, как было сказано выше - приложение либо имеет окно, и тогда оно будет найдено, либо не имеет окна - и тогда его нельзя найти по FindWindow, но оно все равно может создавать иконку в трее. А когда оконное приложение сворачивается в трей, то оно обычно делает ShowWindow(. SW_HIDE) а окно все равно остается
Многие программисты программного обеспечения сталкивались с задачей запрета запуска копий приложения. Это делается с различными целями и зависит от ситуации. Существует даже отдельный термин для решения данной задачи — Mutex.
Также данная задача иногда возникает перед системными администраторами с тем отличием, что приложение стороннее (разработано другой организацией). Эта статья описывает относительно простой способ решения проблемы запрета запуска копий стороннего приложения.
Задача
Как то раз у меня на работе возникла проблема — некоторые сотрудники умудрялись запускать несколько копий приложений. Запуск нескольких копий, конечно, не приводил к катастрофическим результатам, но иногда порождал различные «глюки», нестабильную работу программы. Это, естественно, добавляло мне головной боли от многочисленных жалоб на эти «глюки».
Первым делом я провел разъяснительную беседу с сотрудниками о проблеме запуска копий приложения и о том, как этого избежать. Данная мера помогла на ближайшие пару дней, а далее всё вернулось на круги своя. Жаловаться начальству на такое попустительство некоторых работников было чревато моим увольнением, т.к. начальство безумно ценило этих работников, а ко мне отношение было кардинально противоположным.
Как говориться «Раз гора не идёт к Магомету, то Магомет идёт к горе». Я решил сам программно запретить запуск копий приложения. Задача оказалась не тривиальная.
Несложный анализ выявил 2 особенности моей ситуации:
Во-первых, у меня приложение стороннее, т.е. его разработчик не наша организация и доступа к исходному коду нет (поясню, приложение — один из продуктов Microsoft). Каких-либо регулирующих запуск настроек и параметров приложение не имеет.
Во-вторых, приложение запускается не напрямую, а как программа по умолчанию для открытия файлов определённого расширения. То есть приложение запускается с параметром (путь файла данных, который нужно открыть).
Решение — теория
Поиск в Интернете не дал мне явного решения. Запрета запуска второй копии приложения в виде системных настроек, как я понял не существует (хотя есть API). Также я нашел десятки примеров реализации mutex-ов на различных языках программирования, но все они, естественно, требовали внесения изменений в код и мне не подходили. Надо было искать своё оригинальное решение, и желательно попроще.
- Пользователь инициирует запуск приложения, открывая файл данных, ассоциируемый с приложением.
- По умолчанию вместо требуемого приложения запускается приложение-прослойка.
- Это приложение получает в виде параметра путь к файлу данных, создаёт mutex и запускает требуемое приложение с полученными параметрами. Приложение-прослойка, соответственно, должно быть скрыто.
- Далее запускается требуемое приложение и пользователь работает в нём. Приложение-прослойка всё это время продолжает работу. Его mutex блокирует попытки запуска копии.
- По окончанию работы пользователь закрывает основную программу. Программа-прослойка закрывается автоматически.
Решение — практика
Практическое решение приведено для приложения «Блокнот» (понятное дело, что на его месте может быть любое приложение).
Программный код скрипта (текстовый файл с расширением .au3) не представляет ничего сложного:
Хабраюзер mayorovp правильно отметил, что название семафора «Mutex» лучше заменить на что-то более уникальное.
Как вы сами видите, весь код условно можно разделить на две части: mutex и запуск требуемого приложения. Более детально я объяснять не буду, т.к. статья посвящена не изучению возможностей AutoIt.
Написав скрипт его можно откомпилировать либо в редакторе SciTE Script Editor, либо через контекстное меню файла (правый клик по файлу скрипта). После чего его уже можно использовать. Можно также откомпилировать с дополнительными настройками (битность системы и иконка приложения) при помощи утилиты Aut2Exe, которая также идёт в комплекте с AutoIt.
Далее всё элементарно — помещаем получившееся приложение-прослойку в какую-нибудь директорию и настраиваем открытие по умолчанию для файлов данных (в примере для файлов с расширением .txt) при помощи этого приложения-прослойки.
На этом всё. Проверяем и радуемся решенной задаче — теперь никто не сможет запустить две копии «Блокнота».
Послесловие
Данный способ позволил мне решить проблему двойного запуска приложений. Правда, на следующий день после установки приложения-прослойки ко мне прибежали нерадивые сотрудники со словами «Оно не запускается». Пришлось провести разъяснительную беседу с сотрудниками на тему «Приложение не запускается, потому что уже запущено». Эта беседа оказалась куда эффективнее, т.к. особого выбора у сотрудников не было. Уже почти месяц данных проблем не возникало.
Если кто из читателей знает способ написать mutex в виде .bat файла для данной задачи, то поделитесь опытом. У меня есть подозрение, что такой способ есть.
Как предотвратить повторный запуск приложения?
Это один из тех вопросов, которые легко задать, но трудно ответить. Трудно не потому, что он очень уж сложный, а потому, что ответ на него требует некоторых пояснений того, что именно и почему необходимо сделать.
Для начала, следует определиться с тем, что именно Вы вкладываете в понятие "повторный запуск приложения". Например:
И это далеко не полный перечень самых разных ситуаций, которые могут подразумеваться под термином "повторный запуск приложения".
Собственно, вопрос сводится к набору признаков, по которому Вы хотите идентифицировать приложение. Причем эти признаки должны быть такими, которые однозначно определяются в момент открытия приложения и не могут быть изменены в процессе работы приложения.
Именно поэтому, наиболее распространенный способ определения приложения по его заголовку не может служить таким уникальным идентификатором. По крайней мере, сам по себе. Без каких-либо дополнительных признаков. Просто потому, что заголовок окна приложения легко может быть изменен в процессе работы приложения или же один и тот же заголовок могут иметь разные приложения. Разные в том смысле, который Вы вкладываете в это понятие.
Уникальными идентификаторами могут являться:
Вам могут понадобиться и другие идентификаторы, формируемые либо внутри Вашего приложения, либо самой операционной системой для того, чтобы однозначно определить уникальный экземпляр приложения. Какие именно – решайте сами исходя из Вашей задачи.
Теперь, когда Вы определились с набором признаков, идентифицирующих Ваше приложение, встает следующий вопрос: как и где, хранить этот набор, чтобы он был доступен из другого приложения?
Это "хранилище" реквизитов должно удовлетворять следующим требованиям:
1. Формироваться в момент открытия приложения
2. Быть недоступным для изменения из другого приложения в процессе работы приложения, его создавшего. Однако должно быть доступным на чтение.
3. Очищаться при закрытии приложения. Даже если закрытие приложения произошло в аварийном режиме (сбой питания)
Ну, очевидно, идеальным вариантом такого хранилища является само приложение. Точнее, набор переменных памяти, которые создает само приложение.
Однако использовать напрямую приложение затруднительно. По ряду причин. Например, при таком подходе необходимо будет просканировать вообще все открытые приложения. Ведь заранее неизвестно, какое именно приложение нам нужно найти. Есть и другие причины.
Но, тем не менее, существует довольно простое решение данной проблемы. Это использование так называемых, объектов-семафоров. Эти объекты создаются при помощи специальных API-функций и их можно "увидеть" извне приложения. Т.е. любое другое приложение может сразу определить, существует ли искомый объект или нет.
Поскольку в данном случае необходимо определить существование одного и только одного экземпляра приложения, то лучше всего использовать объект Mutex. Свое название он получил от выражения "mutually exclusive", что означает "взаимно исключающий".
ЗамечаниеЕсли у Вас стоит задача допустить существование фиксированного количества одновременно запущенных экземпляров приложений, то можно использовать объект Semaphore. Но организационно это значительно сложнее.
Полное описание способов использования объекта Mutex смотрите в библиотеке MSDN на сайте Microsoft. В данном случае будет описан один единственный способ, реализующий необходимую функциональность.
Прежде, чем использовать объект Mutex в приложении, необходимо объявить API-функцию для его создания с именем CreateMutex.
lpMutexAttributes – атрибуты защиты. В данном случае не используются, поэтому значение этого параметра устанавливается в 0.
bInitialOwner – начальное состояние объекта в момент инициализации. Значение 1 означает, что приложение создавшее объект становится владельцем этого объекта. Значение 0 означает, что приложение только создает объект, но не владеет им. В данном случае всегда следует использовать значение 1.
lpName – имя объекта. Не должно содержать символа "\" и общая длина не должна превышать 260 символов (MAX_PATH). Регистр букв (большие или маленькие) имеет значение. Т.е для объекта Mutex большие и маленькие буквы – это разные буквы.
Именно имя и будет являться тем уникальным идентификатором, по значению которого и будет определяться факт существования приложения с определенными значениями реквизитов. Само имя – это символьная строка "сложенная" из значений необходимых идентификаторов. Исключая символ "\" и длиной не более 260 символов.
Замечание
В терминальном режиме все объекты ядра (kernel), в том числе и объект mutex, работают в так называемом "пространстве имен". В терминах FoxPro можно сказать, что они имеют определенную "область видимости". По умолчанию, они имеют "область видимости" Session. Это значит, что они "видны" только в той терминальной сессии, в которой и были созданы. Другая сессия (другой пользователь) уже их не видит.
Чтобы созданный объект Mutex был виден из других сессий ему надо задать пространство имен Global. Это делается добавлением префикса "Global\" к сформированному имени. Т.е. имя будет выглядеть так:
Подробнее о пространстве имен объектов ядра в терминальном режиме читайте здесь Kernel Object Namespaces
Функция 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), но запись с таким значением все еще существует. Вот по времени последнего обращения можно оценить: оставлять такую запись или уже пора удалять.
Также эту таблицу можно использовать для получения сведений о том, кто в данный момент работает с приложением
Почему перезагрузка или выход из системы Windows не всегда помогает сбросить состояние компьютера, которое было до него? Все просто, когда завершаете работу или выходите из системы, Windows 10 запоминает, какие приложения открыты. Система автоматически запускает их при следующем старте. Это действие можно отключить, давайте сделаем это.
Как запретить Windows 10 повторно открывать приложения
Нужно перейти в «Параметры»> «Учетные записи»> «Варианты входа».
Прокрутите вниз до раздела «Перезапуск приложений» и установите для параметра «Автоматически сохранять перезапускаемые приложения при выходе и перезапускать их после входа» значение Выкл.
В более старых версиях Windows 10 эта настройка может отличаться. Раздел тот же, но переключатель находится в настройках «Конфиденциальность».
Как запретить Windows повторно открывать папки
Если Windows автоматически открывает такие папки как «Документы» или «Загрузки» в проводнике при входе в систему, то придется изменить настройки в другом месте.
Запустите «Проводник» (желтая папочка) или «Мой компьютер» и перейдите в настройки «Вид» и перейти в «Параметры».
Как отключить программы автозагрузки
Перейдите в Параметры> Приложения и возможности> Автозагрузка и перемещением переключателей регулируйте состояние автозапуска приложений. Вот и все, достаточно простые действия избавят вас от надоедливых открытых приложений и позволят запускать систему более чисто. Есть, конечно, исключения, например, Яндекс браузер нужно отключать внутри его настроек.
Когда вы завершаете работу или выходите из системы, Windows 10 запоминает, какие приложения вы открывали. Он автоматически запускает их при следующем запуске компьютера. Вы можете отключить это, если хотите войти на чистый рабочий стол.
Как запретить Windows 10 повторно открывать приложения
Чтобы изменить этот параметр, перейдите в «Настройки»> «Учетные записи»> «Параметры входа».
Прокрутите вниз до раздела «Перезапуск приложений» и установите для параметра «Автоматически сохранять перезапускаемые приложения при выходе и перезапускать их после входа» значение «Выкл.».
Обновить: В обновлении Windows 10 за май 2020 г. (версия 20H1) на приведенном выше снимке экрана показан текущий интерфейс. Если у вас более старая версия Windows 10, ищите вариант ниже.
Прокрутите вниз до раздела «Конфиденциальность» и установите для параметра «Использовать мои данные для входа, чтобы автоматически завершить настройку устройства и повторно открывать мои приложения после обновления или перезапуска» значение «Выкл.».
Эта функция была добавлена в обновлении Fall Creators Update. В какой-то момент вы могли избежать этого, только выключив компьютер с помощью команды shutdown.exe. В обновлении за апрель 2018 г. добавлен графический переключатель для отключения этого поведения.
Как запретить Windows повторно открывать папки
Если Windows автоматически открывает такие папки, как «Документы» или «Загрузки», в проводнике при входе в систему, это контролируется другим параметром.
Чтобы найти его, запустите проводник, щелкните вкладку «Просмотр» на ленте и нажмите кнопку «Параметры».
На вкладке «Просмотр» прокрутите вниз и найдите параметр «Восстановить окна предыдущих папок при входе в систему». Убедитесь, что он не установлен, иначе Windows снова откроет окна любых папок, когда вы войдете в свой компьютер.
Эта опция также присутствует в Windows 7 и Windows 8.
Как отключить программы автозагрузки
Если приложение продолжает запускаться при запуске, даже если вы отключите эти параметры, скорее всего, это программа запуска, которая автоматически запускается при каждом входе в систему. Вы можете отключить запускаемые программы прямо из приложения «Настройки» Windows 10.
Перейдите в Настройки> Приложения> Автозагрузка, чтобы управлять запускаемыми приложениями. Установите здесь для приложения значение «Выкл.», И оно не будет запускаться, когда вы войдете в свой компьютер.
Отключение некоторых приложений здесь будет иметь последствия. Например, если вы отключите Dropbox, он не будет автоматически синхронизировать ваши файлы, пока вы его не запустите. Если вы отключите аппаратную утилиту, которая обычно запускается в области уведомлений или на панели задач, она не сможет выполнять свою обычную работу в фоновом режиме, пока вы ее не запустите.
Читайте также: