Wie Übergeben einer Methode als Rückruf an einen Windows-API-Aufruf?

8

Ich möchte eine Methode einer Klasse als Rückruf an eine WinAPI-Funktion übergeben. Ist das möglich und wenn ja, wie?

Beispiel für die Einstellung eines Timers:

%Vor%

Danke für Ihre Hilfe!

Bearbeiten : Ziel ist es, eine Methode dieser Klasse als Callback anzugeben. Keine Prozedur außerhalb der Klasse.

Bearbeiten2 : Ich schätze all Ihre Hilfe, aber solange die Methode keine "TMyClass" hat. Vor seinem Namen ist es nicht das, wonach ich suche. Ich habe es auf diese Weise gemacht, aber ich habe mich gefragt, ob ich überhaupt in der objektorientierten Welt bleiben könnte. Zeiger Magie willkommen.

    
Heinrich Ulbricht 07.05.2010, 10:38
quelle

6 Antworten

9
Madshi hat ein MethodTroProcedure Verfahren. Es ist in der "madTools.pas", die im Paket "MadBasic" ist. Wenn Sie es verwenden, sollten Sie die Aufrufkonvention für "TimerProc" in "Stdcall" ändern und die DoIt-Prozedur wird zu

%Vor%


Ich habe noch nie versucht, aber ich denke, man könnte auch versuchen, den Code in der "classes.MakeObjectInstance" zu kopieren, um andere Prozedurtypen als TWndMethod zu übergeben.

    
Sertac Akyuz 07.05.2010, 11:19
quelle
4

Welche Version von Delphi verwenden Sie?

In den letzten können Sie statische Klassenmethoden dafür verwenden:

%Vor%     
Marek Mauder 07.05.2010 13:27
quelle
2

Die TimerProc-Prozedur sollte eine Standardprozedur sein, kein Methodenzeiger.

  

Ein Methodenzeiger ist wirklich ein Paar von   Zeiger; Der erste speichert die Adresse   einer Methode, und die zweite speichert a   Referenz auf das Objekt die Methode   gehört zu

Bearbeiten

Dies könnte so viel OOP sein, wie Sie es bekommen werden. All die fiesen Sachen sind vor jedem versteckt, der deine TMyClass benutzt.

%Vor%

Bearbeiten: (wie von glob erwähnt)

Vergessen Sie nicht, die Aufrufkonvention stdcall hinzuzufügen.

    
Lieven Keersmaekers 07.05.2010 11:08
quelle
1

Antwort auf Ihre zweite Änderung:

Wenn Sie eine Antwort mit einem Zeiger auf eine TMyClass -Instanz wünschen, haben Sie möglicherweise kein Glück. Grundsätzlich hat die Prozedur, die Windows aufruft, eine bestimmte Signatur und ist keine Objektmethode. Du kannst nicht direkt damit umgehen, nicht einmal mit __closure oder procedure of object magic, außer wie unten und in anderen Antworten beschrieben. Warum?

  • Windows weiß nicht, dass es sich um eine Objektmethode handelt, und möchte eine Prozedur mit einer bestimmten Signatur aufrufen.

  • Der Zeiger ist kein einfacher Zeiger mehr - er hat zwei Hälften, die Objektinstanz und die Methode. Es muss die Self sowie die Methode speichern.

Übrigens verstehe ich nicht, was mit einem kurzen Sprung außerhalb der objektorientierten Welt nicht stimmt. Nicht-OO-Code ist nicht unbedingt schmutzig wenn gut verwendet wird.

Ursprüngliche, vor der Bearbeitung stehende Antwort:

Das ist nicht genau so möglich, wie Sie es versuchen. Die Methode, die SetTimer will, muss genau der TIMERPROC Signatur folgen - siehe MSDN-Dokumentation . Dies ist eine einfache non-object Prozedur.

Die Methode TMyClass.DoIt ist jedoch eine Objektmethode. Es besteht eigentlich aus zwei Teilen: dem Objekt, auf dem es aufgerufen wird, und der Methode selbst. In Delphi ist dies ein "procedure of object" oder ein "closure" ( lesen über prozedurale Typen hier ). Die Signaturen sind also nicht kompatibel, und Sie können die Objektinstanz nicht speichern, die Sie benötigen, um eine Objektmethode aufzurufen. (Konventionelle Delphi-Methoden werden auch mit der fastcall -Konvention implementiert, während TIMERPROC CALLBACK angibt, die aus dem Speicher ein Makro ist, das auf stdcall erweitert wird. Weitere Informationen zu Aufrufkonventionen und besonders Fastcall .)

Also, was machst du? Sie müssen Ihren nicht objektorientierten Rückruf in objektorientierten Code mappen.

Es gibt mehrere Möglichkeiten, und die einfachste ist dies:

Wenn Sie nur einen Timer haben, dann wissen Sie, dass dieser Timer ausgelöst wird, wenn Ihr Timer-Callback aufgerufen wird. Speichern Sie einen Methodenzeiger in einer Variablen vom Typ procedure of object mit der entsprechenden Signatur. Weitere Informationen finden Sie oben in der Dokumentation zu Embarcadero. Es wird wahrscheinlich so aussehen:

%Vor%

Initialisiere dann pfMyProc auf nil . In TMyClass.DoIt , set pfMyProc auf @DoIt - das heißt, es zeigt jetzt auf die DoIt Prozedur im Kontext von dieser spezifischen TMyClass Instanziierung. Ihr Rückruf kann dann diese Methode aufrufen.

(Wenn Sie interessiert sind, werden Klassenvariablen, die von einem prozeduralen Typ sind, wie Event-Handler intern gespeichert. Die OnFoo -Eigenschaften eines VCL-Objekts sind Zeiger auf Objektprozeduren.)

Leider ist diese prozedurale Architektur nicht objektorientiert, aber so muss es gemacht werden.

Hier sehen Sie, wie ein vollständiger Code aussehen könnte (ich bin nicht bei einem Compiler, also funktioniert er vielleicht nicht wie geschrieben, aber er sollte geschlossen sein):

%Vor%

Ein anderer Weg wäre, die Tatsache auszunutzen, dass Ihr Timer eine eindeutige ID hat. Speichern Sie eine Zuordnung zwischen der Timer-ID und dem Objekt. Konvertieren Sie in dem Rückruf von der ID in den Zeiger, und rufen Sie die Methode des Objekts auf.

Bearbeiten: Ich habe einen Kommentar zu einer anderen Antwort bemerkt, in der vorgeschlagen wird, die Adresse Ihres Objekts als Timer-ID zu verwenden. Dies funktioniert, ist aber ein potentiell gefährlicher Hack, wenn Sie zwei Objekte zu unterschiedlichen Zeiten an der gleichen Adresse haben und Sie nicht KillTimer aufrufen. Ich habe diese Methode benutzt, mag sie aber nicht persönlich - ich denke, dass die zusätzliche Buchhaltung, eine (Timer-ID, Objektzeiger) zu behalten, besser ist. Es kommt jedoch wirklich auf den persönlichen Stil an.

    
David M 07.05.2010 11:24
quelle
1

Ich habe MakeObjectInstance einige Male verwendet, um das Gleiche zu tun. Hier ist ein Artikel zum Thema: Verwendung einer VCL-Klassenmitgliedsfunktion als Win32-Rückruf

    
Mihaela 07.05.2010 13:47
quelle
0
%Vor%

Nicht perfekt. Achten Sie auf die Threads, Variable überschreiben etc. Aber es macht den Job.

    
dmajkic 07.05.2010 11:24
quelle

Tags und Links