简体   繁体   English

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

[英]Passing a Java class into a void* parameter with JNA

I have a function in C which I'm trying to call from Java with JNA : 我在C中有一个函数,正在尝试使用JNA从Java调用该函数:

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

According to the JNA documentation the void* requires a com.sun.jna.Pointer be passed to the function. 根据JNA文档 ,void *需要将com.sun.jna.Pointer传递给该函数。 In java with JNA I believe the above function will be wrapped as follows: 在使用JNA的Java中,我相信上面的函数将包装如下:

public interface myWrapper extends Library{ 
    public int myCfunc(Pointer s, IntByReference ls);
}

The objects which need to linked to the Pointer, and passed in parameter s will be classes which implement JNA Structure, such as: 需要链接到Pointer并传入参数s将是实现JNA结构的类,例如:

public class myClass extends Structure{
    public int x;
    public int y;
    public int z;
}

Unfortunately, the parameter ls is an integer representing the length of the class in bytes. 不幸的是,参数ls是一个整数,以字节为单位表示类的长度。 Java doesn't have a sizeof function, so this adds an extra bit of complexity. Java没有sizeof函数,因此这增加了额外的复杂性。 The other major problem I'm having is ensuring I'm correctly passing the contents of the object to native memory and back. 我遇到的另一个主要问题是要确保将对象的内容正确传递给本机内存,然后再传递回给本机。

my code is similar to the following: 我的代码类似于以下内容:

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??
}

I'm getting an error that the data passed is of a larger size than is expected by the C function. 我收到一个错误即传递的数据的大小比 C函数预期的大。

The above code roughly following the same sort of steps as provided out in this answer to a question dealing with a similar issue, but in C#. 上面的代码大体上遵循与该问题类似的问题的答案中提供的相同步骤,但使用C#。 I've tried and tested that it works in C#. 我已经尝试并测试了它可以在C#中工作。

My question is similar to another on Stackoverflow , but that deals with a Pointer to an IntByReference rather than a pointer to a class. 我的问题与Stackoverflow上的另一个问题类似,但是问题涉及的是指向IntByReference的指针,而不是指向类的指针。

First of all JNA handle automatically it's own memory allocations which means that to following line is useless (and can damage the memory stack) : 首先,JNA自动处理它自己的内存分配,这意味着到下一行是无用的(并且可能损坏内存堆栈):

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

Next it also automatically deal with native pointer types which means that both lines below are equivalent in your case : 接下来,它还会自动处理本机指针类型,这意味着以下两种情况在您的情况下是等效的:

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

and thus JNA will do myObj.write(); 因此,JNA将执行myObj.write(); and read for you. 并为您read

The following is 100% correct but I suggest that you log len.getValue() before and after your call to myCfunc (which sould give 3*4=12 ; 3 int of 4 bytes) : 以下内容是100%正确的,但我建议您在调用myCfunc之前和之后记录len.getValue() (该值赋予3 * 4 = 12; 4字节的3 int):

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

If all of this is correct then you probably have an error in your structure's prototype. 如果所有这些都正确,那么您的结构原型可能有错误。

From my experience this is mostly due to an outdated C header file or an outdated library : 根据我的经验,这主要是由于过时的C头文件或过时的库造成的:

  • You are using header version 2.0 which states that struct's values are int but your linking against library v1.0 which takes a bytes structure 您正在使用标头版本2.0,该标头说明结构的值是int,但您与采用字节结构的库v1.0的链接
  • You are using header version 2.0 which states that struct's values are int but your linking against library v1.9 which takes two ints and a byte 您正在使用标头版本2.0,该标头说明结构的值是int,但与库v1.9的链接需要两个int和一个字节

in the end your code should look like this : 最后,您的代码应如下所示:

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
}

You can also try to voluntarily decrease len's value for debugging purposes eg : 您也可以尝试出于调试目的自愿降低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);

This won't do what you wan't but at least it should give you the correct "max len" 这不会做您不想要的事情,但至少它应该给您正确的“最大镜头”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM