Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Konsolenfenster im GUI-Mode unterdrücken (https://www.delphipraxis.net/52080-konsolenfenster-im-gui-mode-unterdruecken.html)

naujo 23. Aug 2005 15:22


Konsolenfenster im GUI-Mode unterdrücken
 
Hallo zusammen,

ich habe das folgende Problem:
Das Programm welches ich schreibe soll eine grafische Oberfläche verfügen und auch über die Kommandozeile sich bedienen lassen. Wenn die Kommandozeile verwendet wird dann kommt keine GUI. Wenn jetzt aber die GUI aufgerufen werden soll, dann erscheint im Hintergrund immer das Konsolenfenster.

Das möchte ich aber nicht anzeigen, weil den Anwender sonst zu sehr verwirrt.

Wenn ich aber die
Delphi-Quellcode:
{$APPTYPE CONSOLE}
Compiler-Direktive lösche, dann kann ich keinen Text mehr auf der Konsole ausgeben, es kommt dann immer eine Zugriffverletzung.

Hier mal ein Auszug aus dem Hauptprogramm:
Delphi-Quellcode:
begin
  Application.Initialize;
  Application.Title := 'Main';
  Application.CreateForm(TMainFrm, MainFrm);
  Application.CreateForm(TFrmInfo, FrmInfo);
  (...)

  if (not BatchMode) then
  begin
    (...)
    Application.Run;
  end
  else
  begin
    // Muss eingefuegt werden, da es sonst zu einem Programmabsturz kommt
    {$APPTYPE CONSOLE}
    (...)
    // Hier erfolgen dann Ausgaben in Konsolenfenster
  end;
end.
Vielen Dank dann schon mal für eure Antworten.

MfG

Naujo

c113plpbr 23. Aug 2005 16:39

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Hi Naujo,

nur dass es da keine missverständnisse gibt:
Delphi-Quellcode:
{$APPTYPE CONSOLE}
ist eine *compiler direktive*, d.h. es ist im grunde egal wo das dingens steht, selbst wenn die zeile in der es steht nicht "aufgerufen" wird, besitzt die anwendung dennoch ein konsolenfenster!
D.h. das mit ner einfachen if-abfrage zu lösen kannst du schonmal vergessen.

Wenn du nicht unbedingt eine ausgabe auf der konsole brauchst, sondern nur das programm ausführen willst, dann lass die $APPTYPE CONSOLE-Direktive weg, und erzeuge einfach nur keine graphische oberfläche. Das läuft dann auch in der konsole, nur eben ohne ausgabe & graphische oberfläche.

Eine weitere möglichkeit wäre evtl. noch, das konsolenfenster nach dem start des programmes zu verstecken. Also fenster suchen, und verstecken.

Andere möglichkeiten fallen mir dazu atm. nicht ein ...

ciao, Philipp

jbg 23. Aug 2005 16:45

Re: Konsolenfenster im GUI-Mode unterdrücken
 
AllocConsole macht eine neue Konsole auf.

r2c2 23. Aug 2005 16:49

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Ich weiß jetzt nicht, ob du das hören willst, aber du könntest 2 Programme schreiben. Wenn du OO Programmierst sollte es kein Problem sein, aus der GUI ne Console zu machen.

Ich muss aber zugeben, dass ich wahrscheinlich auch einfach nur das Consolen-Fenster verstecken würde...

mfg

Christian

naujo 24. Aug 2005 06:45

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Moin moin,

Zitat:

Ich weiß jetzt nicht, ob du das hören willst, aber du könntest 2 Programme schreiben.
Das wollte ich auf jeden fall vermeiden. Aber es wäre kein Problem, weil ich alles in Klassen gekapselt habe. Und die Ausgaben sauber von einander getrennt habe, die Logik arbeitet unabhängig vom Modus (so es eigenlich immer sein soll, auch wenn man nur eine grafische Oberfläche oder nur aus Konsolenebene arbeitet).

Zitat:

Eine weitere möglichkeit wäre evtl. noch, das konsolenfenster nach dem start des programmes zu verstecken. Also fenster suchen, und verstecken.
Wie setzt man das in DeLphi um? Das stellt für mich die beste Lösung dar.

Vielen Dank für eure Antworten.

MfG

Naujo

r2c2 24. Aug 2005 08:08

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Zitat:

Zitat von naujo
Zitat:

Eine weitere möglichkeit wäre evtl. noch, das konsolenfenster nach dem start des programmes zu verstecken. Also fenster suchen, und verstecken.
Wie setzt man das in DeLphi um? Das stellt für mich die beste Lösung dar.

Such mal nach Delphi-Referenz durchsuchenFindWindow(Ex). Damit bekommst du das Handle des Fensters. Zum Verstecken gibts auch ne Funktion(HideWindow? :gruebel: weiß nicht mehr). Auf jeden Fall fidest du was, wenn du danach suchst(DP, dsdt.info, swissdelphicenter.ch, goolge...).

mfg

Christian

Olli 24. Aug 2005 09:37

Re: Konsolenfenster im GUI-Mode unterdrücken
 
1.) Diese Frage gibt es hier im Forum mindestens schon einmal
2.) Vergiß es!

Kurze Begründung: a.) habe ich das sehr lange probiert und dazu auch versucht mit RE den Konsolen auf die Spur zu kommen. b.) kann es nicht gehen, weil der PE-Loader bereits die Konsole für den Prozeß alloziert (bei APPTYPE CONSOLE). Damit bist du machtlos und die Konsole wir in jedem Fall kurz erscheinen. Selbst Tricks mit der PEB/TEB (nur unter NT) waren zwecklos. Man dreht sich dort im Kreis, weil die Überprüfung erst geschehen kann, wenn das Programm bereits läuft - zu dem Zeitpunkt existiert aber bereits eine Konsole oder sie existiert eben nicht (APPTYPE GUI) - dann gibt's allerdings auch keine Elternkonsolhandles.

Ich denke mal, daß du das gleiche erreichen möchtest wie ich bei meinem RShutdown2 damals: daß dein Programm von einer "Elternkonsole" aus gestartet werden kann und dann dort seine Ausgaben/Eingaben bekommt. Ich will nicht behaupten, daß es komplett unmöglich sei, aber es ist doch recht fragwürdig - zumal bei dem Aufwand in Sachen RE usw.

Ich habe es übrigens dann ganz pragmatisch über MSDN-Library durchsuchenFreeConsole() gelöst. So wird zwar die Konsole kurz angezeigt, ich habe aber dennoch volle Konsolenfunktionialität, wenn die Parameter dies erfordern. Logischerweise kannst du FindWindow() usw. dann auch knicken, weil Konsolennamen theoretisch verschieden sein können. FreeConsole() tut aber seinen Job hervorragend, da es eh nur eine Konsole (pro Prozeß) geben kann ;) ... sonst würde ja MSDN-Library durchsuchenAllocConsole() das Handle zu einer beliebigen neu erzeugten Konsole zurückliefern und nicht nur Erfolg oder Mißerfolg ;)

Ab Windows XP gibt's noch MSDN-Library durchsuchenAttachConsole(), welches dem o.g. Ziel (wenn dies denn deines ist) durchaus helfen könnte. Ich werde mir das mal im Disassembler angucken und vielleicht mit einer Lösung auch ab NT4 rüberrücken. Aber Win9x-Kompat. kannste da definitiv knicken.

Nachtrag: Ich habe es mir gerade angeguckt. Es hängt doch einiges mehr dran. Das größte Problem aber sind die Client/Server-Nachrichten (CSR-Messages), welche nunmal leider nicht dokumentiert sind. Wenn du eine CSR auf Windows 2000 mit einer bestimmten ID zum Laufen bekommen hast, kannst du dir auf Windows XP damit gut und gerne Hardware zerschiessen. Ist also nix wirklich kompatibles. Zumal fraglich ist, ob diese spezifische CSR schon in Windows 2000 existieren würde. Ich werde es mal demnächst versuchen, könnte ja sein, daß es auch ohne die geht. Aber wer weiß :-/

naujo 24. Aug 2005 09:47

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Moin,

also wenn das alles so einen erheblichen Aufwand darstellt, dann muss halt der Anwender mit einem Konsolenfenster im Hintergrund leben, dafür kann ich dann auch nix.

Und was ich nicht erwähnt hatte das Programm soll auch ab Win 95 bzw. Win NT 4 laufen. Ich hatte gedacht, dass es irgendeine Möglichkeit gibt, dass per Schalter oder API-Aufruf einfach zu unterdrücken.

Vielen Dank aber schon mal für eure Mühe.

MfG

Naujo

Olli 24. Aug 2005 10:02

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Zitat:

Zitat von naujo
Und was ich nicht erwähnt hatte das Programm soll auch ab Win 95 bzw. Win NT 4 laufen. Ich hatte gedacht, dass es irgendeine Möglichkeit gibt, dass per Schalter oder API-Aufruf einfach zu unterdrücken.

Leider nein, da dieses Flag wie gesagt nicht von der EXE sondern schon davor ausgewertet wird ;) ...

himitsu 10. Nov 2007 08:42

Re: Konsolenfenster im GUI-Mode unterdrücken
 
hab jetzt mal einiges von da oben ausprobiert...

AllocConsole und AttachConsole erzeugen beide eine neue Console (unter WinXP)
sieht vorallem witzig aus wenn das Programm von einer Console (oder Batchfile) aus gestartet wurde und nun zwei davon da sind.

mit $APPTYPE CONSOLE hatte ich es schon versucht, aber da bleib ich nun bei GUI (das Programm läuft ja vorwiegend damit)
OK, das Programm arbeitet zwar NonVCL und da werden die Fenster genauso mit Console, als auch ohne (GUI) angezeigt, aber da stört mich schon dieses Konsolenfenster, wenn es nicht benötigt wird.


ich wollte einfach nur eine Statusmeldung in der Konsole ausgebn (wenn diese exisiert) ...
gibt es da nun inzwischen irgendwo eine Lösung dafür?
Input wird nicht benötigt, ich würde nur genr irgendwie ein/zwei Zeilen dareinschreiben.

MfG <(^_^<)


[add]
aaaalso, FreeConsole schließt zwar nur die vom Programm erzeugte
Konsoleund Eine z.B. von 'ner Batch-Datei bleibt geöffnet,
aber nach dem Aufruf st dennoch (war ja irgendwie klar) die Verbindung
zur "Batch-Datei"-Konsole futsch.

Delphi-Quellcode:
{$APPTYPE CONSOLE}
Sleep(2000);
WriteLn('123');             // << in "alter" Konsole
Sleep(2000);
if FreeConsole then A := 'f';
Sleep(2000);
{$i-} WriteLn('456'); {$i+}  // << dieses wird natürlich nie ausgegeben
Sleep(2000);
if AllocConsole then A := A + 'a';
Sleep(2000);
{$i-} WriteLn('789'); {$i+}  // << Ausgabe in neuer Konsole (AllocConsole)
Sleep(2000);                // auch geschützt, da beim der mit AllocConsole
Exception(998, [A]);        // erzeugten Konsole zwar der Text geschrieben wird,
                             // aber dennoch eine Exception auftritt
[add2]
wenn jetzt dieses "kurzzeitige" Konsolenfenster und die Beschränkung auf WinXP/Vista nich wäre,
dann könnte man es wohl so lassen :stupid:
Delphi-Quellcode:
{$APPTYPE CONSOLE}
FreeConsole;
isConsole := AttachConsole(ATTACH_PARENT_PROCESS);

if isConsole then WriteLn('irgendwas');
dieses hat mir auch gleich mal eine Lösug gegeben, wie ich automatisch rausbekommen kann ob GUI oder Konsole.

DP-Maintenance 10. Nov 2007 09:24

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Object-Pascal / Delphi-Language" verschoben.
Delphi-Frage.

himitsu 15. Nov 2007 11:49

Re: Konsolenfenster im GUI-Mode unterdrücken
 
http://fnse.de/S02/15S.gif
ja also, wie gesagt, ich hab 'ne GUI-Anwendung und möchte, falls diese von einer Konsole/Batchfile aus aufgerufen wird, in dieser einen Statustext ausgeben.

Olli 15. Nov 2007 12:39

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Zitat:

Zitat von himitsu
dieses hat mir auch gleich mal eine Lösug gegeben, wie ich automatisch rausbekommen kann ob GUI oder Konsole.

Ich verweise mal spontan auf meinen Beitrag der hier unter #10 abgespeichert ist. Den wirst du wohl uebersehen haben.

Warum gibst du deinen Statustext nicht einfach vor dem FreeConsole aus? Ab Vista (oder war's W2K3?) gibt es eine API um die Handles der Elternkonsole zu ermitteln. Mit viel Frickelei kann man die API fuer die vorigen Systeme nachbauen.

Aber um es nochmal zu wiederholen: die Konsole wird nicht vom Konsolenprogramm erzeugt, folglich kann das Konsolenprogramm auch nicht die Erstellung der Konsole verhindern. War das jetzt klar genug?

OregonGhost 15. Nov 2007 12:47

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Es gibt auf Sourceforge.NET das Projekt Console2. Dieses injiziert in Kindprozesse eine DLL, die unter anderem das Konsolenfenster unterdrückt und ausliest. Das, was in dieser DLL passiert, müsstest du ja auch in deinem eigenen Programm machen können, und dabei müsstest du auch herausfinden können, ob nun eine Konsole da ist oder nicht. Vielleicht ist das interessant für dich, schau mal in den (leider nur mittelmäßig kommentierten) Quellcode.

himitsu 15. Nov 2007 13:04

Re: Konsolenfenster im GUI-Mode unterdrücken
 
die #10 hier ist mein Post :angel:

Zitat:

die Konsole wird nicht vom Konsolenprogramm erzeugt, folglich ...
das hab ich schon mitbekommen

und das Problem bei FreeConsole:
- erstmal müßte ich das Programm in eine ConsolenProgramm umwandeln > {$APPTYPE CONSOLE}
und dann darf ich auch wieder die Dateizugriffe prüfen/ändern (wegen Console=OEM und GUI=ANSI)
- dann sollte das Konsolenfenser ja nicht dableiben, wenn nicht von einer Konsole aus gestartet wurde
kein Ahnung wie ich das prüfen soll, aber FreeConsole gibt True zurück, wenn das "eigene" Konsolenfenster geschlossen werden konnte. (heißt von Konsole gestartet = False)

Hier kann man ja nur bis FreeConsole etwas ausgeben und später nicht mehr
und wenn das Konsolenfenstern wärend der Programmlaufzeit nicht angezeigt werden soll, muß dieses Fenster ja geich bei Programmstart geschlossen werden.
Delphi-Quellcode:
{$APPTYPE CONSOLE}
WriteLn('Programm gestartet');
FreeConsole;
Dieses wäre zwar eine Lösung (auch wenn sie nicht ganz optimal ist und erst seit XP funktioniert)
Delphi-Quellcode:
{$APPTYPE CONSOLE}
FreeConsole;
isConsole := AttachConsole(ATTACH_PARENT_PROCESS);

if isConsole then WriteLn('irgendwas');

@OregonGhost: werd mal reinsehn

Olli 15. Nov 2007 13:32

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Zitat:

Zitat von himitsu
die #10 hier ist mein Post :angel:

Dann hat die DP einen Bug. Wenn man antwortet, wird mein Beitrag exakt davor als #10 angezeigt.

Zitat:

Hier kann man ja nur bis FreeConsole etwas ausgeben und später nicht mehr und wenn das Konsolenfenstern wärend der Programmlaufzeit nicht angezeigt werden soll, muß dieses Fenster ja geich bei Programmstart geschlossen werden.
Logisch. Aber wo ist dabei das Problem? Du muesstest im PEB des Elternprozesses rumwuehlen um an diese Informationen zu gelangen (inkl. Handles). Das laesst sich nur mit den entsprechenden Rechten auf den Elternprozess bewerkstelligen, was aber leider die ganze Geschichte wieder unpraktikabel macht.

himitsu 15. Nov 2007 13:47

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Liste der Anhänge anzeigen (Anzahl: 1)
PEB ... och nöööö :(

hab zwar och mal ein Programm gesehn, was wohl über 'nen Loader (wie z.B. bei UPX) gestartet wurde, welcher dann die entprechende Programmversion geladen hatte (dort war es 'ne DOS/Windows-Vesion oder so ... is schon lange her)

Olli 16. Nov 2007 09:45

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Liste der Anhänge anzeigen (Anzahl: 1)
Konnte mir dieses SF.net-Projekt nur flüchtig ansehen, sieht aber gut aus. Die scheinen einen anderen Weg zu gehen, der ohne die internen Strukturen des Elternprozesses (sprich, in unserem Fall PEB) auskommt. Der Lösungsansatz ist kreativ, mit der Einschränkung, daß auch hier Kompromisse her müssen.

Ich hatte mir mal was anderes überlegt gehabt, aber dann wieder verworfen (also nie probiert). Man könnte ja on-the-fly eine Kopie der EXE erstellen und ausführen, welche man zuvor im Header so modifiziert, daß das Subsystem auf Konsole steht. Natürlich bedeutet es in jedem Fall auch Frickelei.

himitsu 23. Nov 2007 11:06

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Liste der Anhänge anzeigen (Anzahl: 1)
Warum bin ich eigentlich nicht gleich draufgekommen AttachConsole als erstes aufzurufen? :gruebel:
(wozu FreeConsole ... AttachConsole sagt ja auch ob's erfolgreich war)

Das einzige Problem ist jetzt nur noch, daß AttachConsole erst ab XP verfügbar ist.
Und nachprogrammieren ist für mich etwas zu hoch ... hab mal reingeschaut und da werden Dinge aufgerufen, wo ich mit meinem Unwissen nicht rankomm.

Bei allem vor XP wird AttachConsoleDummy verwendet, welches einfach nur sagt daß es nicht ging
und ab XP funktioniert es so eigentlich perfekt. > es wird kine neue Konsole geöffnet und beim Programmstart blinkt auch Keine kurz auf. :angel:

Delphi-Quellcode:
{$APPTYPE GUI}

Uses Windows;

Function AttachConsoleDummy(dwProcessId: LongWord): LongBool;
  Begin
    Result := False;
  End;

Var AttachConsole: Function(dwProcessId: LongWord): LongBool; StdCall;
  ConsoleOutput: Boolean = False;




AttachConsole := GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');
If @AttachConsole = nil Then AttachConsole := @AttachConsoleDummy;

ConsoleOutput := AttachConsole(ATTACH_PARENT_PROCESS);




// und jetzt immer wenn zur Console verbunden wurde etwas reinschreiben
// > WriteLn erzeugt eine Exception, wenn keine Console vorhanden ist (darum ConsoleOutput)
If ConsoleOutput Then WriteLn('irgendwas');


Oder diese kleine Unit
Delphi-Quellcode:
Unit FSSystem;

Interface
  Var ConsoleOutput: Boolean = False;

  Procedure WriteConsole(S: String);

Implementation
  Uses Windows;

  Var AttachConsole: Function(dwProcessId: LongWord): LongBool; StdCall;

  Function AttachConsoleDummy(dwProcessId: LongWord): LongBool;
    Begin
      Result := False;
    End;

  Procedure WriteConsole(S: String);
    Begin
      If (S = '') or not ConsoleOutput Then Exit;
      UniqueString(S);
      CharToOemA(PAnsiChar(S), PAnsiChar(S));
      WriteLn(S);
    End;

Initialization
  AttachConsole := GetProcAddress(GetModuleHandle('kernel32.dll'), 'AttachConsole');
  If @AttachConsole = nil Then AttachConsole := @AttachConsoleDummy;

  ConsoleOutput := AttachConsole(ATTACH_PARENT_PROCESS);

End.
und im Programm dann jeweils einfach nur noch WriteConsole aufrufen
Delphi-Quellcode:
{$APPTYPE GUI}


WriteConsole('irgendwas');

Assertor 16. Mai 2009 10:45

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Hi,

ich habe gerade mal AttachConsole ausprobiert. Es gibt ein Problem, daß nach dem Ende der Anwendung der Prompt nicht angezeigt wird und man einmal Enter drücken muß. Es sieht also so aus wie ein ReadLn() am Ende, jedoch wird alles getippte direkt ausgeführt. Es fehlt tatsächlich nur der Prompt ($p$g) der Befehlszeile am Ende... OS Vista x32, Delphi 2009.

Ist dies jemanden schon aufgefallen und gibt es eine Lösung?

Gruß Assertor

himitsu 16. Mai 2009 10:59

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Aufgefallen ist es mir noch nicht, da weitere Tests und das aktuelle Programm nur via Batchfile liefen/laufen.

Hmmm, was nir auf die schnell einfallen würde, einfach beim Programmende den Prompt noch schnell vom Programm schreiben zu lassen ... irgendwo sollte doch stehn wie der aktuell eingestellte Prompt aussieht? :gruebel:

Assertor 16. Mai 2009 11:16

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Hi himitsu,

Zitat:

Zitat von himitsu
Aufgefallen ist es mir noch nicht, da weitere Tests und das aktuelle Programm nur via Batchfile liefen/laufen.

Hmmm, was nir auf die schnell einfallen würde, einfach beim Programmende den Prompt noch schnell vom Programm schreiben zu lassen ... irgendwo sollte doch stehn wie der aktuell eingestellte Prompt aussieht? :gruebel:

Prinzipiell so wie unter DOS damals - in der Environment Variable Prompt ;) Aber das ist ja Bestandteil des Kommandozeileninterpreters, also müßte man selbst den Prompt parsen und ausgeben. Zusätzlich könnte der Benutzer den "Mogelprompt" per Rücktaste löschen.

Gruß Assertor

himitsu 16. Mai 2009 11:20

Re: Konsolenfenster im GUI-Mode unterdrücken
 
wenn man ihn per Write ausgibt, dann sollte er aber doch nicht zu löschen sein?

Assertor 16. Mai 2009 11:24

Re: Konsolenfenster im GUI-Mode unterdrücken
 
Hi,

Zitat:

Zitat von himitsu
wenn man ihn per Write ausgibt, dann sollte er aber doch nicht zu löschen sein?

Natürlich richtig. Ich war in Gedanken schon wieder bei der App.

Ich schreib mir gerad ein kleines Sudo für Vista, welches die Meldungen halt entweder an die Console oder per GUI zeigen soll. Da stört das Prompt Problem in cmd Fenster.

Das ganze Problem mit diesen console/gui Zwittern ist ja nicht wirklich lösbar. Gibt da ja auch einen guten Artikel in einem MSDN Blog drüber. Der Subsystemtyp ist nunmal teil der EXE, also ist es im Vorwege bestimmt.

Mal sehen, ob ich das irgendwie umgehen kann...

Nachtrag: Das Problem besteht nicht direkt mit AttachConsole, sondern erst sobald 1x WriteLn() nach AttachConsole verwendet wurde.

Gruß Assertor

nru 19. Apr 2014 00:33

AW: Konsolenfenster im GUI-Mode unterdrücken
 
auch wenns schon wirklich sehr lange her ist ... aber gibts zu dem Phantom-ReadLn am Ende eigentlich eine Lösung?
Ich hätte da nämlich gerade aktuell Bedarf ;)

EDIT: ups ... gib doch schon was ... hier http://www.delphipraxis.net/1095086-post10.html


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