Integration der CMD

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
House
Beiträge: 19
Registriert: Fr 24. Okt 2008, 12:54

Integration der CMD

Beitrag von House »

Hi,

nach langer Arbeit mit Delphi, dachte ich mir, auf eine Programmiersprache umzusteigen, die Delphi ähnlich ist, dafür aber kostenlos und ohne Einschränkungen bzg. Erstellung kommerzieller Produkte. Und da bin ich "glücklicherwiese" fündig geworden mit Lazarus.

Nun zu meinem eigentlichen Problemkind:
(im Anhang ein Bild der Form)

ich versuche gerade die Kommandozeile in mein Programm zu integrieren und "LAZARUS" wirft mir gerade mehrere Fehler aus, mit denen ich irgendwie nichts anfangen kann. Ich hatte das ganze schonmal in Delphi verwendet, ohne Probleme.

Code: Alles auswählen

unit command; 
 
{$mode objfpc}{$H+} 
 
interface 
 
uses 
  Windows, Messages, Variants, Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, 
  ExtCtrls, StdCtrls; 
 
type 
 
  { TForm11 } 
 
  TForm11 = class(TForm) 
    //Items (Button, Labels, etc.) 
    //Prozeduren (Click, Create, etc.) 
  private 
  fInputPipeRead, 
  fInputPipeWrite, 
  fOutputPipeRead, 
  fOutputPipeWrite: Cardinal; 
  fProcess: Cardinal; 
  procedure FClbProc(Sender: TObject; const ABuffer: String; ABufSize: Cardinal); 
  procedure FOpenProcess; 
  procedure FCloseProcess; 
  procedure FWriteToStdIn(const AText: String); 
    { private declarations } 
  public 
    { public declarations } 
  end; 
 
  TPipeClbProc = procedure (Sender: TObject; const ABuffer: String; ABufSize: Cardinal) of Object; 
  TPipeReadThread = class(TThread) 
  private 
  fBuffer: String; 
  fBytesRead: Cardinal; 
  fClbProc: TPipeClbProc; 
  fPipeOutput: Cardinal; 
  procedure FSyncProc; 
  protected 
    procedure Execute; override; 
    constructor Create(AClbProc: TPipeClbProc; APipeOutput: Cardinal); 
  end; 
 
var 
  Form11: TForm11; 
 
implementation 
 
{ TForm11 } 
 
constructor TPipeReadThread.Create(AClbProc: TPipeClbProc; APipeOutput: Cardinal); 
begin 
inherited Create(True); 
fClbProc    := AClbProc; 
fPipeOutput := APipeOutput; 
SetLength(fBuffer,5000); 
FreeOnTerminate := True; 
Resume; 
end; 
 
{===========================================================================} 
 
procedure TPipeReadThread.Execute; 
var LBufSize: Cardinal; 
    LRes: Boolean; 
begin 
LBufSize := Length(fBuffer); 
repeat 
LRes := ReadFile(fPipeOutput,fBuffer[1], LBufSize, fBytesRead, nil); 
Synchronize(fSyncProc);                                                     //87.23 
until not (LRes) or Terminated; 
end; 
 
{===========================================================================} 
 
procedure TPipeReadThread.FSyncProc; 
begin 
fClbProc(Self, fBuffer, fBytesRead); 
end; 
 
{===========================================================================} 
 
procedure TForm11.FClbProc(Sender: TObject; const ABuffer: String; ABufSize: Cardinal);  //100.19 
var LNew : String; 
    LPos : Integer; 
begin 
LNew := copy(ABuffer, 1, ABufSize); 
LPos := pos(#$C, LNew); 
if (LPos > 0) then 
begin 
  Console.Text:=''; 
  LNew := copy(LNew, LPos + 1, Length(LNew)); 
end; 
Console.Text := Console.Text + LNew; 
PostMessage(Console.Handle, WM_VSCROLL, SB_BOTTOM, 0); 
end; 
 
{===========================================================================} 
 
procedure TForm11.FOpenProcess; 
var 
    LStartupInfo : TStartupInfo; 
    LProcessInfo : TProcessInformation; 
    LSecurityAttr: TSECURITYATTRIBUTES; 
    LSecurityDesc: TSecurityDescriptor; 
begin 
    FillChar(LSecurityDesc, SizeOf(LSecurityDesc),0);                      //124.27 
    InitializeSecurityDescription(@LSecurityDesc, SECURITY_DESCRIPTOR_REVISION);  //125.34 
    SetSecurityDescriptorDacl(@LSecurityDesc, True, nil, False); 
 
    LSecurityAttr.nLength := SizeOf(LSecurityAttr); 
    LSecurityAttr.lpSecurityDescriptor:= @LSecurityDesc; 
    LSecurityAttr.bInheritHandle := True; 
 
    fProcess := 0; 
    if CreatePipe(fInputPipeRead, fInputPipeWrite, @LSecurityAttr, 0) then 
    begin 
    if CreatePipe(fOutputPipeRead, fOutputPipeWrite, @LSecurityAttr, 0) then 
    begin 
    FillChar(LStartupInfo, SizeOf(LStartupInfo), 0);                            //137.26 
    FillChar(LStartupInfo, SizeOf(LProcessInfo), 0); 
    LStartupInfo.cb          := SizeOf(LStartupInfo); 
    LStartupInfo.hStdOutput  := fOutputPipeWrite; 
    LStartupInfo.hStdInput   := fInputPipeRead; 
    LStartupInfo.hStdError   := fOutputPipeWrite; 
    LStartupInfo.dwFlags     := STARTF_USESTDHANDLES or STARTF_USESHOWINDOW; 
    LStartupInfo.wShowWindow := SW_HIDE; 
    if CreateProcess(nil, 'cmd', @LSecurityAttr, nil, True, 0, nil, nil LStartupInfo, LProcessInfo) //145.100 
    then begin 
     fProcess := LProcessInfo.hProcess; 
     TPipeReadThread.Create(FClbProc, fOutputPipeRead);    //148.37 
    end else begin 
     CloseHandle(fInputPipeRead); 
     CloseHandle(fInputPipeWrite); 
     CloseHandle(fOutputPipeRead); 
     CloseHandle(fOutputPipeWrite); 
     end; 
    end else begin 
     CloseHandle(fInputPipeRead); 
     CloseHandle(fInputPipeWrite); 
    end; 
  end 
end; 
 
{===========================================================================} 
 
procedure TForm11.FCloseProcess; 
begin 
if (fProcess <> 0) then 
begin 
  CloseHandle(fInputPipeRead); 
  CloseHandle(fInputPipeWrite); 
  CloseHandle(fOutputPipeRead); 
  CloseHandle(fOutputPipeWrite); 
  TerminateProcess(fProcess, 0); 
  fProcess := 0; 
end; 
end; 
 
{===========================================================================} 
 
procedure TForm11.FWriteToStdIn(const AText: String); 
var LPos, 
    LWritten: Cardinal; 
    LRes : Boolean; 
begin 
LPos := 1; 
repeat 
  LWritten := 0; 
  LRes := WriteFile(fInputPipeWrite, AText[LPos], Cardinal(Length(AText)) - LPos + 1, LWritten, nil); 
  inc(LPos,LWritten); 
  until not(LRes) or (LPos > Cardinal(Length(AText))); 
end; 
 
{===========================================================================} 
 
procedure TForm11.FormCreate(Sender: TObject); 
var rgn: HRGN; 
begin 
  fProcess := 0; 
  FOpenProcess; 
  begin 
    rgn := CreateRoundRectRgn(0, 
    0, 
    ClientWidth, 
    ClientHight, 
    40, 
    40); 
    SetWindowRgn(Handle, rgn, True); 
end; 
end; 
 
procedure TForm11.FormClose(Sender: TObject; var CloseAction: TCloseAction); 
begin 
  FCloseProcess; 
end; 
 
procedure TForm11.Button2Click(Sender: TObject); 
begin 
  Form11.close; 
end; 
 
procedure TForm11.Button1Click(Sender: TObject); 
begin 
  FWriteToStdIn(EdCmd.Text + #13#10);                 // 222.22 
  EdCmd.Text := '';                                   // 223.8 
end; 
 
procedure TForm11.(Sender : TObject; var Key: Char);   //226.19 
begin 
if Key = #13 then 
begin 
Key : = #0; 
BtnWriteCmdClick(nil); 
end; 
end; 
 
initialization 
  {$I command.lrs} 
 
end.




Wäre für jede Hilfe dankbar.

Das wirft mir Lazarus aus:
command.pas(55,5) Warning: Constructor should be public
command.pas(87,23) Error: Incompatible type for arg no. 1: Got "untyped", expected ""
Hint: Found declaration: TThread.Synchronize(TThreadMethod)
command.pas(124,27) Hint: Local variable "LSecurityDesc" does not seem to be initialized
command.pas(125,34) Error: Identifier not found "InitializeSecurityDescription"
command.pas(137,26) Hint: Local variable "LStartupInfo" does not seem to be initialized
command.pas(145,100) Hint: Local variable "LProcessInfo" does not seem to be initialized
command.pas(148,37) Error: Wrong number of parameters specified for call to "FClbProc"
command.pas(100,19) Hint: Found declaration: TForm11.FClbProc(TObject,const AnsiString, LongWord)
command.pas(222,22) Error: Identifier not found "EdCmd"
command.pas(223,8) Error: Identifier not found "EdCmd"
command.pas(226,19) Fatal: Syntax error, "identifier" expected but "(" found
Dateianhänge
Untitled-1.jpg

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

Re: Integration der CMD

Beitrag von theo »

In TProcess ist sowas plattformübergreifend gekapselt. Ich würd's mal damit versuchen.
http://wiki.lazarus.freepascal.org/Exec ... rograms/de" onclick="window.open(this.href);return false;

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Integration der CMD

Beitrag von Socke »

House hat geschrieben:Das wirft mir Lazarus aus:
command.pas(55,5) Warning: Constructor should be public
command.pas(87,23) Error: Incompatible type for arg no. 1: Got "untyped", expected ""
Hint: Found declaration: TThread.Synchronize(TThreadMethod)
command.pas(124,27) Hint: Local variable "LSecurityDesc" does not seem to be initialized
command.pas(125,34) Error: Identifier not found "InitializeSecurityDescription"
command.pas(137,26) Hint: Local variable "LStartupInfo" does not seem to be initialized
command.pas(145,100) Hint: Local variable "LProcessInfo" does not seem to be initialized
command.pas(148,37) Error: Wrong number of parameters specified for call to "FClbProc"
command.pas(100,19) Hint: Found declaration: TForm11.FClbProc(TObject,const AnsiString, LongWord)
command.pas(222,22) Error: Identifier not found "EdCmd"
command.pas(223,8) Error: Identifier not found "EdCmd"
command.pas(226,19) Fatal: Syntax error, "identifier" expected but "(" found
Hallo erstmal,
theo hat natürlich Recht. Mit TProcess sollte das ganze einfacher gehen.
Zu den Fehlermeldungen:
Da du von Delphi kommst, solltest du mit allen Fehlermeldungen außer evtl. "command.pas(87,23) Error: Incompatible type for arg no. [...]" selbst klarkommen. Der FPC unterstützt meherere (Object-)Pascal-Dialekte. In der Modus {$mode objfpc} bietet Objektorienterte Programmierung (so wie Delphi) aber in einer etwas restrektivereren Syntax. Bsp. muss wenn eine Prozedur-/Funktionsadresse irgendwo gespeichert oder übergeben werden soll auch die Adresse angegeben werden. Wenn du den Prozedurnamen angibst, wird der FPC immer versuchen die Prozedur aufzurufen. Wenn du die Adresse übergeben willst, musst du auch explizit die Adresse angeben:
Synchronize(@fSyncProc); .
Die Restlichen Fehler/Hinweise sollten mit Erfahrung in Delphi locker allein zu lösen sein.

MfG Socke
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

House
Beiträge: 19
Registriert: Fr 24. Okt 2008, 12:54

Re: Integration der CMD

Beitrag von House »

Danke erstmal für den Hinweis mit dem @. Und auch für den Hinweis mit dem TProcess.

Ihr meint wahrscheinlich das, was man bei Lazarus im Reiter "System" findet, oder? Doch welchen soll ich da nehmen?
TASyncProcess oder TProcess oder TProcessUTF8 ? Bzw. wo liegt der Unterschied?
Bei beidem kriege ich im Objektinspektor die Eintragsmöglichkeit einer Applikation. In meinem Fall "cmd.exe"

Doch kriege ich dann einen Fehler:
Failed To Execute cmd.exe : 2
Objektinspektor:
Active : False -> True --> Fehler!!
ApplicationName : cmd.exe
CommandLine : cmd.exe
ConsoleTitle : Kommandkonsole
CurrentDirectory :
Desktop :
Environment :
..
..
StartupOptions :
Priority :
Running : False
..
..

Habt ihr zufällig ein Beispiel hierfür?

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Integration der CMD

Beitrag von Christian »

schau mal in der Lazarus wiki unter "executing external processes"
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Integration der CMD

Beitrag von Socke »

@House:
Ich hab doch tatsächlich mal deinen Screenshot angesehen. Willst du sowas wie ein alternatives Frontend für die cmd.exe erstellen? Das wäre auf jeden Fall eine interessante Sache. Aber ein paar Sachen ließen sich dann schon schöner nur mit Pascal und ohne die cmd.exe bewerkstelligen (dann wär man aber ganz schnell bei seinem eigenen Kommandozeileninterpreter :D ).

MfG Socke
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

House
Beiträge: 19
Registriert: Fr 24. Okt 2008, 12:54

Re: Integration der CMD

Beitrag von House »

Danke nochmal. Mittlerweile konnte ich den Code dank des Hinweises mit dem @ für Lazarus umschreiben. Sprich: Es funktioniert jetzt.

@Socke:
Was meinst du jetzt mit alternativem Frontend?
Ich habe jetzt einfach die CMD in mein eigentliches Programm integriert und die Form von dem Screen kann über einen Button in meinem Programm geöffnet werden. Dann kann der Benutzer über das Editfeld Befehle schreiben und dann (per Enter oder dem Button "Ausführen") wird dann dafür gesorgt, dass die CMD mit den Befehlen umgeht. Und alles wird in einem Memo angezeigt.

Übrigens:
der Code ist nicht von mir, sondern von einem Forum, in dem ich (noch als Delphianwender) unterwegs war/bin. Es handelt sich um das Delphi-PRAXIS Forum. Ich habe jetzt wie gesagt nur den Code umgeschrieben.

creed steiger
Beiträge: 958
Registriert: Mo 11. Sep 2006, 22:56

Re: Integration der CMD

Beitrag von creed steiger »

Schau dir das mal an

https://lazarus-ccr.svn.sourceforge.net ... s/process/" onclick="window.open(this.href);return false;

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Integration der CMD

Beitrag von Socke »

House hat geschrieben:@Socke:
Was meinst du jetzt mit alternativem Frontend?
Ich habe jetzt einfach die CMD in mein eigentliches Programm integriert und die Form von dem Screen kann über einen Button in meinem Programm geöffnet werden. Dann kann der Benutzer über das Editfeld Befehle schreiben und dann (per Enter oder dem Button "Ausführen") wird dann dafür gesorgt, dass die CMD mit den Befehlen umgeht. Und alles wird in einem Memo angezeigt.
Genau das meinte ich: man hat nicht mehr das Standard-Fenster der Eingabeaufforderung sondern ein eigenes.

Mit TProcess hast du den Vorteil platformunabhängig zu sein; d.h. du könntest (theoretisch) auch die bash oder ein andere beliebige shell unter Linux (oder wo anders) anstelle der cmd.exe verwenden (ob das funktioniert kann ich nicht sagen, da ich mich damit nicht beschäftigt habe).

MfG Socke
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

monta
Lazarusforum e. V.
Beiträge: 2809
Registriert: Sa 9. Sep 2006, 18:05
OS, Lazarus, FPC: Linux (L trunk FPC trunk)
CPU-Target: 64Bit
Wohnort: Dresden
Kontaktdaten:

Re: Integration der CMD

Beitrag von monta »

eventuell ist da auch folgende Komponente für interessant:
http://wiki.lazarus.freepascal.org/CmdLine" onclick="window.open(this.href);return false;
Johannes

Antworten