我在 C 中有一个函数,我试图用 JNA 从 Java 中调用它:
int myCfunc(void *s, int *ls);
根据JNA documentation void* 需要 com.sun.jna.Pointer
传递给函数。在带有 JNA 的 Java 中,我相信上面的函数将被包装如下:
public interface myWrapper extends Library{
public int myCfunc(Pointer s, IntByReference ls);
}
需要链接到Pointer,并传入参数s
的对象将是实现JNA Structure的类,例如:
public class myClass extends Structure{
public int x;
public int y;
public int z;
}
不幸的是,参数ls
是一个整数,表示以字节为单位的类的长度。 Java 没有sizeof
函数,因此这增加了一些额外的复杂性。
我遇到的另一个主要问题是确保我正确地将对象的内容传递到 native 内存并返回。
我的代码类似于以下内容:
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
public void foo(){
myWrapper wrapper = (myWrapper) Native.loadLibrary("SomeDllWithLegacyCode", myWrapper.class);
myClass myObj = new myClass();
myObj.x = 1;
myObj.y = 2;
Pointer myPointer = myObj.getPointer();
int size = Native.getNativeSize(myClass.class);
IntByReference len = new IntByReference(size);
myObj.write(); //is this required to write the values in myObj into the native memory??
wrapper.myCfunc(myPointer, len);
myObj.read(); //does this read in the native memory and push the values into myObj??
myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC??
}
我收到一个错误,提示传递的数据比 C 函数预期的要大。
以上代码大致遵循相同的步骤 as provided out in this answer处理类似问题的问题,但在 C# 中。我已经尝试并测试了它在 C# 中的工作情况。
我的问题类似于another on Stackoverflow ,但它处理指向 IntByReference 的指针而不是指向类的指针。
最佳答案
首先,JNA 自动处理它自己的内存分配,这意味着以下行是无用的(并且可能损坏内存堆栈):
myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC??
接下来它还会自动处理 native 指针类型,这意味着下面两行在您的情况下是等效的:
public int myCfunc(Pointer s, IntByReference ls);
public int myCfunc(myClass s, IntByReference ls);
因此 JNA 将为您执行 myObj.write();
和 read
。
以下内容 100% 正确,但我建议您在调用 myCfunc
之前和之后记录 len.getValue()
(这会给出 3*4=12 ; 3 int of 4 bytes) :
int size = Native.getNativeSize(myClass.class);
IntByReference len = new IntByReference(size);
如果所有这些都是正确的,那么您的结构原型(prototype)可能有错误。
根据我的经验,这主要是由于过时的 C 头文件或过时的库造成的:
- 您使用的 header 版本 2.0 声明结构的值为 int,但您链接到采用字节结构的库 v1.0
- 您使用的 header 版本 2.0 声明结构的值是 int,但您链接到库 v1.9,它需要两个 int 和一个字节
最后你的代码应该是这样的:
public void foo(){
myWrapper wrapper = (myWrapper) Native.loadLibrary("SomeDllWithLegacyCode", myWrapper.class);
myClass myObj = new myClass();
myObj.x = 1;
myObj.y = 2;
int size = Native.getNativeSize(myClass.class);
IntByReference len = new IntByReference(size);
//log len.getValue
wrapper.myCfunc(myObj, len);
//log len.getValue
}
您也可以尝试自愿降低 len 的值以进行调试 例如:
IntByReference len = new IntByReference(size-1);
IntByReference len = new IntByReference(size-2);
IntByReference len = new IntByReference(size-3);
//...
IntByReference len = new IntByReference(size-11);
这不会做你不想做的事,但至少它应该给你正确的“最大长度”
关于java - 使用 JNA 将 Java 类传递给 void* 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4100990/