2010-03-16 15 views
12

He creado una instalación básica del servicio de Windows usando Inno Setup. Tanto la instalación como la desinstalación funcionan correctamente.Actualizando el servicio de Windows usando Inno Setup

Sin embargo, tengo problemas con el procedimiento de actualización.

Para actualizar el ejecutable del servicio, es necesario detener el servicio, y solo después de que el servicio se haya detenido por completo, los ejecutables actualizados se pueden colocar en la carpeta de destino.

¿Cómo puedo ejecutar un comando de parada de servicio y esperar a que el servicio se detenga por completo antes de que se inicie el paso de implementación del archivo?

Respuesta

5

Hay dos partes a esto:

  1. ¿Cómo puede un instalador creado con Inno Setup iniciar y detener los servicios, ¿cómo puede crear y eliminar ellos, ¿cómo puede cambiar su modo de inicio?

    Al usar las funciones auxiliares provistas en este collection of routines escritas para este propósito. Está escrito para la versión Ansi de Inno Setup, por lo que será necesario realizar cambios en las importaciones de la función API y en los tipos de parámetros PChar, pero debe comenzar.

  2. ¿Cómo se puede detener un servicio existente antes de que se copie la nueva versión del archivo?

    Tiene básicamente dos formas de hacerlo. Utilizaría las secuencias de comandos de Pascal para ejecutar las funciones vinculadas a las anteriores para detener el servicio, solo tiene que decidir si lo hace en una de las funciones de eventos, o si lo hará en una función personalizada que se llamará a través del parámetro Check de la entrada de archivo para el ejecutable del servicio. Definitivamente lo haría en el primero, para que pueda verificar si el servicio se detuvo con éxito y prohibir que la instalación realmente se inicie cuando esto falló.

    Debe consultar las funciones de evento CurStepChanged() y NextButtonClick(), dependiendo de si necesita evitar el próximo paso. Los ejemplos de Inno Setup muestran el uso de ambas funciones.

16

El código siguiente proviene de la página siguiente:
http://www.vincenzo.net/isxkb/index.php?title=Service_-_Functions_to_Start%2C_Stop%2C_Install%2C_Remove_a_Service

Sin embargo, he tenido que aplicar una solución de menor importancia para hacer que funcione.

Tenga en cuenta que originalmente publiqué esta respuesta en 2010. El código en la página anterior se actualizó en 2011, por lo que podría valer la pena una visita.

Utilizo este código en mi instalador, como #include. Se compila en Inno Setup ANSI.
Puede funcionar para la versión Unicode de Inno Setup reemplazando [email protected] con [email protected] en todas las declaraciones external (gracias JeroenWiertPluimers por señalar eso).

También tenga en cuenta que StartService y StopService solo envían una señal de inicio/parada, pero no espere a que el servicio esté en estado detenido.Puede construir código que esperaría a que se ejecute el servicio, utilizando el IsServiceRunning junto con la función Pascal Script Sleep(). O simplemente Sleep() una cantidad predefinida de segundos.

El código implementa estas funciones:

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; 

El código real:

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 'CloseSe[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

Heredé un código que se parece a tu respuesta. No mencionaron la fuente ni * ANSI *, así que me tomó un tiempo darme cuenta de que el error 'ERROR_INVALID_NAME' también conocido como 123 (0x7B) lanzado por' OpenSCManager' podría resolverse reemplazando 'A @' con 'W @' en todos declaraciones 'externas' cuando estaba ejecutando Inno Setup * Unicode *. –

6

A partir de Inno Setup 5.5.0, los CloseApplications y RestartApplications directivas están ahora disponibles. Estas opciones detectarán archivos en uso y cerrarán las aplicaciones que los usan.

+0

Creo que estos no funcionan para Servicios ... – Roddy

+0

CerrarAplicaciones y reiniciar aplicacionesutilice el [Windows Restart Manager] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa373524.aspx), y admite aplicaciones de GUI, consola y ** servicio **. – jachguate

+0

No pude hacer que CloseApplications funcione para un servicio, no estoy seguro de por qué – pogorman

2

Estoy usando un archivo de proceso por lotes que detiene, desinstala, instala e inicia un servicio dado, solo llamo al archivo por lotes usando innosetup después de que se hayan copiado todos los archivos.

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

puse los siguientes comandos en mi archivo por lotes

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 

Funciona como un encanto y es muy sencillo. se puede utilizar para una instalación por primera vez o para una actualización. Espero que te ayude

Cuestiones relacionadas