Передача класса Java в параметр void* с помощью JNA
у меня есть функция в C, которую я пытаюсь вызвать из Java с JNA:
int myCfunc(void *s, int *ls);
по словам документация JNA пустота* требуется com.sun.jna.Pointer
быть передано функции. В java с JNA я считаю, что вышеуказанная функция будет обернута следующим образом:
public interface myWrapper extends Library{
public int myCfunc(Pointer s, IntByReference ls);
}
объекты, которые нужно связать с указателем и передать в параметре s
будут классы, которые реализуют структуру JNA, такую as:
public class myClass extends Structure{
public int x;
public int y;
public int z;
}
к сожалению, параметр ls
- это целое число, представляющее длину класса в байтах. Java не было!--7--> функция, так что это добавляет немного сложности.
Другая серьезная проблема, с которой я сталкиваюсь, - это правильная передача содержимого объекта в собственную память и обратно.
мой код похож на следующий:
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, а не указателя на класс.
1 ответов
прежде всего, 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% правильно, но я предлагаю вам войти len.getValue()
до и после вызов myCfunc
(который должен дать 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, в котором говорится, что значения структуры int, но ваша связь с библиотекой v1.9 который принимает два Инта и Байт
в итоге код должен выглядеть так :
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);
это не будет делать то, что вы не хотите, но, по крайней мере, это должно дать вам правильный "Макс лен"