使用JNA将Java类传递到void*参数

使用JNA将Java类传递到void*参数,java,pointers,jna,Java,Pointers,Jna,我有一个C语言的函数,我正试图通过以下方式从Java调用该函数: 根据函数,void*需要向函数传递一个。在使用JNA的java中,我相信上述函数将包装如下: public interface myWrapper extends Library{ public int myCfunc(Pointer s, IntByReference ls); } 需要链接到指针并传入参数s的对象将是实现JNA结构的类,例如: public class myClass extends Structu

我有一个C语言的函数,我正试图通过以下方式从Java调用该函数:

根据函数,void*需要向函数传递一个。在使用JNA的java中,我相信上述函数将包装如下:

public interface myWrapper extends Library{ 
    public int myCfunc(Pointer s, IntByReference ls);
}
需要链接到指针并传入参数
s
的对象将是实现JNA结构的类,例如:

public class myClass extends Structure{
    public int x;
    public int y;
    public int z;
}
不幸的是,参数
ls
是一个整数,表示类的长度(以字节为单位)。Java没有
sizeof
函数,因此增加了额外的复杂性。 我遇到的另一个主要问题是确保正确地将对象的内容传递到本机内存并返回

我的代码类似于以下代码:

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函数预期的数据大

上面的代码大致遵循处理类似问题的问题的相同步骤,但使用C#。我试过并测试过它在C#中是否有效


我的问题与类似,但它处理的是指向IntByReference的指针,而不是指向类的指针。

首先,JNA会自动处理它自己的内存分配,这意味着到以下行是无用的(并且会损坏内存堆栈):

接下来,它还会自动处理本机指针类型,这意味着以下两行在您的情况下是等效的:

public int myCfunc(Pointer s, IntByReference ls);
public int myCfunc(myClass s, IntByReference ls);
因此JNA将执行
myObj.write()
为您阅读

以下内容100%正确,但我建议您在调用
myCfunc
之前和之后记录
len.getValue()
(应该给出3*4=12;3 int/4字节):

如果所有这些都是正确的,那么您的结构原型中可能存在错误

根据我的经验,这主要是由于过时的C头文件或过时的库:

  • 您使用的是header version 2.0,该版本声明struct的值为int,但您的链接针对的是采用字节结构的library v1.0
  • 您使用的是header version 2.0,该版本声明struct的值为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的值 例如:

这不会做你不想做的事,但至少它会给你正确的“max len”

public int myCfunc(Pointer s, IntByReference ls);
public int myCfunc(myClass s, IntByReference ls);
int size = Native.getNativeSize(myClass.class);
IntByReference len = new IntByReference(size);
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
}
IntByReference len = new IntByReference(size-1);
IntByReference len = new IntByReference(size-2);
IntByReference len = new IntByReference(size-3);
//...
IntByReference len = new IntByReference(size-11);