2010-03-16 10 views
12

Ich habe eine grundlegende Windows-Dienstinstallation mit Inno Setup erstellt. Sowohl die Installation als auch die Deinstallation funktionieren ordnungsgemäß.Aktualisieren des Windows-Dienstes mit Inno Setup

Allerdings habe ich Probleme mit dem Upgrade-Verfahren.

Um die ausführbare Datei des Dienstes zu aktualisieren, ist es erforderlich, den Dienst zu stoppen, und erst nachdem der Dienst vollständig gestoppt wurde, können die aktualisierten ausführbaren Dateien in den Zielordner gestellt werden.

Wie kann ich einen Service-Stop-Befehl ausführen und darauf warten, dass der Dienst vollständig gestoppt wird, bevor der Dateibereitstellungsschritt initiiert wird?

Antwort

5

Es gibt zwei Teile dazu:

  1. Wie kann ein Installationsprogramm mit Inno Setup erstellt Dienste starten und stoppen, wie es sie erstellen und löschen, wie kann es seine Startmodus ändern?

    Durch die Verwendung der Hilfsfunktionen in diesem collection of routines genau für diesen Zweck geschrieben. Es wird für die Ansi-Version von Inno Setup geschrieben, so dass Änderungen an den API-Funktionsimporten und den PChar Parametertypen erforderlich sind, aber es sollte Ihnen den Einstieg erleichtern.

  2. Wie kann ein bestehender Dienst gestoppt werden, bevor die neue Dateiversion kopiert wird?

    Sie haben grundsätzlich zwei Möglichkeiten, dies zu tun. Sie würden Pascal Scripting verwenden, um die oben verlinkten Funktionen auszuführen, um den Dienst zu stoppen. Sie müssen lediglich entscheiden, ob Sie dies in einer der Ereignisfunktionen tun oder in einer benutzerdefinierten Funktion, die über den Parameter Check aufgerufen wird des Dateieintrags für die ausführbare Datei des Dienstes. Ich würde es definitiv in ersterem tun, also können Sie überprüfen, ob der Service erfolgreich beendet wurde, und die Installation davon abhalten, wirklich zu beginnen, als dieser fehlschlug.

    Sie sollten in die Ereignisfunktionen CurStepChanged() und NextButtonClick() schauen, je nachdem, ob Sie möglicherweise den nächsten Schritt verhindern müssen. Die Inno Setup-Beispiele zeigen die Verwendung beider Funktionen.

16

Der folgende Code stammt aus der folgenden Seite:
http://www.vincenzo.net/isxkb/index.php?title=Service_-_Functions_to_Start%2C_Stop%2C_Install%2C_Remove_a_Service

Allerdings habe ich eine kleine Korrektur anwenden musste, damit es funktioniert.

Bitte beachte, dass ich ursprünglich diese Antwort geschrieben im Jahr 2010. Den Code auf die Seite oben wurde im Jahr 2011 aktualisiert, so könnte es einen Besuch wert sein.

Ich verwende diesen Code in meinem Installer als #include. Es ist kompiliert in Inno Setup ANSI.
Es kann für die Unicode-Version von Inno-Setup funktionieren, indem [email protected] durch [email protected] in allen external Deklarationen ersetzt wird (danke JeroenWiertPluimers für das hinweisend).

Beachten Sie auch, dass die StartService und StopService nur einen Start senden/Stopp-Signal, aber warten Sie nicht für den Dienst in den Betrieb der gestoppten Zustand zu sein.Sie können Code erstellen, der darauf warten würde, dass der Dienst ausgeführt wird. Verwenden Sie dazu den Befehl IsServiceRunning in Verbindung mit der Funktion Pascal Script Sleep(). Oder einfach Sleep() eine vordefinierte Anzahl von Sekunden.

Der Code implementiert diese Funktionen:

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; 

Der eigentliche Code:

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] 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

Ich habe einen Code geerbt, der genau wie Ihre Antwort aussieht. Sie haben weder die Quelle noch * ANSI * erwähnt, also brauchte ich eine Weile, um zu erkennen, dass der 'ERROR_INVALID_NAME' alias 123 (0x7B) -Fehler von' OpenSCManager' durch Ersetzen von 'A @' mit 'W @' behoben werden konnte 'externe' Deklarationen, da ich Inno Setup * Unicode * ausgeführt habe. –

6

Ab Inno Setup 5.5.0, die CloseApplications und RestartApplications Richtlinien sind jetzt verfügbar. Mit diesen Optionen werden die verwendeten Dateien erkannt und die Anwendungen, die diese verwenden, heruntergefahren.

+0

Ich denke, diese funktionieren nicht für Dienste ... – Roddy

+0

CloseApplications und RestartApplications verwenden den [Windows Restart Manager] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa373524.aspx), und es unterstützt GUI, Konsole und ** Service ** -Anwendungen. – jachguate

+0

Ich konnte CloseApplications nicht für einen Dienst arbeiten lassen - nicht sicher warum – pogorman

2

Ich verwende eine Batch-Datei, die stoppt, deinstalliert, installiert und startet einen bestimmten Dienst, ich rufe nur die Batchdatei mit innosetup, nachdem alle Dateien kopiert wurden.

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

Ich habe die folgenden Befehle in meiner Batch-Datei

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 

Es funktioniert wie ein Charme und ist sehr einfach. kann zum ersten Mal installiert oder für ein Update verwendet werden. Hoffe es hilft dir.

Verwandte Themen