Pull to refresh

Запрет запуска копии стороннего приложения

Reading time 4 min
Views 26K
Робот сжигающий копии блокнотаМногие программисты программного обеспечения сталкивались с задачей запрета запуска копий приложения. Это делается с различными целями и зависит от ситуации. Существует даже отдельный термин для решения данной задачи — Mutex.

Также данная задача иногда возникает перед системными администраторами с тем отличием, что приложение стороннее (разработано другой организацией). Эта статья описывает относительно простой способ решения проблемы запрета запуска копий стороннего приложения.


Задача


Как то раз у меня на работе возникла проблема — некоторые сотрудники умудрялись запускать несколько копий приложений. Запуск нескольких копий, конечно, не приводил к катастрофическим результатам, но иногда порождал различные «глюки», нестабильную работу программы. Это, естественно, добавляло мне головной боли от многочисленных жалоб на эти «глюки».

Первым делом я провел разъяснительную беседу с сотрудниками о проблеме запуска копий приложения и о том, как этого избежать. Данная мера помогла на ближайшие пару дней, а далее всё вернулось на круги своя. Жаловаться начальству на такое попустительство некоторых работников было чревато моим увольнением, т.к. начальство безумно ценило этих работников, а ко мне отношение было кардинально противоположным.

Как говориться «Раз гора не идёт к Магомету, то Магомет идёт к горе». Я решил сам программно запретить запуск копий приложения. Задача оказалась не тривиальная.

Несложный анализ выявил 2 особенности моей ситуации:
Во-первых, у меня приложение стороннее, т.е. его разработчик не наша организация и доступа к исходному коду нет (поясню, приложение — один из продуктов Microsoft). Каких-либо регулирующих запуск настроек и параметров приложение не имеет.
Во-вторых, приложение запускается не напрямую, а как программа по умолчанию для открытия файлов определённого расширения. То есть приложение запускается с параметром (путь файла данных, который нужно открыть).

Решение — теория


Поиск в Интернете не дал мне явного решения. Запрета запуска второй копии приложения в виде системных настроек, как я понял не существует (хотя есть API). Также я нашел десятки примеров реализации mutex-ов на различных языках программирования, но все они, естественно, требовали внесения изменений в код и мне не подходили. Надо было искать своё оригинальное решение, и желательно попроще.

Единственное решение, которое я видел, было создание своеобразной «прослойки» между пользователем и приложением. Должно происходить следующие:
  • Пользователь инициирует запуск приложения, открывая файл данных, ассоциируемый с приложением.
  • По умолчанию вместо требуемого приложения запускается приложение-прослойка.
  • Это приложение получает в виде параметра путь к файлу данных, создаёт mutex и запускает требуемое приложение с полученными параметрами. Приложение-прослойка, соответственно, должно быть скрыто.
  • Далее запускается требуемое приложение и пользователь работает в нём. Приложение-прослойка всё это время продолжает работу. Его mutex блокирует попытки запуска копии.
  • По окончанию работы пользователь закрывает основную программу. Программа-прослойка закрывается автоматически.

Как вы понимаете, такой подход достаточно универсален. Это приложение-прослойка может выполнять не только задачу запрета запуска копии программы, но и многие другие (логирование, запуск сопутствующих программ, оповещение и т.д.). Для пользователя работа приложения-прослойки будет незаметным.

Решение — практика


Практическое решение приведено для приложения «Блокнот» (понятное дело, что на его месте может быть любое приложение).

Выбор языка программирования для написания приложения-прослойки не вызвал у меня трудностей. Мне нужно было это сделать быстро и без заморочек, поэтому я выбрал язык автоматизации AutoIt. Легковесный AutoIt изначально «заточен» под работу со сторонними приложениями. Скачать его можно с официального сайта. В комплекте помимо самого пакета языка идёт достаточно удобный редактор кода SciTE Script Editor, в котором удобно писать скрипты для AutoIt.
Естественно, можно использовать любой другой язык с необходимыми возможностями.

Программный код скрипта (текстовый файл с расширением .au3) не представляет ничего сложного:

; ** Скрипт запрещения двойного запуска приложений**

; Функция Singleton создаёт семафор при помощи  WinAPI. Если такой семафор уже создан, то заканчиваем работу 
Func Singleton($semaphore)
    Local $ERROR_ALREADY_EXISTS = 183
    DllCall("kernel32.dll", "int", "CreateSemaphore", "int", 0, "long", 1, "long", 1, "str", $semaphore)
    Local $lastError = DllCall("kernel32.dll", "int", "GetLastError")
    If $lastError[0] = $ERROR_ALREADY_EXISTS Then Exit -1
EndFunc

Singleton("Mutex")

; Системная функция ShellExecuteWait запускает приложение и ожидает окончания работы с ним
; Дожидаться завершения программы нужно, чтобы корректно работал Mutex
; $CmdLineRaw - параметр запуска получаемый скриптом
ShellExecuteWait("C:\WINDOWS\notepad.exe", $CmdLineRaw, @ScriptDir, "open", @SW_MAXIMIZE)

Хабраюзер mayorovp правильно отметил, что название семафора «Mutex» лучше заменить на что-то более уникальное.

Как вы сами видите, весь код условно можно разделить на две части: mutex и запуск требуемого приложения. Более детально я объяснять не буду, т.к. статья посвящена не изучению возможностей AutoIt.

Написав скрипт его можно откомпилировать либо в редакторе SciTE Script Editor, либо через контекстное меню файла (правый клик по файлу скрипта). После чего его уже можно использовать. Можно также откомпилировать с дополнительными настройками (битность системы и иконка приложения) при помощи утилиты Aut2Exe, которая также идёт в комплекте с AutoIt.

Далее всё элементарно — помещаем получившееся приложение-прослойку в какую-нибудь директорию и настраиваем открытие по умолчанию для файлов данных (в примере для файлов с расширением .txt) при помощи этого приложения-прослойки.

На этом всё. Проверяем и радуемся решенной задаче — теперь никто не сможет запустить две копии «Блокнота».

Послесловие


Данный способ позволил мне решить проблему двойного запуска приложений. Правда, на следующий день после установки приложения-прослойки ко мне прибежали нерадивые сотрудники со словами «Оно не запускается». Пришлось провести разъяснительную беседу с сотрудниками на тему «Приложение не запускается, потому что уже запущено». Эта беседа оказалась куда эффективнее, т.к. особого выбора у сотрудников не было. Уже почти месяц данных проблем не возникало.

Если кто из читателей знает способ написать mutex в виде .bat файла для данной задачи, то поделитесь опытом. У меня есть подозрение, что такой способ есть.
Tags:
Hubs:
+3
Comments 24
Comments Comments 24

Articles