Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Dienst installieren + unter anderen Benutzerdaten starten (https://www.delphipraxis.net/95703-dienst-installieren-unter-anderen-benutzerdaten-starten.html)

Stephan 11. Jul 2007 20:34


Dienst installieren + unter anderen Benutzerdaten starten
 
Hallo,

Ich habe einen Systemdienst in Delphi erstellt und möchte diesen zusammen mit einem kleinen Hilfsprogramm an den Kunden ausliefern. Über das Hilfsprogramm soll der Kunde die Möglichkeit haben, einen Windows Benutzeraccount anzugeben. Hierbei soll der Systemdienst installiert werden und unter dem angegebenen Benutzeraccount gestartet werden (sowas lässt sich unter Windows ansonsten über "Systemsteuerung -> Dienste -> <<Dienst doppelt anklicken>> -> Tab Anmelden" konfigurieren).

Die Installation des Dienstes ist kein Problem. Dies geht ja über einen zusätzlichen Parameter "-install". Lassen sich so vielleicht auch die entsprechenden Zugangsdaten als Parameter übermitteln? Leider habe ich diesbezüglich nichts im Forum gefunden.

RavenIV 12. Jul 2007 07:55

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Ein Dienst wird normalerweise gestartet, bevor sich jemand am System anmelden kann, beim Booten.
Der Dienst kann sich mit einer Benutzerkennugn anmelden. Normalerweise ist dies "Administrator".

Stephan 12. Jul 2007 08:16

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo RavenIV,

Danke für deine Antwort.
Das ist klar, ich glaub ich hab mich etwas missverständlich ausgedrückt. Das kleine Hilfsprogramm soll lediglich den Dienst installieren und dabei schon bestimmte Anmeldedaten für diesen Dienst hinterlegen - unter welchen er beim Systemstart ausgeführt werden soll. Ich möchte so dem Endanwender lediglich den Weg über "Systemsteuerung -> Dienste" ersparen.

et2004 13. Jul 2007 08:01

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Ich habe schon seit einer Weile das gleiche Problem. Installieren, starten und stoppen mache ich mit folgenden Funktionen:

Delphi-Quellcode:
procedure ServiceInstall;
var
   SvcMgr, Svc: HWND;
begin
   SvcMgr := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);

   try
      Svc := CreateService(SvcMgr, APPLICATION_NAME, PChar(APPLICATION_NAME), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, PChar(WorkDir + FILE_SERVICE), '', nil, '', nil, '');
   finally
      CloseServiceHandle(Svc);
   end;

   CloseServiceHandle(SvcMgr);
end;


function ServiceStart(Machine, ServiceName: String): Boolean;
//******************************************************************************
//* Parameter:
//*    Machine: Computername
//*    Service: Name des Dienstes
//******************************************************************************
var
   h_manager, h_svc: SC_Handle;
   ServiceStatus: TServiceStatus;
   dwCheckPoint: DWORD;
   ServiceArgVectors: PChar;
begin
   h_manager := OpenSCManager(PChar(Machine), nil, SC_MANAGER_CONNECT);
   if h_manager > 0 then
   begin
      h_svc := OpenService(h_manager, PChar(ServiceName), SERVICE_START or SERVICE_QUERY_STATUS or SC_MANAGER_ALL_ACCESS);
      if h_svc > 0 then
      begin
         if (StartService(h_svc, 0, ServiceArgVectors)) then { succeeded }
         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
                     // couldn't check status
                     break;
                  if (ServiceStatus.dwCheckPoint < dwCheckPoint) then
                     break;
               end;
           end;
         end;
         CloseServiceHandle(h_svc);
      end;
   
      CloseServiceHandle(h_manager);
   end;

   Result := (SERVICE_RUNNING = ServiceStatus.dwCurrentState);
end;


function ServiceStop(Machine, ServiceName: String): Boolean;
//******************************************************************************
//* Parameter:
//*    Machine: Computername
//*    Service: Name des Dienstes
//******************************************************************************
var
   h_manager, h_svc: SC_Handle;
   ServiceStatus: TServiceStatus;
   dwCheckPoint: DWORD;
begin
   h_manager := OpenSCManager(PChar(Machine), nil, SC_MANAGER_CONNECT);
   if h_manager > 0 then
   begin
      h_svc := OpenService(h_manager, PChar(ServiceName), 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
               while (SERVICE_STOPPED <> ServiceStatus.dwCurrentState) do
               begin
                  dwCheckPoint := ServiceStatus.dwCheckPoint;
                  Sleep(ServiceStatus.dwWaitHint);
                  if (not QueryServiceStatus(h_svc, ServiceStatus)) then
                     // couldn't check status
                     break;
                  if (ServiceStatus.dwCheckPoint < dwCheckPoint) then
                     break;
               end;
            end;
         end;
         CloseServiceHandle(h_svc);
      end;
      CloseServiceHandle(h_manager);
   end;

   Result := (SERVICE_STOPPED = ServiceStatus.dwCurrentState);
end;
Bloss, wie ich dem Dienst vor dem Starten einen anderen Benutzer zuweisen muss, habe ich noch nicht heraus gefunden. Ich werde diesen Thread aber noch im Auge behalten.

Stephan 13. Jul 2007 09:09

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo et2004,

Laut http://msdn2.microsoft.com/en-us/library/ms682450.aspx kann man für die letzten zwei Parameter bei CreateService ein Benutzerkonto mit übergeben. Ich werde das mal testen und mich dann wieder zurück melden.

et2004 13. Jul 2007 10:31

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo Stephan,

es klappt! Danke für den Tip. Manche Funktionsbeschreibungen sollte man (ich) bis zum Ende durchlesen (grins).

Delphi-Quellcode:
Svc := CreateService(SvcMgr, APPLICATION_NAME, PChar(APPLICATION_NAME), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, PChar(WorkDir + FILE_SERVICE), '', nil, '', 'COMPUTER\Administrator', '*******');
Die letzten beiden Parameter waren die Lösung: Benutzername und Passwort. Beim Benutzernamen musste ich den Computernamen einfügen, da es immer ein lokaler Benutzer sein muss.

Viele Grüssse

Stephan 13. Jul 2007 10:40

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo et2004,

Danke für deine Rückmeldung :)

Zitat:

Beim Benutzernamen musste ich den Computernamen einfügen, da es immer ein lokaler Benutzer sein muss.
Das wird sicherlich auch mit Domänenbenutzern funktionieren. Statt dem lokalen Computername heißt es dann eben "domaeneXY\Benutzername" :)

Schwedenbitter 17. Sep 2008 00:35

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Delphi-Quellcode:
Svc := CreateService(SvcMgr, APPLICATION_NAME, PChar(APPLICATION_NAME), SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, PChar(WorkDir + FILE_SERVICE), '', nil, '', 'COMPUTER\Administrator', '*******');
Wenn ich das richtig verstehe, muss man dabei das Passwort in den Quelltext eingebe.

Das beantwortet aber immer noch nicht die ursprüngliche Frage des Titels (Dienst installieren + unter anderen Benutzerdaten starte). Mich würde auch interessieren, ob eine Möglichkeit besteht, dem Dienst gleich bei der Installation entsprechende Benutzerdaten mitzugeben; möglichst auch gleich noch vom installierenden Benutzer abgefragt...

Ich suche (mittlerweile krampfhaft) nach einer Lösung mittels Dienst auf Dateien einer Netzwerkfreigabe zuzugreifen. Ich könnte theoretisch auch den Benutzer System mit leerem Passwort auf dem Server anlegen, halte das aber nicht für sicher. Sollte das alles nicht klappen, werde ich wohl in den sauren Apfel beißen und eine Applikation bauen müssen, die als normales Programm einfach nur in den Tray minimiert und geschlossen wird.

Gruß, Alex

nahpets 17. Sep 2008 09:52

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo,

bei einem Service gibt es die Methode
Delphi-Quellcode:
procedure ServiceBeforeInstall(Sender: TService);
Hier müsstest Du mal probieren, ob Du an Kommandozeilenparameter kommst, ggfls. auch eine INI-Datei lesen, die das Installationsprogramm schreibt, bevor es den Dienst zur Installation aufruft.

Paramstr(0)... sollte aber funktionieren, da diverse Dienste mit Parametern gestartet werden.

Wenn Du ein eigenes Eventmessagefile für Deinen Dienst hast, muss Du dies in der Registrierung eintragen, das geht z. B. so:
Delphi-Quellcode:
// Messagefile registrieren
procedure TReplikator.ServiceBeforeInstall(Sender: TService);
Var
    Reg : TRegistry;
begin
  Reg := TRegistry.Create;
  Reg.RootKey := HKEY_LOCAL_MACHINE;
  Reg.OpenKey('system\CurrentControlSet\Services\EventLog\Application\' + Self.Name,True);
  Reg.WriteString('EventMessageFile',ParamStr(0));
  Reg.WriteInteger('TypesSupported',7);
  Reg.CloseKey;
  Reg.OpenKey('system\CurrentControlSet\Services\Replikator\' + Self.Name,True);
  Reg.WriteString('Description','Repliziert die Daten zwischen Asterix und Obelix');
  Reg.CloseKey;
  Reg.Free;
end;
Wenn wir hier schon in der Registrierung sind:

Auf der gleichen Ebene gibt es für die Dienste, die einen anderen Benutzer verwenden, einen Eintrag "ObjectName", der den Namen des Benutzerkontos enthält. Bei dem Dienst "aspnet_state" ist das z. B. zu sehen.

Hier würde also die Zeile
Delphi-Quellcode:
  Reg.WriteString('ObjectName',ParamStr(2));
eventuell schon reichen.

Was ich (noch) nicht herausgefunden habe, ist, wird das Passwort gespeichert, wenn ja wo und wie?
Reicht es eventuell aus, dass in der Systemsteuerung beim Eintragen der Anmeldung das richtige Passwort eingegeben wird? (Wäre wohl etwas zu billig.)
Eventuell wirst Du hierzu ja bei MSDN oder so fündig.


Stephan

Schwedenbitter 17. Sep 2008 12:12

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Zitat:

Zitat von nahpets
Delphi-Quellcode:
**Reg.WriteString('Description','Repliziert die Daten zwischen ...');
  Reg.WriteString('ObjectName',ParamStr(2));

Ist genau das, was ich suchte. Danke!

Ich komme aber nicht dahinter, wie ich das mit dem Benutzernamen/Passwort machen kann. Ich bin daher dazu übergegangen, meinen "Dienst" als VCL-Applikation ohne Fenster zu schreiben und das Beenden zu unterbinden. Das hat den Nachteil kein Dienst zu sein.
Aber es hat auch den Vorteil, ohne zutun als angemeldeter Benutzer zu laufen und gleich ein Formular mitzuliefern, welches ich für meine Interaktion sowieso brauche. Letzteres ist ja - so entnehme ich es diversen Äußerungen im Forum - sicherheitstechnisch gesehen riskant. Das Fenster blende ich einfach ein und aus...

[edit]
Zum Starten trage ich es einfach so ein:
Delphi-Quellcode:
**Reg:=TRegistry.Create;
  Reg.RootKey:=HKEY_LOCAL_MACHINE;
  Reg.OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run',True);
  Reg.WriteString('Mein Programm',ParamStr(0));
  Reg.Free;
[/edit]

Gruß, Alex

dfried 17. Sep 2008 12:21

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Zitat:

Zitat von Schwedenbitter
Aber es hat auch den Vorteil, ohne zutun als angemeldeter Benutzer zu laufen...

Aber leider halt auch nur wenn ein Benutzer auch angemeldet ist, nicht wenn niemand angemeldet ist!

Schwedenbitter 17. Sep 2008 12:27

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Zitat:

Zitat von dfried
Aber leider halt auch nur wenn ein Benutzer auch angemeldet ist, nicht wenn niemand angemeldet ist!

Das ist OK!
Ich hatte bereits geschrieben, dass mein Programm auf Benutzereingaben angewiesen ist. Ich möchte ständig ein Verzeichnis auf Dateien prüfen. Sind welche da, kommt ein Fenster, dass dem Benutzer das Sortieren und ablegen ermöglicht. Anschließend wird es wieder geschlossen.
Ohne angemeldeten Benutzer ist das sinnlos. Ich fand es nur unter dem Gesichtspunkt "dümmster anzunehmender User" gut, dass man an Diensten nicht so leicht manipulieren kann und den meisten Benutzern der Schalter /uninstall zum Deinstallieren doch nicht bekannt ist.

nahpets 17. Sep 2008 12:41

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo,

unter Deinem letzten Gesichtpunkt:

Wenn der Dienst nur laufen soll, wenn ein Benutzer angemeldet ist und mit dessen Rechten, dann installiere den Dienst wie gehabt und starte ihn (per Batch?) über den Run-Zweig mit net start meindienst.
Wenn Du den Run-Zweig von Local-Machine nimmst, startet der Dienst bei jedem Benutzer und den Zweig kann nicht jeder Benutzer manipulieren (wenn die Rechte stimmen).
Wenn der Dienst dann einmal läuft, dann läuft er auch bei abgemeldetem Benutzer weiter, bis zum Runterfahren des Systems.

Stephan

PS: Drei Sätze und alle fangen mit Wenn an, das ist jetzt aber keine stilistische Glanzleistung :oops:

Schwedenbitter 17. Sep 2008 13:13

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Zitat:

Zitat von nahpets
Wenn der Dienst nur laufen soll, wenn ein Benutzer angemeldet ist und mit dessen Rechten, dann installiere den Dienst wie gehabt und starte ihn (per Batch?) über den Run-Zweig mit net start meindienst.

Ich muss leider gestehen, dass ich das verstehe, aber nicht weiß, wie ich es anstellen soll. Die Dienste werden doch über Einträge in der Registry gesteuert vom BS gestartet, oder? Was soll ich da mit einer Batch?

Zitat:

Zitat von nahpets
Wenn Du den Run-Zweig von Local-Machine nimmst, startet der Dienst bei jedem Benutzer und den Zweig kann nicht jeder Benutzer manipulieren (wenn die Rechte stimmen).

Das ist genau das, was ich will. Laufen und nicht ändern können. Der Dienst ist für mein Software-Paket notwendig. Zumindest solange man mit Delphi keine Drucker-Treiber selbst schreiben kann

Zitat:

Zitat von nahpets
Wenn der Dienst dann einmal läuft, dann läuft er auch bei abgemeldetem Benutzer weiter, bis zum Runterfahren des Systems.

Das werde ich mla probieren. Dann bleibt mir nur der Trick, meinen "Dienst" nur einmal startbar zu machen. Wenn er weiter läuft, ist es nicht schlimm. Denn ohne Benutzerinteraktion macht er ja nichts.

Alex

P.S. Das mit den 3 "Wenn(s)" ist OK. Ich will was lernen. Aber ganz bestimmt nicht Deutsch. Das wäre dann das falsche Forum. :-D

nahpets 17. Sep 2008 13:29

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo,

auf der Kommandozeile kannst Du Dienste auch von "Hand" starten.
Delphi-Quellcode:
net start deindienstname
startet Deinen Dienst.
Delphi-Quellcode:
net stop deindienstname
beendet ihn wieder.

Dienste über die Registierung zu starten ist ein Weg, aber nicht der Einzige. Es ginge auch über die Windows-API.

Wenn ich Dienste entwickle, dann teste ich immer über 'ne Batch, geht einfach schneller als über die Systemsteuerung. Im Batch kann ich halt vorher auch noch Dateien an die entsprechenden Stellen kopieren oder das install bzw. das uninstall mit aufnehmen. Bin da halt faul.

Neben dem Run-Zweig wäre auch die Autostart noch eine Option.

Deine Batchdatei, die Du im RUN-Zweig aufrufst, muss nur
Delphi-Quellcode:
net start Dienstname
enthalten, eventuell reicht in der Registrieung aber auch sowas:

Delphi-Quellcode:
"MeinenDienstStarten"="net start MeinDienst"
Einfach mal ausprobieren, einer der beiden Wege sollte für Deinen Bedarf ausreichen.

Stephan

nahpets 17. Sep 2008 14:30

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Hallo,

mir fällt da gerade noch was ein:

Parallel zu Run gibt es auch noch RunServices. Der funktioniert auch ohne Benutzeranmeldung (aber da fehlt Dir dann wohl die passende Anmeldung).

http://support.microsoft.com/kb/179365/de

Stephan

Gremlin 18. Sep 2008 13:28

Re: Dienst installieren + unter anderen Benutzerdaten starte
 
Du kannst dem Service die Parameter für die Kontendaten (Login/Pass) wie nachfolgend im Beispiel aufgeführt übergeben.
Weiss grad nicht, ob der Dienst dazu gestoppt sein muss, ich verwende diese Routine zum Setzen der Werte kurz nach der
eigentlichen Installation. Die Kontenangaben müssen einem gültigen Konto entsprechen.

Delphi-Quellcode:
function ServiceSetLoginPass(const Service, Login, Pass, MachineName:pchar):integer; stdcall;
var
  SCMH : SC_HANDLE;
  SVCH : CARDINAL;
begin
  Result := 0;
  if (StrLen(Service) <> 0) then begin
    if (MachineName=nil) or (StrLen(MachineName)=0) then
      SCMH := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT or GENERIC_READ)
    else SCMH := OpenSCManager(MachineName, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT or GENERIC_READ);

    if SCMH <> 0 then begin
      SVCH := OpenService(SCMH , Service, SERVICE_CHANGE_CONFIG);
      if SVCH <> 0 then begin
        if ChangeServiceConfig(SVCH , SERVICE_WIN32_OWN_PROCESS (*SERVICE_NO_CHANGE*), SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
            nil, nil, nil, nil, Login, Pass, nil) then
          Result := 1;
        CloseServiceHandle(SVCH );
      end;
      CloseServiceHandle(SCMH );
    end;
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:41 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