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

发布于 2024-10-01 04:49:47 字数 2071 浏览 2 评论 0原文

我在 C 中有一个函数,我试图用 JNA 从 Java

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

调用它 : JNA 文档 void* 需要 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 函数预期的要大

上面的代码大致遵循相同的步骤如本答案中所提供的,针对处理类似问题的问题,但使用的是 C#。我已经尝试并测试了它在 C# 中的工作原理。

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

I have a function in C which I'm trying to call from Java with JNA:

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

According to the JNA documentation the void* requires a com.sun.jna.Pointer be passed to the function. In java with JNA I believe the above function will be wrapped as follows:

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:

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. Java doesn't have a sizeof function, so this adds an extra bit of complexity.
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.

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#. I've tried and tested that it works in 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

北风几吹夏 2024-10-08 04:49:47

首先,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% 正确,但我建议您在调用 myCfunc 之前和之后记录 len.getValue() (这将给出 3*4=12 ; 3 int 4 字节):

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

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

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

  • 您正在使用标头版本 2.0,其中声明结构的值为 int,但您对库 v1.0 的链接采用字节结构
  • 您正在使用标头版本 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 的值以进行调试目的
例如:

IntByReference len = new IntByReference(size-1);
IntByReference len = new IntByReference(size-2);
IntByReference len = new IntByReference(size-3);
//...
IntByReference len = new IntByReference(size-11);

这不会做你不想做的事情,但至少它应该给你正确的“最大长度”

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

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(); and read for you.

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

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 :

  • 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
  • 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

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 :

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"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文