Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Windowsdienst mit Delphi starten (https://www.delphipraxis.net/151284-windowsdienst-mit-delphi-starten.html)

hirsch 11. Mai 2010 12:51


Windowsdienst mit Delphi starten
 
Liebes Forum,
ich habe nun eine Anwendung fertig, die mit MySQL - DatenbankTabellen umgeht. Funktioniert soweit auch ganz ok.
Ich würde nun gerne den Dienst: 'MySQL' starten, wenn meine Anwendung gestartet wurde und ebenso diesen Dienst wieder beenden, wenn meine Anwendung beendet wird. Wie muss ich an das Thema am besten herangehen?

Astat 11. Mai 2010 13:03

Re: Windowsdienst mit Delphi starten
 
Zitat:

Zitat von hirsch
..an das Thema am besten herangehen?

Delphi-Quellcode:

unit utils;

interface

uses
  windows, SysUtils, classes, WinSvc;

  function ServiceGetStatus(szMachine, szService: PChar): DWORD;
 
  function ServiceRunning(szMachine, szService: PChar): Boolean;

  function ServiceStart(szMachine, szServiceName: PChar;
    ServiceArgVectors: array of PChar): Boolean;

  function ServiceStop(szMachine, szServiceName: PChar;
    Timeout: DWORD = 60000): Boolean;

  function ServiceRegister(szMachine, szServiceFile, szServiceName,
    szDisplayName: PChar): Boolean;

  function ServiceUnRegister(szMachine, szServiceName: PChar): Boolean;

implementation


{*------------------------------------------------------------------------------
  Function zur Ermittlung eines Service Status
  @param szMachine PChar Name des Zielcomputers
  @param szService PChar Name des Services
  @return -1 = ERROR
  @return 1 = SERVICE_STOPPED
  @return 2 = SERVICE_START_PENDING
  @return 3 = SERVICE_STOP_PENDING
  @return 4 = SERVICE_RUNNING
  @return 5 = SERVICE_CONTINUE_PENDING
  @return 6 = SERVICE_PAUSE_PENDING
  @return 7 = SERVICE_PAUSED
-------------------------------------------------------------------------------}
function ServiceGetStatus(szMachine, szService: PChar): DWORD;
var
  SCManHandle, SvcHandle: SC_Handle;
  SS: TServiceStatus;
  dwStat: DWORD;
begin
  dwStat := 0;
  SCManHandle := OpenSCManager(szMachine, nil, SC_MANAGER_CONNECT);
  if (SCManHandle > 0) then begin
    SvcHandle := OpenService(SCManHandle, szService, SERVICE_QUERY_STATUS);
    if (SvcHandle > 0) then begin
      if (QueryServiceStatus(SvcHandle, SS)) then
        dwStat := ss.dwCurrentState;
      CloseServiceHandle(SvcHandle);
    end;
    CloseServiceHandle(SCManHandle);
  end;
  Result := dwStat;
end;

function ServiceRunning(szMachine, szService: PChar): Boolean;
begin
  Result := SERVICE_RUNNING = ServiceGetStatus(szMachine, szService);
end;


// szMachine ist UNC path oder nil wenn local machine
function ServiceStart(szMachine, szServiceName: PChar;
  ServiceArgVectors: array of PChar): Boolean;
var
  h_manager, h_svc: SC_Handle;
  ServiceStatus: TServiceStatus;
  dwCheckPoint: DWORD;
  szServiceArgVectors: PPChar;
begin
  h_manager := OpenSCManager(szMachine, nil, SC_MANAGER_CONNECT);
  if h_manager > 0 then begin
    h_svc := OpenService(h_manager, szServiceName,
      SERVICE_START or SERVICE_QUERY_STATUS or SC_MANAGER_ALL_ACCESS);
    if h_svc > 0 then begin
      szServiceArgVectors := nil;
      if Length(ServiceArgVectors) > 0 then
        szServiceArgVectors := @ServiceArgVectors[0];

      if (StartService(h_svc, Length(ServiceArgVectors), szServiceArgVectors^)) then
      begin
        if (QueryServiceStatus(h_svc, ServiceStatus)) then begin
          while (SERVICE_RUNNING <> ServiceStatus.dwCurrentState) do begin
            dwCheckPoint := ServiceStatus.dwCheckPoint;
            Sleep(ServiceStatus.dwWaitHint);
            if (not QueryServiceStatus(h_svc, ServiceStatus)) then break;
            if (ServiceStatus.dwCheckPoint < dwCheckPoint) then break;
          end;
        end;
      end;
      CloseServiceHandle(h_svc);
    end;
    CloseServiceHandle(h_manager);
  end;
  Result := (SERVICE_RUNNING = ServiceStatus.dwCurrentState);
end;

// szMachine ist UNC path oder nil wenn local machine
function ServiceStop(szMachine, szServiceName: PChar;
  Timeout: DWORD = 60000): Boolean;
var
  h_manager, h_svc: SC_Handle;
  ServiceStatus: TServiceStatus;
  dwCheckPoint: DWORD;
  dwStart: DWORD;
begin
  h_manager := OpenSCManager(szMachine, nil, SC_MANAGER_CONNECT);
  if h_manager > 0 then begin
    h_svc := OpenService(h_manager, szServiceName,
      SERVICE_STOP or SERVICE_QUERY_STATUS);
    if h_svc > 0 then begin
      if (ControlService(h_svc, SERVICE_CONTROL_STOP, ServiceStatus)) then begin
        if (QueryServiceStatus(h_svc, ServiceStatus)) then begin
          dwStart := GetTickCount;
          while (SERVICE_STOPPED <> ServiceStatus.dwCurrentState) do begin
            dwCheckPoint := ServiceStatus.dwCheckPoint;
            Sleep(ServiceStatus.dwWaitHint);
            if (not QueryServiceStatus(h_svc, ServiceStatus)) then break;
            if (ServiceStatus.dwCheckPoint < dwCheckPoint) then break;
            if GetTickCount - dwStart > Timeout then break;
          end;
        end;
      end;
      CloseServiceHandle(h_svc);
    end;
    CloseServiceHandle(h_manager);
  end;
  Result := (SERVICE_STOPPED = ServiceStatus.dwCurrentState);
end;

function ServiceRegister(szMachine, szServiceFile, szServiceName,
  szDisplayName: PChar): Boolean;
var
  h_manager, h_svc: SC_Handle;
begin
  Result := false;

  h_manager := OpenSCManager(szMachine, nil, SC_MANAGER_ALL_ACCESS);
  if h_manager > 0 then begin

    h_svc := CreateService(h_manager,
      szServiceName,
      szDisplayName,
      SERVICE_START or SERVICE_QUERY_STATUS or _DELETE,
      SERVICE_WIN32_OWN_PROCESS, // or SERVICE_INTERACTIVE_PROCESS,
      SERVICE_AUTO_START,
      SERVICE_ERROR_NORMAL,
      szServiceFile,
      nil, nil, nil, nil, nil);

    if h_svc > 0 then begin
      result := true;
      CloseServiceHandle(h_svc);
    end;

    CloseServiceHandle(h_manager);
  end;
end;

function ServiceUnRegister(szMachine, szServiceName: PChar): Boolean;
var
  h_manager, h_svc: SC_Handle;
begin
  Result := false;

  h_manager := OpenSCManager(szMachine, nil, SC_MANAGER_ALL_ACCESS);
  if h_manager > 0 then begin

    h_svc := OpenService(h_manager, szServiceName, SERVICE_ALL_ACCESS);
    if h_svc > 0 then begin
      result := DeleteService(h_svc);
      CloseServiceHandle(h_svc);
    end;

    CloseServiceHandle(h_manager);
  end;
end;

end.
lg. Astat

hirsch 11. Mai 2010 15:59

Re: Windowsdienst mit Delphi starten
 
@Astat, vielen Dank,
das mit dem Dienst starten klappt ja einwandfrei, aber beim Programm beenden hab ich noch son Problem.
Als erstes beende ich ja alle Konnektoren usw.
Dann beende ich den MySQL-Dienst. Der stoppt auch.
Dann bekomme ich die Fehlermeldung 'Can't connect to MySQL-Server'
Is ja auch so. Soll ja so sein, nur will ich eben die Fehlermeldung nicht.
Achja und das Programm wird auch nicht geschlossen.....

Delphi-Quellcode:
procedure TMenue.BuendClick(Sender: TObject);
var st : integer;
begin
   st:=ServiceGetStatus(PChar(PC), PChar(Dienst));
   Datamodule1.CDS1.Active:=False;
   Datamodule1.CDS2.Active:=False;
   Datamodule1.SDS1.Active:=False;
   Datamodule1.SDS2.Active:=False;
   Datamodule1.DBConnect.Connected:=False;
   ServiceStop(nil, PChar(Dienst), 500);
   showmessage('Dienst wird beendet');
   Sleep(500);
   repeat
     st:=ServiceGetStatus(PChar(PC), PChar(Dienst));
   until st = 1;
        Application.Terminate;
end;

shmia 11. Mai 2010 17:00

Re: Windowsdienst mit Delphi starten
 
Zitat:

Zitat von hirsch
Als erstes beende ich ja alle Konnektoren usw.

Wie viele sind das denn?
Pro Datenbank sollte es nur eine Connection geben.
Delphi-Quellcode:
repeat
   st:=ServiceGetStatus(PChar(PC), PChar(Dienst));
until st = 1;
Macht das wirklich Sinn endlos auf die Beendigung des Dienstes zu warten?
Ich denke nicht.
Wenn der MySQL-Dienst nicht beendet werden kann, dann wird das seine Gründe haben.
Darauf zu warten ist doch sinnlos; es gibt dem Benutzer nur das Gefühl dass dein Programm sich aufgehängt hat.

hirsch 12. Mai 2010 07:08

Re: Windowsdienst mit Delphi starten
 
Zitat:

Zitat von hirsch
Delphi-Quellcode:
   Datamodule1.DBConnect.Connected:=False;
   ServiceStop(nil, PChar(Dienst), 500);

Hallo Shmia,
es gibt nur einen....

Ich glaube ich werde es anders machen. Den Dienst auf mauell umstellen, beim Programmstart dann den Dienst starten und dann wenn das Programm beendet wird, den Dienst einfach weiter laufen lassen.....

generic 12. Mai 2010 08:47

Re: Windowsdienst mit Delphi starten
 
Ich glaube nicht, dass das gehen wird. Zum Dienst starten werden erhöhte Rechte benötigt. Diese hat kein User und somit auch nicht dein Programm.

Du solltest eine Embedded-Variante nutzen, welche du mit einer DLL einbinden kannst.
Alternativ kannst du den Mysql im Usercontext starten. Allerdings geht das nicht als einen Dienst.

Bernhard Geyer 12. Mai 2010 08:52

Re: Windowsdienst mit Delphi starten
 
Bedenke auch das wenn dein Programm verkaufst und es nicht OpenSource ist das du für jede Verteilung eine MySQL-Serverlizenz benötigst.
Bei Embedded auf jeden fall und bei "richigen" Server wenn du nur mit diesem Lauffähig bist.

Luckie 12. Mai 2010 12:09

Re: Windowsdienst mit Delphi starten
 
Hinzukommt, dass dein Programm Administratorenrechte benötigt, um den Dienst zu starten und zu stoppen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz