AGB  ·  Datenschutz  ·  Impressum  







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

WndProc in Klasse

Ein Thema von Chewie · begonnen am 16. Jul 2003 · letzter Beitrag vom 21. Feb 2004
Antwort Antwort
Seite 3 von 4     123 4      
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#21

Re: WndProc in Klasse

  Alt 18. Jul 2003, 22:22
Tja ich hatte zwar schon mal geantwortet, aber irgendwie wurde es verschluckt.

Du benutzt eine globale Fensterprocedure als Dispatcher von fensterprocedure: stdcall zu Methode.
Nachdem du im Object das Fensterhandle erzeugt hast muß mit GetWindowLong(gwl_WndProc) die originale Fensterprocedure geholt und im Object gespeichert werden. Danach wird mit SetProp() Self im fensterhandle gespeichert und anschließend mit SetWindowLong(gwl_WndProc, WndProcDispatcher) ein erneutes subclassing durchgeführt.

Delphi-Quellcode:
var
  SelfAtom: TAtom;

function WndProcDispatcher(Wnd: hWnd; Msg,wParam,lParam: Integer): Integer; stdcall;
var
  M: TMessage;
  Self: TMyObjct;
begin
  M.Msg := Msg;
  M.wParam := wParam;
  M.lParam := lParam;
  M.Result := 0;
  Integer(Self) := GetProp(Wnd, SelfAtom);
  Self.WindowMethod(M);
  Result := M.Result;
end;

// unter Vorbehalt alles aus dem Gedächtnis,
// für Headcrash oder 3. Weltkrieg wird also keine Vrantwortung übernommen
Gruß Hagen

PS: für den 2. Weg bastel ich noch ein Beispiel, da ich eigentlich diese preferiere
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#22

Re: WndProc in Klasse

  Alt 18. Jul 2003, 23:19
So hier die 2. Methode, wenns Fragen gibt WEIL es NICHT funktioniert dann wurschtel dich erstmal durch

Delphi-Quellcode:
type
  TCallDispatcher = packed record
    POP_EAX: Byte;
    PUSH_CONST: Byte;
    Self: Pointer;
    PUSH_EAX: Byte;
    JMP_RELATIVE: Byte;
    Offset: Integer;
  end;

procedure InitDispatcher(var Dispatcher: TCallDispatcher; Self, Method: Pointer);
begin
  Dispatcher.POP_EAX := $58;
  Dispatcher.PUSH_CONST := $68;
  Dispatcher.Self := Self;
  Dispatcher.PUSH_EAX := $50;
  Dispatcher.JMP_RELATIVE := $E9;
  Dispatcher.Offset := PChar(Method) - PChar(@Dispatcher) - SizeOf(Dispatcher);
end;

type
  TMyObject = class
    FDispatcher: TCallDispatcher;
    FHandle: hWnd;
    function WndProc(Wnd: hWnd; Msg,wParam,lParam: Integer): Integer; stdcall;
    procedure CreateHandle;

  end;

function TMyObject.WndProc(Wnd: hWnd; Msg,wParam,lParam: Integer): Integer; stdcall;
begin

end;

procedure TMyObject.CreateHandle;
// zur ansatzweisen Demonstration
var
  Params: TCreateParams;
begin

// TControl.CreateParams(Params);

  InitDispatcher(FDispatcher, Self, @TMyObject.WndProc);
  Params.WindowClass.lpfnWndProc := @FDispatcher;

// Windows.RegisterClass();

  with Params do
    FHandle := CreateWindowEx(ExStyle, WinClassName, Caption, Style,
      X, Y, Width, Height, WndParent, 0, WindowClass.hInstance, Param);
end;

{
Aufruf aus dem OS sieht so aus

  PUSH  lParam
  PUSH  wParam
  PUSH  Msg
  PUSH  Wnd
  CALL  WndProc ->  PUSH ReturnAddress
                    JMP  WndProc -> zeigt auf @FDispatcher

WndProc.FDispatcher code ist

  POP  EAX            = ReturnAddress
  PUSH  Self
  PUSH  EAX
  JMP  TMyObject.WndProc

}


procedure Test_WindowProc;
var
  TestWndProc: function(Wnd: hWnd; Msg,wParam,lParam: Integer): Integer; stdcall;
  TestObject: TMyObject;
begin
  TestObject := TMyObject.Create;
  try
    InitDispatcher(TestObject.FDispatcher, TestObject, @TMyObject.WndProc);

    TestWndProc := @TestObject.FDispatcher;

    TestWndProc(1, 2, 3, 4);
  finally
    TestObject.Free;
  end;
end;

// Beispiel für einen anderen CallDispatcher
function TForm1.DoEnumWindows(Wnd: hWnd; Param: Integer): Bool; stdcall;
begin
end;

procedure TForm1.Test_Enum;
var
  Enum: TCallDispatcher;
begin
  InitDispatcher(Enum, Self, @TForm1.DoEnumWindows);
  EnumWindows(@Enum, 0);
end;
Im obigen Beispiel wird vorrausgesetzt fas
1.) TMyObject.WndProc eine statische Methode ist also NICH virtual oder dynamic
2.) TMyObject.WndProc stdcall und identisch mit einer normalen Fensterfunktion

Der TCallDispatcher und InitDispatcher kann mit JEDER anderen STDCALL Callback umgehen. Z.b. also auch mit EnumWindows() ö.ä. Quatsch wie oben gezeigt.

Für deine Zwecke wird also als Fensterprocedure deines Fenster die Adresse von @FDispatcher gesetzt.

Achso eines noch: da ich aufzeigen wollte wie man mit dieser Methode von Anfang an JEDE Fenstermessage mitbekommt, also auch wm_Create, wm_NCCreate usw. hat sie eine nicht unwesentliche Schwäche.
Da für jedes Object das auf diese Weise arbeitet eine eigene Fensterfunktion die individuell ist existiert, wird auch jedesmal eine eigene Fensterklasse benötigt. D.h. JEDESMAL muß eine eigene Fensterklasse registriert werden. Dies ist natürlich für die Mehrfache Erzeugung des gleichen Objectes inakzeptabel.

Dann muß man schon ähnliche Wege gehen wie es Borland macht. Als Start-Fensterfunction wird eine globale Procedure benutzt die nur EINMAL durch wm_Create aufgerufen wird. Diese Funktion mappt dann über GetProp() gespeicherte Werte auf obigen FDispatcher jeweils individuell, mit SetWindowLong(gwl_WndProc,...), Fertig. Bei Borland heist diese Prozedur "StdWndProc". Um es perfekt zu machen musst du also mein letztes Posting mit dem Trick in diesem Posting kombinieren.

Gruß Hagen
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#23

Re: WndProc in Klasse

  Alt 19. Jul 2003, 00:55
Netter Trick mit TCallDispatcher. Nur solltest du noch sicherstellen, das der Speicherbereich auch ausführbar ist. Ein VirtualProtect wäre also angebracht.

Delphi-Quellcode:
procedure InitDispatcher(var Dispatcher: TCallDispatcher; Self, Method: Pointer);
var
  OldProtect: Cardinal;
  AlignedAddress: Cardinal;
begin
  Dispatcher.POP_EAX := $58;
  Dispatcher.PUSH_CONST := $68;
  Dispatcher.Self := Self;
  Dispatcher.PUSH_EAX := $50;
  Dispatcher.JMP_RELATIVE := $E9;
  Dispatcher.Offset := PChar(Method) - PChar(@Dispatcher) - SizeOf(Dispatcher);

  if IsBadCodePtr(@Dispatcher) then
  begin
   // @Dispatcher auf Speicher-Seite ausrichten (4 KB)
    AlignedAddress := Cardinal(@Dispatcher) and $FFFFF000;
    VirtualProtect(Pointer(AlignedAddress), 4096, PAGE_EXECUTE_READWRITE, OldProtect);
  end;
end;
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#24

Re: WndProc in Klasse

  Alt 19. Jul 2003, 02:24
Gute Feststellung. Ich habe dies aber absichtlich nicht erwähnt da ich noch nie Probleme damit hatte das irgendein Speicherbereich nicht auch ausführbar war. Soviel ich weiß sind normales Codesegement, Stacks und durch Borland MM angelegter Speicher immer ausführbar.

Ich lasse mich aber gerne vom Gegenteil überzeugen )

Schwieriger wird es dann schon zu erklären warum eine so erzeugte "Callback" Funktion die ja in unserem Prozessbezogenen lokalen Speicher liegt denoch aus anderen Prozessen heraus dispatcht werden können

Gruß Hagen
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#25

Re: WndProc in Klasse

  Alt 19. Jul 2003, 11:12
Zitat von negaH:
durch Borland MM angelegter Speicher immer ausführbar.
Wenn ich mir den Code aus GetMem.inc so anschaue, so muss ich sagen, dass der Speicher vom BorlandMM als PAGE_READWRITE markiert wird. Aber anscheinend macht da Win2000/XP keinen Unterschied, da der Code trotzdem ausführbar ist.


Zitat:
Schwieriger wird es dann schon zu erklären warum eine so erzeugte "Callback" Funktion die ja in unserem Prozessbezogenen lokalen Speicher liegt denoch aus anderen Prozessen heraus dispatcht werden können
Und was ist da so interessant daran? Es ist auch nur Speicher, wie bei jeder anderen Prozedur/Methode.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#26

Re: WndProc in Klasse

  Alt 19. Jul 2003, 12:13
Jedes Processmodul bekommt seinen eigenen virtuellen Speicherbereich. Fordern wir einen Speicherblock an, zB. ein Object mit FDispatcher, so ist die Speicheradresse individuell auf den Process bezogen. D.h. zwei Prozesse mit unseren TMyObject könnten rein theoretisch ein Object allozieren das aus unserer Sicht and der gleichen Adresse im Speicher liegt und denoch an unterschiedlicher Adresse im physikalischen Speicher. Eben ein Feature von Protected Mode Systemen.

Nun installieren wir eine Fensterprocedure die ja auf unsere virtuell Speicheradresse zeigt. Aber diese Fensterfunktion kann Prozessübergreifend benutzt werden. Das macht das OS für uns per CallWindowProc() API.

Aber interessant ist es allemale, da ich immer wieder von naiven Versuchen von Programmierern höre die mit GetWindowLong(gwl_Wndproc) versuchen aus Fensterhandles die zu anderen Prozessen gehören die Fensterprocedure zu lesen und direkt aufzurufen !!

Aber aus deiner Antwort entnehme ich das dir das schon klar sein dürfte

Gruß Hagen
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#27

Re: WndProc in Klasse

  Alt 19. Jul 2003, 13:40
Zitat von negaH:
Eben ein Feature von Protected Mode Systemen.
Man kann den Protected Mode auch anders betreiben. Man betrachte nur Windows 3.1 und Borland Pascal 7 (DPMI). Eine GDT für alle Prozesse (ehem. GlobalAlloc) und eine LDT für jeden einzelnen Prozess (ehem. LocalAlloc). Und da hat jeder Prozess im Prinzip Lese-Zugriff auf den Speicher von anderen Prozessenn. Durch das Paging, das mit dem 80386 eingeführt wurde, wurde dieses Manko von Win 3.1 behoben.
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#28

Re: WndProc in Klasse

  Alt 19. Jul 2003, 17:19
Ah, die zweite Methode ist das, was ich wollte. Habe es jetzt noch nicht ausprobiert, das werd ich gleich tun. Danke auch für das Beispiel der ersten Methode, auch wenn das nicht erforderlich war, da ich das dank deiner Erklärung und dem SDK selbst zusammengebastelt habe.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#29

Re: WndProc in Klasse

  Alt 19. Jul 2003, 18:19
So, ich hab mir das jetzt mal angekuckt.
In der Form kann ich das leider nicht gebrauchen, da das Parent-Control bei mir schon existieren muss.
Ich erklär mal kurz, wie das funktionieren soll: Die Klasse THexListView ist - wie der Name schon sagt - ein Listview, das als HexViewer funktioniert. Dieses wird dann entweder in der Nachrichtenschleife einer nonVCL-Anwendung oder aber irgendwo in einer VCL-Anwendung erzeugt. Da ich also nicht weiß, in welcher "Umgebung" die Klasse funktionieren soll, will ich die Klasse autonom gestalten, sodass die Nachrichtenschleife des übergeordneten Objektes nicht verändert werden muss. Dafür subclasse ich die Nachrichtenschleife ja in der HexView-Klasse.
Ich will nun nichts weiter tun, als in der Klasse die Nachrichten an das Parent zu verarbeiten, bevor das Parent selbst sie verarbeitet.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#30

Re: WndProc in Klasse

  Alt 19. Jul 2003, 20:49
Naja dann musst das Parent.Handle eben subclassen. Dein ListView Control enthält dann eine ParentWndProc() und ein FParentDispatcher. Mit SetWindowLong(Paran.Handle, GWL_WNDPROC, @FParentDispatcher) subclasst du dann.

Gruß Hagen
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 4     123 4      


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 18:14 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