Callbackfunktion Syntax
-
Ich sags gleich vorher, es wird kompliziert ...
Ich benutze einen Treiber, dem ich einen Zeiger auf eine Callbackfunktion mitgeben kann, um bei Aktivität benachrichtigt zu werden. Der Zeiger wird in eine Datenstruktur gepackt, die der Funktion als Parameter übergeben wird. Laut Dokumentation so:
// Treiberfunktion, die ich aufrufe UINT32 FGInitModule(FGINIT pArg); /* Struktur von FGINIT (die anderen Member sind mir egal - geht nur um *pCallback) */ typedef struct { void* hWnd; UINT16 Msg; FGCALLBACK *pCallback; // Pointer to callback void* Context; // Context for callback UINT32 Flags; }FGINIT; // Definition von FGCALLBACK laut Doku typedef void (FGCALLBACK)(void* Context,UINT32 wParam,void* lParam);
Den letzten typedef kapiert ich auch nicht, falls mir das mal wer erklären könnte, wär ich dankbar.
So, in welcher Syntax muss ich das jetzt zusammenschustern, damit es klappt?
Mein Ansatz war:void CallbackFunktion(void* Context, UINT32 wParam, void* lParam) { // mach was } int main(void) { FGINIT init; init.hWnd = NULL; init.Msg = 0; init.pCallback = CallbackFunktion; init.Flags = 0; FGInitModule(&init); return 0; }
Das geht natürlich nicht.
Compiler schrieb:
...\anwendung.cpp(16) : error C2440: '=': 'void (__cdecl *)(void *,unsigned long,void *)' kann nicht in 'FGCALLBACK (__stdcall *)' konvertiert werden
Wie muss der Code aussehen, damit es klappt?
-
init.pCallback = (FBCALLBACK*)CallbackFunktion;
-
Super, das klappt. Was ist mit dem typedef? Was wird da genau gemacht?
-
Also ich kann deinen Fehler nicht nachvollziehen. Visual C++ 2005 kompiliert das!
#include <stdlib.h> void CallbackFunction(void* Context, unsigned int wParam, void* lParam) { } int main() { typedef void (FGCALLBACK)(void* Context, unsigned int wParam, void* lParam); FGCALLBACK* pCallback = CallbackFunction; pCallback(NULL, 0, NULL); }
-
Der Grund warum das nicht implizit konvertierbar ist liegt wohl darin dass void(__cdecl*)(...) und void(__stdcall*)(...) Funktionen mit unterschiedlichen Aufrufkonventionen sind. Es sollte klappen wenn Du Deine Funktion so deklarierst:
void __stdcall CallbackFunktion(void* Context, UINT32 wParam, void* lParam) { // mach was }
@hmmmm...:
Klar, wenn Du das Typedef und die Funktionssignatur 100% übereinstimmen lässt klappt das auchEDIT: Um das Beispiel auf die tatsächliche Situation zu übertragen:
#include <stdlib.h> void CallbackFunction(void* Context, unsigned int wParam, void* lParam) { } int main() { typedef void (__stdcall FGCALLBACK)(void* Context, unsigned int wParam, void* lParam); FGCALLBACK* pCallback = CallbackFunction; pCallback(NULL, 0, NULL); }
@DarthZiu:
Casten geht natürlich, allerdings im Sinne von "ich weiss was ich tue" - und das tust Du hier eigentlich nicht (nicht übel nehmen bitte ;))
-
Und woher kommt auf einmal das __stdcall? Das steht doch gar nicht im typedef drin.
-
Also sollte ich das hier nicht tun?
schrieb:
init.pCallback = (FBCALLBACK*)CallbackFunktion;
Ich kann den typedef nicht ändern. Ist vom Treiber vorgegeben.
-
Ich denke der Hund liegt begraben in der Angabe "laut Doku".
Je nachdem mit welchem Compiler die DLL erstellt wurde (liegt vermutlich nur binär vor), kann die Aufrufkonvention nunmal eine andere sein. Theoretisch kann die DLL in Pascal geschrieben sein, denn da ist stdcall IMHO Standard. Dann brauch nur der Erzeuger der Doku keine oder weniger Ahnung von Cross-Language-Calls gehabt haben und wir haben den Salat
-
DarthZiu schrieb:
Also sollte ich das hier nicht tun?
init.pCallback = (FBCALLBACK*)CallbackFunktion;
Korrekt.
Ich kann den typedef nicht ändern. Ist vom Treiber vorgegeben.
Du kannst aber die Callback-Funktion ändern
-
ich denke mal die doku ist falsch! guck doch mal in den header! habe mir FirePackage 2.0 angeguckt und da ist das typedef wirklich ohne stdcall aber vielleicht hat sich das geändert nur die Doku wurde nicht angepasst.
-
Man man man.
Ich hatte es eben mit dem Cast gemacht ((FGCALLBACK*) CallbackFunktion) und die Funktion wurde auch aufgerufen. Nur beim Beenden des Programmes gabs jedesmal ne Access-Violation.
Wollte meinen Rechner schon aus dem Fenster befördern. Aber mit "__stdcall" klappts.
Danke für die Hilfe.
-
#ifdef FGLUSESTDCALL #define LINKCONVENTION __stdcall #else #define LINKCONVENTION __cdecl #endif typedef void (LINKCONVENTION FGCALLBACK)(void* Context,UINT32 wParam,void* lParam);
-
Davor steht noch:
/* Always use standard call if not suppressed */ #ifndef FGLUSECDECL #define FGLUSESTDCALL 1 #endif