![]() |
Re: WndProc in Klasse
Ok, es gibt viele Wege.
Man kann, wenn man erst NACH der Erzeugung eines Fensterhandles ein normales Subclassing durchführen will, per Properties zum Fensterhandle arbeiten. Unter Properties sind NICHT die aus der VCL bekannten gemein, sondern die per API mit SetProp() einem Fenster zugeordnet werden. Man alloziert einmal ein Globales Atom, also einen System-eindeutigen String der per Handle angesprochen wird. Über dieses Handle kann man nun einen DWord mit SetProp() einem Fensterhandle zuordnen. Sozusagen eine neue Eigenschaft einem Fensterhandle definieren. Dahinein kommt dann Self. Die Fensterprocedure ist für alle Fenster die diesen Weg nutzen gleich und liest nun mit GetProp() Self des Fensterhandles aus. Danach ruft sie Szum Self die Fenstermethode auf. Dieser Weg setzt voraus das man erst NACH der Erzeugung des Fensterhandles dieses Subclassing durchführen kann. D.h. mindestens die Messages wm_Create und wm_NCCreate und wm_NCCalcSize werden verschluckt. Eine andere Methode würde einen Speicherbereich allozieren in dem individueller Code steht. Dieser Speicherbereich wäre sozusagen ein ausführbarer Caller-Stub. Ich nutzen diesen Weg z.b. über Stackbasierte, lokale Variablen um z.b. Methodbasierende Callbacks aufrufen zu können. D.h. eigentlich müsste diese Callback mit einer Standard API konforme Aufrufkonvention deklariert sein, z.b. stdcall. So kann man z.b. EnumWindows() eine Callback übergeben die eigentlich eine Objectmethode aufruft. Ähnliches geht auch mit Fensterproceduren. In deinem Falle könntest Du diesen Speicherbereich direkt als Record Member im Object definieren. Sowas wie
Delphi-Quellcode:
@Self.FStub wäre dann die Fensterprocedure. In FStub.MOV_EAX_OpCode muß der OpCode für MOV EAX,Konstant rein. In FStub.JMP_OpCode muß der OpCode für JMP +-OFFSET Konstant rein. Also ein relativer Sprung.type TMyObject = class private FStub: packed record MOV_EAX_OpCode: Byte; Self: Pointer; JMP_OpCode: Byte; Offset: Integer; end; end; Gruß Hagen |
Re: WndProc in Klasse
Ich glaube, ich kann noch eine weitere Methode anbieten:
Hinter jedem Fenster ist Platz für einen Zeiger, den du mit SetWindowLongPtr anhängen kannst. Bei der Erzeugung des Fenster hängst du hier einfach den this-Zeiger (oder wie heißt der noch unter Delphi? Ach ja, Self) an. Zusätzlich erzeugst du eine "globale" Fensterprozedur, die du auch bei der Erstellung des Fensters angibst. Diese macht nichts anderes, als mit GetWindowLongPtr den Self-Zeiger aus dem Fenster zu holen und dann die Klassenmethode, die die Nachricht bearbeiten soll, aufruft. Weiß nicht, wie das unter Delphi ist, aber in C++ kann man die globale Fensterprozedur einfach der Klasse zuordnen, indem man sie als static deklariert (ist für die Übersicht besser). Pseudo-Code:
Code:
So in etwa. Hab' mir die Methode bei Microsoft abgeguckt und sie funktioniert ganz gut und ist auch relativ einfach. Musst halt in der Fensterklasse nur noch die CommonWndProc als Fensterprozedur angeben.
function CommonWndProc(...);
var pClass: TDeineKlasse; begin pClass := TDeineKlasse(GetWindowLongPtr(hWnd, GWLP_USERDATA)); Result := pClass.WindowProc(...); end; function TDeineKlasse.MyCreateWindow(...); var hWnd: THandle; begin hWnd := CreateWindow(...); SetWindowLongPtr(hWnd, GWLP_USERDATA, Self); end; |
Re: WndProc in Klasse
Hi OregonGhost,
die Methode mit den Fensterprops, arbeitet genau wie deine. Mit dem Unterschied das GWL_USERDATA vielen Programmieren bekannt ist und z.b. von deren Tools wie Mousetreiber usw. schon genutzt werden könnte. Es ist also mit GWL_USRDATA nicht sicher das dieser Platz mehrfach verwendet wird und somit unser Self überschrieben wird. Deshalb mein Vorschlag mit SetProp() und einem eindeutigen Atom. Gruß Hagen |
Re: WndProc in Klasse
So meinst du das... Hatte nur ein paar Worte gelesen, dir mir im ersten Moment spanisch vorkamen ;c)
Wie dem auch sei, der Platz bei GWLP_USERDATA ist, wie der Name andeutet, für die (fensterbesitzende) Anwendung reserviert, und Treiber, die diesen Platz verwenden, sind daher nicht gut programmiert. Zitat:
Jedenfalls, in meiner Anwendung hat sich kein Treiber da einzunisten ;c) |
Re: WndProc in Klasse
Danke euch beiden, ich werde mir das mal zu Gemüte führen. Muss das erstmal verdauen...
|
Re: WndProc in Klasse
OK, ich hab also hier drei Methoden zur Auswahl.
So, ich hab mir das nochmal aufgeschrieben, ums zu verstehen. Da Methode1 nicht viel aufwändiger ist als Methode 3, aber sicherer, fällt Methode 3 weg. Aber negaH, könntest du mir bitte nochmal die zweite Methode erklären? Wäre sehr nett. |
Re: WndProc in Klasse
Vielleicht versuche ich es nochmal.
Du kannst (musst aber nicht) ein Atom reservieren. Ein Atom ist ein 16bit-Wert (ungefaehr wie ein Handle). Statt des Atoms kannst du SetProp() und GetProp() auch direkt einen String (mit Namen der Property) uebergeben. Hagen schlug das nur vor um die Eindeutigkeit des Wertes auf dem System zu gewaehrleisten. Denn Atome sind systemweit eindeutig! Allerdings sind sie wie auch DDE ein Relikt aus den Zeiten von Win16 (werden aber selbst in XP noch von MS benutzt). Wenn du XP mit Themes benutzt, wird JEDES Fenster eine Window-Property haben, die dem Theme-Manager irgendwas sagt. Naeheres habe ich noch nicht rausbekommen. Wenn du Lust hast, kannst du mit meinem ![]() Ein Nachteil von Window-Properties soll nicht verschwiegen werden: sie sind weit langsamer als zB SetWindowLong(). SetWindowLongPtr() ist im uebrigen an mehreren Stellen falsch dokumentiert und deklariert (zumindest bei Delphi 4). Zitat:
|
Re: WndProc in Klasse
Dass man statt den Atomenn auch Strings nehmen kann, ist mir klar, steht ja im SDK bei SetProp() dabei.
Hab ich ja auch geschrieben: Zitat:
|
Re: WndProc in Klasse
Davon kannst du dich definitiv verabschieden. Callbacks als Methode einbinden ist IMMER so eine Sache. Die Mechanismen haste ja in deinem ersten Post selbst erlaeutert :)
|
Re: WndProc in Klasse
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02: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