Wie caste ich von std::function nach LPVOID und zurück



  • Hallo zusammen

    An eine vorgegebene Funktionssignatur die einen LPVOID definiert muss ich eine std::function übergeben.
    Wie caste ich denn die std::function in LPVOID und in der Funkion dann wieder zurück auf std::function.



  • Das geht so direkt nicht.

    Wenn deine Callback-Funktion einen "User-Data" Parameter hat, dann kannst du eine Zwischenfunktion verwenden indem du die Adresse der std::function als "User-Data" Argument übergibst.

    Wenn deine Callback-Funktion keinen "User-Data" Parameter hat, dann bist du in Rue de la Gack.



  • @hustbaer sagte in Wie caste ich von std::function nach LPVOID und zurück:

    Rue de la Gack.

    🙂

    Callback? Hatte ich das irgendwo geschrieben? Aber du hast recht es ist eine Callback.

    Die Callback hat zwei Parameter. Der erste ist eine struct und der zweite steht zur Verfügung für User Data und ist vom Typ LPVOID.

    Die API die ich da verwende ist c. Um das ganze zu entkoppeln Richtung modernem c++ ich würde nun gerne der callback über die user params vom typ LPVOID meine std::function mit übergeben. Damit man in der callback dann die std::function aufrufen kann.

    also muss ich nun erst meine std::function in LPVOID casten und nachher in der callback wieder zurück.



  • Man soll ja etwas Code zeigen sorry:

    Das ist die Definition der Callback

    typedef BOOL (* __OUTSIDE_CISS__ DM_DATA_SERVICE_PROCA)(
        LPDM_DATA_SERVICEA lpds,
        LPVOID             lpvUser);
    

    Callback anmelden

    {
       // der einfach halber für das Beispiel hier:
       const std::function<void(shared_ptr<DmDataService>)> func;
    
       InstallDataService(serviceName, (OnReceiveData), LPVOID(&func));
    }
    

    callback definition

    static BOOL OnReceiveData(LPDM_DATA_SERVICE lpds, LPVOID lpvUser);
    {
       // geht so nicht 
       const auto* const func = static_cast<std::function<void(shared_ptr<DmDataService>)>*>(lpvUser);
     
       const auto spds = make_shared<DmDataService>();
       
        // Funktion aufrufen
        (*func)(spds);
    }
    


  • Da geht wohl nur ein reinterpret_cast<...>.



  • Eine C API braucht unbedingt Callbacks die als "extern C" definiert wurden. Was auch immer an C++ Konstrukt benutzt wird, normalerweise sind C++ Funktionen nicht "extern C" definiert, und man darf auf gar keinen Fall Exceptions durch den C Callstack hindurch propagieren.



  • @Th69 sagte in Wie caste ich von std::function nach LPVOID und zurück:

    Da geht wohl nur ein reinterpret_cast<...>.

    ja das hatte ich auch schon probiert. Da komme ich auf das selbe Ergebnis.

    const auto* const func = reinterpret_cast<std::function<void(shared_ptr<DmDataService>)>*>(lpvUser);
    

    Exception beim Aufruf der Funktion

    (*func)(spds);
    


  • Bei "geht nicht" dachte ich an einen Compilerfehler.
    Was für eine Exception?

    Kann es sein, daß der Callback erst später aufgerufen wird, also wenn InstallDataService schon wieder verlassen wurde (siehst du ja am Stacktrace bzw. wenn du einen Breakpoint nach dem Aufruf setzt)?

    Dann darfst du natürlich keine lokale Variable als Callback-Parameter übergeben!

    Das ist also keine Casting-Problem, sondern ein Speichermanagement-Laufzeitfehler.



  • https://en.cppreference.com/w/cpp/utility/functional/function/target

    Bitte nicht mit reinterpret_cast rumschludern.



  • Ja natürlich du hast recht. Die Funktion hatte ich inline definiert:

    auto func = [=](shared_ptr<wincc::DmDataService> spds)
    {
        std::string payload = reinterpret_cast<char*>(&spds->byData[0]);
    
        BufferIncomingMessage(payload, spds);
    };
    

    heißt ich muss das als Klassenmeber machen?



  • Ähm stehe ich gerade auf dem Schlauch. Ist doch egal wenn die Funktion selber inline ist oder? Nur die verwendeten Variablen müssen halt als Kopie übergeben werden und nicht als Referenz. Aber das habe ich doch mit dem Scope:
    [=] gemacht.

    Ich suche schreib noch die Exception raus.



  • Exception thrown at 0x00000000 in script.exe: 0xC0000005: Access violation executing location 0x00000000.

    Die ist nicht gerade viel sagend.



  • Du übergibst doch einen Zeiger auf func, also muß dieses Objekt noch existieren, wenn die Callback-Funktion aufgerufen wird (ob als Klassenmember kommt darauf an, wielange dieses Objekt "leben" muß).



  • @Th69 sagte in Wie caste ich von std::function nach LPVOID und zurück:

    Du übergibst doch einen Zeiger auf func, also muß dieses Objekt noch existieren, wenn die Callback-Funktion aufgerufen wird (ob als Klassenmember kommt darauf an, wielange dieses Objekt "leben" muß).

    Ja und func ist ein lamda und der ist doch auch solange gültig solange die umschliessende Klasse bestand hat. Oder nicht?
    Die Klasse ist auf jeden Fall noch da wenn die Callback ausgeführt wird.



  • @booster sagte in Wie caste ich von std::function nach LPVOID und zurück:

    Ja und func ist ein lamda und der ist doch auch solange gültig solange die umschliessende Klasse bestand hat. Oder nicht?
    Die Klasse ist auf jeden Fall noch da wenn die Callback ausgeführt wird.

    Wenn das lambda in einer funktion erstellt wurde, dann ist ein zeiger darauf nur bis zum ende dieser Funktion gültig.
    Was funktionieren könnte ist, wenn du den lamba einer std::function zuweist, welche ein Member der Klasse ist und dann einen zeiger auf diese std::function der C-Methode übergibst.



  • Warum eigentlich nicht direkt this (oder auch ein Objekt, das darin erstellt wurde) an die Callbackfunktion übergeben und eine Memberfunktion direkt aufrufen?
    Und warum der Umweg über DmDataService (und warum shared_ptr), wenn dich ohnehin anscheinend nur eine Zeichenkette aus DM_DATA_SERVICE interessiert?

    typedef struct {
     DWORD dwTeleType;
     char szService[MAX_DM_SERVICE_NAME + 1];
     char szSendingApp[MAX_DM_APP_NAME + 1];
     DWORD dwSendingMachine;
     DWORD dwDataSize;
     BYTE byData[1];                       // <- das  hier, oder?
     }
     DM_DATA_SERVICE;
    


  • @firefly sagte in Wie caste ich von std::function nach LPVOID und zurück:

    Wenn das lambda in einer funktion erstellt wurde, dann ist ein zeiger darauf nur bis zum ende dieser Funktion gültig.

    Da würde ich glatt mal das Gegenteil behaupten.



  • @yahendrik sagte in Wie caste ich von std::function nach LPVOID und zurück:

    Und warum der Umweg über DmDataService (und warum shared_ptr), wenn dich ohnehin anscheinend nur eine Zeichenkette aus DM_DATA_SERVICE interessiert?

    Da kennt jemand die Structur 🙂

    @yahendrik sagte in Wie caste ich von std::function nach LPVOID und zurück:

    warum der Umweg über DmDataService

    Deshalb:
    https://www.c-plusplus.net/forum/topic/351647/kopieren-eines-arrays-in-einem-struct-hack/8

    Problem ist dass es zwei unterschiedliche Structuren gibt. Einmal für Ansii und einmal für Unicode.
    Je nach WinCC Version. Und dass muss ich nach außen vereinheitlichen. Deshalb der Umweg über meine eigene Struktur DmDataService

    @yahendrik sagte in Wie caste ich von std::function nach LPVOID und zurück:

    wenn dich ohnehin anscheinend nur eine Zeichenkette aus DM_DATA_SERVICE interessiert?

    Wer sagt das? Das habe ich nirgends geschrieben.



  • Woran erkenne ich denn ob die std::function noch gültig ist?



  • This post is deleted!

Log in to reply