Comments 24
Под linux есть замечательная консольная утилита flock. С её помощью скрипт, запрещающий повторный запуск пишется в пару строк. Возможно в виндах есть аналог?
Для пользователей Qt4/5 есть очень простое кроссплатформенное решение, используем в своих приложений — QtSingleApplication
Хочу все-таки придраться, и сообщить, что Mutex — это примитив синхронизации потоков ядра, и к блокированию двойных запусков он имеет крайне опосредованное отношение.
Решение данной задачи основано на совершенно другой идее, которая называется «именованные объекты ядра». Фактически, вместо семафора (который почему-то назван мьютексом) можно было использовать абсолютно любой другой объект ядра. Популярными вариантами также являются использование файлов и сокетов.
Кстати, вместо имени «Mutex» я бы рекомендовал использовать что-то более уникальное. Например, название вашей программы, GUID, или же полный путь к исполнимому файлу.
Решение данной задачи основано на совершенно другой идее, которая называется «именованные объекты ядра». Фактически, вместо семафора (который почему-то назван мьютексом) можно было использовать абсолютно любой другой объект ядра. Популярными вариантами также являются использование файлов и сокетов.
Кстати, вместо имени «Mutex» я бы рекомендовал использовать что-то более уникальное. Например, название вашей программы, GUID, или же полный путь к исполнимому файлу.
Кстати, вот решение на пакетных файлах. Уже ночь, так что пишу по памяти и без тестирования, надеюсь, что сильно не накосячу.
Смысл в том, что файл с запущенной программой защищен от записи — а потому попытка перезаписать его неизбежно провалится.
@echo off
rem runonce.bat - запуск указанного исполнимого файла с блокированием повторных запусков
copy /b /y %1 %1~.exe || goto error
start %1~.exe
exit /b
:error
cls
echo Повторный запуск программы запрещен
pause
Смысл в том, что файл с запущенной программой защищен от записи — а потому попытка перезаписать его неизбежно провалится.
После закрытия приложения повторный запуск невозможен у вас, кажется.
А, то есть мы расчитываем, что exe-шник открыт на чтение во время работы приложения. Тогда понял. Но тут может зависеть от ПО, думаю — не каждое ПО будет так оставлять файл. Может там преЛончер какой или типа того.
Ну, по сути, запрета таки нет, есть защита от дурака.
Пример на PowerShell. Зачем семафоры ядра, можно флаг-файлами делать
Скрин того, что получается
+ добавить скрипт очистки %APPDATA%\*.flg при логоне, мало ли что.
Делать ярлыки на
(Я -WindowStyle Hidden опустил)
Пример на PowerShell. Зачем семафоры ядра, можно флаг-файлами делать
Скрин того, что получается
+ добавить скрипт очистки %APPDATA%\*.flg при логоне, мало ли что.
Делать ярлыки на
C:\Windows\SYstem32\WindowsPOwerSHell\v1.0\powershell.exe -STA -NoLogo -NoProfile -WindowStyle Hidden -File "C:\.....\UniqueAppRunner.ps1" -AppID UNIQUENOTEPAD
(Я -WindowStyle Hidden опустил)
Param(
[string]$AppID=$null
)
$appList = @{
'UNIQUENOTEPAD' = 'C:\WINDOWS\notepad.exe'
'UNIQUECALC' = 'C:\WINDOWS\System32\CALC.exe'
}
if ($AppID -eq $null) {
Write-Host 'Приложение не указано!' #Тут должен быть MessageBox, но лень
Exit
}
if ($appList[$appID.ToUpper()] -eq $null) {
Write-Host 'Запуск этого приложения через скрипт не предусмотрен!' #Тут должен быть MessageBox, но лень
Exit
}
if ($(Test-Path -Path $appList[$appId.ToUpper()] -ErrorAction SilentlyContinue ) -ne $true) {
Write-Host 'Исполняемый файл не обнаружен!' #Тут должен быть MessageBox, но лень
Exit
}
$appFlagFile = Join-Path -Path $env:APPDATA -ChildPath $($AppID + '.flg' )
If ( $(Test-Path -Path $appFlagFile ) -ne $false) {
Write-Host "Приложение $($AppID) уже запущено - присутствует флаг-файл $($appFlagFile)!" #Тут должен быть MessageBox, но лень
Exit
}
$(Get-Date ) | Out-File -FilePath $appFlagFile
Write-Host -ForegroundColor Green 'Запуск приложения'
Start-Process -FilePath $appList[$appID.ToUpper()] -Wait
Remove-Item -Path $appFlagFile -Force -Confirm:$false
Exit
Или можно с Get-Process поизвращаться…
Ну и свято дело в моем скрипте есть что доработать — ночь.
Ну и свято дело в моем скрипте есть что доработать — ночь.
Отлично! Пропадает питание — и приложение больше не запустится, пока админ не удалит файл-флаг вручную.
Если делать файл-флагами, то надо хотя бы pid в файл записывать…
Если делать файл-флагами, то надо хотя бы pid в файл записывать…
После закрытия приложения семафор сам скинется?
Как я понимаю, да. По крайне мере данное решение работает без нареканий почти месяц.
Не «скинется» — таким свойством обладают только мьютексы — а удалится.
Я так понимаю, если программа уже запущена, то двойной клик по ассоциированному файлу закончится фейлом.
Может, если открытый документ не изменялся / сохранился, закрыть программу и открыть с новым файлом?
Можно даже попытаться заставить сохранить ранее открытый и изменённый файл.
Может, если открытый документ не изменялся / сохранился, закрыть программу и открыть с новым файлом?
Можно даже попытаться заставить сохранить ранее открытый и изменённый файл.
Когда-то очень давно, курсе эдак на первом или втором, делал подобную штуку, но чуть более специфичную: нужно было запретить запуск более одного инстанса программы в пределах одной локальной сети. Сделал обёртку над программой, которая сначала опрашивала у сервера возможность запуска, а потом отправляла уведомление о завершении.
Мне кажется, в случае, когда программа уже запущена, было бы лучше не молча завершать работу прослойки, а предварительно разворачивать окно уже запущенной копии.
Решение, приведённое здесь, как и сам его код, судя хотя бы по добавлению в foreach, совсем не идеальны.
При запуске или существовании копии имени какого-то процесса, естественно, и сообщение будет выбрасывать на экран, (плюс ко всему, я пока точно не могу сказать, точно ли сохраняется равенство при конвертации, это надо работу метода преобразования изучать), короче говоря, это очень приблизительный и очень ленивый набросок, по которому можно только понять идею:
При запуске или существовании копии имени какого-то процесса, естественно, и сообщение будет выбрасывать на экран, (плюс ко всему, я пока точно не могу сказать, точно ли сохраняется равенство при конвертации, это надо работу метода преобразования изучать), короче говоря, это очень приблизительный и очень ленивый набросок, по которому можно только понять идею:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace forHabr
{
class Program
{
static void Main(string[] args)
{
Process[] allProcesses = Process.GetProcesses(); // берём все процессы.
List<string> processName = new List<string>();
foreach (Process p in allProcesses)
{
string name = p.ProcessName;
processName.Add(name);
}
string[] allProcessName = processName.ToArray<string>(); // имена всех процессов
string[] distinctProcessName = processName.Distinct<string>().ToArray<string>(); // "уникальные" процессы
for (; ; ) {
if (allProcessName.Count<string>() == distinctProcessName.Count<string>()) { }
else
{
Task task1 = Task.Run(() => { MessageBox.Show("Вы запустили копию процесса"); });
}
}
}
}
}
Sign up to leave a comment.
Запрет запуска копии стороннего приложения