PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++] C API Callbacks



anda_skoa
24-04-2005, 14:24
Wenn man aus C++ Code heraus C APIs benutzt, kommt man manchmal in die Situation eine Callback Funktion im C Stil angeben zu müssen, aber man gerne eine Methode einer bestimmten Instanz einer eigenen Klasse aufgerufen hätte.

Das läßt sich üblicherweise ohne weitere Probleme bewerkstelligen, denn die Funktionen der C API, die zum Registrieren der Callbacks benutzt werden, bzw. die Signaturen der Callbacks sehen üblicherweise ein Kontextargument vor.

Dieses Kontextargument benutzt man um die Instanz der Klasse zu transportieren, sie ist ja in diesem Fall unser Anhaltspunkt.

Konkret sieht das so aus:


#include <iostream>

using std::cout;
using std::endl;

///////////////////// C API /////////////////////
// Ab hier steht die "Simulation" unserer C API, d.h. dieser Abschnitt dient nur zur
// Vereinfachung des Beispiels, normalerweise wäre das in der jeweiligen Bibliothek
// implementiert und wir würden den entsprechenden Header inkludieren
int numArgs;
char** args;

// die simulierte Callbackregistrierfunktion ruft nur gleich direkt den Callback
// auf
int registerCallback(int callback(void*, int, char**), void* context)
{
if (callback == 0) return 0;

return callback(context, numArgs, args);
}
///////////////////// C API /////////////////////

// Ab hier beginnt der eigentliche C++ Teil

class CallbackHandler
{
public:
// Die static Methode entspricht in ihrer Signatur genau den Anforderungen
// für den C API Callback. Da sie static ist, kann sie ohne Instanz benutzt werden
// und kann darum an die C API weiter gegeben werden, die ja nichts von
// Instanzen weiß

static int callback(void* context, int argCount, char** args)
{
cout << "CallbackHandler::callback: context=" << context << endl;

if (context == 0) return 0;

// wie wir "wissen" ist das Kontextargument unsere Instanz, also brauchen wir
// nur zu casten und die "echte" Methode zur Behandlung der Daten aufrufen
CallbackHandler* handler = reinterpret_cast<CallbackHandler*>(context);

return handler->doCallback(argCount, args);
}

private:
// Methode die die Daten eigentlich verarbeiten soll und dabei Zugriff auf
// eine bestimmte Instanz der Klasse haben soll, also nicht static sein kann
int doCallback(int argCount, char** args)
{
cout << "CallbackHandler::doCallback: this=" << this << endl;

for (int i = 0; i < argCount; ++i)
{
cout << "args[" << i << "]=" << args[i] << endl;
}

return 1;
}
};

int main(int argc, char** argv)
{
// Daten für unsere C API Simulation bereitstellen
numArgs = argc;
args = argv;

// Unseren Handler erzeugen
CallbackHandler handler;

// static Methode als Callback angeben und die Instanz, bzw. den Pointer darauf
// als Wert für das Kontextargument
bool success = registerCallback(CallbackHandler::callback, &handler) != 0;

cout << "success=" << (success ? "true" : "false") << endl;

return 0;
}


Ciao,
_

Akleson
28-10-2005, 22:07
Danke für die Hinweise. Ich werde morgen ausprobieren.
Raspen

pucki
27-06-2007, 21:44
bei callbacks kann man sich gelegentlich auch mit strukturen behelfen, wenn die anzahl der zulässigen parameter nicht ausreicht.

ich habe das mal bei fltk 1.1.7 gemacht, da ich mir die verwendung von globalen variablen untersagt hatte ;-). war ganz witzig, hat aber ganz schön zeit gekostet ...

gruesse

reinhard

ps: alternativ natürlich eine klasse ;-) wenn man schon gezielt bei der objektorientierten SWE bleiben will ...

Angelina_Apr
25-12-2009, 02:28
Hi All,

I also need to have this connector for webservices API. i think it would be really useful connector for many organizations.

Please let me know what is the status or when it can be released ?

Thanks,
Piyush.