JNA вызывает C ++ объект из DLL - java.lang.IllegalArgumentException: класс структуры имеет неизвестный или нулевой размер - PullRequest
0 голосов
/ 22 января 2019

Я пытаюсь получить доступ с помощью JNA к моей простой DLL, написанной на C ++ (Windows 32 bit, Java 8, JNA 5.2.0, Visual Studio 2017 C ++). У DLL есть функция, которая создает объект. И я хочу получить указатель на объект и получить доступ к объектной функции внутри JAVA-кода.
Я получаю JNA-Pointer для нативного объекта и пытаюсь инициализировать его реализацию Java-структуры.
И здесь у меня есть исключение при инициализации JNA-структуры:

    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) в 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) в 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 в его родительский IMyClass в коде C ++ и объявить поле значения в IMyClass в коде Java. В этом случае у меня также есть исключение:

Исключение в потоке "main" java.lang.Error: Structure.getFieldOrder () для класса edu.nyu.cpptest.cpplib.CppLibDemo $ CppLib $ IMyClass возвращает имена ([]), которые не соответствуют объявленным именам полей ([[] значение]) в 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)

Я проверил это с помощью простого консольного приложения, которое загружает мою DLL в Viusual Studio и работает нормально. И я также могу вызывать мою DLL через JNI, используя генерацию Java-оболочки и DLL-оболочки SWIG. Интересно, если это возможно с JNA.

1 Ответ

0 голосов
/ 23 января 2019

В структуре Java должны быть открытые поля, совпадающие с полями собственной структуры, и необходимо объявить эти поля в правильном порядке.Обычно ваш Java-код будет иметь аннотацию, которая делает это:

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

    // rest of the implementation...
}
...