10 Stimmen

C-API-Funktionsrückrufe in C++-Memberfunktionscode umwandeln

Also, ich benutze die FMOD-API und es ist wirklich eine C-API.

Nicht dass das irgendwie schlecht wäre. Es ist nur so, dass es nicht gut mit C++-Code interagiert.

Zum Beispiel mit

FMOD_Channel_SetCallback( Kanal, Rückruffunktion ) ;

Es erwartet eine C-Style-Funktion für Rückruffunktion, aber ich möchte ihm eine Methodenfunktion einer Klasse übergeben.

Am Ende habe ich den Win32-Trick verwendet, um die Methodenfunktion statisch zu machen. Dann funktioniert sie als Rückruf in FMOD.

Jetzt muss ich meinen Code auseinandernehmen, um einige der Elemente statisch zu machen, nur um FMODs C-Natur zu berücksichtigen.

Ich frage mich, ob es in FMOD möglich ist oder ob es eine Möglichkeit gibt, den Rückruf mit einer spezifischen C++-Objektinstanz-Mitgliedsfunktion zu verknüpfen (nicht eine statische Funktion). Es wäre viel geschmeidiger.

12voto

R Samuel Klatchko Punkte 72641

Sie können keine Memberfunktion direkt übergeben. Eine Memberfunktion hat den impliziten Parameter this und C-Funktionen nicht.

Sie müssen einen Trampoline erstellen (ich bin mir nicht sicher über die Signatur des Rückrufs, also mache hier einfach etwas Zufälliges).

extern "C" int fmod_callback( ... args ...)
{
    return object->member();
}

Ein Problem ist, woher dieser Objektpointer stammt. Hoffentlich stellt Ihnen fmod einen generischen Kontextwert zur Verfügung, der Ihnen beim Aufruf Ihres Callbacks übergeben wird (dann können Sie den Objektpointer übergeben).

Wenn nicht, müssen Sie ihn einfach global machen, um darauf zugreifen zu können.

5voto

Denis K Punkte 1408

Ich vermute, es soll so funktionieren:
Sie können bestimmte Benutzerdaten einem Kanal zuweisen, indem Sie FMOD_Channel_SetUserData aufrufen. Diese Benutzerdaten sollten ein Zeiger auf Ihr C++-Objekt sein, das Ereignisse behandelt. Dann sollten Sie einen C-Style Callback schreiben, der dieses Objekt extrahiert, indem er FMOD_Channel_GetUserData aufruft, und dann Ihre C++-Instanzmethode auf diesem Objekt aufruft.

2voto

Eclipse Punkte 43775

Es gibt eine nicht portable und ziemlich hackische Lösung, die den Vorteil hat, zumindest threadsicher zu sein, was bei den "Trampoline"-Methoden nicht der Fall ist.

Sie können den tatsächlichen Funktionenmaschinencode auf die Schnelle generieren. Die Grundidee ist, dass Sie eine Vorlage für Ihre Rückruffunktion haben, die einen Objektpointer und einen Memberfunktionszeiger verwendet und Ihnen einen Block von Heap-Speicher gibt, den Sie der Bibliothek als C-Rückruffunktion übergeben können, die, wenn sie aufgerufen wird, die Memberfunktion auf diesem Objekt aufruft.

Es ist unordentlich und Sie müssen eine Implementierung für jede neue Plattform bereitstellen (jedes Mal, wenn sich die Aufrufkonvention ändert), aber es funktioniert und ist threadsicher. (Natürlich müssen Sie auch auf DEP achten). Die andere threadsichere Lösung besteht darin, auf Thread-lokale Speicher zurückzugreifen (vorausgesetzt, Sie wissen, dass der Rückruf auf demselben Thread erfolgt wie der von Ihnen gemachte Aufruf).

Siehe http://www.codeproject.com/KB/cpp/GenericThunks.aspx für ein Beispiel, wie Sie Thunks generieren können.

1voto

Chris Jester-Young Punkte 212385

Meiner bescheidenen Meinung nach ist es ein fehlerhaftes Design, nur einen Funktionszeiger (und keinen zusätzlichen separaten Objektfunktionszeiger) für einen C-Callback zu verwenden.

Wenn die Funktion stattdessen FMOD_Channel_SetCallback(channel, callbackFunc, callbackObj) wäre, dann würde Ihre statische Methode einfach eine Instanz des Objekts entgegennehmen und dann callbackObj->func() aufrufen (was offensichtlich nicht statisch sein kann).

0voto

Antti Huima Punkte 24441

Sie müssen ein Trampolin verwenden und den Zeiger auf das Objekt, auf dem Sie die Memberfunktion aufrufen möchten, in einer globalen oder statischen Variablen speichern, d.h.

Object *x;
void callback_trampoline() { x->foobar(); }
...
FMOD_Channel_SetCallback(CHANNEL, callback_trampoline);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X