Ausgabe einer Kommandozeilenhilfe

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
joe
Beiträge: 37
Registriert: Fr 28. Mai 2010, 15:47

Ausgabe einer Kommandozeilenhilfe

Beitrag von joe »

Hallo!

Ich habe eine App mit grafischem UI, welche auch diverse Kommandozeilenparameter akzeptiert.
Beim Aufruf der App mit -h oder /? (oder was sonst noch so üblich ist (Mac?) will ich alle verfügbaren Optionen auflisten.

Unter Linux kann ich auch in einer grafischen App via Writeln auf die Konsole schreiben. Ich klinke mich dann also direkt ins .lpr ein und gebe ggf. meine Hilfe aus:

Code: Alles auswählen

begin
  {$I TV.lrs}
  if (ParamStr(1)='/?') or (ParamStr(1)='-h') or (ParamStr(1)='-help') or (ParamStr(1)='--help') then
    begin
    Writeln('Hier ist die Hilfe');
    Exit;
    end;
  Application.Initialize;
  Application.CreateForm(TFormMain, FormMain);
  Application.Run;
end.
Unter Windows geht das allerdings nicht. Da muss ich mich offenbar entscheiden, ob ich eine Konsolenanwendung oder eine GUI-App bin.
Also würde ich unter Windows vielleicht ein TForm mit 'nem TMemo öffnen und dort die Hilfe anzeigen.

Frage: Gibt es dafür einen irgendwie gearteten portablen Lösungsansatz oder muß ich mir das selbst machen?

Gruss,
Joe.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6877
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von af0815 »

Es wird zwar nicht helfen :-)

Starte bei Windows das Programm mal von der Kommandozeile aus - dann funktioniert es. Dein Problem ist, das Windows keine Konsole beim Starten von GUI-Apps geöffnet ist, somit wird deine Hilfe nicht angezeigt.

Wenn der Benutzer von der Konsole aus startet, die wenigsten kommen auf die Idee, dann funktioniert es.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 10949
Registriert: Mo 11. Sep 2006, 19:01

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von theo »

Wenn ich mich recht erinnere, kackt der aber ab, wenn du writeln machst und keine Konsole da ist.
Man könnte versuchen, in try except zu writeln, oder vielleicht gehts mit AllocConsole.
http://msdn.microsoft.com/en-us/library ... S.85).aspx

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von Hitman »

Da würde ich unter Windows in der Tat eher mit ShowMessage, MessageDlg oder wie du sagst einem eigenen Formular arbeiten. Unter Windows sind Konsolenfenster nunmal unüblich.
Technisch machbar sollte es schon sein, da du sicherlich überprüfen kannst, ob du in einer Konsole läufst oder nicht ("File not found" sagt ja in dem Fall, dass stdout nicht verfügbar ist). Dann müsste man aber immernoch den Fall abhandeln, dass der Nutzer /? per Shortcut oder Run aufgerufen hat, wo dann ebenfalls keine Konsole verfügbar wäre.

joe
Beiträge: 37
Registriert: Fr 28. Mai 2010, 15:47

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von joe »

Was ich eigentlich möchte ist:
- Bei Aufruf ohne -h soll die App ganz normal gestartet werden
- Bei Aufruf mit -h soll auf der Konsole (so die App von Konsole gestartet wurde) die Hilfe ausgegeben werden
Wurde die App mit -h nicht von Konsole gestartet, dann ist mir (erstmal) egal was geschieht...

Das Kernproblem besteht also darin: Wie bekomme ich unter Windows meinen Output in die Konsole, von der aus ich gestartet wurde?

Also in Win32\System.pp heisst es:

Code: Alles auswählen

procedure SysInitStdIO;
begin
  { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
    displayed in a messagebox }
  StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  if not IsConsole then
   begin
     AssignError(stderr);
     AssignError(stdout);
     Assign(Output,'');
     Assign(Input,'');
     Assign(ErrOutput,'');
   end
  else
   begin
     OpenStdIO(Input,fmInput,StdInputHandle);
     OpenStdIO(Output,fmOutput,StdOutputHandle);
     OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
     OpenStdIO(StdOut,fmOutput,StdOutputHandle);
     OpenStdIO(StdErr,fmOutput,StdErrorHandle);
   end;
end;
... aber ich finde keine MessageBox in der mein Writeln landet.

Mein Writeln bringt unter Windows eine Exception die ich mit try/except wegfangen kann.
Wenn ich ein Assign(Output,''); Rewrite(Output); davor schreibe kommt keine Exception, aber trotzdem auch keine Ausgabe auf der Konsole.

Mit vorherigem AllocConsole bekomme ich entlich eine Ausgabe:

Code: Alles auswählen

begin
  {$I ConsoleHelp.lrs}
  if ParamStr(1)='-h' then
    begin
    AllocConsole;
    Assign(Output,'');
    Rewrite(Output);
    Writeln('Hallo');
    end;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
Allerdings macht mir Windows dann immer eine neue Konsole auf, auch wenn ich meine App von der Kommandozeile aus gestartet habe.

Ok, jetzt noch mal Tests ohne -WG, sodass meine App unter Windows als Konsolenanwendung gilt.
Damit funktioniert ja ein Writeln erstmal grundsätzlich und meine Formulare etc. werden trotzdem auch sichtbar.
Doof ist nur, dass dann beim Start meiner App (z.B. durch Klick auf das EXE im Explorer) per default immer eine Konsole aufgemacht wird.
Die bekomme ich zwar (für den Fall dass ich ohne -h aufgerufen wurde) mit FreeConsole() wieder weg, aber für kurze Zeit ist sie eben sichtbar. Unschön also.

Also -WG wieder eingeschaltet.
Lt. http://msdn.microsoft.com/en-us/library ... 85%29.aspx" onclick="window.open(this.href);return false; soll man mit AttachConsole(-1); die Konsole des Parent Prozesses bekommen.
Den Export

Code: Alles auswählen

AttachConsole(pid: LongInt): WINBOOL; external 'kernel32' name 'AttachConsole';
habe ich mir selbst gemacht, da er in rtl\inc\wininc\func.inc nicht enthalten war.
Bringt aber auch nichts, offenbar ist die Konsole von der aus ich meine App starte unter Windows nicht mein Parent?!
Statt dessen bekomme ich nach beenden meiner App einen Runtime error 217 in $0040A6DC in einer MessageBox (sowie 3 weitere Adressen) angezeigt.

Auch andere haben dafür scheinbar keine saubere Lösung gefunden (http://stackoverflow.com/questions/5453 ... p-exe-help" onclick="window.open(this.href);return false;).
Der in http://code.google.com/p/dualsubsystem" onclick="window.open(this.href);return false; beschriebene Trick mit 'nem Bla.com und Bla.exe gefällt mir jedenfalls nicht.

Nun denn, da werd' ich wohl für Windows doch ein TMemo verwenden müssen. Selbst Windows eigene Tools (wie z.B. WinDiff) machen das auf diese Weise.

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von Hitman »

Deiner AttachConsole Deklaration fehlt sicherlich das "stdcall". Das könnte dann durchaus den Fehler erklären. Ob es auch das Nicht-Funktionieren erklärt ... wir werden sehen ;-)

joe
Beiträge: 37
Registriert: Fr 28. Mai 2010, 15:47

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von joe »

Hitman hat geschrieben:Deiner AttachConsole Deklaration fehlt sicherlich das "stdcall". Das könnte dann durchaus den Fehler erklären. Ob es auch das Nicht-Funktionieren erklärt ... wir werden sehen ;-)
In der Tat, mit stdcall klappt es :)
Ich hatte mir die Deklaration von einer der vielen anderen aus func.inc abgeguckt und die sind nahezu (bis auf 2) alle ohne stdcall!
Doch leider folgt das nächste Problem: In der Konsole wird sofort nach dem Start meiner App wieder der Prompt angezeigt, also noch bevor mein Output angezeigt wird :(
Für meinen Zweck ist das also leider die etwas falsche Reihenfolge, schade eigentlich.

Hitman
Beiträge: 512
Registriert: Mo 25. Aug 2008, 18:17
OS, Lazarus, FPC: ArchLinux x86, WinVista x86-64, Lazarus 0.9.29, FPC 2.4.1
CPU-Target: x86
Wohnort: Chemnitz

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von Hitman »

Na der von dir verlinkte Artikel (zu idasm) sagte es ja eigentlich schon, wie's geht (wenn überhaupt): die Anwendung als Konsolenanwendung schreiben, und die Konsole halt wieder freigeben wenn man sie nich braucht. Also eben genau umgekehrt wie du es jetzt machst.

joe
Beiträge: 37
Registriert: Fr 28. Mai 2010, 15:47

Re: Ausgabe einer Kommandozeilenhilfe

Beitrag von joe »

Hatte ich schon probiert (siehe oben):
Ok, jetzt noch mal Tests ohne -WG, sodass meine App unter Windows als Konsolenanwendung gilt.
Damit funktioniert ja ein Writeln erstmal grundsätzlich und meine Formulare etc. werden trotzdem auch sichtbar.
Doof ist nur, dass dann beim Start meiner App (z.B. durch Klick auf das EXE im Explorer) per default immer eine Konsole aufgemacht wird.
Die bekomme ich zwar (für den Fall dass ich ohne -h aufgerufen wurde) mit FreeConsole() wieder weg, aber für kurze Zeit ist sie eben sichtbar. Unschön also.
Die Konsole wird dann leider immer kurz sichtbar, wenn ich meine App per Shortcut oder Explorer starte; und das sind in meinem Fall 99% der App-Starts.

Antworten