![]() |
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 |
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 |
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. |
Re: Sichtbarkeit von Variablen bei Diensten
Zitat:
|
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. |
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.
|
Re: Sichtbarkeit von Variablen bei Diensten
Aber jetzt hab ich's im OnStart-Ereignis. Warum klappt's da auch nicht?
|
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); ... |
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. |
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 |
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 00:22 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