Delphi-PRAXiS
Seite 4 von 4   « Erste     234   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi .exe zu .exe Kommunikation (https://www.delphipraxis.net/196064-exe-zu-exe-kommunikation.html)

Codehunter 14. Sep 2018 11:25

AW: .exe zu .exe Kommunikation
 
Ich greife diesen Thread mal auf, weil mein Anliegen thematisch hier sehr gut rein passt. Folgendes Problem bei mir:

1. Es soll zwei Programme geben. Eine Hostanwendung und eine oder mehrere Instanzen einer Client-Anwendung. Beide von mir geschrieben.

2. Die Hostanwendung ist ein Systemdienst, der unter dem SYSTEM-Konto läuft.

3. Die Hostanwendung startet die Client-Anwendung(en) selbst, Art und Weise wie diese Prozesse erzeugt werden, da bin ich flexibel.

4. Die Client-Anwendung beackert externe Programme, die wiederum NICHT von mir sind und hin und wieder mal zu Instabilität neigen. Raucht so ein Programm unerwartet ab, bleibt meine Client-Anwendung u.U. in einem undefinierten Zustand stehen. Deshalb sollen die Client-Anwendungen eine (konfigurierbare) Lifetime haben. Innerhalb derer müssen sie sich sauber beenden (wird in Datenbank geloggt). Tun sie das nicht, sollen sie zuerst vom Host per IPC eine Anweisung zum Shutdown bekommen (wird seitens Hostanwendung ebenfalls geloggt). Reagieren sie darauf auch nicht, z.B. per Antwort-Message und Shutdown, soll die Hostanwendung den hängenden Client-Prozess hart terminieren.

Soweit so einfach. Die Kommunikation zwischen meinen beiden Anwendungen ist eher trivial, eine einfache Event-Signalisierung, die keine komplexen Daten übermitteln muss. Schlimmstenfalls ein paar DWords.

Der Kniff an der Sache ist, dass die Client-Instanzen ggf. unter abweichenden Benutzerkonten gestartet werden müssen. Das hat mit den wiederum von den Client-Instanzen genutzten externen Programmen zu tun, die aus Sicherheitsgründen nicht im Systemkonto laufen. Darum scheidet wohl alles aus, das auf Window-Handles basiert. Welche Art IPC würdet ihr empfehlen für dieses Szenario?

Sherlock 14. Sep 2018 12:29

AW: .exe zu .exe Kommunikation
 
TCP/IP über localhost sollte gehen, da die Ports systemweit einmalig sind.

Server Dienst hat einen fixen Port und Clients melden sich dort an und quatschen munter drauf los.

Sherlock

himitsu 14. Sep 2018 12:39

AW: .exe zu .exe Kommunikation
 
Nja, am "Einfachten" und oft gemacht sind TCP/IP-Verbindungen. (dafür gibt es massenhaft ProcedureCall-Frameworks, wenn du nichts selberbauen willst)

Named-Pipes gingen auch, kommen vom Protokol auf das Gleiche.
Oder ohne Name, wenn du irgendwie anders die Handles übergibst.

Memory-Mapped-Files (MMF), aber für's "schicken" von Befehlen nicht so praktisch.
Also nur MMF ist schlecht, da man dann Pollen müsste, oder über andere Wege (Messages/Events/...) über neue Daten informiert.

WindowsMessages gingen, aber da gibt es leider nur die eine WM_COPYDATA, welche auch Texte/Daten übertragen kann (wobei man bei Texten das auch über WM_SETTEXT an ein/mehrere "EDITS" schicken könnte) und dann muß du alles da rein machen, wenn du verschiedene Messages schicken willst, z.B. über ein Byte/Flag am Anfang der Daten.
Und bei den Messages mußt du aufpassen, dass sich die Beiden diese Messages überhaupt schicken dürfen. (kennst z.B. von Anwendung an Admin-Anwendung, wo standardmäßig nicht alles erlaubt ist)
Alternativ zu WM_COPYDATA, die Daten in MMF, GlobalMemory oder Files und das Handle in LPARAM/WPARAM.

mjustin 14. Sep 2018 13:03

AW: .exe zu .exe Kommunikation
 
Hier ist ein Beispiel, in dem ein Indy TCP Server einem Client eine einfache Nachricht sendet. (Artikel Link)

Der Server-Code muss nur in der DoExecute-Methode angepasst werden und dort z.B. das nächste an den Client zu sendende Datenpaket erstellen. Da die Server-Klasse für jede Connection einen eigenen Thread verwendet, gilt der Code in der DoExecute Methode für die aktuelle Connection. DoExecute wird in einer Schleife ausgeführt bis die Verbindung getrennt wurde oder eine Exception auftritt.

Der Client-Code läuft in einem Thread um im Hintergrund auf neue Nachrichten des Servers zu warten. Der ReadLn Aufruf wartet, bis entweder eine Nachricht eintrifft, oder das Timeout erreicht ist, und wird dann wieder ausgeführt.

Delphi-Quellcode:
unit Unit1;
 
interface
 
uses
  IdCustomTCPServer, IdTCPClient, IdContext,
  SysUtils, Classes, Forms, StdCtrls, Controls;
 
type
  TMyPushClientThread = class(TThread)
  private
    TCPClient: TIdTCPClient;
    FLog: TStrings;
  public
    constructor Create(AHost: string; APort: Word; ALog: TStrings);
    destructor Destroy; override;
    procedure Execute; override;
  end;
 
  TMyPushServer = class (TIdCustomTCPServer)
  protected
    function DoExecute(AContext: TIdContext): Boolean; override;
  end;
 
  TServerPushExampleForm = class(TForm)
    MemoLog: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    ExampleClient: TMyPushClientThread;
    ExampleServer: TMyPushServer;
  end;
 
var
  ServerPushExampleForm: TServerPushExampleForm;
 
implementation
 
uses
  IdGlobal;
 
{$R *.dfm}
 
procedure TServerPushExampleForm.FormCreate(Sender: TObject);
begin
  ExampleServer := TMyPushServer.Create;
  ExampleServer.DefaultPort := 8088;
  ExampleServer.Active := True;
 
  ExampleClient := TMyPushClientThread.Create('localhost', 8088, MemoLog.Lines);
end;
 
procedure TServerPushExampleForm.FormDestroy(Sender: TObject);
begin
  ExampleServer.Free;
  ExampleClient.Terminate;
  ExampleClient.WaitFor;
  ExampleClient.Free;
end;
 
{ TMyPushServer }
 
function TMyPushServer.DoExecute(AContext: TIdContext): Boolean;
begin
  Result := inherited;
 
  // simulate hard work
  Sleep(Random(3000));
 
  AContext.Connection.IOHandler.WriteLn(
    'Completed at ' + TimeToStr(Now), IndyTextEncoding_UTF8);
end;
 
{ TMyPushClientThread }
 
constructor TMyPushClientThread.Create(AHost: string; APort: Word; ALog: TStrings);
begin
  inherited Create(False);
 
  FLog := ALog;
 
  TCPClient := TIdTCPClient.Create;
  TCPClient.Host := AHost;
  TCPClient.Port := APort;
  TCPClient.ReadTimeout := 500;
end;
 
destructor TMyPushClientThread.Destroy;
begin
  TCPClient.Free;
  inherited;
end;
 
procedure TMyPushClientThread.Execute;
var
  S: string;
begin
  TCPClient.Connect;
 
  while not Terminated do
  begin
    S := TCPClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
 
    if not TCPClient.IOHandler.ReadLnTimedout then
    begin
      TThread.Queue(nil,
        procedure
        begin
          FLog.Append(S);
        end);
    end;
 
  end;
 
  TCPClient.Disconnect;
end;
 
end.

Jumpy 14. Sep 2018 13:05

AW: .exe zu .exe Kommunikation
 
Mich würde auch mal interessieren, wie du Punkt 3 realisieren willst, wenn die unter einem anderen User laufen sollen. Wie macht man sowas?

Codehunter 14. Sep 2018 13:11

AW: .exe zu .exe Kommunikation
 
Zitat:

Zitat von Jumpy (Beitrag 1413186)
Mich würde auch mal interessieren, wie du Punkt 3 realisieren willst, wenn die unter einem anderen User laufen sollen. Wie macht man sowas?

CreateProcessWithLogonW

mschaefer 14. Sep 2018 16:19

AW: .exe zu .exe Kommunikation
 
Hier findet sich die Variante mit
Messages.

Assarbad 16. Okt 2018 14:28

AW: .exe zu .exe Kommunikation
 
Zitat:

Zitat von CCRDude (Beitrag 1399949)
WM_COPYDATA kommt spätestens an seine Grenzen, wenn ein Prozess elevated ist und der andere nicht (was logischerweise auch der Fall ist bei Kommunikation mit einem Systemdienst).

Hier kann MSDN-Library durchsuchenChangeWindowMessageFilterEx Abhilfe schaffen, sofern sich die Fenster auf dem gleichen Desktop (oder war's die gleiche WindowStation?) aufhalten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:55 Uhr.
Seite 4 von 4   « Erste     234   

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