Interaktives Programm im hintergrund starten

Hi allseits,

ich suche nach einer „waidmännischen“ Methode, folgendes zu erreichen:

 es existiert ein Programm, das wie üblich aus einem Hauptformular (Form1) besteht, auf dem sich diverse Controls befinden, und auf dem es einen „Start“ Button gibt, der dann etwas startet. Dementsprechend gibt es auch einen „Stop“ Button der das Teil wieder stoppt. Während es läuft, loopt das Programm unermüflich durch Daten und tut was mit ihnen, und schreibt dabei hin und wieder ein paar Log Einträge weg. Benutzereingaben sind nicht mehr erforderlich. Allerdings muss das Form1 ordentlich geladen werden, man hat der EInfachheit halber auch einige Konfigurationsdaten dort in Felder gespeichert, die das Programm benötigt.

Jetzt kommt irgendwer auf die Idee, das Programm als Systemdienst im Hintergrund laufen lassen zu wollen. Ab und zu jedenfalls, die Variante mit dem sichtbaren Fenster soll weiterhin funktionieren.

Wir beschließen nun, dem Programm einfach einen Parameter, sagen wir mal „/Auto“ mitzugeben, und dann soll das Programm sich praktisch seinen „Start“ Button selber drücken.

Da ich die Rückwirkungen auf Form1 bisher nicht abschätzen kann habe ich erst mal zur meiner Meinung nach ungefährlichsten Methode gegriffen: die FormLoad Routine zieht einen Timer auf, und nach einigen Sekunden feuere ich den selben Event ab, den der Start Button abfeuert … damit hoffe ich, dass das eigentlich für interaktiven Betrieb ausgelegte und getestete Programm vom „Hintergrundbetrieb“ nix merkt und  es klappt auch. Aber elegant ist sowas natürlich nicht.

Elegant wäre, die onClick Methode des Start Buttons direkt aufzurufen. Allerdings erst, nachdem Form1 vollständig geladen wurde, damit alle Controls auf dem Form korrekt initialisiert werden.

Wo ist der waidmännische Einhängpunkt dafür?

Gruss Armin.

hi,

um etwas nach dem ersten Anzeigen einer Form auszuführen kannst Du auch die Windows-Messages verwenden. Dazu definierst Du eine eigene MEssage:

const
WM_AFTER_SHOW = WM_USER + 300; // custom message

im Formular reagierst Du dann auf die Message:

private
procedure WmAfterShow(var Msg: TMessage); message WM_AFTER_SHOW;

Dann musst Du nur noch die Message im OnShow des Formulars abschicken:


PostMessage(Self.Handle, WM_AFTER_SHOW, 0, 0);

Das machst Du natürlich als letzte Anweisung in AfterShow. Dann kannst Du dein Button.Click in WMAfterShow direkt aufrufen…

Grüße

Hi Wolfgang,

danke für Deine Idee, das teste ich gleich mal.

Ich hatte selber auch schon mit ähnlichen Ideen experimentiert, bin aber auf die Schnelle zu keinem guten Ergebnis gekommen, weil die Form on… Routinen die ich probiert habe auch losgegangen sind, wenn das Fernster beispielsweise maximiert wurden. Deshalb am Ende die Idee mit dem TImer, weil ich so sicherstellen kann, dass er wirklich nur ein einziges Mal feuert.

Warum ich damit unzufrieden bin ist auch damit erklärt: wenn das Programm im Hintergrund geschlossen wird, möchte ich gerne noch den „Stop“ Button klicken, da ist derzeit auch noch ein wenig Funktionalität drinnen (letztes Log und Konfigwerte wegschreiben), und da vesagt mein Timer Trick natürlich. Nun ist mir durchaus bekannt, dass der Windows Service Manager auch eine Message schickt bevor ein Dienst heruntergefahren wird, die ich abfangen könnte, aber ich dachte mir ich bekomme einen einfacheren Ansatz wenn ich mich ans Form dranhänge. Dazu müsste ich eine on… Routine finden die vom Form aufgerufen wird sobald das Form komplett initialisiert da steht (also die Message-Loop läuft), und eine die aufgerufen wird bevor die Message Loop gestoppt wird.

Der langen Rede kurzer Sinn: kennst Du eine Quelle, wo die VCL Bibliothek mal genau dokumentiert wird? Ich fand bisher nichts wo genau diese Dinge beschrieben sind, also welche Events werden aufgerufen während ein Form initialisiert wird, welche wenn es vergrößert/verkleinert wird, und welche wenn es zerstört wird.

Hast Du mir da einen TIpp, dann komme ich selber weiter.

Thanx

Armin

Hi,

das einfache zuerst: Schau einfach in den Code der VCL: Da wirst Du schnell fündig was nacheinander passiert und mit Text Suchen findest Du auch schnell die restlichen Stellen bei denen das selbe Event gefeuert wird. Bie Form.Create oder Form.Show lässt sich das schnell nachvollziehen…

Wobei Du sprichst hier schon wieder von einem Dienst: Ich habe es noch nie gemacht, aber ich bezweifle, dass deine VCL-Anwendung so schmerzfrei als Dienst läuft. Hast Du das schon am laufen?

Ansonsten empfehle ich dir deine Businesslogik aus der VCL-Anwendung zu extrahieren und für den Dienst ein eigenes Projekt anzulegen - d.h. eine Businesslogik im Hintergrund, die sowohl vom Dienst als auch von der VCL-Oberfläche verwendet wird…

Grüße

Hi Wolfgang,

Hi,

das einfache zuerst: Schau einfach in den Code der VCL: Da

Form.Show lässt sich das schnell nachvollziehen…

Wobei Du sprichst hier schon wieder von einem Dienst:

Sorry, der interne Sprachgebrauch hier ist so, ich lasse mich daovn gerne mal einfangen :smile:

Es geht darum, eine eigentlich als interaktives Programm konzipierte Lösung *manchmal* auch als Dienst laufen zu lassen. Grund: die Applikation läuft in einigen Firmenteilen interaktiv, in Anderen auf einem Server. Diese startet nach einem Shutdown des Servers natürlich nicht wieder, weil sie derzeit unter einem User-Account bertieben wird. Jemand muss von Hand hinschlappen, sich anmelden, und das Teil anschubsen, und danach den bildschirm sperren. Ein automatischer Login kommt aus Sicherheitsgründen nicht in Frage, und selbst wenn würde sich dieser kaum selber auf den „Start“ Button drücken können --> das Programm muss im Hintergrund gestartet werden können, und ich kann ihm dabei leicht einen Parameter mitgeben um ihm einen heißen Tipp zu geben, sich selber zu starten.

Das mit dem Abtrennen der Business-Logik war auch mein erster Gedanke, ich habs aber verworfen, bereits nach schneller Durchsicht einiger Codeteile sieht man, dass der Programmcode sehr eng mit dem Form und seinen Controls verzahnt wurde --> der Aufwand für die EInarbeitung in den reichlich wirren, undokumentierten Code und die Trennung samt Test des Ganzen steht im keinem Verhältnis zum Nutzen.

Ich habe
es noch nie gemacht, aber ich bezweifle, dass deine
VCL-Anwendung so schmerzfrei als Dienst läuft. Hast Du das
schon am laufen?

Aber klar, sie läuft wie eine eins. Ich habe den Eindruck gewonnen, dass der Unterschied zwischen einem „normalen“ Programm und einem WIndows-Dienst gar nicht einmal so groß ist. In erster Linie reagieren Dienste zusätzlich auf spezielle Service Control Manager Messages zum Starten/Stopppen, und einiges muss man natürlich anders machen weil die Oberfläche an sich wegfällt. Hat das Programm eine, stört das aber den Dienstbetrieb erst einmal nicht, sofern man natürlich eine Möglichkeit findet, das Programm ohne Oberfläche zu bedienen. Im vorliegenden Fall ist das fast problemlos, da das Programm alle EInstellungen unter HKLM speichert, kann man es interaktiv starten und konfigurieren und testen, und erst danach schiebt man es in den Hintergrund, die Einstellungen passen, nur dass da halt keiner auf „Start“ und „Stop“ drücken kann.

Ansonsten empfehle ich dir deine Businesslogik aus der
VCL-Anwendung zu extrahieren und für den Dienst ein eigenes
Projekt anzulegen - d.h. eine Businesslogik im Hintergrund,
die sowohl vom Dienst als auch von der VCL-Oberfläche
verwendet wird…

Wäre sicher gut, geht für die Aufgabe („Mach das Ding mal in den Hntergrund“) eindeutig zu weit.

VCL Quellcode? Das wäre toll, die Arbeit würde ich mir auch gerne machen, aber ich wüsste nicht dass der Code öffentlich einsehbar ist - zumindest habe ich bei Embarcadero nichts gefunden. Hast Du einen Link wo der Quellcode steht?

Gruss Armin

VCL Quellcode? Das wäre toll, die Arbeit würde ich mir auch
gerne machen, aber ich wüsste nicht dass der Code öffentlich
einsehbar ist - zumindest habe ich bei Embarcadero nichts
gefunden. Hast Du einen Link wo der Quellcode steht?

Quellcode der VCL ist bei jeder Professional und höher dabei… Einfach bei TForm mal die Deklaration anzeigen lassen…

Quellcode der VCL ist bei jeder Professional und höher dabei…
Einfach bei TForm mal die Deklaration anzeigen lassen…

„Show declaration“ auf TForm endet in Fehlermeldung „unable to locate file vcl.forms.pas“.

… Platte durchsucht --> Datei gibts tatsächlich nicht. Sollte aber laut Internet Teil meiner Distro sein, und in c:\program files (x86)\embarcadero\rad studio\12.0\source gespeichert sein … Verzeichnis existiert, aber es ist bis auf den Source-Code von DUnit leer.

… scheint bei meiner Installation (XE5 Architect) zu fehlen. Ich dachte immer, Architect sei die umfangreichste RAD Studio Edition? Aber da fällt mir ein, dass ich das Help System seinerzeit ebenfalls von Hand nachinstallieren musste, der Installer der XE5 Version scheint recht buggy zu sein.

Also nochmal von Hand ran.

… Auch Nachinstallationsversuch mit modify/repair brachte keine Besserung. VCL Source scheint bei den wählbaren installationsoptionen nicht auf - bin aber mangels Vergleichsinstallation nicht sicher ob es überhauzpt eine wählbare Option wäre

… Suche auf dem installationmedium brachte mehrere vielversprechend aussehende Archive (source… .7zip) ans Licht, die sich aber mit 7zip nicht einsehen lassen („illegal function call“). Außerdem seien die Files - sagt das Internet - sowieso mit einem Passwort geschützt, welches keiner kennt. Also wieder Sackgasse.

… Embarcadero Discussion Forum meint, Sourcecode sei nicht Bestandteil der Trial Version --> meine Version ist keine Trial Version.

… ich bins leid, meine Zeit zu verplempern, ich bleibe bei der Timer Lösung. Da sie ja immerhin funktioniert kann ich meinem Teamleiter nicht schlüssig verklickern, wieso ich sundenweise Zeit verplempere mit Kampf gegen meine IDE. Es ist, meint er, ohnehin ein Update auf XE7 geplant --> eventuell löst das das Problem, meint er, und er muss kein Budget für die Fehlersuche locker machen, meint er. Ich meine, er meint nicht weise, sondern nur bequem, aber Ober sticht Unter :smile:

Danke für Deine Mühe

Armin.

Hallo,

beim Erstellen und Anzeigen durchläuft ein Formular eine Reihe von Ereignissen und zwar in folgender Reihenfolge:
OnCreate
OnShow
OnPaint
OnActivate
OnResize

Das Formular wird das erste mal nach dem Ereignis OnShow sichtbar. Wird das Formular nur erstellt und nicht angezeigt, entfallen die letzten 4 Ereignisse. Zudem gibt es Komponenten, die sich in diese Reihenfolge einmischen, manche Komponenten-Ereignisse werden sogar vor dem OnCreate-Ereignis ausgelöst.

Beim Beenden werden folgende Ereignisse durchlaufen:

OnCloseQuery
OnClose
OnHide
OnDestroy

Das Formular verschwindet beim Ereignis OnHide. Genauere Beschreibungen zu den Ereignissen findest du in der OnlineHilfe unter TCustomForm.

Ich bin mir zwar nicht ganz sicher, ob Du mit diesem Wissen auf Deinen ungeliebten Timer verzichten kannst, aber vielleicht. OnShow ist auf jeden Fall noch lange nicht der letzte Aufruf beim Erstellen eines Formulars.

Gruß Ebi