Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Mit Delphi ein anderes Delphiprogramm ansprechen (https://www.delphipraxis.net/178594-mit-delphi-ein-anderes-delphiprogramm-ansprechen.html)

Back2Code 16. Jan 2014 13:50

Delphi-Version: 2010

Mit Delphi ein anderes Delphiprogramm ansprechen
 
Hallo ich habe bereits ein Programm geschrieben als Konsolenanwendung welches mit Parametern arbeitet. Nun würde ich gerne noch eine Oberfläche dazu programmieren.

Damit ich mir Arbeit & Zeit spare habe ich mir gedacht, dass es doch sicher eine Möglichkeit gibt mein bereits bestehendes Programm einfach mit meinem neuen Programm aufrufen könnte und die Parameter übergeben würde.

Meine Frage ist jetzt wie genau ich so etwas anstelle und ob es auch möglich ist z.b Fehlermeldungen also allgemein Ausgaben aus dem Konsolenprogramm welches dann im Hintergrund laufen soll auszulesen und in der GUI wiederzugeben.

MyRealName 16. Jan 2014 13:53

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
ShellExecute kann Programme aufrufen. Da kannst auch Parameter mit übergeben. Die können über ParamStr(x) gelesen werden
Mit Returncodes kannst Du auch fehler an den Aufrufer melden.
Zum bsp mit der Procedure Halt in Delphi, die akzeptiert eine Numemr als Parameter und die kannst in einer batch datei oder in Delphi abfangen.

Zacherl 16. Jan 2014 13:58

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Das ist sogar nicht auf Fehlercodes beschränkt. Du kannst den kompletten Inhalt des Konsolenprogramms über Pipes auslesen:
http://stackoverflow.com/questions/2...ui-application

Back2Code 16. Jan 2014 13:59

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Zitat:

Zitat von MyRealName (Beitrag 1243971)
ShellExecute kann Programme aufrufen. Da kannst auch Parameter mit übergeben. Die können über ParamStr(x) gelesen werden
Mit Returncodes kannst Du auch fehler an den Aufrufer melden.
Zum bsp mit der Procedure Halt in Delphi, die akzeptiert eine Numemr als Parameter und die kannst in einer batch datei oder in Delphi abfangen.

Bei ShellExecute kann ich doch auch das entsprechende Programm irgendwie Hidden also versteckt nicht sichtbar ausführen oder? Wie lautet da der genaue Paramter zu :)?

DeddyH 16. Jan 2014 14:02

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx
Zitat:

nShowCmd [in]

Type: INT

The flags that specify how an application is to be displayed when it is opened. If lpFile specifies a document file, the flag is simply passed to the associated application. It is up to the application to decide how to handle it. These values are defined in Winuser.h.

SW_HIDE (0)

Hides the window and activates another window.

...

himitsu 16. Jan 2014 14:03

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Und ansonsten noch alles, was mit IPC zu tun hat.
Messages, Pipes, Sockets, MMFs ........

Die bisher genannten Dinge, sind aber Möglichkeiten, die praktisch jedes Programm von Haus aus bietet, über die bekannten Standardwege.
Alles Andere wird praktisch speziell "zusätzlich" in beide Programme eingebaut, damit diese sich direkt unterhalten können.

Der schöne Günther 16. Jan 2014 14:03

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Hätte ich spontan auch gesagt, wenn auch keinen Code zur Hand: Ich hätte deinen "Kindprozess" mittels CreateProcess gestartet und somit gleich die stdOut-Handles auf eine Pipe, welche deine Elternanwendung aufmacht, umgebogen.

Das hier auf SO scheint exakt in diese Richtung zu gehen:
http://stackoverflow.com/q/2957490/2298252

Back2Code 16. Jan 2014 14:35

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1243976)
Hätte ich spontan auch gesagt, wenn auch keinen Code zur Hand: Ich hätte deinen "Kindprozess" mittels CreateProcess gestartet und somit gleich die stdOut-Handles auf eine Pipe, welche deine Elternanwendung aufmacht, umgebogen.

Das hier auf SO scheint exakt in diese Richtung zu gehen:
http://stackoverflow.com/q/2957490/2298252

Gibts hier im Board bzw im Netz eine gute Erklärung zu den Begriffen "Pipe & stdOut? Höre ich jetzt zum ersten Mal :oops:

sx2008 16. Jan 2014 14:45

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Wenn du dein Konsolenprogramm in zwei Teile splitten würdest könnst du den Teil der die eigentliche Arbeit verrichtet auch in der Anwendung mit der GUI einbinden.
Das ist einfacher und sicherer als von der GUI-Anwendung auf die Konsolenanwendung zuzugreifen.
Dazu benötigst du eine Klasse in einer eigenen Unit die von beiden Programmen mit
Delphi-Quellcode:
uses
eingebunden wird.
Dieser Klasse wird über Properties alle Informationen eingespeist und dann eine "DoWork"-Methode aufgerufen.
Falls während dieser Arbeit eine Rückmeldung erforderlich sein sollte, dann lässt sich dies über ein Event bewerkstelligen.
Man braucht dann in der Konsolenanwendung noch eine weitere Klasse die das Event empfängt und die Info per
Delphi-Quellcode:
writeln
an die Konsole ausgibt, aber das ist halb so schlimm wie es sich anhört.

himitsu 16. Jan 2014 15:05

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Stell dir eine Pipe wie einen TFileStream vor ... allerdings nur im Lesemous, bzw nur im Schreibmodus und ohne Seek und Co. , also nur Read ORDER Write.
(drum kann man die Ein und Ausgaben auch so schön auf Dateien umleiten, wie man es z.B. aus den BAT-Dateien mit dem ">" kennt)

Es gibt bei Konsolenanwendungen 3 dieser Pipes:
StdIn > der Stream für die Eingabe von der Tastatur
StdOut > der Stream für die Ausgabe zum Monitor (also in die Konsole)
ErrOut > der Strream geht auch auf den Monirot und gibt quasi die Fehlermeldungen aus (oder irgendwie sowas)

DeddyH 16. Jan 2014 15:07

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
http://de.wikipedia.org/wiki/Standard-Datenstr%C3%B6me
ErrOut = stderr ;)

Der schöne Günther 16. Jan 2014 15:08

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Zitat:

Zitat von Back2Code (Beitrag 1243985)
Gibts hier im Board bzw im Netz eine gute Erklärung zu den Begriffen "Pipe & stdOut? Höre ich jetzt zum ersten Mal :oops:

Das MSDN-Tutorial hier ist eigentlich genau das, was wir wollen. Ich habe es in Kürze einmal versucht, nachzubauen, hat auch halbwegs funktioniert. In meiner VCL-Memo konnte ich sehen, was der (unsichtbare) Kindprozess einfach mittels WriteLn() rausgeworfen hat. Das hat auf die Schnelle auch geklappt, nur müsste ich noch eine Lösung finden, nicht bis in alle Unendlichkeit zu warten, bis jemand etwas in die Pipe schreibt.

Ich werfe es hier einfach mal hinein:

Delphi-Quellcode:
unit Unit13;

interface

uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
   System.Classes, Vcl.Graphics,
   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
   TMainForm = class(TForm)
      gridpanel: TGridPanel;
      startButton: TButton;
      stopButton: TButton;
      stdOutMemo: TMemo;
      Timer1: TTimer;

      procedure Timer1Timer(Sender: TObject);
      procedure startButtonClick(Sender: TObject);
      procedure stopButtonClick(Sender: TObject);

      private const
         // relativer Pfad ausgehend vom Arbeitsverzeichnis
         childProcessApplicationName: String = '.\..\ChildProcess\Win32\Debug\ChildProcessProject.exe';


      private var
         myProcess: TProcessorNumber;

         readHandle: THandle;
         writeHandle: THandle;

      private
         procedure startProcess();
         procedure stopProcess();

         procedure tryStartProcess();
         procedure tryStopProcess();

         procedure createMeAPipe(
            var readHandle: THandle;
            var writeHandle: THandle
         );

         /// <exception cref="EFileNotFoundException" />
         procedure checkChildPossible();

         procedure tryReadFromPipe();
         function isValidReadHandle(): Boolean;

   end;

var
   MainForm: TMainForm;

implementation

{$R *.dfm}

{ TMainForm }

procedure TMainForm.startButtonClick(Sender: TObject);
begin
   startProcess();
end;

procedure TMainForm.startProcess();
begin
   startButton.Enabled := False;
   try
      tryStartProcess();
      stopButton.Enabled := True;
   except
      startButton.Enabled := True; raise;
    end;
end;

procedure TMainForm.stopButtonClick(Sender: TObject);
begin
   stopProcess();
end;

procedure TMainForm.stopProcess();
begin
   stopButton.Enabled := False;
   try
      tryStopProcess();
      startButton.Enabled := True;
   except
      stopButton.Enabled := True; raise;
   end;


end;

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
   if isValidReadHandle() then
      tryReadFromPipe();
end;

procedure TMainForm.tryReadFromPipe();
const
   readBufferLength = 2400;
var
   buffer: Array[0..readBufferLength] of AnsiChar;
   bytesRead: DWORD;
begin

   ReadFile(readHandle, buffer, readBufferLength, bytesRead, nil);
   buffer[bytesRead] := #0;

   stdOutMemo.Lines.Append(buffer);

end;

function TMainForm.isValidReadHandle(): Boolean;
begin
   Result :=
      not (readHandle = 0)
   and
      not (readHandle = INVALID_HANDLE_VALUE)
   ;

end;

procedure TMainForm.tryStartProcess();
var
   startInfo: TStartupInfo;
   processInfo: TProcessInformation;

   errorCode: Cardinal;
   errorMsg: String;

   dwCreationFlags: DWORD;
   cmdLine: String;

   applicationName: String;
begin

   checkChildPossible();
   createMeAPipe(readHandle, writeHandle);

   startInfo := Default(TStartupInfo);
   startInfo.cb := SizeOf(startInfo);

   startInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
   startInfo.wShowWindow := SW_SHOW;

   // Wegen STARTF_USESTDHANDLES in den dwFlags explizit alle drei Handles setzen
   startInfo.hStdOutput := writeHandle;
   startInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
   startInfo.hStdError := GetStdHandle(STD_ERROR_HANDLE);

   processInfo := Default(TProcessInformation);

   applicationName :=
      GetCurrentDir()+PathDelim+
      childProcessApplicationName;

   if not CreateProcess(
      PWideChar(applicationName),
      nil,
      nil,    // Standard-Sicherheit, Handle wird nicht vererbt
      nil,    // Standard-Sicherheit, Handle wird nicht vererbt
      True,    // Handles (Schreibepipe!) vererben
      0,    // Keine besonderen dwCreationFlags
      nil,
      nil,
      startInfo,
      processInfo
   ) then raise Exception.Create(
      'TMainForm.tryStartProcess: Errorcode '+
      GetLastError().ToString()+
      ' bei CreateProcess'
      )
   ;


end;

procedure TMainForm.checkChildPossible();
begin
   if not FileExists(
      GetCurrentDir()+childProcessApplicationName
   ) then raise EFileNotFoundException.Create(
      'TMainForm.checkChildPossible: '
      +'Datei '
      +childProcessApplicationName.QuotedString()
      +' nicht gefunden. Aktuelles Arbeitsverzeichnis ist '
      +GetCurrentDir().QuotedString()
   );
end;


procedure TMainForm.createMeAPipe(
   var readHandle: THandle;
   var writeHandle: THandle
);
var
   saSecurity: TSecurityAttributes;
begin

   saSecurity.nLength := SizeOf(TSecurityAttributes);
   saSecurity.bInheritHandle := True;
   saSecurity.lpSecurityDescriptor := nil;

   if not CreatePipe(readHandle, writeHandle, @saSecurity, 0) then
      raise Exception.Create('TMainForm.createMeAPipe: Konnte keine Pipe erstellen');


end;

procedure TMainForm.tryStopProcess;
begin
   raise EProgrammerNotFound.Create('derp');
end;

end.

himitsu 16. Jan 2014 15:28

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
Zitat:

Zitat von DeddyH (Beitrag 1243992)

Das hatte ich zuerst und dachte mir dann "nee, sieht komisch aus, machst'e es doch andersrum" :oops:

Klaus01 16. Jan 2014 18:15

AW: Mit Delphi ein anderes Delphiprogramm ansprechen
 
.. hast Du die source-codes von dem consolen Programm nicht.
Wenn ja würde ich eher die zur Hand nehmen und in das GUI-Pogramm einbinden.

Grüße
Klaus


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