У сторонней DLL есть функция, которая ожидает указатель на указатель на структуру как аргумент:
__declspec(dllimport) int __stdcall
SegmentImages( unsigned char* imageData, int imageWidth, int imageHeight,
int* numOfFinger, SlapInfo** slapInfo, const char* outFilename );
Он сегментирует "пощечину" изображение отпечатков пальцев numOfFinger (обычно 4) на отдельные отпечатки пальцев (outFilename + число пальцев).
Определение SlapInfo:
struct SlapInfo {
int fingerType;
Point fingerPosition[4];
int imageQuality;
int rotation;
int reserved[3];
};
struct Point {
int x;
int y;
};
Отрывок из примера в C:
unsigned char* imageData;
int imageWidth, imageHeight;
//obtain imageData, imageWidth and imageHeight from scanner...
int numOfFinger;
SlapInfo* slapInfo;
int result = SegmentImages( imageData, imageWidth, imageHeight, &numOfFinger,
&slapInfo, FINGER_IMG_PATH);
Согласно FAQ JNA, в моем случае я должен использовать "Structure.ByReference []":
void myfunc(simplestruct** data_array, int count); // use Structure.ByReference[]
Итак, я сопоставлен в Java/JNA следующим образом:
public class Point extends Structure {
public int x;
public int y;
public Point(){
super();
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("x", "y");
}
}
public class SlapInfo extends Structure {
public int fingerType;
public Point[] fingerPosition = new Point[4];
public int imageQuality;
public int rotation;
public int[] reserved = new int[3];
public SlapInfo() {
super();
}
public SlapInfo(Pointer pointer){
super(pointer);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("fingerType", "fingerPosition", "imageQuality",
"rotation", "reserved");
}
public static class ByReference extends SlapInfo implements Structure.ByReference { }
}
int SegmentImages(byte[] imageData, int imageWidth, int imageHeight,
IntByReference numOfFinger, SlapInfo.ByReference[] slapInfo,
String outFileName);
//imageData, width and height are with valid values
IntByReference nrOfFingers = new IntByReference();
SlapInfo.ByReference[] slapInfoArray = (SlapInfo.ByReference[])
new SlapInfo.ByReference().toArray(4);
//Usually, there are 4 fingers in a slap, but the correct
//value should be the returned in nrOfFingers
int result = lib.SegmentImages(imageData, width, height,
nrOfFingers, slapInfoArray, FINGER_IMG_PATH);
Но с этим методом я получаю ошибку:
java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:419)
at com.sun.jna.Function.invoke(Function.java:354)
at com.sun.jna.Library$Handler.invoke(Library.java:244)
at com.sun.proxy.$Proxy0.SegmentImages(Unknown Source)
at scanners.JNAScanner.segmentToFile(JNAScanner.java:366)
Я также пробовал:
Во всех случаях я получил сообщение об ошибке "Недопустимый доступ к памяти".
Что я делаю неправильно?
Если SegmentImages
возвращает адрес одной или нескольких структур в slapInfo
, вам нужно использовать PointerByReference
. Фактическим нативным типом является struct **
, но значение, которое вы возвращаете в slapInfo
является указателем.
IntegerByReference iref = new IntegerByReference();
PointerByReference pref = new PointerByReference();
int result = SegmentImages(..., iref, pref, ...);
Если структуры возвращаются в одном блоке, вы можете сделать это:
SlapInfo s = new SlapInfo(pref.getValue());
SlapInfo[] slaps = s.toArray(iref.getValue());
__stdcall
в объявлении функции C - ваша библиотека не использует соглашение о вызовах cdecl. Ваш интерфейс библиотеки расширяетStdCallLibrary
?slapInfoArray
? Но с другой стороны, пример C выделяет только указатель, предполагая, что функция может заменить указатель массивом, который она выделяет сама. Почти невозможно высказать предположения о том, что может пойти не так без доступа к библиотеке или ее документации.