Delphi-PRAXiS
Seite 2 von 4     12 34      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi WndProc in Klasse (https://www.delphipraxis.net/6606-wndproc-klasse.html)

negaH 16. Jul 2003 23:59

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:

type
  TMyObject = class
  private
    FStub: packed record
      MOV_EAX_OpCode: Byte;
      Self: Pointer;
      JMP_OpCode: Byte;
      Offset: Integer;
    end;
  end;
@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.

Gruß Hagen

OregonGhost 17. Jul 2003 10:49

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:
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;
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.

negaH 17. Jul 2003 12:50

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

OregonGhost 17. Jul 2003 13:07

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:

Zitat von Microsoft
GWLP_USERDATA [...] This data is intended for use by the application that created the window. Its value is initially zero.

Davon abgesehen kann man den Platz hinter dem Fenster beim Erzeugen, ich glaube der Klasse, vergrößern. Deine Methode ist wahrscheinlich sicherer, da hast du recht, aber dafür einen Tick umständlicher ;c)

Jedenfalls, in meiner Anwendung hat sich kein Treiber da einzunisten ;c)

Chewie 17. Jul 2003 18:40

Re: WndProc in Klasse
 
Danke euch beiden, ich werde mir das mal zu Gemüte führen. Muss das erstmal verdauen...

Chewie 18. Jul 2003 12:00

Re: WndProc in Klasse
 
OK, ich hab also hier drei Methoden zur Auswahl.
  • Zunächst die erste Möglichkeit von negaH. Der Propertylist von dem Control wird als Property ein Zeiger auf das Objekt angehängt. Um auf diesen Pointer zuzugreifen, brauch ich dann nur das Fensterhandle und den Bezeichner, entweder ein String oder, noch besser, ein globales Atom. Klingt einfach und logisch, der Nachteil ist, dass ich immer noch keine Methode habe, also auch keinen Zugriff auf private-Felder.
  • Dann die andere Möglichkeit von negaH, die ich ehrlich gesagt nicht verstehe...
  • Und OregenGhosts ist im Ergebnis der ersten identisch, nur mit dem Unterschied, dass der Zeiger an das Fenster selbbst angehängt wird, allerdings ist dort in der Regel nur Platz für ein Zeiger, und wenn der schon belegt ist, gibts Probleme.

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.

Gast 18. Jul 2003 15:54

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 EDA mal etwas rumprobieren. Es kann Window-Properties fremder Anwendungen auslesen.

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:

The most typical use for atoms is in Dynamic Data Exchange (DDE) applications. In the DDE protocol, applications use global atoms to identify the applications exchanging data, the nature of the data being exchanged, and the actual data items being exchanged. For more information about DDE, see Atoms and Shared Memory Objects. For examples that show how to use atoms, see the following topics:
  • Initiating a Conversation
  • Retrieving an Item from the Server
  • Submitting an Item to the Server
  • Terminating a Data Link

@OregonGhost: nicht der Treiber, sondern eine Hook-DLL subclassed die Fenster und haengt Werte an. Dies geschieht um bestimmte Rad-Features auch auf Fenstern zu benutzen, welche eigentlich diese Nachrichten nicht verarbeiten.

Chewie 18. Jul 2003 16:29

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:

Um auf diesen Pointer zuzugreifen, brauch ich dann nur das Fensterhandle und den Bezeichner, entweder ein String oder, noch besser, ein globales Atom.
Mein einziges Problem ist wie gesagt, dass ich die WndProc gerne als Methode haben würde. Aber so wie es aussieht, muss ich mich wohl davon verabschieden. Dürfte auch so gehen.

Gast 18. Jul 2003 16:35

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 :)

Chewie 18. Jul 2003 16:42

Re: WndProc in Klasse
 
Zitat:

Zitat von Assarbad
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 :)

Stimmt. Na ja, ich hab gedacht, vielleicht ließe sich vor Aufruf der Methode der Self-Zeiger in den Stack pushen, die Methode dann als Funktion simulieren und innerhalb der Funktion dann den Self-Zeiger wieder von Stack holen. Oder so was in der Art. Aber was solls, ich habs jetzt über die Properties geregelt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:37 Uhr.
Seite 2 von 4     12 34      

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