2015-02-20 13 views
7

Ho un po 'di sottaceti con Inno Setup: su un computer utente, il mio programma di installazione stava funzionando lentamente (qualcosa che devo ancora diagnosticare, potrebbe essere un problema specifico con quel computer, ancora non lo so). Questo ha portato l'utente a eseguire di nuovo l'installazione, mentre la prima istanza era ancora in esecuzione - e con mia sorpresa, entrambi sembravano essere in esecuzione per qualche tempo, prima di arrestarsi e bruciarli ...Inno Setup - impedisce l'esecuzione del programma di installazione più volte simultaneamente

Ho cercato in giro ma ho non è stato trovato alcun modo per disabilitare questo comportamento - la maggior parte delle mie query si sono concluse con la funzione mutex di Inno Setup, che non è proprio ciò che sto cercando. Qualcuno ha dei suggerimenti su come assicurarsi che ci sia solo un'istanza/processo di esecuzione dell'installatore? Grazie!

+2

Non sono a conoscenza di alcuna direttiva che consentirebbe solo un'istanza di installazione (presumo per 'AppId'). Peccato che il 'CreateMutex' non restituisca nulla di utile; ecco ['a workaround'] (http://pastebin.com/sGcrC3pY) per questo. Ma sarebbe una buona funzionalità integrata. – TLama

+0

Più uno per la nostalgia. Non sapevo nemmeno che l'installazione di Inno fosse ancora una cosa. – Lee

+0

@Lee, sto [sprecando il mio tempo] (http://i.imgur.com/INfeUYD.jpg) qui :-) – TLama

risposta

12

Dal Inno Setup 5.5.6 è possibile utilizzare la direttiva SetupMutex:

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

Se si desidera modificare un testo del messaggio, che consente di visualizzare quando un altro programma di installazione è già in esecuzione, l'uso:

[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. 

Prima di questa versione, non vi era alcun meccanismo incorporato a disposizione. Ma potresti scrivere il tuo semplicemente semplicemente. Il principio è che si crea un mutex univoco all'avvio del setup. Ma, come prima cosa controlla se non c'è già un tale mutex creato. Se sì, si esce dal setup, in caso contrario si crea il mutex:

[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

Grazie per il tuo tempo e aiuto TLama, è apprezzato. Ho letto che il mutex approch non è al 100% non disponibile per quanto riguarda le condizioni di gara - anche se sembra l'opzione migliore.Terrò conto della proposta che hai collegato nell'altra risposta; Penso che una cosa del genere dovrebbe essere stata implementata anni fa, giusto? Grazie ancora! – Takeshi

+0

Le condizioni di gara sono solitamente correlate a thread all'interno di un processo. Questa è la corsa tra i processi. Ma sì, il rischio è lì, ma molto, molto piccolo. L'utente dovrebbe eseguire la seconda istanza esattamente prima che la prima istanza crei il mutex ma dopo aver verificato l'esistenza di mutex (quindi dovrebbe essere tra le chiamate 'CheckForMutexes' e' CreateMutex', che è al massimo in millisecondi). Inoltre, le persone usano mutex per verificare se le loro applicazioni sono già in esecuzione; è una pratica comune (non conosco nessuna funzione atomica che possa evitare questa condizione di competizione). – TLama

+0

Mi sono appena reso conto di [questo] (http://www.codeproject.com/Articles/538/Avoiding-Multiple-stances-of-an-Application). Ora so che è un campo lungo, ma ho sentito casi in cui l'area di supporto ha ricevuto chiamate da client con più istanze del nostro software in esecuzione (utilizza la tecnica mutex), quindi so che succede. – Takeshi

-1

Se il programma di installazione è stato chiamato setup.exe, ad esempio, è possibile utilizzare il seguente codice per verificare se setup.exe è in esecuzione e terminare l'installazione.

[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

Questo non è affatto affidabile. Potrebbe esserci un processo 'setup.exe' completamente diverso e questa non è la ragione per terminare la configurazione. – TLama

+0

Ma questo sarebbe abbastanza improbabile. Per evitare questo nome la tua configurazione come 'MyApplication_Setup_Ver_1.2.3.4.exe'. A mio parere, questo è più facile da usare e non intrappola l'utente a rinominare il file 'setup.exe' in qualcosa che preferisce. –

+0

Ho usato solo il nome setup.exe per semplificare il codice di esempio. Sono d'accordo con Wernfried. Nel codice prodotto il nome del file di installazione deve contenere il nome del prodotto e il numero di versione. Di solito imposto il nome del programma di installazione utilizzando OutputBaseFilename = Setup {#MyAppName} {# MyAppVersion} –

Problemi correlati