Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Delphi und Serviceanwendungen, demo? (https://www.delphipraxis.net/196258-delphi-und-serviceanwendungen-demo.html)

Mavarik 5. Mai 2018 07:19

Delphi und Serviceanwendungen, demo?
 
Hallo Zusammen...

Hat jemand ein working demo um einen Service-Anwendung zu starten, stoppen und zu beenden.

Nicht mit NET START... Sondern per Token die Adminrechte holen und dann WinSVC?

Ich habe vor Jahren - da gab es noch keinen TeamViewer - "so etwas" als Service programmiert. Das hat jedoch alles auf JEDI-Zeugs aufgebaut, was ich in der neuen Anwendungen nicht verwenden möchte...

Vielleicht hat ja jemand so ein codeschnipsel...

Vorab Danke

Mavarik :coder:

timog 5. Mai 2018 07:58

AW: Delphi und Serviceanwendungen, demo?
 
Von Luckie und CalganX stammt da ein Post mit OpenSCManager/OpenService. Nutze den mit einem Admin-Manifest für das Starten, Beenden und die Statusabfrage für Services. Ist die API dahinter noch aktuell?

jaenicke 5. Mai 2018 08:17

AW: Delphi und Serviceanwendungen, demo?
 
Zitat:

Zitat von Mavarik (Beitrag 1401324)
Sondern per Token die Adminrechte holen und dann WinSVC?

Wir starten einfach die eigene Anwendung mit passenden Parametern und Adminaufforderung im Hintergrund. Das ist deutlich einfacher, zudem hatten wir mit der Out-Of-Process COM Variante schon Probleme auf manchen Systemen, vor allem mit Antivirenprogrammen. Deshalb sind wir wieder bei der einfachen, aber so gut wie immer funktionierenden, Variante gelandet.

Und dann könntest du einfach ganz normal Quelltext wie diesen nutzen, um den Dienst zu starten oder zu stoppen:
https://www.entwickler-ecke.de/topic...toppen_77.html

Auch wenn es deiner Anforderung nicht entspricht (benutzt net start, weil wie erwähnt die OOP-COM-Variante wieder ausgebaut ist) verlinke ich trotzdem mal ein Beispiel wie wir bei uns Dienste gestalten:
https://www.delphipraxis.net/1323261-post24.html
Diese kann man normal als Anwendung starten und bekommt dann eine GUI zum Installieren, Starten usw., natürlich mit Statusprüfung über die API. An den Stellen, wo wir extern net.exe benutzen kann natürlich auch einfach der verlinkte Quelltext eingesetzt werden.

HolgerX 5. Mai 2018 12:43

AW: Delphi und Serviceanwendungen, demo?
 
Hmm..

hab hier ne Unit (weiß nicht mehr woher), jedoch ist die mit Delphi6 erstellt und würde wohl Überarbeitungen im Bezug auf PChar benötigen ;)
Für die benötigten Admin-Rechte musst Du jedoch selber schauen ;)

Ich verwende Sie zum Auflisten/Starten/Stoppen von Diensten...

Delphi-Quellcode:
unit UStartStopService;

interface

uses
  Windows, Classes, SysUtils;

function ServiceGetStatus(sMachine, sService : string ) : DWord;

function ServiceStart(sMachine, sService : string ) : boolean;
function ServiceStop(sMachine, sService : string ) : boolean;

function ServiceRunning(sMachine, sService : string ) : boolean;
{
// "alerter" service on \ComputerName was started take appropriate action here
if( ServiceStart('\ComputerName','alerter' ) )then begin
end;
// stop "alerter" service running on the local computer
if( ServiceStop('','alerter' ) )then begin
end;
}

function ServiceGetList(sMachine : string; dwServiceType, dwServiceState : DWord;
  slServicesList : TStrings ): boolean;
{
To get a list of all Windows services into a listbox named ListBox1:
ServiceGetList( '', SERVICE_WIN32, SERVICE_STATE_ALL, ListBox1.Items );
}

const
  // Service Types
  SERVICE_KERNEL_DRIVER      = $00000001;
  SERVICE_FILE_SYSTEM_DRIVER = $00000002;
  SERVICE_ADAPTER            = $00000004;
  SERVICE_RECOGNIZER_DRIVER  = $00000008;

  SERVICE_DRIVER             =
    (SERVICE_KERNEL_DRIVER or
     SERVICE_FILE_SYSTEM_DRIVER or
     SERVICE_RECOGNIZER_DRIVER);

  SERVICE_WIN32_OWN_PROCESS  = $00000010;
  SERVICE_WIN32_SHARE_PROCESS = $00000020;
  SERVICE_WIN32               =
    (SERVICE_WIN32_OWN_PROCESS or
     SERVICE_WIN32_SHARE_PROCESS);

  SERVICE_INTERACTIVE_PROCESS = $00000100;

  SERVICE_TYPE_ALL           =
    (SERVICE_WIN32 or
     SERVICE_ADAPTER or
     SERVICE_DRIVER or
     SERVICE_INTERACTIVE_PROCESS);

implementation

uses WinSvc;

//-------------------------------------
// get service status
// return status code if successful
// 0 if not
//
// return codes:
//   SERVICE_STOPPED
//   SERVICE_RUNNING
//   SERVICE_PAUSED
//
// following return codes
// are used to indicate that
// the service is in the
// middle of getting to one
// of the above states:
//   SERVICE_START_PENDING
//   SERVICE_STOP_PENDING
//   SERVICE_CONTINUE_PENDING
//   SERVICE_PAUSE_PENDING
//
// sMachine:
//   machine name, ie: \SERVER
//   empty = local machine
//
// sService
//   service name, ie: Alerter

function ServiceGetStatus(sMachine, sService : string ) : DWord;
var
  schm,                        // service control manager handle
  schs  : SC_Handle;          // service handle
  ss    : TServiceStatus;     // service status
  dwStat : DWord;              // current service status
begin
  dwStat := 0;
  // connect to the service control manager
  schm := OpenSCManager( PChar(sMachine), Nil, SC_MANAGER_CONNECT);
  // if successful...
  if(schm > 0)then begin
    // open a handle to the specified service
    schs := OpenService( schm, PChar(sService),
      SERVICE_QUERY_STATUS); // we want to query service status
    // if successful...
    if(schs > 0)then begin
      // retrieve the current status of the specified service
      if(QueryServiceStatus( schs, ss))then begin
        dwStat := ss.dwCurrentState;
      end;
      CloseServiceHandle(schs); // close service handle
    end;
    CloseServiceHandle(schm);  // close service control manager handle
  end;
  Result := dwStat;
end;



// start service
// return TRUE if successful
// sMachine:
//   machine name, ie: \SERVER
//   empty = local machine
// sService
//   service name, ie: Alerter
function ServiceStart(sMachine, sService : string ) : boolean;
var
  schm,                    // service control manager handle
  schs  : SC_Handle;      // service handle
  ss    : TServiceStatus; // service status
  psTemp : PChar;          // temp char pointer
  dwChkP : DWord;          // check point
begin
  ss.dwCurrentState := 0;
  // connect to the service control manager
  schm := OpenSCManager( PChar(sMachine), Nil, SC_MANAGER_CONNECT);
  // if successful...
  if(schm > 0)then begin
    // open a handle to the specified service
    schs := OpenService( schm, PChar(sService),
      SERVICE_START or         // we want to start the service and
      SERVICE_QUERY_STATUS);   // query service status
    // if successful...
    if(schs > 0)then begin
      psTemp := Nil;
      if(StartService( schs, 0, psTemp))then begin
        // check status
        if(QueryServiceStatus( schs, ss))then begin
          while(SERVICE_RUNNING <> ss.dwCurrentState)do begin
            // dwCheckPoint contains a value that the service
            // increments periodically to report its progress
            // during a lengthy operation.
            dwChkP := ss.dwCheckPoint; // save current value
            // wait a bit before checking status again
            // dwWaitHint is the estimated amount of time
            // the calling program should wait before calling
            // QueryServiceStatus() again

            // idle events should be handled here...
            Sleep(ss.dwWaitHint);
            if(not QueryServiceStatus( schs, ss))then begin
              break;   // couldn't check status break from the loop
            end;
            if(ss.dwCheckPoint < dwChkP)then begin
              // QueryServiceStatus didn't increment
              // dwCheckPoint as it should have.
              // avoid an infinite loop by breaking
              break;
            end;
          end;
        end;
      end;
      CloseServiceHandle(schs); // close service handle
    end;
    // close service control manager handle
    CloseServiceHandle(schm);
  end;
  // return TRUE if the service status is running
  Result := SERVICE_RUNNING = ss.dwCurrentState;
end;

// stop service
//
// return TRUE if successful
//
// sMachine:
//   machine name, ie: \SERVER
//   empty = local machine
//
// sService
//   service name, ie: Alerter
//
function ServiceStop(sMachine, sService : string ) : boolean;
var
  schm,                    // service control manager handle
  schs  : SC_Handle;      // service handle
  ss    : TServiceStatus; // service status
  dwChkP : DWord;          // check point
begin
  // connect to the service control manager
  schm := OpenSCManager(PChar(sMachine), Nil, SC_MANAGER_CONNECT);
  // if successful...
  if(schm > 0)then begin
    // open a handle to the specified service
    schs := OpenService( schm, PChar(sService),
      SERVICE_STOP or      // we want to stop the service and
      SERVICE_QUERY_STATUS);// query service status
    // if successful...
    if(schs > 0)then begin
      if(ControlService( schs, SERVICE_CONTROL_STOP, ss))then begin
        // check status
        if(QueryServiceStatus( schs, ss))then begin
          while(SERVICE_STOPPED <> ss.dwCurrentState)do begin
            // dwCheckPoint contains a value that the service
            // increments periodically to report its progress
            // during a lengthy operation.

            // save current value
            dwChkP := ss.dwCheckPoint;
            // wait a bit before checking status again
            // dwWaitHint is the estimated amount of time
            // the calling program should wait before calling
            // QueryServiceStatus() again
            // idle events should be handled here...
            Sleep(ss.dwWaitHint);
            if(not QueryServiceStatus( schs, ss))then begin
              break;   // couldn't check status break from the loop
            end;
            if(ss.dwCheckPoint < dwChkP)then begin
              // QueryServiceStatus didn't increment
              // dwCheckPoint as it should have.
              // avoid an infinite loop by breaking
              break;
            end;
          end;
        end;
      end;
      CloseServiceHandle(schs);    // close service handle
    end;
    CloseServiceHandle(schm);      // close service control manager handle
  end;
  // return TRUE if the service status is stopped
  Result := SERVICE_STOPPED = ss.dwCurrentState;
end;

function ServiceRunning(sMachine, sService : string ) : boolean;
begin
  result := ServiceGetStatus(sMachine, sService) = SERVICE_RUNNING;
end;

// Get a list of services
// return TRUE if successful
// sMachine:
//   machine name, ie: \SERVER
//   empty = local machine
// dwServiceType
//   SERVICE_WIN32,
//   SERVICE_DRIVER or
//   SERVICE_TYPE_ALL
// dwServiceState
//   SERVICE_ACTIVE,
//   SERVICE_INACTIVE or
//   SERVICE_STATE_ALL
// slServicesList
//   TStrings variable to storage
function ServiceGetList(sMachine : string; dwServiceType, dwServiceState : DWord;
  slServicesList : TStrings ): boolean;
const
  // assume that the total number of services is less than 4096.
  // increase if necessary
  cnMaxServices = 4096;
type
  TSvcA = array[0..cnMaxServices] of TEnumServiceStatus;
  PSvcA = ^TSvcA;
var
  j : integer;
  schm         : SC_Handle;   // service control manager handle
  nBytesNeeded,                // bytes needed for the next buffer, if any
  nServices,                   // number of services
  nResumeHandle : DWord;       // pointer to the next unread service entry
  ssa : PSvcA;                 // service status array
begin
  Result := false;
  slServicesList.Clear;
  // connect to the service control manager
  schm := OpenSCManager(PChar(sMachine), Nil, SC_MANAGER_ALL_ACCESS);
  // if successful...
  if(schm > 0)then begin
    nResumeHandle := 0;
    New(ssa);
    EnumServicesStatus( schm, dwServiceType, dwServiceState, ssa^[0],
      SizeOf(ssa^), nBytesNeeded, nServices, nResumeHandle );
    // assume that our initial array was large enough to hold all
    // entries. add code to enumerate if necessary.
    for j := 0 to nServices-1 do begin
      slServicesList.Add( StrPas(ssa^[j].lpServiceName ) + '=' + StrPas(ssa^[j].lpDisplayName ) );
    end;
    Result := true;
    Dispose(ssa);
    CloseServiceHandle(schm); // close service control manager handle
  end;
end;


end.

himitsu 5. Mai 2018 15:37

AW: Delphi und Serviceanwendungen, demo?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Der Code über mir sieht auf den ersten Blick bezüglich Unicode nicht schlecht aus.
Gut, die Fehlerbehandlung lässt manchmal etwas zu Wünschen über, falls es einen nicht nur interessiert ob etwas nicht ging, sondern auch warum es nicht ging.


----

Nja, der Code selbst läuft mit Unicode und könnte sich wohl auch im ANSI heimisch fühlen, aber da einige Typen generisch deklariert sind, ist es erstmal etwas egal. (TArray<> und Co. könnte man aber notfalls rauswerfen).

Für Start/Stop muß der Entwickler selber für die nötigen Rechte sorgen. (noch)

Das Ganze ist eine Pascal-OOP-Kapselung, also also in einer Klasse verpackt, zuzüglich globale Klasse mit Grundfunktionen, alles mit String statt PChar, ENUMs statt Konstanten und Eyceptions statt Errorcodes.
Und ich hatte da ein bissl mit DocInsight/HelpInsight und Attributen für die Dokumentation rumgespielt. [edit]nee, fehlte noch, aber es sollte selbsterklärend sein und alle Konstanten wurden noch nicht übersetzt[/edit]
> siehe h5u.WinAPI.pas

Und in die Basis-Units besser nicht so genau reingucken. Musste mal schnell bissl was rauswerfen, damit es kompiliert.

Rollo62 5. Mai 2018 19:53

AW: Delphi und Serviceanwendungen, demo?
 
http://cc.embarcadero.com/Item/28354

Hatte auf der Basis mal was gemacht, wenn es das ist was du suchst.

Mavarik 6. Mai 2018 10:55

AW: Delphi und Serviceanwendungen, demo?
 
Zitat:

Zitat von jaenicke (Beitrag 1401333)
... Das ist deutlich einfacher, zudem hatten wir mit der Out-Of-Process COM Variante schon Probleme auf manchen Systemen, vor allem mit Antivirenprogrammen.

Hmm... "Out-Of-Process" das war der Begriff der mir nicht eingefallen war... Probleme... Doof!

Der Trick mit dem sich doppelt selbst startenden Programmen um Admin-Rechte zu bekommen, funktioniert leider in diesem Fall nicht, trotzdem Danke!

Mavarik

himitsu 6. Mai 2018 11:03

AW: Delphi und Serviceanwendungen, demo?
 
Out-Of-Process ... neuer Prozess mit höheren Rechten ... komplett abgetrennt.

In-Process, da stellt man die Rechte für einen Thread um (genauso kann man auch den "Desktop" für einen Thread ändern, um z.B. auf die UAC-Fenster zugreifen zu können), aber da haben dann die anderen Threads Zugriff auf den gemeinsamen Speicher/Programmcode. Auch Threads von Fremd-Code aus DLLs, die dir jemand wie Maustreiber, TeamViewer oder weniger Böswillige in deinen Process gehookt haben.


Wenn dein Programm aber nicht das Recht zum Ändern der Rechte besitzt, dann funktioniert das nicht.
(vor allem in Firmenumgebungen ist da oftmls sehr viel eingeschränkt)

Mavarik 6. Mai 2018 11:13

AW: Delphi und Serviceanwendungen, demo?
 
Zitat:

Zitat von himitsu (Beitrag 1401395)
Wenn dein Programm aber nicht das Recht zum Ändern der Rechte besitzt, dann funktioniert das nicht.
(vor allem in Firmenumgebungen ist da oftmls sehr viel eingeschränkt)

Das ist nicht das Problem... Aber ich glaube Daniel hatte mal als UAC noch ganz frisch war ein Demo gezeigt um einen "eigenen" Thread mit Admin-Rechten zu starten... Das Problem ist, wenn ich zum Beispiel in einer Resource eine mini-exe mitliefere die das alles kann, schlagen die Virenscanner wieder an.

Vielleicht finde ich in den Tiefen meiner Delphi-Sourcen noch die richtige procedure...

himitsu 6. Mai 2018 11:17

AW: Delphi und Serviceanwendungen, demo?
 
Du kannst auch dein Programm nochmals mit Adminrechten starten und via Parameter nur die gewünschte Aktion ausführen.

Der Witz: EXE und DLL sind praktisch das Gleiche (abgesehn von der Startprozedur).
Ich hatte auch mal ein Programm, das sich selber oder von Fremden als DLL geladen werden konnte.
> Ein Programm kann nicht nur Einwas machen.

Windows kann sogar in einer EXE mehrere Services laufen lassen.
Nur die TService-Implementierung von Delphi kann das nicht.
Man kann nativ nichtmal die selbe EXE/Service mehrmals in einem System starten (Startparameter/Registrierung überschreiben und beim Start manuell drauf reagieren)
- eine EXE mehrmals mit unterschiedlichem Namen starten
- oder mehrere Services aus einer EXE in unterschiedlichen Prozessen starten
- oder mehrere Services innerhalb eines Prozesses starten


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:58 Uhr.
Seite 1 von 2  1 2      

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