Autor Beitrag
UweK
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 11
Delphi Enterprise XE6
BeitragVerfasst: Di 13.01.26 17:56 
Hallo allerseits,

Ich habe eine Frage zu einem Problem mit DDE. Ich weiß, dass das Verfahren veraltet ist, aber ich möchte ein ansonsten gutes altes Programm an dieser einen Problemstelle mit möglichst wenig Aufwand verbessern. Bitte schickt mir darum keine Vorschläge zu anderen Methoden der Kommunikation.

Mein Client verbindet sich mit dem Server so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
with MainDDEClientConv do

{Aktion nur ausführen, wenn das betreffende Serverprogramm läuft. Sonst käme Fehlermeldungsfenster: "D:\Verzeichnis\ControlDDEServerConv": File not found", das ich von Hand wegklicken muss.}
  if ProcessExists('MyControlProgram.exe'then
  begin
    SetLink('MyControlProgram''ControlDDEServerConv');
    OpenLink
    PokeDataLines('ControlDDEServerItem', TempStringList); // TempStringList: TStringList ist irgend ein Text
    CloseLink;
  end{if ProcessExists(}


Das funktioniert fast immer, außer wenn der Server gerade durch eine aufwendige Operation beschäftigt ist, z.B. eine 30 Sekunden lange Berechnung. Dieser seltene, aber mögliche Fall ist mein Problem. Denn wenn der Server beschäftigt ist, und dann offensichtlich nicht auf die Anfrage des Client sofort reagieren kann, erhalte ich vom Client genau dasselbe Fehlermeldungsfenster wie oben "File not found", obwohl der Prozess natürlich auch jetzt noch in Windows zu sehen ist.

Ich habe es mit einer Exception-Behandlung versucht:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
with MainDDEClientConv do

{Aktion nur ausführen, wenn das betreffende Serverprogramm läuft. Sonst käme Fehlermeldungsfenster: "D:\Verzeichnis\ControlDDEServerConv": File not found", das ich von Hand wegklicken muss.}
  if ProcessExists('MyControlProgram.exe'then
  begin
    try
      SetLink('MyControlProgram''ControlDDEServerConv');
      OpenLink
      PokeDataLines('ControlDDEServerItem', TempStringList); // TempStringList: TStringList ist irgend ein Text
      CloseLink;
    except
      on E: Exception do
// Nichts tun. Der Timer im Client wird diese Anfrage in ein paar Sekunden einfach wiederholen.
    end;
  end{if ProcessExists(}


Diese Exception-Behandlung bringt aber nichts. In der Delphi-Hilfe habe ich auch keinen Hinweis gefunden, ob diese DDE-Funktionen überhaupt Exceptions auslösen.

Mein Problem ist eigentlich nur das Fehlermeldungsfenster, denn das muss ich erst von Hand wegklicken, bevor der Client weitermacht und dann in ein paar Sekunden die Anfrage wiederholt. Ich bräuchte also vermutlich nichts weiter ändern, wenn ich eine Möglichkeit finde, dieses Fehlermeldungsfenster automatisch verschwinden, oder gar nicht erst entstehen zu lassen.

Über Tipps würde ich mich sehr freuen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19337
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 13.01.26 18:35 
Dein größtes Problem ist, dass du den Rückgabewert von OpenLink komplett ignorierst. Dadurch bekommst du gar nicht mit, wenn dieses aus den genannten Gründen fehlschlägt.

Die Dialoge kannst du mit aktuellen Delphiversionen wohl nicht direkt unterdrücken. Du kannst aber versuchen, ob du WM_DDE_ACK in der WndProc abfangen kannst. Aber ich bin nicht sicher, ob das bei dem Fehlerdialog kommt. Oder du setzt Hook auf WH_CALLWNDPROC und fängst dort WM_INITDIALOG ab. Dann kannst du dort prüfen, ob das ein solcher Fehlerdialog ist. Den Hook brauchst du, weil die Nachricht nicht an deine Anwendung geht, sondern an den fremden Dialog.

Leider wirst du bei DDE nicht um solche Workarounds herumkommen.

Die eigentliche Frage ist aber, warum dein Hauptthread so lange blockiert ist. Lange laufende Aufgaben gehören in Threads...
UweK Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 11
Delphi Enterprise XE6
BeitragVerfasst: Fr 16.01.26 17:58 
Mit dem Thread hast du recht, aber das vorliegende Programm ist nun einmal so, und ich kann es nicht komplett umschreiben.

Der Rückgabewert von OpenLink hilft nichts:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
with MainDDEClientConv do

{Aktion nur ausführen, wenn das betreffende Serverprogramm läuft. Sonst käme Fehlermeldungsfenster: "D:\Verzeichnis\ControlDDEServerConv": File not found", das ich von Hand wegklicken muss.}
  if ProcessExists('MyControlProgram.exe'then
  begin
    try
      SetLink('MyControlProgram''ControlDDEServerConv');
      if OpenLink then
      begin
        PokeDataLines('ControlDDEServerItem', TempStringList); // TempStringList: TStringList ist irgend ein Text
        CloseLink;
      end;
    except
      on E: Exception do
// Nichts tun. Der Timer im Client wird diese Anfrage in ein paar Sekunden einfach wiederholen.
    end;
  end{if ProcessExists(}


Er ist immer true, egal ob die Fehlermeldung kommt oder nicht. Ich habe versucht, die Fehlerstelle mit den drei ShowMessage genau zu lokalisieren:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
with MainDDEClientConv do

{Aktion nur ausführen, wenn das betreffende Serverprogramm läuft. Sonst käme Fehlermeldungsfenster: "D:\Verzeichnis\ControlDDEServerConv": File not found", das ich von Hand wegklicken muss.}
  if ProcessExists('MyControlProgram.exe'then
  begin
    try
      SetLink('MyControlProgram''ControlDDEServerConv');
      ShowMessage('Pos1');
      if OpenLink then
      begin
        ShowMessage('Pos2');
        PokeDataLines('ControlDDEServerItem', TempStringList); // TempStringList: TStringList ist irgend ein Text
        CloseLink;
      end;
    except
      on E: Exception do
        ShowMessage('Pos3');
// Nichts tun. Der Timer im Client wird diese Anfrage in ein paar Sekunden einfach wiederholen.
    end;
  end{if ProcessExists(}


Pos 1 wird erreicht. Quittiere ich dieses Meldungsfenster, erscheint nach rund 1 Sekunde Verzögerung die zu Beginn genannte Fehlermeldung "File not found", und sofort darüber Pos2. Pos 3 wird nie erreicht. Das heißt, das Fehlermeldungsfenster "File not found" kommt gar nicht hier beim Abschicken, sondern vom Server, wenn dieser gerade bechäftigt ist. Was ja einetlich gar nicht möglich sein sollte, denn er ist ja beschäftigt und kann auf die Anfrage gar nicht reagieren.

Die Ursache habe ich nun gefunden: Wenn der Server beschäftigt ist, wird vom Client aus durch OpenLink automatisch eine NEUE Instanz des Servers gestartet. Die ist natürlich noch nicht vorbereitet, und antwortet wohl darum mit einer unpassenden Fehlermeldung. Sie erscheint als Miniaturfenster, so dass ich sie bisher nicht bemerkte. Leider habe ich da keine Möglichkeit gefunden, dieses Öffnen der neuen Instanz zu verhindern. TDDEClientConv.ConnectMode kann ich zwar auf ddeAutomatic oder ddeManual setzen. Aber das entscheidet nur, ob bei Nichtvorhandensein des Servers dieser schon durch SetLink zwangsweise gestartet wird, oder erst durch OpenLink. Den momentan nicht antwortenden Server muss der Client dann wohl für nicht vorhanden halten, und nach dem oben bebachteten Timeout von 1 Sekunde starten.

Als Lösung fällt mir jetzt höchstens noch ein, den Server so einzurichten, dass er nur einmal laufen kann und den Start weiterer Instanzen von sich verhindert. Hast du dazu einen Tipp?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19337
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 17.01.26 08:09 
Dann macht das ganze auch mehr Sinn, ja. Dann liegt das nur daran, dass DDE nicht weiß, dass der Server schon läuft, wenn er nicht reagiert. Da sollte deine Lösung reichen, dass der Server nur einmal laufen kann.

Um den Mehrfachstart zu verhindern, nutze ich meistens einen Mutex (CreateMutex). Dazu findest du hier im Forum viele Beispiele wie dieses: Programm nur einmal starten

Moderiert von user profile iconTh69: URL-Titel hinzugefügt.

Für diesen Beitrag haben gedankt: UweK
UweK Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56
Erhaltene Danke: 1

Win 11
Delphi Enterprise XE6
BeitragVerfasst: Mo 26.01.26 11:24 
Danke, das war die Lösung.