2010-03-16 24 views
12

Ho creato un'installazione di base del servizio Windows utilizzando Inno Setup. sia l'installazione che la disinstallazione funzionano correttamente.Aggiornamento del servizio Windows tramite Inno Setup

Tuttavia, sto riscontrando problemi con la procedura di aggiornamento.

Per aggiornare l'eseguibile del servizio è necessario interrompere il servizio e solo dopo che il servizio è stato completamente arrestato è possibile posizionare gli eseguibili aggiornati nella cartella di destinazione.

Come è possibile eseguire un comando di arresto del servizio e attendere che il servizio venga arrestato completamente prima dell'avvio del passaggio di distribuzione del file?

risposta

5

Ci sono due parti a questo:

  1. Come può un programma di installazione creata con Inno Setup avviare e interrompere i servizi, come può creare ed eliminare loro, come può cambiare la sua modalità di avvio?

    Utilizzando le funzioni di supporto fornite in questo collection of routines scritto esattamente per questo scopo. È scritto per la versione Ansi di Inno Setup, quindi le modifiche saranno necessarie alle importazioni della funzione API e ai tipi di parametri PChar, ma dovrebbe iniziare.

  2. Come può essere arrestato un servizio esistente prima che venga copiata la nuova versione del file?

    Hai due modi per farlo. Dovresti usare lo scripting Pascal per eseguire le funzioni collegate sopra per interrompere il servizio, devi solo decidere se farlo in una delle funzioni dell'evento, o se farlo in una funzione personalizzata che verrà chiamata tramite il parametro Check della voce del file per l'eseguibile del servizio. Lo farei sicuramente nel primo caso, in modo da poter verificare se il servizio è stato interrotto con successo e proibire l'avvio effettivo dell'installazione quando questo non è riuscito.

    È necessario esaminare le funzioni degli eventi CurStepChanged() e NextButtonClick(), a seconda che sia necessario impedire il passaggio successivo. Gli esempi di installazione Inno mostrano l'uso di entrambe le funzioni.

16

Il codice di seguito viene dalla seguente pagina:
http://www.vincenzo.net/isxkb/index.php?title=Service_-_Functions_to_Start%2C_Stop%2C_Install%2C_Remove_a_Service

Tuttavia, ho dovuto applicare una correzione minore per farlo funzionare.

Nota che ho originariamente pubblicato questa risposta nel 2010. Il codice a la pagina di cui sopra è stato aggiornato nel 2011, quindi forse vale la pena una visita.

Io uso questo codice nel mio installatore, come #include. È compilato in Inno Setup ANSI.
Può funzionare per la versione Unicode di Inno Setup sostituendo [email protected] con [email protected] in tutte le dichiarazioni external (grazie JeroenWiertPluimers per averlo indicato).

Si noti inoltre che lo StartService e StopService inviano semplicemente un segnale di avvio/arresto, ma non si attende che il servizio sia in stato di arresto.È possibile creare codice che aspetterebbe che il servizio sia in esecuzione utilizzando IsServiceRunning in combinazione con la funzione Pascal Script Sleep(). O solo Sleep() un numero predefinito di secondi.

Il codice implementa queste funzioni:

function IsServiceInstalled(ServiceName: string) : boolean; 
function IsServiceRunning(ServiceName: string) : boolean; 
function InstallService(FileName, ServiceName, DisplayName, Description : string;ServiceType,StartType :cardinal) : boolean; 
function RemoveService(ServiceName: string) : boolean; 
function StartService(ServiceName: string) : boolean; 
function StopService(ServiceName: string) : boolean; 
function SetupService(service, port, comment: string) : boolean; 

Il codice attuale:

type 
    SERVICE_STATUS = record 
     dwServiceType    : cardinal; 
     dwCurrentState    : cardinal; 
     dwControlsAccepted   : cardinal; 
     dwWin32ExitCode    : cardinal; 
     dwServiceSpecificExitCode : cardinal; 
     dwCheckPoint    : cardinal; 
     dwWaitHint     : cardinal; 
    end; 
    HANDLE = cardinal; 

const 
    SERVICE_QUERY_CONFIG  = $1; 
    SERVICE_CHANGE_CONFIG  = $2; 
    SERVICE_QUERY_STATUS  = $4; 
    SERVICE_START    = $10; 
    SERVICE_STOP    = $20; 
    SERVICE_ALL_ACCESS   = $f01ff; 
    SC_MANAGER_ALL_ACCESS  = $f003f; 
    SERVICE_WIN32_OWN_PROCESS = $10; 
    SERVICE_WIN32_SHARE_PROCESS = $20; 
    SERVICE_WIN32    = $30; 
    SERVICE_INTERACTIVE_PROCESS = $100; 
    SERVICE_BOOT_START   = $0; 
    SERVICE_SYSTEM_START  = $1; 
    SERVICE_AUTO_START   = $2; 
    SERVICE_DEMAND_START  = $3; 
    SERVICE_DISABLED   = $4; 
    SERVICE_DELETE    = $10000; 
    SERVICE_CONTROL_STOP  = $1; 
    SERVICE_CONTROL_PAUSE  = $2; 
    SERVICE_CONTROL_CONTINUE = $3; 
    SERVICE_CONTROL_INTERROGATE = $4; 
    SERVICE_STOPPED    = $1; 
    SERVICE_START_PENDING  = $2; 
    SERVICE_STOP_PENDING  = $3; 
    SERVICE_RUNNING    = $4; 
    SERVICE_CONTINUE_PENDING = $5; 
    SERVICE_PAUSE_PENDING  = $6; 
    SERVICE_PAUSED    = $7; 

{ nt based service utilities } 
function OpenSCManager(lpMachineName, lpDatabaseName: string; dwDesiredAccess :cardinal): HANDLE; 
external '[email protected] stdcall'; 

function OpenService(hSCManager :HANDLE;lpServiceName: string; dwDesiredAccess :cardinal): HANDLE; 
external '[email protected] stdcall'; 

function CloseServiceHandle(hSCObject :HANDLE): boolean; 
external '[email protected].dll stdcall'; 

function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: string;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: String; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :string): cardinal; 
external '[email protected] stdcall'; 

function DeleteService(hService :HANDLE): boolean; 
external '[email protected] stdcall'; 

function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : boolean; 
external '[email protected] stdcall'; 

function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : boolean; 
external '[email protected] stdcall'; 

function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : boolean; 
external '[email protected] stdcall'; 

function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : boolean; 
external '[email protected] stdcall'; 

function GetLastError() : cardinal; 
external '[email protected] stdcall'; 

function OpenServiceManager() : HANDLE; 
begin 
    if UsingWinNT() = true then begin 
     Result := OpenSCManager('','',SC_MANAGER_ALL_ACCESS); 
     if Result = 0 then 
      MsgBox('the servicemanager is not available', mbError, MB_OK) 
    end 
    else begin 
      MsgBox('only nt based systems support services', mbError, MB_OK) 
      Result := 0; 
    end 
end; 

function IsServiceInstalled(ServiceName: string) : boolean; 
var 
    hSCM : HANDLE; 
    hService: HANDLE; 
begin 
    hSCM := OpenServiceManager(); 
    Result := false; 
    if hSCM <> 0 then begin 
     hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_CONFIG); 
     if hService <> 0 then begin 
      Result := true; 
      CloseServiceHandle(hService) 
     end; 
     CloseServiceHandle(hSCM) 
    end 
end; 

function InstallService(FileName, ServiceName, DisplayName, Description : string;ServiceType,StartType :cardinal) : boolean; 
var 
    hSCM : HANDLE; 
    hService: HANDLE; 
begin 
    hSCM := OpenServiceManager(); 
    Result := false; 
    if hSCM <> 0 then begin 
     hService := CreateService(hSCM,ServiceName,DisplayName,SERVICE_ALL_ACCESS,ServiceType,StartType,0,FileName,'',0,'','',''); 
     if hService <> 0 then begin 
      Result := true; 
      { Win2K & WinXP supports additional description text for services } 
      if Description<> '' then 
       RegWriteStringValue(HKLM,'System\CurrentControlSet\Services\' + ServiceName,'Description',Description); 
      CloseServiceHandle(hService) 
     end; 
     CloseServiceHandle(hSCM) 
    end 
end; 

function RemoveService(ServiceName: string) : boolean; 
var 
    hSCM : HANDLE; 
    hService: HANDLE; 
begin 
    hSCM := OpenServiceManager(); 
    Result := false; 
    if hSCM <> 0 then begin 
     hService := OpenService(hSCM,ServiceName,SERVICE_DELETE); 
     if hService <> 0 then begin 
      Result := DeleteService(hService); 
      CloseServiceHandle(hService) 
     end; 
     CloseServiceHandle(hSCM) 
    end 
end; 

function StartService(ServiceName: string) : boolean; 
var 
    hSCM : HANDLE; 
    hService: HANDLE; 
begin 
    hSCM := OpenServiceManager(); 
    Result := false; 
    if hSCM <> 0 then begin 
     hService := OpenService(hSCM,ServiceName,SERVICE_START); 
     if hService <> 0 then begin 
      Result := StartNTService(hService,0,0); 
      CloseServiceHandle(hService) 
     end; 
     CloseServiceHandle(hSCM) 
    end; 
end; 

function StopService(ServiceName: string) : boolean; 
var 
    hSCM : HANDLE; 
    hService: HANDLE; 
    Status : SERVICE_STATUS; 
begin 
    hSCM := OpenServiceManager(); 
    Result := false; 
    if hSCM <> 0 then begin 
     hService := OpenService(hSCM,ServiceName,SERVICE_STOP); 
     if hService <> 0 then begin 
      Result := ControlService(hService,SERVICE_CONTROL_STOP,Status); 
      CloseServiceHandle(hService) 
     end; 
     CloseServiceHandle(hSCM) 
    end; 
end; 

function IsServiceRunning(ServiceName: string) : boolean; 
var 
    hSCM : HANDLE; 
    hService: HANDLE; 
    Status : SERVICE_STATUS; 
begin 
    hSCM := OpenServiceManager(); 
    Result := false; 
    if hSCM <> 0 then begin 
     hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_STATUS); 
     if hService <> 0 then begin 
      if QueryServiceStatus(hService,Status) then begin 
       Result :=(Status.dwCurrentState = SERVICE_RUNNING) 
      end; 
      CloseServiceHandle(hService) 
      end; 
     CloseServiceHandle(hSCM) 
    end 
end; 
+4

Ho ereditato un codice che assomiglia alla tua risposta. Non hanno menzionato la fonte né * ANSI *, quindi mi ci è voluto un po 'per capire che l'errore "ERROR_INVALID_NAME' alias 123 (0x7B) generato da" OpenSCManager "poteva essere risolto sostituendo" A @ "con" W @ "in tutti dichiarazioni 'esterne' mentre eseguivo Inno Setup * Unicode *. –

6

Come di Inno Setup 5.5.0, le direttive e CloseApplicationsRestartApplications sono ora disponibili. Queste opzioni rileveranno i file in uso e chiuderanno le applicazioni che li utilizzano.

+0

Penso che questi non funzionino per i servizi ... – Roddy

+0

CloseApplicazioni e restartApplicazioni utilizzano [Gestione riavvio di Windows] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa373524.aspx), e supporta applicazioni GUI, Console e ** service **. – jachguate

+0

Non riesco a far funzionare CloseApplications per un servizio, non so perché – pogorman

2

Sto utilizzando un file batch che interrompe, disinstalla, installa e avvia un determinato servizio, ho appena chiamato il file batch utilizzando innosetup dopo che tutti i file sono stati copiati.

[Run] 
Filename: "{app}\Scripts\installwindowsService.bat"; Parameters: "{app}"; Flags: runhidden 

ho messo i seguenti comandi nel mio file batch

net stop MyService 

%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u MyService.exe 

%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\installutil.exe MyService.exe /unattended 

net start MyService 

Funziona come un fascino ed è molto semplice. può essere utilizzato per una prima installazione o per un aggiornamento. Spero che ti aiuti.

Problemi correlati