JNA从DLL调用C ++对象-java.lang.IllegalArgumentException:结构类的大小未知或为零

时间:2019-01-21 21:45:54

标签: java c++ pointers dll jna

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

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

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

我还尝试将“值”字段从MyClass移到C ++代码中的父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。(Structure.java:202)在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)

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

1 个答案:

答案 0 :(得分:1)

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

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

    // rest of the implementation...
}