如何在 JNA 中使用 C++ 对象
How to work with C++ objects in JNA
我正在尝试使用 JNA 从 Java 访问 C++ 库。为此,我围绕我需要的 C++ 方法编写了一个简单的包装器。但是,包装 C++ 对象、传递给 Java 并返回到 C++ 会导致在访问 C++ 中的对象时出现无效内存访问。关于为什么会发生这种情况的任何指示都会非常有帮助。
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
我尝试从 C++ 方法 newEncoder()
中调用 encode()
方法,结果按预期工作。只有当我收到在 java 中转换为 void* 的编码器对象并将其传递回 C++ 方法 enocode()
.
时,才会发生此内存错误
抱歉post在这里发表评论,我没有足够的代表在评论部分正确post。
我对 java JNA 的东西没有太多经验,但在 C++ 世界
extern "C" {}
用于使C++代码具有C链接。在 encoder_wrapper.h 中,您使用的是 std::string,这是一个纯 C++ 结构。您是否尝试删除外部 "C"?
正如 Vybz 所建议的,您的问题是将 C++ 与 JNA 混合使用。 JNA 不了解 C++ 结构,需要纯 C。
换句话说,您不能假设 Java 字符串与 std::string 相同。您不能在界面中使用 std::string。
我通过将 void* 包含在一个结构中并将该结构返回给 JNA 来解决这个问题。每次调用 newEncoder
时,都会创建一个结构实例,该实例将有一个新的编码器对象,该对象被转换为 void* 作为成员。
结构对象每次都传递给encode
函数。此方法依次将 void* 转换回对象并调用 originalEncode
方法。
我正在尝试使用 JNA 从 Java 访问 C++ 库。为此,我围绕我需要的 C++ 方法编写了一个简单的包装器。但是,包装 C++ 对象、传递给 Java 并返回到 C++ 会导致在访问 C++ 中的对象时出现无效内存访问。关于为什么会发生这种情况的任何指示都会非常有帮助。
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
我尝试从 C++ 方法 newEncoder()
中调用 encode()
方法,结果按预期工作。只有当我收到在 java 中转换为 void* 的编码器对象并将其传递回 C++ 方法 enocode()
.
抱歉post在这里发表评论,我没有足够的代表在评论部分正确post。
我对 java JNA 的东西没有太多经验,但在 C++ 世界
extern "C" {}
用于使C++代码具有C链接。在 encoder_wrapper.h 中,您使用的是 std::string,这是一个纯 C++ 结构。您是否尝试删除外部 "C"?
正如 Vybz 所建议的,您的问题是将 C++ 与 JNA 混合使用。 JNA 不了解 C++ 结构,需要纯 C。
换句话说,您不能假设 Java 字符串与 std::string 相同。您不能在界面中使用 std::string。
我通过将 void* 包含在一个结构中并将该结构返回给 JNA 来解决这个问题。每次调用 newEncoder
时,都会创建一个结构实例,该实例将有一个新的编码器对象,该对象被转换为 void* 作为成员。
结构对象每次都传递给encode
函数。此方法依次将 void* 转换回对象并调用 originalEncode
方法。