【问题标题】:JNA calling C++ object from DLL - java.lang.IllegalArgumentException: Structure class has unknown or zero sizeJNA 从 DLL 调用 C++ 对象 - java.lang.IllegalArgumentException:结构类的大小未知或为零
【发布时间】:2019-01-21 21:45:53
【问题描述】:

我正在尝试使用 JNA 访问我用 C++(Windows 32 位、Java 8、JNA 5.2.0、Visual Studio 2017 C++)编写的简单 DLL。 DLL 具有创建对象的功能。我想获取对象上的指针并访问 JAVA 代码中的对象函数。
我收到指向本机对象的 JNA-Pointer 并尝试初始化它的 Java-Structure 实现。
在这里我在 JNA-Structure 初始化期间有异常:

    public IMyClass(Pointer p) { 
            super(p); 

线程“main”中的异常 java.lang.IllegalArgumentException:结构类 edu.nyu.cpptest.cpplib.CppLibDemo$CppLib$IMyClass 在 com.sun.jna.Structure 的大小未知或为零(确保所有字段都是公共的) .deriveLayout(Structure.java:1374) 在 com.sun.jna.Structure.calculateSize(Structure.java:1158) 在 com.sun.jna.Structure.calculateSize(Structure.java:1110) 在 com.sun.jna。 Structure.useMemory(Structure.java:350) at com.sun.jna.Structure.(Structure.java:202) at com.sun.jna.Structure.(Structure.java:193) at com.sun.jna.Structure .(Structure.java:189) at edu.nyu.cpptest.cpplib.CppLibDemo$CppLib$IMyClass.(CppLibDemo.java:30) at edu.nyu.cpptest.cpplib.CppLibDemo.(CppLibDemo.java:52)

C++ 代码:

MyClass.h:

class __declspec(dllexport) IMyClass {
public: 
    //int value;
    virtual int getValue() = 0;
    virtual void increment() = 0;
};

class MyClass : public IMyClass {
public:
    int value;
    MyClass();
    MyClass(int v);
    int getValue();
    void increment();
};  

extern "C"
{
    __declspec(dllexport) IMyClass* createMyClass();
};

MyClass.cpp:

MyClass::MyClass() {this->value = 0;}
MyClass::MyClass(int v) { this->value = v; }
int MyClass::getValue() { return value; }
void MyClass::increment() { value++; }

cpplib.cpp

extern "C" __declspec(dllexport) IMyClass* createMyClass() {
    MyClass *mcl = new MyClass(0);
    return mcl;
}

Java 代码:

public class CppLibDemo {
    public interface CppLib extends StdCallLibrary  {
        CppLib INSTANCE = Native.loadLibrary("cpplib.dll", CppLib.class);
        Pointer createMyClass();
        class IMyClass extends Structure {
            interface Increment extends Callback {
                public void invoke();
            }
            interface GetValue extends Callback {
                public int invoke();
            }
            public IMyClass() { }
            public IMyClass(Pointer p) { 
                super(p); 
                super.read();
            }
            Increment increment;
            GetValue getValue;
            //public int value;//I tried to add 'value' field in IMyClass-native and java code
            //public void read() {
            //    value = (int)readField("value");
            //    super.read();
            //}
        }
    }
    CppLib.IMyClass myClass;
    public CppLibDemo() {
        Pointer ptr = CppLib.INSTANCE.createMyClass();
        myClass = new CppLib.IMyClass(ptr);
    }
    public int getValue() {
        return myClass.getValue.invoke();
    }
    public void increment() {
        myClass.increment.invoke();
    }
}

我还尝试在 C++ 代码中将“值”字段从 MyClass 移动到它的父 IMyClass,并在 Java 代码中的 IMyClass 中声明值字段。在这种情况下,我也有例外:

线程“main”java.lang.Error 中的异常:edu.nyu.cpptest.cpplib.CppLibDemo$CppLib$IMyClass 类上的 Structure.getFieldOrder() 返回的名称 ([]) 与声明的字段名称 ([价值]) 在 com.sun.jna.Structure.getFields(Structure.java:1088) 在 com.sun.jna.Structure.deriveLayout(Structure.java:1233) 在 com.sun.jna.Structure.calculateSize(Structure.java:1158) ) 在 com.sun.jna.Structure.useMemory(Structure.java:350) 在 com.sun.jna.Structure.(Structure.java:202) 在 com.sun.jna.Structure.(Structure.java:193)在 com.sun.jna.Structure.(Structure.java:189) 在 edu.nyu.cpptest.cpplib.CppLibDemo$CppLib$IMyClass.(CppLibDemo.java:30)

我使用简单的控制台应用程序对此进行了测试,该应用程序在 Viusual Studio 中加载了我的 DLL,并且运行良好。 而且我还可以使用 SWIG java & DLL-wrapper 生成通过 JNI 调用我的 DLL。有趣的是,如果 JNA 可以做到这一点。

【问题讨论】:

标签: java c++ pointers dll jna


【解决方案1】:

Java 结构需要具有与本机结构匹配的公共字段,并且需要以正确的顺序声明这些字段。通常,您的 Java 代码将具有执行此操作的注释:

@Structure.FieldOrder({"value"})
public class ExampleStruct extends Structure {
    public int value;

    // rest of the implementation...
}

【讨论】:

  • 谢谢!这有助于修复此异常并继续前进。现在下一步是正确地初始化 MyClass.increment 变量,因为它在 myClass.increment.invoke() 中为空。
猜你喜欢
  • 1970-01-01
  • 2021-12-24
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
相关资源
最近更新 更多