2015-02-20 6 views
7

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

Я искал вокруг, но не обнаружено никакого способа отключить это поведение - большинство моих запросов попало на функцию Innute Setup mutex, чего я не ищу. Кто-нибудь получил советы о том, как убедиться, что выполняется только один экземпляр/процесс установки? Спасибо!

+2

Я не в курсе каких-либо директивы, которая позволила бы только один экземпляр установки (я предполагаю, что на 'AppId'). Жаль, что 'CreateMutex' не возвращает ничего полезного; здесь ['обходной путь'] (http://pastebin.com/sGcrC3pY) для него. Но это была бы хорошая встроенная функция. – TLama

+0

Плюс один для ностальгии. Я даже не знал, что установка Inno все еще есть. – Lee

+0

@ Lee, я [трачу свое время] (http://i.imgur.com/INfeUYD.jpg) здесь :-) – TLama

ответ

12

Поскольку программа установки Inno 5.5.6 вы можете использовать SetupMutex директиву:

[Setup] 
AppId=MyProgram 
SetupMutex=SetupMutex{#SetupSetting("AppId")} 

Если вы хотите изменить текст сообщения, который отображает, когда другой установщик работает уже, использование:

[Messages] 
SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. 

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

[Setup] 
AppName=My Program 
AppVersion=1.5 
DefaultDirName={pf}\My Program 

[Code] 
const 
    // this needs to be system-wide unique name of the mutex (up to MAX_PATH long), 
    // there is a discussion on this topic http://stackoverflow.com/q/464253/960757 
    // you can expand here e.g. the AppId directive and add it some 'salt' 
    MySetupMutex = 'My Program Setup 2336BF63-DF20-445F-AAE6-70FD7E2CE1CF'; 

function InitializeSetup: Boolean; 
begin 
    // allow the setup to run only if there is no thread owning our mutex (in other 
    // words it means, there's no other instance of this process running), so allow 
    // the setup if there is no such mutex (there is no other instance) 
    Result := not CheckForMutexes(MySetupMutex); 
    // if this is the only instance of the setup, create our mutex 
    if Result then 
    CreateMutex(MySetupMutex) 
    // otherwise tell the user the setup will exit 
    else 
    MsgBox('Another instance is running. Setup will exit.', mbError, MB_OK); 
end; 
+0

Спасибо за ваше время и помощь TLama, это оценено. Я читал, что mutex approch не является 100% неуместным в отношении гоночных условий - хотя это похоже на лучший вариант.Я буду следить за предложением, которое вы связали в другом ответе; Я думаю, что нечто подобное должно было быть реализовано много лет назад, верно? Еще раз спасибо! – Takeshi

+0

Условия гонки обычно связаны с потоками внутри процесса. Это гонка между процессами. Но да, риск есть, но очень, очень маленький. Пользователь должен будет запустить второй экземпляр точно до того, как первый экземпляр создаст мьютекс, но после того, как он проверит существование мьютекса (поэтому он должен находиться между вызовами «CheckForMutexes» и «CreateMutex», что не более чем в миллисекундах). Кроме того, люди используют мьютексы для проверки того, запущены ли их приложения; это обычная практика (я не знаю никакой атомной функции, которая могла бы избежать этого состояния гонки). – TLama

+0

Я только что узнал об этом [http://www.codeproject.com/Articles/538/Avoiding-Multiple-Instances-of-an-Application). Теперь я знаю, что это длинный снимок, но я слышал случаи, когда область поддержки получала звонки от клиентов с несколькими экземплярами нашего программного обеспечения (он использует технику мьютекса), поэтому я знаю, что это происходит. – Takeshi

-1

Если ваш установщик был вызван setup.exe, например, вы можете использовать следующий код, чтобы проверить, запущен ли файл setup.exe и завершить установку.

[Code] 
function IsAppRunning(const FileName : string): Boolean; 
var 
    FSWbemLocator: Variant; 
    FWMIService : Variant; 
    FWbemObjectSet: Variant; 
begin 
    Result := false; 
    FSWbemLocator := CreateOleObject('WBEMScripting.SWBEMLocator'); 
    FWMIService := FSWbemLocator.ConnectServer('', 'root\CIMV2', '', ''); 
    FWbemObjectSet := FWMIService.ExecQuery(Format('SELECT Name FROM Win32_Process Where Name="%s"',[FileName])); 
    Result := (FWbemObjectSet.Count > 0); 
    FWbemObjectSet := Unassigned; 
    FWMIService := Unassigned; 
    FSWbemLocator := Unassigned; 
end; 

function InitializeSetup: boolean; 
begin 
    result := not IsAppRunning('setup.exe'); 
    if not result then 
    MsgBox('setup.exe is already running', mbError, MB_OK); 
end; 
+1

Это ненадежное устройство. Возможно, существует совсем другой процесс 'setup.exe', и это не является причиной прекращения вашей настройки. – TLama

+0

Но это было бы маловероятно. Чтобы избежать этого имени, выполните следующие действия: «MyApplication_Setup_Ver_1.2.3.4.exe». По-моему, в любом случае это более удобно для пользователя и не заставляет пользователя переименовывать 'setup.exe' в какой-то его выбор. –

+0

Я использовал имя setup.exe для упрощения кода примера. Я согласен с Вернфридом. В коде продукта имя файла установки должно содержать имя продукта и номер версии. Обычно я устанавливаю имя установщика с помощью OutputBaseFilename = Setup {#MyAppName} {# MyAppVersion} –

Смежные вопросы