ShowMessage bei Programmstart

Rund um die LCL und andere Komponenten
Antworten
Mathias
Beiträge: 6193
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

ShowMessage bei Programmstart

Beitrag von Mathias »

Kann ich unter Win32, ausserhalb der Klasse ein Showmessage aufrufen, so wie in diesem Beispiel.

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;
 
type
  TForm1 = class(TForm)
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
begin
  Application.MessageBox('1234','1234',0);
  ShowMessage('1234');
end.


Unter Linux 64Bit geht dies, aber leider unter Win32 beliber er in der Win32WSControls, bei Zeile 244 stecken.

Code: Alles auswählen

       raise Exception.Create('Failed to create win32 control, error: ' + IntToStr(AErrorCode) + ' : ' + GetLastErrorText(AErrorCode)); 


Ich initialisiere ein Messkarte, ausserhalb der Klasse, und wen er dort die Karte nicht findet, will ich eine Warnung ausgeben.
Ich könnte es auch mit eine globale Variable lösen, und dies im Hauptform abfragen, aber vielleicht geht es doch eleganter.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4888
Registriert: Fr 8. Apr 2011, 09:01

Re: ShowMessage bei Programmstart

Beitrag von wp_xyz »

In der Projekt-Datei geht's bei mir (WIn 10 64 bit, Laz 32 bit) ohne Probleme:

Code: Alles auswählen

program Project1;
 
{$mode objfpc}{$H+}
 
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, Unit1, Dialogs
  { you can add units after this };
 
{$R *.res}
 
begin
  RequireDerivedFormResource:=True;
  ShowMessage('1234');
  Application.Initialize;
  Application.MessageBox('1234', '1234', 0);
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Warf
Beiträge: 1909
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: ShowMessage bei Programmstart

Beitrag von Warf »

Zunächst mal, in eine Unit gehört kein begin Statement, ich weiß nicht warum das überhaupt zugelassen wird, aber eine Unit ist eine Bibliothek und kein Programm. Und als Bibliothek hat eine Unit einen initialization und einen finalization part (was allein von der Nomenklatur mehr Sinn macht, da eine Bibliothek ja eingebunden wird und nicht ausgeführt wird).
Also nächstes steht das was du da Produziert hast gegen alle Konzepte der Objekt Orientierung, und und würde sich (über die Form Load der Mainform) aber sehr gut in diese Konzepte eingliedern lassen.

Nun zu deinem Problem, der Begin (bzw. initialization) Block wird von unten nach oben ausgeführt, das heißt, wenn dein Programm unit1 und Unit2 verwendet, und Unit1 Unit3 verwendet werden Zunächst die Units in der Usesklausel in der reihenfolge wie sie dort stehen initialisiert (also Unit1 dann Unit2) da Unit1 Unit3 verwendet muss zunächst Unit3 Initialisiert werden damit Unit1 Initialisiert werden kann (Die abhängigkeiten kann man sich also als Baum vorstellen, wo es von den Blättern zur Wurzel initialisiert wird). Erst nach der Initialisierung der Units (also dem begin/initialization Block) kann der Code vom Programm ausgeführt werden.

Nun wird bei einer LCL Anwendung erst im Code vom Progamm Application.Initialize ausgeführt, was bedeutet du hast erst ab diesem Punkt die volle Funktionalität der Application Klasse zur Verfügung. Wenn du jetzt allerdings vorher (z.B. im initialize/begin block einer Unit die verwendet wird) Application.MessageBox ausführst kann natürlich vor dem Application.Initialize nicht gewährleistet werden das die Application Klasse diesen Code ausführen kann. Das es unter Linux funktioniert ist damit wohl eher ein Zufall durch die Implementierung (da die, aber ich würde nicht davon auf die allgemeine Funktionalität schließen (Da die TApplication Klasse Plattformabhängigen Code intern verwendet).

Hättest du dich an die OOP Strukturen der LCL gehalten (mit FormLoad) kann dir sowas nicht passieren ;)

Mathias
Beiträge: 6193
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ShowMessage bei Programmstart

Beitrag von Mathias »

Und als Bibliothek hat eine Unit einen initialization und einen finalization part

Das ist in meiner Unit auch so gemacht, ich habe nur den Beispiel-Code auf das wesentliche vereinfacht.
Ich hätte meine Mess-Klasse auch im Public-Teil des HauptForm-Klasse initialisieren können.

Das aber die Mess-Klasse von mehreren Forms verwendet wird, hätte ich die Forms untereinander verknüpfen müssen.
Aber so ist die Mess-Klasse für sich.

Das Ende der Mess-Unit sieht so aus:

Code: Alles auswählen

initialization
 
  MyMess := TMess.Create;
 
finalization
 
  MyMess.Free;
 
end

Und im Konstructer wird die Mess-Karte initialisiert, und bei einem Fehler wollte ich eine Warnung ausgeben.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1909
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: ShowMessage bei Programmstart

Beitrag von Warf »

Mathias hat geschrieben:
Und als Bibliothek hat eine Unit einen initialization und einen finalization part

Das ist in meiner Unit auch so gemacht, ich habe nur den Beispiel-Code auf das wesentliche vereinfacht.
Ich hätte meine Mess-Klasse auch im Public-Teil des HauptForm-Klasse initialisieren können.

Das aber die Mess-Klasse von mehreren Forms verwendet wird, hätte ich die Forms untereinander verknüpfen müssen.
Aber so ist die Mess-Klasse für sich.

Das Ende der Mess-Unit sieht so aus:

Code: Alles auswählen

initialization
 
  MyMess := TMess.Create;
 
finalization
 
  MyMess.Free;
 
end

Und im Konstructer wird die Mess-Karte initialisiert, und bei einem Fehler wollte ich eine Warnung ausgeben.


LCL Formularanwendungen haben die Eigenschaft, dass mit dem Start der Anwendung das Hauptformular initialisiert wird, und mit der Zerstörung dessen die Anwendung beendet wird (darum kümmert sich die TApplication Klasse). Daher kannst du immer die entsprechenden Events (FormCreate, FormDestroy) verwenden statt den Initialization bzw Finalization statements. Da sonst (wie du schon bemerkt hast) komische Nebeneffekte auftreten können (vor allem wenn man irgendwie die Reihenfolge in der Uses wechselt, und plötzlich gar nichts mehr geht).

Und die Forms musst du auch nicht verknüpfen, Beispiel:
Unit Messkarte.pas

Code: Alles auswählen

unit Messkarte;
...
interface
...
type
  TMess = class(...)
  ...
  end;
 
var
  MyMess: TMess;
 
...
end.


deine Mainform.pas

Code: Alles auswählen

unit MainForm;
...
implementation
...
procedure TMainForm.FormCreate(Sender: TObject);
...
begin
  MyMess := TMess.Create(...);
  ...
end;
 
...
 
procedure TMainForm.FormDestroy(Sender: TObject);
...
begin
  MyMess.Free;
  ...
end;
...
 


Die Messkarten Unit musst du ja so oder so einbinden, dann kannst du dort auch die Klassenvariable speichern.

Und von allen Forms kannst du dann darauf zugreifen, da die Mainform (solange man es nicht selbst ändert) zu erst Erstellt wird

Was du auch machen kannst, was natürlich nicht so schön ist wie die OOP Lösung ist, in der .lpr Datei (also deinem Programm) vor Application.Run die Initialisierung vorzunehmen (also bevor der MessageLoop abgearbeitet wird) und nach Application.Run (also nachdem die Mainform geschlossen wurde) das Objekt wieder Freizugeben.

Thomas B.
Beiträge: 90
Registriert: Fr 2. Nov 2007, 13:32
OS, Lazarus, FPC: Win (L 1.0 FPC 2.6.0)
CPU-Target: 32Bit
Wohnort: Ulm

Re: ShowMessage bei Programmstart

Beitrag von Thomas B. »

Ich bin da anderer Meinung.
Die Unit/DLL von der Messkarte sollte autark ihre Fehlermeldungen darstellen können, weshalb ich unter Windows die Unit Windows einbinde, über die mittels

Code: Alles auswählen

MessageBox(0, PChar('Mein Hinweis an den User'), 'Information', MB_ICONSTOP {und falls nötig noch: or MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST});
der Hinweis dargestellt wird, und dann ggf. ein Programmabbruch erfolgt.

Warf
Beiträge: 1909
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: ShowMessage bei Programmstart

Beitrag von Warf »

Thomas B. hat geschrieben:Ich bin da anderer Meinung.
Die Unit/DLL von der Messkarte sollte autark ihre Fehlermeldungen darstellen können


Eine Datenklasse sollte niemals irgendetwas darstellen. Denn stell dir mal vor, du hättest eine Klasse, nehmen wir einfach mal an einen HTML Parser, eine Klasse die grundsätzlich nichts mit grafischer Darstellung zu tun hat. Nun sagst du, bei einem Parsingfehler soll diese Klasse selbst die Fehlermeldung darstellen. Das funktioniert auch für deine Anwendung schön und gut, du verwendest eine Messagebox und bist Happy. Dann willst du ein Programm schreiben was wieder den HTML Parser verwendet, allerdings kein Grafisches Interface besitzt (z.B. eine Konsolenanwendung für einen Command Line Linux Server). Dann musst du die Unit kopieren, und alle Vorkommen von MessageBox durch WriteLn ersetzen. Spaß macht das nicht.
Das hauptproblem ist nun aber, du hast 2 mal die Grundsätzlich gleiche Klasse, das heißt bei Optimierungen, Erweiterungen, Bugfixes, etc. musst du immer dran denken es bei beiden Klassen zu machen. Dann vergisst du es, denkst die Funktion wäre anders (weil sie es bei der anderen Klasse ist) und dir fliegt alles um die Ohren.
Wenn du dann noch eine Implementierung haben möchtest die die Fehler nicht anzeigt sondern nur logt (oder schlicht weg ignoriert) hast du sogar 3 Klassen. Für verschiedene Sprachen musst du dann noch andere Sprachen in deinen Fehlermeldungen unterstützen musst du bei jedem Vorkommen von Messagebox das abändern (bei allen 2-3 Dateien).

Zwar bekommt man das mit Conditional Compiling in den Griff, aber das ist definitiv keine gute Lösung. Viel schöner sind da Exceptions. Ein Sprachfeature was viel zu sehr unterschätzt wird bei Lazarus. Du hast einen Fehler->Feuerst die Exception in deiner Klasse, die Benutzerfunktion muss sich darum kümmern die zu behandeln, oder sie wird direkt bis zum User hochgereicht. Funktioniert grafisch, dann werden Messageboxen gezeigt, oder Textuell. Hier ein link dazu. Und das beste, das ist weder Betriebsystem noch Widgetset abhängig.

Mathias
Beiträge: 6193
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ShowMessage bei Programmstart

Beitrag von Mathias »

@Thomas B.

Danke, genau dies hatte ich gesucht.

Klar ist das nicht dir eleganteste Lösung. aber für diesen Zweck reicht es.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Thomas B.
Beiträge: 90
Registriert: Fr 2. Nov 2007, 13:32
OS, Lazarus, FPC: Win (L 1.0 FPC 2.6.0)
CPU-Target: 32Bit
Wohnort: Ulm

Re: ShowMessage bei Programmstart

Beitrag von Thomas B. »

@Mathias: Bitteschön - ist für die Eingangsfrage mit Win32 meiner Meinung nach die schnellste/einfachste Lösung.

Warf
Beiträge: 1909
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: ShowMessage bei Programmstart

Beitrag von Warf »

Mathias hat geschrieben:Klar ist das nicht dir eleganteste Lösung. aber für diesen Zweck reicht es.


So nun das ist was ich nicht verstehe, es ist schlechter, und komplizierter als eine Exception, aber dennoch bevorzugst du es, warum?
Statt Showmessage könntest du einfach sowas schreiben

Code: Alles auswählen

uses SysUtils;
type EMesskartenException = Exception;
 
// Deine Klasse
 
...
// Fehler:
  raise EMesskartenException.Create('Fehlermeldung');
 
//bzw für ganz faule ohne eigenen typen
  raise Exception.Create('Fehlermeldung');


Dann kümmert sich Lazarus/Pascal komplett autonom darum 1. Die Fehlermeldung auszugeben, 2. die Prozedur abzubrechen (da es ja keinen sinn macht bei fehlender Messkarte weiter zu machen).
Und das beste, wenn du die Fehlerausgabe selbst übernehmen willst, oder den Fehler abfangen/behandeln willst verwendest du einfach Try-Except oder TApplication.OnException.

Und eine Messagebox zu feuern, mit Betriebsystemabhängigem Code der über Compilerswitches realisiert wird ist doch wohl kaum einfacher oder?

Mathias
Beiträge: 6193
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: ShowMessage bei Programmstart

Beitrag von Mathias »

(da es ja keinen sinn macht bei fehlender Messkarte weiter zu machen).

Das Programm darf trotzdem weiter laufen, man kann dann einfach keine neue Messungen erfassen, aber alte angucken sollte trotzdem erlaubt sein.

Und eine Messagebox zu feuern, mit Betriebsystemabhängigem Code der über Compilerswitches realisiert

Dieser Teil ist sowieso Windows abhängig, da die Mess-Karte sowieso nur unter Windows läuft.

Die Mess-Karte läuft später auf einem Win-PC in der Firma.

Für mich zuhause, habe ich eine Messmöglichkeit über einen Arduino, welcher dann unter Linux läuft.
So kann ich fast das ganze Programm unter Linux entwickeln (ausser die Mess-Karten spezifischen Sachen, und zum Schluss eine End-Kompilierung auf Windows machen, welches dann in der VirtualBox läuft.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten