2016-07-20 25 views
0

Ich versuche auf eine C++ - Bibliothek von Java mit JNA zuzugreifen. Um dies zu tun, habe ich einen dünnen Wrapper um die C++ - Methoden geschrieben, die ich benötige. Das Umbrechen des C++ - Objekts, die Übergabe an Java und zurück an C++ führt jedoch beim Zugriff auf das Objekt in C++ zu einem ungültigen Speicherzugriff. Hinweise dazu, warum dies geschieht, sind sehr hilfreich.Wie arbeite ich mit C++ - Objekten in JNA

newencoder.h

Class Encoder { 

public: 
Encoder(); 
~Encoder(); 

template<class Type> 
bool originalEncode(Type* input); 

} 

encoder_wrapper.h

typedef void* EncoderWrap; 

    extern "C" { 
    EncoderWrap newEncoder(); 

    const char* encode(EncoderWrap vcEncoder); 
    } 

encoder_wrapper.cpp

#include "encoder_wrapper.h" 
#include "newencoder.h" 

EncoderWrap newEncoder() { 
    return reinterpret_cast<void*>(new Encoder()); 
} 

const char* encode(EncoderWrap encoderObj) { 
     std::string input; 
     (reinterpret_cast<Encoder*>(encoderObj))->originalEncode(&input); //This is where the invalid memory access occurs. Commenting this line and returning a placeholder string does not throw any error. 
     return input.c_str(); 
    } 

JNA

private static class Encoder { 

    public static native Pointer newEncoder(); 
    public static native String encode(Pointer encoderObj); 

    static { 
      Native.setProtected(true); 
      Native.register("encoderlib"); 
    } 

} 

//Code that calls the native methods 

Pointer encoderObj = Encoder.newEncoder(); //Does not fail 
String result = Encoder.encode(encoderObj); //Results in Invalid Memory access 

ich Aufruf versucht, die encode() Methode aus dem C++ Methode newEncoder() und das funktioniert wie erwartet. Dieser Speicherfehler tritt nur auf, wenn ich das Encoderobjekt, das in Java als void * übergeben wurde, an die C++ - Methode enocode() zurückgebe.

+0

Sie _definitely_ können nicht 'std :: string' zurückgeben, müssen Sie einen zugewiesenen Speicherblock zurückgeben, der eine C-Zeichenfolge enthält (nominal std :: string.c_str()), die garantiert erst nach JNA freigegeben wird hat die Möglichkeit, basierend auf seinen Inhalten eine Java-Zeichenfolge zu erstellen. – technomage

+0

Ich würde empfehlen, die Objektcodierung für das Objekt selbst zu speichern (selbst wenn es bei jedem Aufruf von 'encode' neu generiert wird), damit der Speicher nicht freigegeben wird, und dann einen Zeiger auf den C-Zeichenfolgenpuffer der Zeichenfolge zurückgibt. – technomage

Antwort

0

Ich löste das, indem ich das void * in eine Struktur einfügte und die Struktur an JNA zurückgab. Jedes Mal, wenn der newEncoder aufgerufen wird, wird eine Strukturinstanz erstellt, in der ein neues Encoder-Objekt als void * als Mitglied angegeben wird.

Das Strukturobjekt wird jedes Mal an die Funktion encode übergeben. Diese Methode wiederum führt den void * zurück zum Objekt und ruft die Methode originalEncode auf.

0

Entschuldigung für das Posten eines Kommentars hier, ich habe nicht genug Rep, um richtig im Kommentarbereich zu posten.

Ich habe nicht viel Erfahrung mit Sachen Java JNA aber in der Welt ++ C

extern "C" {} 

für die Herstellung von C++ Code haben Verknüpfung C verwendet wird. In encoder_wrapper.h verwenden Sie std :: string, das ein reines C++ - Konstrukt ist. Hast du versucht, das externe "C" zu entfernen?

1

Wie Vybz vorschlägt, ist Ihr Problem Mischen von C++ mit JNA. JNA kennt C++ - Strukturen nicht und erwartet reines C

Mit anderen Worten können Sie nicht annehmen, dass ein Java-String der gleiche wie ein std :: string ist. Sie können in Ihrer Schnittstelle nicht std :: string verwenden.

+0

Ich glaube nicht, dass das hier das Problem ist. Ich habe den String in char * geändert und der Fehler ist immer noch derselbe am selben Punkt. – AdityaTS