AGB  ·  Datenschutz  ·  Impressum  







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

Hook für eigene Windows Message

Ein Thema von s.h.a.r.k · begonnen am 29. Jun 2010 · letzter Beitrag vom 30. Jun 2010
Antwort Antwort
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#1

Hook für eigene Windows Message

  Alt 29. Jun 2010, 23:34
Hallo zusammen,

und zwar streite ich mich immer noch mit meinen Threads. Ich habe im Moment einen LogController, der von verschiedenen Threads aus bedient werden kann, d.h. die Log()-Methode steht für diese zur Verfügung. In der Log-Methode wird eine Queue gefüllt und via PostThreadMessage eine Nachricht an den Haupt-Thread geschickt.

Beim Erzeugen des LogControllers (was im HauptThread geschieht -> explizites synchronisiertes Erzeugen) wird ein globaler Hook registriert:
Delphi-Quellcode:
const
  WM_LOG_NOTIFIER = WM_USER + 123;

////////////////////////////////////////////////////////////////////////////////////////////////////
////
//
//
constructor TLogController.Create();
var
  Method: TMethod;
begin
  inherited Create();

  { ... }

  // FHookMethodPointer and FHookHandle are private variables
  Method.Code := @TLogController.HookProc;
  Method.Data := Self;
  FHookMethodPointer := MakeProcInstance(Method);
  FHookHandle := SetWindowsHookEx(WH_GETMESSAGE, FHookMethodPointer, 0, System.MainThreadID);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////
////
//
//
function TLogController.HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LResult; stdcall;
var
  P: PMsg;
begin
  case nCode < HC_ACTION of
    True:
      Result := CallNextHookEx(FHookHandle, nCode, wParam, lParam);
  else
    if (lParam <> 0) then
    begin
      P := PMsg(lParam);
      if (P^.message = WM_LOG_NOTIFIER) then
        Self.DoPropagateLog();
    end;

    Result := CallNextHookEx(FHookHandle, nCode, wParam, lParam);
  end;
end;
Nun ist es so, dass dieser Hook nicht wirklich auf die Nachricht reagiert, die via PostThreadMessage() versendet wird. Hier noch der Aufruf: PostThreadMessage(System.MainThreadID, WM_LOG_NOTIFIER, 0, 0);

Ich sehe nicht wirklich, warum der Hook nicht auf diese Nachricht reagieren sollte Wobei ich sagen muss, dass ich nicht weiß, ob PMsg der richtige Typ für lParam ist. Ich habe bisher noch nichts passenderes gefunden.
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#2

AW: Hook für eigene Windows Message

  Alt 30. Jun 2010, 03:43
Ich hab mir nun ein externes kleines Programm geschrieben, bei dem der Hook funktioniert. In der SetWindowsHookEx muss WH_GETMESSAGE verwendet werden und in der Hook-Function ist lParam von Typ PMsg. Nur erhalte ich nun diese eine Nachricht doppelt *grml* Aber das ist eine neue Frage, ergo ein neuer Thread.

Anbei noch das Test-Project, falls es mal jemandem helfen sollte.

// edit

So, anbei nun die gefixte Version, in der nur einmal die Message beachtet wird. Dann will ich mal hoffen, dass es in meinem aktuellen Projekt korrekt funktioniert
Angehängte Dateien
Dateityp: rar PostThreadMessage-Demo.rar (9,4 KB, 17x aufgerufen)
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)

Geändert von s.h.a.r.k (30. Jun 2010 um 03:55 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#3

AW: Hook für eigene Windows Message

  Alt 30. Jun 2010, 09:15
Ich tippe hier ganz stark auf einen Designfehler. Warum willst du deine eigene Message hooken? wäre es nicht sinnvoller die Nachricht nicht direkt zu schicken sondern über eine Klasse die du dafür erstellst? Und diese Klasse kann das loggen ja dann übernehmen (bereits beim absenden).
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#4

AW: Hook für eigene Windows Message

  Alt 30. Jun 2010, 12:42
Hm, ich lasse mich gerne vom Gegenteil überzeugen und mir ein einfacheres Konzept unterbreiten Hier das Problem, welche ich erschlagen muss:

Ich habe einen LogController, der als Singleton-Pattern angelegt ist, d.h. ich hole mit die Instanz via einer statischen Klassenmethode TLogController.GetInstance() . Ich logge ebenso über eine statische Klassenmethode TLogController.Log( {Parameter} ); , die intern die GetInstance()-Methode verwendet.

Es gibt die Möglichkeit bei dem LogController EventListener zu registrieren, d.h. ich übergebe einen Zeiger auf eine Methode, die dann gecalled wird. Ebenso kann ich auch Module registrieren, die mehr Funktionalitäten bieten -- diese Module implementieren meinem Interface ILogModule. Ein Module ist im Moment z.B. das FileLogModule, welches, wie der Name schon sagt, die eintreffenden Logs in bestimmte Dateien schreibt.

Ganz wichtig ist, dass dieser LogController von mehreren Threads parallel benutzt werden kann und somit threadsicher sein muss. Ich habe in letzter Zeit schon mehrere Threads (hier im Forum ) geschrieben, die mir Lösungen zu diesem Problem geben sollten. So recht gefällt mir das mit diesem globalen Thread ja auch nicht. Jedenfalls habe ich im Moment nun folgendes Konzept: Die statische Klassenmethode Log() ist mit CriticalSections geschützt. Intern werden verschiedene Queues gefüllt -- für alle EventListener eine und für jedes Module separat eine. Danach wird die Nachricht WM_LOG_NOTIFIER (selbst definiert) via PostThreadMessage an den MainThread geschickt. Nun will ich ja, dass ich für den LogController keinerlei weiteren Code in das eigentliche Programm schreiben muss, da dies sonst Probleme beim Ändern oder Entfernen des LogControllers geben kann. Daher will ich in den MainThread auch nicht die passende Weiterleitung der Nachricht implementieren und mir bleibt nur der Weg über den globalen Hook.

Warum aber diese Nachricht? Das hat den Hintergrund, dass die EventListener und Module synchronisert benachrichtigt werden sollen (ohne Messages, da ich das bisherige Konzept beibehalten will), da teilweise auf die VCL zugegriffen werden kann. Die Message an den MainThread sorgt dafür, dass der Code für die Benachrichtigung auf unter dessen Kontext statt findet. Nachdem der MainThread ja unter Umständen auch mal blockiert sein kann (durch die CriticalSection in der Log()-Methode) ist eine Nachricht eben das/ein passende Mittel, um einen Deadlock zu umgehen -- weitere kenne ich im Moment leider nicht.

Ich habe im Moment aber auch noch die folgende Idee: Die Log-Methode wird komplett umgebaut, sodass darin in etwa folgendes steht (frei runtergeschrieben):
Delphi-Quellcode:
class procedure TLogController.Log(const AMessage: String; const ALogType: TLogType);
begin
  TThread.Synchronize(
    nil
    procedure()
    var
      LR : PLogRecord;
    begin
      New(LR);
      LR^.Text := AMessage;
      LR^.MsgType := ALogType;
      PostMessage(TLogController.Handle, WM_LOG_NOTIFIER, Integer(LR), 0);
    end
  );
end;
Die Idee hierbei ist es, dass ich dem TLogController ein Handle zur hand gebe und die Benachrichigung syncronisiert da hin schicke. Ich weiß nur leider nicht, ob das möglich ist, da ic das nur konzeptionell in meinem Kopf habe

Wenn jemand aber die super Idee hat, dann teile er sie mir doch bite mit Herzlichsten Dank!
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
3.159 Beiträge
 
#5

AW: Hook für eigene Windows Message

  Alt 30. Jun 2010, 19:50
Also, noch als kurzes Feedback zu meinem letzen Beitrag: ich habe nun auf den globalen Hook verzichtet, da es nun wahrlich mit Kanonen auf Bits geschossen ist. Ich habe die Idee umgesetzt, die ich weiter unten erwähnt habe: synchronisiertes PostMessage. Es funktioniert einwandfrei (endlich mal)
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Antwort Antwort


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 22:27 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