2010-11-04 131 views
9

我有在C函数,我试图从Java与JNA拨打:传递一个Java类转换为一个void *参数与JNA

int myCfunc(void *s, int *ls); 

按照JNA documentation虚空*需要com.sun.jna.Pointer是传递给函数。在与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函数。

上述代码粗略地遵循相同类型的步骤as provided out in this answer来处理类似问题,但在C#中。我试过并测试过它可以在C#中使用。

我的问题类似于another on Stackoverflow,但它处理的是指向IntByReference的指针,而不是指向类的指针。

回答

6

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

myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC?? 

接下来,它也自动地处理本机指针类型,这意味着下面两条线都在你的情况相当于:

public int myCfunc(Pointer s, IntByReference ls); 
public int myCfunc(myClass s, IntByReference ls); 

,因此JNA会为你做myObj.write();read

下面是100%正确的,但我建议您在通话之前和之后登录len.getValue()myCfunc(其中前人的精力给3 * 4 = 12; 3整型4个字节):

int size = Native.getNativeSize(myClass.class); 
IntByReference len = new IntByReference(size); 

如果所有这是正确的,那么你的结构原型可能有错误。

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

  • 您正在使用头版本2.0其中指出结构的价值观诠释,但你对库V1.0连接这需要一个字节结构
  • 您正在使用标题版本2。0其中指出结构的价值观诠释,但你对库V1.9这需要两个整数和字节

到底链接你的代码应该是这样的:

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); 

这不会做你wan't什么,但至少应该给你正确的“max len”