将数据从非托管内存指针复制到Java中的托管无符号字节数组

时间:2020-09-28 17:04:22

标签: java arrays callback jna

我有一个C#代码,我正在尝试使用JNA在Java中实现,该代码目前停留在设备扫描过程中返回预览图像

C#

[DllImport("RS_SDK.dll",
          CharSet = CharSet.Ansi,
        EntryPoint = "RS_RegisterPreviewCallback")]
        public static extern int RS_RegisterPreviewCallback(int deviceHandle, RSPreviewDataCallback captureCallback); 


public delegate void RSRawPreviewCallback(int errorCode, byte[] imageData, int imageWidth, int imageHeight);


RSPreviewDataCallback previewCallback = new RSPreviewDataCallback(previewDataCallback);

private void previewDataCallback(int deviceHandle, int errorCode, IntPtr imageData, int imageWidth, int imageHeight)
        {
            log("previewDataCallback called....");
            if (imageData != null)
            {
                int prevImageWidth = imageWidth;
                int prevImageHeight = imageHeight;
                byte[] prevImageData = new byte[imageWidth * imageHeight];
                Marshal.Copy(imageData, prevImageData, 0, imageWidth * imageHeight);
                
                RSRawPreviewCallback callback = new RSRawPreviewCallback(previewCallbackInt);
                Invoke(callback, errorCode, prevImageData, prevImageWidth, prevImageHeight);
            }
            log("previewDataCallback done....");
        }

m_result = RS_RegisterPreviewCallback(deviceHandle,previewCallback);

到目前为止,我的Java实现

public interface RSPreviewDataCallback extends Callback {
        void RSPreviewDataCallback(int deviceHandle, int errorCode, Pointer imageData, int imageWidth, int imageHeight);
    }

public interface RS_SDK extends StdCallLibrary {
        RS_SDK INSTANCE = (RS_SDK)
                Native.load("RS_SDK_64", RS_SDK.class);

int RS_RegisterPreviewCallback(int deviceHandle, RSPreviewDataCallback captureCallback);
}

    @Override
    public void RSPreviewDataCallback(int deviceHandle, int errorCode, Pointer imageData, int imageWidth, int imageHeight) {

        byte[] dataByteArray = new byte[imageWidth * imageHeight];
        System.arraycopy( imageData, 0, dataByteArray, 0, imageWidth * imageHeight);
        try {
            String data = new String(dataByteArray, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

    }

我遇到了这个错误:

java.lang.ArrayStoreException: arraycopy: source type com.sun.jna.Pointer is not an array
    at java.base/java.lang.System.arraycopy(Native Method)

我相信imageData是字节数组的内存引用,Marshal.Copy(imageData, prevImageData, 0, imageWidth * imageHeight);将内存中的位置复制到位图数组。

  1. 我不确定我的界面RSPreviewDataCallback签名是否正确
  2. 我不知道是否有等效的JNA将内存位置复制到字节数组中

1 个答案:

答案 0 :(得分:1)

关于问题2,从highest_no_new = no_new_cases['total_cases'].max() 获取字节数组的JNA调用是Pointer.getByteArray()。因此,您可以使用Pointer从指针中获取字节。

请注意,Java没有无符号的imageData.getByteArray(0, imagewidth * imageheight)变量,因此尽管二进制文件是正确的,但您必须执行转换为更宽泛的类型才能获得正值。位掩码byte将为您扩展为b & 0xff并恢复“无符号”值。

关于问题1,如果您使用问题2的答案,映射将起作用。在大多数JNA函数数组映射中,可以通过将int数组作为参数来简化此过程。但是,JNA需要为回调提供专门映射的类型,因此不包括原始数组,因此首选byte[]方法。