Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Sichtbarkeit von Variablen bei Diensten (https://www.delphipraxis.net/150045-sichtbarkeit-von-variablen-bei-diensten.html)

Caps 6. Apr 2010 10:40


Sichtbarkeit von Variablen bei Diensten
 
Moin,

ich bin dabei, einen Dienst zu programmieren, und habe folgendes Problem:
Im Interface-Teil der Unit habe ich einige Variablen deklariert, die ich im ServiceAfterInstall-Handler des Dienstes aus einer INI-Datei lese. Das geht auch - d.h. die Variablen (global) haben innerhalb der Funktion ServiceAfterInstall die eingelesenen Werte.
Jedoch innerhalb der Funktion Log sind die Werte verschwunden. Da komm ich nicht klar. Keine Ahnung, warum.
Ich benutze showmessage, um die Werte auszugeben.

Die Quelle:

Delphi-Quellcode:
unit Unit1;


interface

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

type
  Tmvideo_sync = class(TService)
    procedure ServiceExecute(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceAfterUninstall(Sender: TService);
    procedure ServiceBeforeUninstall(Sender: TService);
    procedure ServiceAfterInstall(Sender: TService);
  private
    { Private-Deklarationen }
  public
    function GetServiceController: TServiceController; override;
    { Public-Deklarationen }
  end;


var
   mvideo_sync: Tmvideo_sync;

   videos_dir, // Relativer Pfad
   videos_neu_dir, // Relativer Pfad
   mvideo_sync_homedir : String; // Absoluter Pfad zur Dienst-Executable

   IniFile : TIniFile;
   LogFileName : String; // Ohne Pfadangabe
   IniStringList : TStringList;

   hour_of_execution : Word; // Stunde, zu der das Update durchgeführt werden soll
   UpdateExecuted : Boolean; // Wurde das Update durchgeführt? Dient dazu, einen weiteren Durchlauf während der "Update-Stunde" zu verhindern


implementation

{$R *.DFM}

const
     IniFileName = 'mvideo_sync.ini';


procedure Log(Msg: String);
var
   DTStr : String;
   LogFile : Textfile;
begin showmessage(IntToStr(hour_of_execution) + ', ' + LogFileName + ', ' + videos_dir + ', ' + videos_neu_dir + ', ' + mvideo_sync_homedir); // <------ PROBLEM
  DateTimeToString(DTStr, 'dd.mm.yy hh:mm', now);
  AssignFile(LogFile, mvideo_sync_homedir + '\' + LogFileName);
  Try
     if not FileExists(mvideo_sync_homedir + '\' + LogFileName) then //ReWrite(LogFile)
                                                                else ;//Append(LogFile);
//     Try
//        WriteLn(LogFile, DTStr + ' : ' + Msg);
//     except end;
  finally
//         CloseFile(LogFile);
  end;

end;


procedure ExecNewProcess(ProgramName : String); // Mit relativem Pfad aufzurufen
var
   StartInfo : TStartupInfo;
   ProcInfo : TProcessInformation;
   CreateOK : Boolean;
   AbsProgramName : String;
begin
AbsProgramName := mvideo_sync_homedir + '\' + ProgramName;
{ fill with known state }
FillChar(StartInfo, SizeOf(TStartupInfo), #0);
FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
StartInfo.cb := SizeOf(TStartupInfo);

CreateOK := CreateProcess(nil, PChar(AbsProgramName), nil, nil, false, CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS, nil, nil, StartInfo, ProcInfo);

if CreateOK then
   //may or may not be needed. Usually wait for child processes
   WaitForSingleObject(ProcInfo.hProcess, INFINITE)
            else begin
                 // Log error
                 MessageDlg('Scheiße!', mtError, [mbOK], 0);
                 exit;
                 end;
end;


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


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


procedure Tmvideo_sync.ServiceExecute(Sender: TService);
var
   h, m, s, ms : Word;
begin
while not terminated do begin
      //ServiceThread.ProcessRequests(false);
      DecodeTime(now, h, m, s, ms);
      if h = hour_of_execution + 1 then UpdateExecuted := false; // Indikator rücksetzen, um in ca. 23 Stunden wieder ready zu sein
      if (h = hour_of_execution) and not UpdateExecuted then begin
         Log('Beginning Update...');
         // irgendwas...
         Log('Finished Update');
         UpdateExecuted := true;
                                                             end;
                        end;
end;


procedure Tmvideo_sync.ServiceStart(Sender: TService; var Started: Boolean);
begin
Started := true;
UpdateExecuted := false;

Log('Service started');
end;


procedure Tmvideo_sync.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
Log('Service stopped');
end;

procedure Tmvideo_sync.ServiceAfterUninstall(Sender: TService);
begin
Log('Service has been uninstalled');
end;

procedure Tmvideo_sync.ServiceBeforeUninstall(Sender: TService);
begin
Log('Service is tried to be uninstalled');
end;

procedure Tmvideo_sync.ServiceAfterInstall(Sender: TService);
begin
IniFile := TIniFile.Create(ExtractFilePath(ParamStr(0)) + IniFileName);
IniStringList := TStringList.Create;

IniFile.ReadSectionValues('mvideo_sync', IniStringList);

hour_of_execution := StrToInt(IniStringList.Values ['hour_of_execution']);
LogFileName := IniStringList.Values ['logfile'];
videos_dir := IniStringList.Values ['videos_dir'];
videos_neu_dir := IniStringList.Values ['videos_neu_dir'];
mvideo_sync_homedir := IniStringList.Values ['mvideo_sync_homedir'];

showmessage(IntToStr(hour_of_execution) + ' ' + LogFileName + ' ' + videos_dir + ' ' + videos_neu_dir + ' ' + mvideo_sync_homedir); // <----- KEIN PROBLEM
end;

end.

Für jede Idee dankbar,
Caps

mkinzler 6. Apr 2010 11:39

Re: Sichtbarkeit von Variablen bei Diensten
 
AfterInstall wird doch nach der Installation aufgerufen, nicht nach dem Start des Services. Dort solltest du die Ini auslesen.
Ich würde auch auf globale Variablen und freie Funktionen verzichten

Caps 6. Apr 2010 11:51

Re: Sichtbarkeit von Variablen bei Diensten
 
Danke für Deine Antwort, aber kannst Du dir trotzdem vorstellen, warum der Wert der Variablen verschwindet?

Edit: ich hatte das Auslesen aus der INI vorher in dem OnStart-Ereignis, es hat auch nicht funktioniert. :glaskugel:
Edit2: ich hatte auch eine public-Eigenschaft hinzugefügt, sie im OnInstall-Handler gesetzt, und in der Funktion Log ausgelesen, sie war auch leer.

mkinzler 6. Apr 2010 11:56

Re: Sichtbarkeit von Variablen bei Diensten
 
Zitat:

Danke für Deine Antwort, aber kannst Du dir trotzdem vorstellen, warum der Wert der Variablen verschwindet?
Diese verschwinden nicht, sondern werden nicht ausgelesen, da diese Methode nur beim Installieren aufgerufen wird. Danach wird der Dienst gestartet ( anderer Prozess), der diese Methode nie ausführt

Caps 6. Apr 2010 12:08

Re: Sichtbarkeit von Variablen bei Diensten
 
Ich dachte es läuft so:

1) Der Dienst wird installiert. Dabei werden den Variablen die entsprechenden Werte zugewiesen.
2) Der Dienst wird gestartet, die Variablen sollten immernoch die Werte haben.
Haben sie aber nicht. Das verstehe ich nicht.


Ich deinstalliere und installiere den Dienst jedesmal neu, wenn ich ihn compiliert habe.
By the way: ich habe die INI-Auslesevorgang jetzt aber im START-Handler, es geht trotzdem nicht. (??? !)


Man betrachte die Variable testi:
- die ist eine public-Eigenschaft des Service-Objectes
- sie wird im START-Ereignis gesetzt und in verschiedenen Methoden (keine freien Funktionen) ausgelesen
showmessage(testi); bringt jedesmal NIX

Delphi-Quellcode:
unit Unit1;


interface

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

type
  Tmvideo_sync = class(TService)
    procedure ServiceExecute(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceAfterUninstall(Sender: TService);
    procedure ServiceBeforeUninstall(Sender: TService);
    procedure ServiceAfterInstall(Sender: TService);
  private
    { Private-Deklarationen } 
  public
    testi : string;
    function GetServiceController: TServiceController; override;
    { Public-Deklarationen } 
  end;


var
   mvideo_sync: Tmvideo_sync;

   videos_dir, // Relativer Pfad
   videos_neu_dir, // Relativer Pfad
   mvideo_sync_homedir : String; // Absoluter Pfad zur Dienst-Executable

   IniFile : TIniFile;
   LogFileName : String; // Ohne Pfadangabe
   IniStringList : TStringList;

   hour_of_execution : Word; // Stunde, zu der das Update durchgeführt werden soll
   UpdateExecuted : Boolean; // Wurde das Update durchgeführt? Dient dazu, einen weiteren Durchlauf während der "Update-Stunde" zu verhindern


implementation

{$R *.DFM} 

const
     IniFileName = 'mvideo_sync.ini';


procedure Log(Msg: String);
var
   DTStr : String;
   LogFile : Textfile;
begin showmessage(mvideo_sync.testi + IntToStr(hour_of_execution) + ', ' + LogFileName + ', ' + videos_dir + ', ' + videos_neu_dir + ', ' + mvideo_sync_homedir);
  DateTimeToString(DTStr, 'dd.mm.yy hh:mm', now);
  AssignFile(LogFile, mvideo_sync_homedir + '\' + LogFileName);
  Try
     if not FileExists(mvideo_sync_homedir + '\' + LogFileName) then //ReWrite(LogFile)
                                                                else ;//Append(LogFile);
//     Try
//        WriteLn(LogFile, DTStr + ' : ' + Msg);
//     except end;
  finally
//         CloseFile(LogFile);
  end;

end;


procedure ExecNewProcess(ProgramName : String); // Mit relativem Pfad aufzurufen
var
   StartInfo : TStartupInfo;
   ProcInfo : TProcessInformation;
   CreateOK : Boolean;
   AbsProgramName : String;
begin
AbsProgramName := mvideo_sync_homedir + '\' + ProgramName;
{ fill with known state } 
FillChar(StartInfo, SizeOf(TStartupInfo), #0);
FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
StartInfo.cb := SizeOf(TStartupInfo);

CreateOK := CreateProcess(nil, PChar(AbsProgramName), nil, nil, false, CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS, nil, nil, StartInfo, ProcInfo);

if CreateOK then
   //may or may not be needed. Usually wait for child processes
   WaitForSingleObject(ProcInfo.hProcess, INFINITE)
            else begin
                 // Log error
                 MessageDlg('Scheiße!', mtError, [mbOK], 0);
                 exit;
                 end;
end;


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


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


procedure Tmvideo_sync.ServiceExecute(Sender: TService);
var
   h, m, s, ms : Word;
begin
while not terminated do begin
      //ServiceThread.ProcessRequests(false);
      DecodeTime(now, h, m, s, ms);
      if h = hour_of_execution + 1 then UpdateExecuted := false; // Indikator rücksetzen, um in ca. 23 Stunden wieder ready zu sein
      if (h = hour_of_execution) and not UpdateExecuted then begin
         Log('Beginning Update...');
         // irgendwas...
         Log('Finished Update');
         UpdateExecuted := true;
                                                             end;
                        end;
end;


procedure Tmvideo_sync.ServiceStart(Sender: TService; var Started: Boolean);
begin
IniFile := TIniFile.Create(ExtractFilePath(ParamStr(0)) + IniFileName);
IniStringList := TStringList.Create;

IniFile.ReadSectionValues('mvideo_sync', IniStringList);

hour_of_execution := StrToInt(IniStringList.Values ['hour_of_execution']);
LogFileName := IniStringList.Values ['logfile'];
videos_dir := IniStringList.Values ['videos_dir'];
videos_neu_dir := IniStringList.Values ['videos_neu_dir'];
mvideo_sync_homedir := IniStringList.Values ['mvideo_sync_homedir'];

testi := 'gesetzt';

Started := true;
UpdateExecuted := false;

Log('Service started');
end;


procedure Tmvideo_sync.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
showmessage(testi);
Log('Service stopped');
end;

procedure Tmvideo_sync.ServiceAfterUninstall(Sender: TService);
begin
showmessage(testi);
Log('Service has been uninstalled');
end;

procedure Tmvideo_sync.ServiceBeforeUninstall(Sender: TService);
begin
showmessage(testi);
Log('Service is tried to be uninstalled');
end;

procedure Tmvideo_sync.ServiceAfterInstall(Sender: TService);
begin
IniFile := TIniFile.Create(ExtractFilePath(ParamStr(0)) + IniFileName);
IniStringList := TStringList.Create;

IniFile.ReadSectionValues('mvideo_sync', IniStringList);

hour_of_execution := StrToInt(IniStringList.Values ['hour_of_execution']);
LogFileName := IniStringList.Values ['logfile'];
videos_dir := IniStringList.Values ['videos_dir'];
videos_neu_dir := IniStringList.Values ['videos_neu_dir'];
mvideo_sync_homedir := IniStringList.Values ['mvideo_sync_homedir'];

showmessage(testi + IntToStr(hour_of_execution) + ' ' + LogFileName + ' ' + videos_dir + ' ' + videos_neu_dir + ' ' + mvideo_sync_homedir);
end;

end.

mkinzler 6. Apr 2010 12:12

Re: Sichtbarkeit von Variablen bei Diensten
 
Nein. Beim Installieren wird die Exe als normales Programm im Kontext des angemeldeten Benutzers gestartet, welche den Dienst registriert ( Eintragungen in der Registry). Dann wird der Dienst gestartet ( neuer Prozess! unter einem anderen Benutzerkontext!). Der ursprüngliche Prozess wird dann beendet.

Caps 6. Apr 2010 12:14

Re: Sichtbarkeit von Variablen bei Diensten
 
Aber jetzt hab ich's im OnStart-Ereignis. Warum klappt's da auch nicht?

mkinzler 6. Apr 2010 12:23

Re: Sichtbarkeit von Variablen bei Diensten
 
Ich wiederhole mich gerne noch einmal:
Keine gloablen Variablen und freie Funktionen/Prozeduren

Delphi-Quellcode:
Tmvideo_sync = class(TService)
    procedure ServiceExecute(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceAfterUninstall(Sender: TService);
    procedure ServiceBeforeUninstall(Sender: TService);
    procedure ServiceAfterInstall(Sender: TService);
  private
    { Private-Deklarationen }
  public

   videos_dir, // Relativer Pfad
   videos_neu_dir, // Relativer Pfad
   mvideo_sync_homedir : String; // Absoluter Pfad zur Dienst-Executable

   IniFile : TIniFile;
   LogFileName : String; // Ohne Pfadangabe
   IniStringList : TStringList;

   hour_of_execution : Word; // Stunde, zu der das Update durchgeführt werden soll
   UpdateExecuted : Boolean; // Wurde das Update durchgeführt? Dient dazu, einen weiteren Durchlauf während der "Update-Stunde" zu verhindern
    function GetServiceController: TServiceController; override;
    procedure Log(Msg: String);
    { Public-Deklarationen }
  end;

  ...

procedure Tmvideo_sync.Log(Msg: String);
...

Caps 6. Apr 2010 12:30

Re: Sichtbarkeit von Variablen bei Diensten
 
Ok, ich danke Dir erstmal, ich habe jetzt keine freien Funktionen und keine globalen Variablen mehr (habe mal eine Test-Unit gebaut, nur noch das Gerüst). Es funktioniert dennoch nicht (= showmessage bringt eine leere Box statt des Strings "gesetzt").
Ich bin vielleicht ein bisschen blind oder kapiere irgendeinen Wink nicht, wie gesagt ich hab jetzt (anscheinend) alles, was Du gesagt hast, befolgt (langsam glaub ich an Hexerei ;-))...

Delphi-Quellcode:
unit Unit1;


interface

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

type
  Tmvideo_sync = class(TService)
    procedure ServiceExecute(Sender: TService);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceAfterUninstall(Sender: TService);
    procedure ServiceBeforeUninstall(Sender: TService);
    procedure ServiceAfterInstall(Sender: TService);
  private
    { Private-Deklarationen } 
  public
    testi : string;
    function GetServiceController: TServiceController; override;
    { Public-Deklarationen } 
  end;


var
   mvideo_sync: Tmvideo_sync;


implementation

{$R *.DFM} 


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


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


procedure Tmvideo_sync.ServiceExecute(Sender: TService);
var
   h, m, s, ms : Word;
begin
while not terminated do begin
      //ServiceThread.ProcessRequests(false);
                        end;
end;


procedure Tmvideo_sync.ServiceStart(Sender: TService; var Started: Boolean);
begin
testi := 'gesetzt';
Started := true;
end;


procedure Tmvideo_sync.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
showmessage(testi);
end;

procedure Tmvideo_sync.ServiceAfterUninstall(Sender: TService);
begin
showmessage(testi);
end;

procedure Tmvideo_sync.ServiceBeforeUninstall(Sender: TService);
begin
showmessage(testi);
end;

procedure Tmvideo_sync.ServiceAfterInstall(Sender: TService);
begin
showmessage(testi);
end;

end.

Caps 6. Apr 2010 12:36

Re: Sichtbarkeit von Variablen bei Diensten
 
Ok, innerhalb von ServiceExecute wird der Wert ausgelesen.
Ich mache also alles zu Eigenschaften und Methoden des Service-Objektes. Dann müsste es klappen, oder? Alles, was nach ServiceStart und vor ServiceStop passiert, kann "miteinander reden"...?

Wie die globalen Variablen allerdings gehandhabt werden bzw. wie ich mir das vorstellen soll, verstehe ich allerdings immernoch nicht so richtig... :wall:

Caps

Caps 6. Apr 2010 12:59

Re: Sichtbarkeit von Variablen bei Diensten
 
LÖSUNG
Falls jemand das gleiche Problem hat:

(Danke mkinzler)

- Das Installieren und Deinstallieren eines bestimmten Dienstes sind eigene Prozesse
- Das Ausführen eines Dienstes (ServiceStart, ServiceExecute, etc..., ServiceStop) ist ein eigener Prozess

Informationen zwischen diesen Prozessen können nicht über Variablen transportiert werden.
Globale Variablen können benutzt werden, aber sie gelten (natürlich) ebenfalls nur in einem bestimmten Prozess.
Möglicherweise verhält es sich mit freien Funktionen ähnlich.

Beste Grüße
Caps


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:50 Uhr.

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