【发布时间】:2017-11-21 18:21:15
【问题描述】:
第 3 方 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 中示例的 sn-p:
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);
JNA
根据JNA FAQ,在我的情况下,我应该使用“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)
我也试过了:
- PointerByReference 而不是 SlapInfo.ByReference[](如 Pointer to array of structures as JNA method arguments 中所述)
- “指针”类,如JNA: pointers to array of pointers 中所述
- SlapInfo[](仅供尝试)
在所有情况下,我都收到错误“无效的内存访问”。
我做错了什么?
【问题讨论】:
-
请注意 C 函数声明中的
__stdcall- 您的库未使用 cdecl 调用约定。您的库接口是否扩展了StdCallLibrary? -
嗯,我正在尝试重现无效的内存访问,但无法重现。你确定你分配了足够大的
slapInfoArray吗?但是话又说回来,C 示例只分配了一个指针,这表明该函数可能正在用它自己分配的数组替换指针。如果不访问该库或其文档,几乎不可能猜测可能出了什么问题。 -
是的,它扩展了 StdCallLibrary,是的,正如在 C 示例中看到的,本机代码分配内存(还有另一个函数可以释放它)。
-
尝试用 C 创建一个函数原型,然后将其移植到 Java。
-
this 是一个指针结构工作示例,如果您的代码与此示例一样并且无法正常工作,则您的结构可能存在特定问题