Announcement

Collapse
No announcement yet.

NT Service aus NT Service starten

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • NT Service aus NT Service starten

    Hallo,<br>
    ich versuche einen NT Service aus der <i>ServiceStart</i> Routine eines anderen Service zu starten. Das klappt auch, nur dass man die Fehlermeldung bekommt, dass der (aufrufende) Service nicht korrekt gestartet werden konnte (obwohl dieser läuft). Gibt es in diesem speziellen Fall vielleicht etwas zu beachten?<br>
    Hier vielleicht noch ein Stück Code:<br>
    <pre>
    procedure TNTInvClientInit.ServiceStart(Sender: TService; var Started: Boolean);
    var
    mgr, svc : THandle;
    Status : TServiceStatus;
    p : PChar;
    SysDir : Array [0..254] of char;
    HWndProgMan : THandle;
    begin

    // COM+ initialisieren. Das muss gemacht werden, weil für den Dienst ein
    // Thread abgespalten wird. Immer wenn man auf COM Objekte zugreift (hier z.B. RDS)
    // muss man das explizit tun. (s.a. A.Kosch Delphi Win32 Lösungen Seite 472/473)
    CoInitialize(nil);

    mgr := 0;
    svc := 0;
    GetSystemDirectory(SysDir, SizeOf(SysDir));
    FSysDir := AppendDirBackSlash(SysDir);

    try
    mgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    if mgr = 0 then
    begin
    FEventLogger.LogMessage('Service-Manager nicht erreicht!', EVENTLOG_WARNING_TYPE, 0, 1);
    exit;
    end;
    svc := OpenService(mgr, INVSERVICE_NAME, SERVICE_ALL_ACCESS);
    if svc = 0 then
    begin
    // Service (noch) nicht vorhanden, nichts tun
    FEventLogger.LogMessage('Service '+INVSERVICE_NAME+' nicht gefunden!', EVENTLOG_WARNING_TYPE, 0, 1);
    exit;
    end
    else
    begin
    // NTInvClient Service stoppen
    QueryServiceStatus(svc, Status);
    // Wenn NTInvClient läuft, diesen stoppen
    if Status.dwCurrentState = SERVICE_RUNNING then
    begin
    ControlService(svc, SERVICE_CONTROL_STOP, Status);
    end;
    end;

    if (svc <> 0) then
    begin
    // Warten bis Service gestoppt ist
    QueryServiceStatus(svc, Status);

    while (Status.dwCurrentState <> SERVICE_STOPPED) do
    QueryServiceStatus(svc, Status);

    if Status.dwCurrentState = SERVICE_STOPPED then
    begin
    // Update checken
    if UpdateInvClientService = 0 then
    begin

    // NTInvClient wieder starten (wenn Update erfolgreich war);
    QueryServiceStatus(svc, Status);
    if Status.dwCurrentState <> SERVICE_RUNNING then
    begin
    p := nil;

    // BIS HIERHIN GING ES:

    { TEST *** KANN WIEDER RAUS }
    // AKTUELLER TESTPUNKT
    Started := TRUE;
    exit;
    { TEST ENDE *** KANN WIEDER RAUS }

    // ###################################
    // STARTSERVICE MACHT DAS PROBLEM !!!!!!
    // ###################################
    StartService(svc, 0, p);

    end;
    end;
    end;
    end;
    finally
    if mgr <> 0 then CloseServiceHandle(mgr);
    if svc <> 0 then CloseServiceHandle(svc);
    end;
    Started := TRUE;
    end;
    </pre>
    Viele Grüsse<br>
    Hermann

  • #2
    Hallo,<br>
    Aus einem Programm kann man so einen Service starten aus einem Service hab ich noch nie probiert.
    <pre>
    unit ServiceU;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs;

    type
    TmyService = class(TService)
    private
    { Private-Deklarationen }
    public
    function GetServiceController: TServiceController; override;
    function StartMSTRService(SrvName: String): Boolean;
    { Public-Deklarationen }
    end;

    var
    myService: TmyService;

    implementation
    uses WinSvc;
    {$R *.DFM}

    procedure ServiceController(CtrlCode: DWord); stdcall;
    begin
    myService.Controller(CtrlCode);
    end;

    function TmyService.GetServiceController: TServiceController;
    begin
    Result := ServiceController;
    end;

    function TmyService.StartMSTRService(SrvName: String): Boolean;
    var
    mgr: THandle;
    svc: THandle;
    status: TServiceStatus;
    p: PChar;
    //s_name: String;
    begin
    Result := False;
    mgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
    if mgr = 0 then
    raise Exception.Create('Service-Manager nicht erreicht!');
    svc := OpenService(mgr, PChar(SrvName), SERVICE_ALL_ACCESS);
    if svc = 0 then
    raise Exception.Create(Format('Service %s nicht gefunden!',[SrvName]));
    QueryServiceStatus(svc, status);
    // nur starten, wenn der Service nicht bereits läuft
    if status.dwCurrentState <> SERVICE_RUNNING then
    begin
    p := nil;
    StartService(svc, 0, p);
    end;
    CloseServiceHandle(svc);
    CloseServiceHandle(mgr);
    Result := True;
    end;

    end.
    </pre>
    Gruß Andreas H

    Comment


    • #3
      Hallo,

      wenn man keinen eigenen Arbeits-Thread für den Service erzeugen will, steht das TService-Ereignis <b>OnExecute</b> zur Verfügung, um von dort aus den 2. Service starten zu können. Ich hatte vor einiger Zeit dazu einen Demo-Service geschrieben, aus dem der folgende Teil stammt:
      <pre>
      procedure TM_START.M_STARTExecute(Sender: TService);
      resourcestring
      cTry = 'M_START.Execute: Versuche die Dienste zu starten.';
      cMsg = 'M_START: Dienst »%s« konnte erfolgreich gestartet werden.';
      cErr = 'M_START: Dienst »%s« konnte nicht gestartet werden.';
      var
      tel: TEventLogger;
      sServiceName : String;
      begin
      tel := TEventLogger.Create('MStart');
      try
      tel.LogMessage(cTry, EVENTLOG_INFORMATION_TYPE);
      // 1. Service starten
      sServiceName := 'M_TEST';
      if StartMSTRService(sServiceName) then
      tel.LogMessage(Format(cMsg, [sServiceName]), EVENTLOG_INFORMATION_TYPE)
      else
      tel.LogMessage(Format(cErr, [sServiceName]), EVENTLOG_INFORMATION_TYPE);
      // Wartepause
      Sleep(500);
      // 2. Service Starten
      finally
      tel.Free;
      end;
      end;

      {---------------------------------------------------------------}
      { Private Methode }
      {---------------------------------------------------------------}

      function TM_START.StartMSTRService(SrvName: String): Boolean;
      var
      mgr: THandle;
      svc: THandle;
      status: TServiceStatus;
      p: PChar;
      s_name: String;
      begin
      Result := False;
      mgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
      if mgr = 0 then
      raise Exception.Create('Service-Manager nicht erreicht!');
      svc := OpenService(mgr, PChar(SrvName), SERVICE_ALL_ACCESS);
      if svc = 0 then
      raise Exception.Create(Format('Service %s nicht gefunden!',[SrvName]));
      QueryServiceStatus(svc, status);
      // nur starten, wenn der Service nicht bereits läuft
      if status.dwCurrentState <> SERVICE_RUNNING then
      begin
      p := nil;
      StartService(svc, 0, p);
      end;
      CloseServiceHandle(svc);
      CloseServiceHandle(mgr);
      Result := True;
      end;
      </pre>
      Wenn der Weg über OnExecute aus irgend einem Grund nicht in Frage kommt, muss man in <b>ServiceStart</b> sofort einen Thread abspalten, damit diese Methode sofort zurückkehren kann und der SCM keinen Timeout auslöst ("... Dienst konnte nicht gestartet werden..."). Das Hochfahren des zweiten Services wird dann in diesem Thread erledigt, wobei hier die dafür benötigte Zeitdauer unkritisch ist.
      <pre>
      procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
      begin
      TestThread := TTestThread.Create(False);
      Started := True;
      end;
      </pre&gt

      Comment


      • #4
        Vielen Dank Herr Kosch,<br>
        hat mal wieder sehr geholfen. Ich hatte versucht, den zweiten Service
        in <i><b>OnStart</b></i> zu starten. In <i><b>OnExecute</b></i> klappt es

        Comment

        Working...
        X