Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Nachrichtenschleife bauen? (https://www.delphipraxis.net/170887-nachrichtenschleife-bauen.html)

geskill 8. Okt 2012 17:24

Nachrichtenschleife bauen?
 
Hallo,
ich hab mich schon ein bisschen durch das Forum gewühlt auf der Suche wie man eine Nachrichtenschleife baut und diese selbst abarbeitet ohne zu großen Aufwand zu treiben.

Zum Ausgangsproblem. Ich habe mehrere Komponenten (Edits, Comboboxen etc.) diese habe ich in einem Interface gebündelt und man kann auf dessen aktuellen Wert zugreifen. Das ganze soll aber aus dem Hauptthread passieren und aus N verschiedenen anderen Threads.
Ich hatte das bis jetzt per SendMessage() gemacht, was soweit geklappt hat, aber irgendwann kam es dann zu Problemen wenn mehrere Threads darauf zugreifen.

Hier mal der Codeausschnitt:
Delphi-Quellcode:
procedure TIBasic.WndProc(var Msg: TMessage);
begin
  if Msg.Msg = WM_CONTROL_VALUE_CHANGE then
  begin
    SetControlValue(WideString(Msg.WParam));
  end
  else
    Msg.Result := DefWindowProc(FHandle, Msg.Msg, Msg.WParam, Msg.LParam);
end;

constructor TIBasic.Create;
begin
  FHandle := AllocateHWnd(WndProc);

  // [...]
end;

function TIBasic.GetValue;
begin
  FValueLock.BeginRead;
  try
    Result := FValue;
  finally
    FValueLock.EndRead;
  end;
end;

procedure TIBasic.SetValue(AValue: WideString);
begin
  // SendMessage würde hier funktionieren
  PostMessage(FHandle, WM_CONTROL_VALUE_CHANGE, Integer(AValue), 0);
end;

procedure TIBasic.ControlOnChange(Sender: TObject);
begin
  FValueLock.BeginWrite;
  try
    FValue := GetControlValue;
  finally
    FValueLock.EndWrite;
  end;

  // [...]
end;

function TIBasic.GetControlValue;
begin
  Result := FEdit.Text;
end;

procedure TIBasic.SetControlValue(AValue: WideString);
begin
  FEdit.Text := AValue;
end;
Man soll (so ist es jedenfalls gedacht) per Get/SetValue auf den Wert der Komponente zugreifen können. Dazu wird für jede Komponente bei der Erstellung ein virtuelles Fenster erzeugt. Wenn sich der Wert verändert, wird über das OnChange Event der aktuelle Wert in ein string (hier: FValue) geschrieben (durch MREW gesichert). Beim lesen über GetValue wird also nicht direkt von der VCL Komponente gelesen sondern von der FValue, was an sich ja ThreadSafe ist. Wenn jetzt jemand diesen Wert außerhalb des Eingabefeldes ändern möchte sollte dies über SetValue("Blub"); geschehen, aber das läuft noch gar nicht rund.
Da bekomme ich dann Teilweise ganz andere (von anderen Nachrichten) Werte in diese Felder, also irgendwie muss da noch was drum herum gebaut werden damit das läuft, aber da hakt es :/

Grüße

DeddyH 8. Okt 2012 17:49

AW: Nachrichtenschleife bauen?
 
Ich bin nicht sicher, ob ich Dein Vorhaben richtig verstanden habe, aber das scheint eine Art DataBinding werden zu sollen, richtig? In dem Fall solltest Du Dir vielleicht Stevies DSharp einmal ansehen, dann musst Du das Rad nicht selbst neu erfinden.

Bummi 8. Okt 2012 17:51

AW: Nachrichtenschleife bauen?
 
bei
Delphi-Quellcode:
PostMessage(FHandle, WM_CONTROL_VALUE_CHANGE, Integer(AValue), 0);
ist der Zeiger auf AValue als Stackwert ungültig bis die Message abgearbeitet wird,da SetValue bereits wieder verlassen wurde.

himitsu 8. Okt 2012 18:02

AW: Nachrichtenschleife bauen?
 
Zitat:

Zitat von Bummi (Beitrag 1186255)
bei
Delphi-Quellcode:
PostMessage(FHandle, WM_CONTROL_VALUE_CHANGE, Integer(AValue), 0);
ist der Zeiger auf AValue als Stackwert ungültig bis die Message abgearbeitet wird, da SetValue bereits wieder verlassen wurde.

Das wollte ich auch grade sagen :cry:

Dann noch das Gecaste mit dem bösen Integer.
Nimm stattdessen den Typ LPARAM, bzw. WPARAM, LRESULT oder eben NativeInt und Co.

Statt SendMessage kannst du auch Perform nutzen.
Delphi-Quellcode:
SendMessage(FHandle, WM_CONTROL_VALUE_CHANGE, LPARAM(AValue), 0);

Perform(WM_CONTROL_VALUE_CHANGE, LPARAM(AValue), 0);

geskill 8. Okt 2012 18:16

AW: Nachrichtenschleife bauen?
 
@DeddyH
Ja das hatte ich letztens schonmal gesehen. Hört sich sehr interessant an.

@Bummi
:thumb: Das muss man natürlich erstmal verinnerlichen. Wenn ich danach nun ein Application.ProcessMessages; funktioniert es. Aber ich glaube wenn das ein Thread aufruft ist das nicht so gut. Ich weiß gerade auch nicht so genau.

@himitsu
Okay habe den Integer verbannt und WPARAM Einzug halten lassen (aber das wäre ja sowieso nur für x64 interessant)

Auf Perform kann ich ja gar nicht zugreifen (ist ja kein TControl).
Delphi-Quellcode:
  TIBasic = class(TInterfacedObject, IBasic)
  protected
    FEdit: TcxTextEdit;

Bummi 8. Okt 2012 18:21

AW: Nachrichtenschleife bauen?
 
Warum nicht so?
Delphi-Quellcode:

procedure TIBasic.SetValue(AValue: WideString);
begin
  FValue:=AValue;
  PostMessage(FHandle, WM_CONTROL_VALUE_CHANGE, 0, 0);
end;


if Msg.Msg = WM_CONTROL_VALUE_CHANGE then
  begin
    SetControlValue(FValue);

himitsu 8. Okt 2012 18:33

AW: Nachrichtenschleife bauen?
 
Zitat:

Zitat von Bummi (Beitrag 1186265)
Warum nicht so?

Rufe jetzt mehrmals hintereinander diese Methode auf.
Das macht viel Sßaß, wenn zwischenzeitlich keine Messages verarbeitet wurden (es gehen informationen verloren).
Und wenn man das jetzt auch noch per multithread macht, dann geht voll die Post ab. :roll:

Zitat:

Wenn ich danach nun ein Application.ProcessMessages; funktioniert es. Aber ich glaube wenn das ein Thread aufruft ist das nicht so gut. Ich weiß gerade auch nicht so genau.
Was mag da wohl passieren?
PostMessage schreibt das in die MessageQueue und ProcessMessages arbeitet diese Queue ab.
Natürlich wird das dann rechtzeitig abgarbeitet, bevor der Zeiger ungültig wird ... es werden allerdings alle Messages in der Queue verarbeitet. (und im Thread geht das eh nicht)

Was macht denn nun SendMessage?
Es schickt auch diese Nachricht los, aber dieses wird quasi sofort verarbeitet, bevor dieser Aufruf zurückkehrt. Und es wird NUR diese Nachricht verarbeitet und sonst nix (außer der MessageHandler ruft in sich ein ProcessMessages auf)

geskill 8. Okt 2012 18:57

AW: Nachrichtenschleife bauen?
 
SendMessage() ist aber auch blockierend.

SetValue() müsste dann nur den Wert in einer Liste (Schlange) speichern bis er in WndProc() abgearbeitet wurde. Dort wird der dann entfernt. So gehen keine Daten verloren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:37 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz