AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Object mit SendMessage an MainThread senden

Ein Thema von Captnemo · begonnen am 26. Jun 2014 · letzter Beitrag vom 27. Jun 2014
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#1

Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 10:16
Delphi-Version: 5
Hi,

ich möchte ein Object aus meinem Thread an den Hauptthread senden.

So hab ich mir das vorgestellt. (TLogMessage ist hier nur ein Beispiel, was ich zum Testen genommen habe).

Verschicken:
Delphi-Quellcode:
var
  LogMsg: TLogMessage;
const
   PM_MsgFromThread = WM_USER +4;

procedure TComThread.SendMsgToMain(LogText: string; Debug: Boolean);
begin
  LogMsg:=TLogMessage.Create;
  LogMsg.sLogText:=LogText;
  LogMsg.bIsDebug:=Debug;
  SendMessage(FMainFormHandle, PM_MsgFromThread, Integer(@LogMsg), 0);
end;
Empfangen im Hauptthread:
Delphi-Quellcode:
procedure Tfrm_main.LogMsgFromThread(var msg: TMessage);
var
  P: TLogMessage;
  fdebug: Boolean;
  fLogText: string;
begin
  P:=Pointer(msg.WParam);
  fdebug:=P.bIsDebug;
  fLogText:=P.sLogText;
  //P.Free; //Ich müßte das Object auch wieder freigeben.
end;
Ich befürchte aber, dass ich es mal komplett falsch mache.
Auf P.bIsDebug kann ich noch zugreifen, und bei P.sLogText knallt es mit einer Zugriffsverletzung.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#2

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 10:38
Integer ist nicht gut, stell dir mal vor man verwendet den Code mal im Win64.
NativeInt, oder für Pointer besser IntPtr, oder im Fall von SendMessage/PostMessage den OriginalTyp LRESULT.
function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

Was mag wohl passieren, wenn mal zwei Threads zugleich diese Variable nutzen wollen?



Objekte sind schon Pointer und lassen sich problemlos in "Integer" konvertieren, aber egal wie, man muß das schon richtig machen.
Delphi-Quellcode:
LPARAM(@LogMsg) => PPointer(msg.LParam)^
LPARAM(LogMsg) => PPointer(msg.LParam) // ohne externe Variable
Also warum ist LogMsg eine globale Variable, und warum gibt es die überhaupt?



Und ja, das müsstest du. (Free)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (26. Jun 2014 um 10:40 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#3

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 11:11
Objekte sind schon Pointer und lassen sich problemlos in "Integer" konvertieren, aber egal wie, man muß das schon richtig machen.
Delphi-Quellcode:
LPARAM(@LogMsg) => PPointer(msg.LParam)^
LPARAM(LogMsg) => PPointer(msg.LParam) // ohne externe Variable
Also warum ist LogMsg eine globale Variable, und warum gibt es die überhaupt?



Und ja, das müsstest du. (Free)
Global, so wie ich es aus dem verstanden habe, was ich gelesen habe, muß sie ja global sein, damit sie im Heap liegt und auch von anderen Threads überhaupt gelesen werden kann, oder ist das jetzt wieder falsch?

Aber ich hab jetzt meinen Fehler gefunden, lag in der Deklaration von P   P: ^TLogMessage; So funktioniert's zwar, aber beim Free hab ich immer noch eine Exception.

Das mit den Int64 macht natürlich Sinn.
Also so: SendMessage(FMainFormHandle, PM_MsgFromThread, Intptr(@LogMsg), 0); ?

Leider hab ich Probleme, deine durchaus sinnvollen und hilfreichen Anmeldungen in meinen oben beschriebenen Code umzusetzen. Weil ich tatsächlich nicht weiß, ob ich das jetzt richtig interpretiert habe. Problematisch ist halt immer, wenn es oft mehrere Möglichkeiten gibt, genau das gleiche zu machen. Und wenn man dann in dem Thema nicht fit ist, dann würfelt man (in dem Fall ich) halt schnell was durcheinander.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von stoxx
stoxx

Registriert seit: 13. Aug 2003
1.111 Beiträge
 
#4

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 12:23
müsste eigenlich sein: (ohne @)

Integer(LogMsg) Weil ein Object ist schon selbst ein Pointer.
Ein TObject auf Integer zu casten hat eigentlich immer funktioniert.
Phantasie ist etwas, was sich manche Leute gar nicht vorstellen können.
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#5

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 12:39
Dann bekomme ich wieder beim zugriff auf sLogText eine Zugriffsverletzung.

Ich hab's jetzt so:

Senden:
Delphi-Quellcode:
procedure TComThread.SendMsgToMain(LogText: string; Debug: Boolean);
begin
  LogMsg:=TLogMessage.Create;
  LogMsg.sLogText:=LogText;
  LogMsg.bIsDebug:=Debug;
  SendMessage(FMainFormHandle, PM_MsgFromThread, Intptr(@LogMsg), 0);
end;
Empfangen:
Delphi-Quellcode:
var
  f: TextFile;
  fname: string;
  P: ^TLogMessage;
  fdebug: Boolean;
  fLogText: string;
begin
  P:=Pointer(msg.WParam);
  fdebug:=P.bIsDebug;
  fLogText:=P.sLogText;
  //TLogMessage(p).free;
end;
Funktioniert auch gut. Aber ich müßte das Object auch mal wieder Freigeben. Aber das Problem ist, ich weißt nicht wirklich wie?
So wie oben? oder p.free?
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.464 Beiträge
 
Delphi 12 Athens
 
#6

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 13:41
Du versendest die Adresse einer lokalen Variablen (@LogMsg) in der die Adresse des Objektes gespeichert ist.

Sinnvoller ist es natürlich die Adresse des Objektes zu versenden.
Delphi-Quellcode:
SendMessage(FMainFormHandle, PM_MsgFromThread, Integer(Pointer(LogMsg)), 0);

{...}
var
  P: TLogMessage;
begin
  P := Pointer(msg.WParam);
  {...}
end;
Vermutlich ist dir nicht klar, das diese Nachricht mit SendMessage noch innerhalb des Absender-Threads ausgeführt wird!
Wenn das Objekt beim Empfänger nur wärend der Verarbeitung der Nachricht benötigt wird, sollte es beim Absender danach wieder freigegeben werden.
Es ist ja nicht sichergestellt, dass der Empfänger die Nachricht auch in jedem Fall erhält.
Delphi-Quellcode:
  LogMsg:=TLogMessage.Create;
  try
    SendMessage(FMainFormHandle, PM_MsgFromThread, Integer(Pointer(LogMsg)), 0);
  finally
    LogMsg.Free;
  end;
Im Gegensatz dazu wird die Nachricht mit Postmessage erst einmal in die Nachrichtenschlange des Fensters geschoben und dort vieleicht irgendwann vom Hauptthread abgeholt.
Hier muss der Empfänger die Freigabe übernehmen. Allerdings ist auch hier nicht sichergestellt, dass die Nachricht den Empfänger erreicht. Dann würde ein Speicherleck entstehen.

Für diesen Fall ist es möglich ein eigene Verwaltung der Nachrichtenobjekte anzulegen (z.B. eine Objektliste auf die aus beiden Threads nur über eine CriticalSection zugegriffen wird). Der Mainthread wird als Observer per Postmessage benachrichtigt, dass neue Nachrichtenobjekte eingegangen sind, muss diese aber selbst abholen. Nicht verarbeitete Nachrichtenobjekte können so auch z.B. beim Beenden des Threads oder spätestens bei der Freigabe der Nachrichtenverwaltung freigegeben werden.

Geändert von Blup (26. Jun 2014 um 13:44 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stoxx
stoxx

Registriert seit: 13. Aug 2003
1.111 Beiträge
 
#7

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 13:45
jetzt übergibst Du einen Pointer von einem Pointer .. also doppelt gemoppelt.
So wie ich das geschrieben habe, geht es auf jeden Fall. Ich habe für sowas sogar extra eine Klasse gebaut, die (urpsrünglich) normale Events als asynchrone Events genau nach dieser Methode vom Thread an den Hauptthread schickt.

Umwandlung dann natürlich:
... nicht Pointer() sondern TLogMessage()


Delphi-Quellcode:
var
  logMessage: TLogMessage;
  fdebug: Boolean;
  fLogText: string;
begin
  logMessage := TLogMessage(msg.WParam);

mit dem doppelt gemoppelten Pointer in Deiner jetzigen Version wäre das dann:

logMessage := TLogMessage(msg.WParam^);
Phantasie ist etwas, was sich manche Leute gar nicht vorstellen können.

Geändert von stoxx (26. Jun 2014 um 13:49 Uhr)
  Mit Zitat antworten Zitat
jojo-sp

Registriert seit: 6. Sep 2006
Ort: Heiligenroth
10 Beiträge
 
Delphi 2009 Professional
 
#8

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 13:53
Blup hat recht und ist die beste Lösung,

Du läufst Gefahr, wenn du z.B. den Text direkt in einem Label ausgeben möchtest, dass du deinen Thread mit der VCL synchronisieren musst und je nach Menge der Messages deinen Thread damit auch ausbremst.

Generier eine ObjectList<TLogMessage> und schließe einen Gegenseitigen Zugriff auf die Liste mit den Critical Sections aus.

Du brauchst dann auch nur den Index der neuesten Nachricht an den Empfänger senden anstatt des Objects oder eines Pointers auf das Object.
Jeder hat einmal klein angefangen; ich zum Beispiel als Baby.
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.767 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 13:56
Du brauchst dann auch nur den Index der neuesten Nachricht an den Empfänger senden anstatt des Objects oder eines Pointers auf das Object.
.. wenn zwischenzeitlich nichts aus der Liste gelöscht wird,
ansonsten ist der überlieferte Index nicht mehr korrekt.

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
jojo-sp

Registriert seit: 6. Sep 2006
Ort: Heiligenroth
10 Beiträge
 
Delphi 2009 Professional
 
#10

AW: Object mit SendMessage an MainThread senden

  Alt 26. Jun 2014, 14:00
Stimmt!

Eigentlich sollte der Index eh irrelevant sein, da der Empfänger alle Nachrichten nacheinander abarbeitet (arbeiten sollte) und dann entfernt.
Jeder hat einmal klein angefangen; ich zum Beispiel als Baby.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:38 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