Seite 1 von 1

Callback aus C-dll

Verfasst: 10. September 2010 17:26
von delegug
Tag,

ich habe eine dll, die in C-geschrieben ist. die dll hat eine Funktion mit Callback, in der man einen Funktionszeiger übergibt.
Leider kann ich jetzt nur eine globale Funktion aufrufen lassen, da meine c-dll keine Klassen objekte kennt.
Ich möchte aber, dass meine Klasse ein Signal auslöst, sobald die Callback-Funktion ausgelöst wird. Wie bekomme ich eine Verbindung zwischen der globalen Funktion und das Signal in der Klasse?



Code: Alles auswählen

bool opcControl::registerCallback()
{
    bool result=false;
    typedef bool (*RegType)(void (*)(int,char *));
    RegType RegCallBack= (RegType) lib.resolve("registerCallback");
    if (RegCallBack) {
        //Callback->funktion registrieren
        result=RegCallBack(&datachange);
        ...




}

Code: Alles auswählen

void datachange(int handle,char* value)
{
    qDebug()<<handle<<value;
    QString newValue=value;
  
    ///????????????????????????????????
    
}
[/url]

Verfasst: 11. September 2010 11:36
von franzf
Das ist leider eine doofe Library. Denn normalerweise kommt bei einem C-Callback auch ein Parameter "void* UserData" mit. Demm könntest du deinen this-Zeiger mitgeben.
Aber so wie du das gepostet hast, geht es nicht.

Was für eine dll ist das denn? Kannst du die nicht wechseln? Oder dem Developer sagen, er soll doch bitte Konventionen einhalten, und einen UserData-Pointer mitnehmen?

Verfasst: 13. September 2010 08:35
von delegug
ich habe jetzt den code der dll mir besorgt und soweit verstanden. wie kann ich nun diesen void* UserData einfügen und das this-Object übergeben? Gibt es ein Beispiel?

Verfasst: 13. September 2010 09:11
von franzf
delegug hat geschrieben:ich habe jetzt den code der dll mir besorgt und soweit verstanden. wie kann ich nun diesen void* UserData einfügen und das this-Object übergeben? Gibt es ein Beispiel?
Was willst du denn jetzt machen? Die Lib anpassen? Oder gibt es doch einen Callback mit void* userdata?

Hier einfach ein kurzes Beispiel:

Code: Alles auswählen

#include <iostream>

typedef void (*CallBack)(int, void*);

// Das ist die Funktion, wie sie von der Library zur Verfügung gestellt wird.
void c_function_with_callback( int value, CallBack cb, void* user_data)
{
    value *= 2;
    cb(value, user_data);
}

struct Type {
    // Das soll jetzt im Callback aufgerufen werden
    void doIt(int value) {
        std::cout << "Member Function Callback " << value << std::endl;
    }
};

// Unsere Callback-Funktion, die an die Lib-Funktion übergeben wird.
void my_callback_fun(int value, void* data) {
    Type* obj = static_cast<Type*>(obj);
    obj->doIt(value);
}

int main() {
    Type t;
    c_function_with_callback(10, my_callback_fun, &t);
}
Für mehr Beispiele sollte google (z.B. nach "c++ c-callback user data") befragt werden.

Verfasst: 13. September 2010 09:45
von delegug
ok, vielen dank. hab die lib angepasst und funktioniert mit übergabe des klassenobjekts und danach diesen casten.
hier noch ein hilfreicher link
http://www.newty.de/fpt/callback.html

Verfasst: 13. September 2010 10:23
von franzf
Zwei kurze Anmerkungen zu der Seite (scheint veraltet zu sein, jedenfalls aus C++-Sicht):
1) #include <iostream.h> gibt es nicht (mehr)! Das heißt jetzt nur "<iostream>
2) Casts im C-Style (wie auf der Seite) sollte man in C++ nicht machen, sie veschleiern was eigentlich wirklich passiert. C-Casts können sein
* static_cast
* reinterpret_cast
* const_cast
Bitte verwende immer die C++-Casts (auch wenn es etwas mehr Schreibaufwand ist), dann weißt du auch ganz genau, was da wirklich passiert, und bei einem cast-Fehler beschwert sich der Compiler!
Hier in dem Beispiel ist ein static_cast alles was du brauchst.

Verfasst: 13. September 2010 12:04
von RHBaum
Wie bekomme ich eine Verbindung zwischen der globalen Funktion und das Signal in der Klasse?
Prinzipiell geht das aber auch.
gibt nur ein unschoenes Gebilde aus einer globalen Instanz einer klasse die statische Methoden auf Signale mappt. Oder man schreibt ne Proxy Dll, die das Interface anpasst und die "Clients" sauber verwaltet.

Die Loesung mit dem "Userdata" ist aber definitiv die elegantere und flexiblerer. Leider gibts noch paar Bib-Erzeuger, die das ned unterstuetzen. Dafuer muss man dann ganz schoen unsaubere oder umstaendliche Dinge in Kauf nehmen.

Ciao ...