我如何处理JNA中的不透明指针?

时间:2015-04-03 22:20:02

标签: java c++ jna

我的Java应用程序使用JNA通过制造商提供的API与设备驱动程序进行通信。 API使用Windows消息进行通信。在执行期间,设备具有作为LPARAM传递的一组数据。 LPARAM是指向包含我需要的数据的结构向量的指针。

在C ++中,我可以像这样访问这些数据:

ImagesStruct *Images = { 0 };
...
Images = (ImagesStruct *)lParam;

本机ImagesStruct看起来像这样:

typedef struct _CompressedImage
{
  BYTE *pBuffer;
  int BufferLen;
}
CompressedImage;

typedef struct _ImagesStruct
{
  DWORD DocNumber;
  CompressedImage *Images;
  BOOL SnippetFront;
}
ImagesStruct;

在Java中,我的结构映射如下:

// ImagesStruct
public class IMAGES extends Structure {
    public int DocNumber;
    public COMPRESSED_IMAGE.ByReference Images; // pointer
    public boolean SnippetFront;

    public IMAGES() { super(); }
    public IMAGES(Pointer p) { super(p); }

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("DocNumber", "Images", "SnippetFront");
    }
}

// CompressedImage
public class COMPRESSED_IMAGE extends Structure {
    public Pointer pBuffer; // pointer
    public int BufferLen;

    public COMPRESSED_IMAGE() { super(); }
    public COMPRESSED_IMAGE(Pointer p) { super(p); }

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("pBuffer", "BufferLen");
    }

    public static class ByReference extends COMPRESSED_IMAGE implements Structure.ByReference {
        public ByReference() { super(); }
        public ByReference(Pointer p) { super(p); read(); }
    }
}

以下是我尝试在Java中访问该数据的众多方法之一

Pointer p = lparam.toPointer(); // this works
IMAGES pImages = new IMAGES();
IMAGES[] pa = (IMAGES[]) pImages.toArray(pImages.size()); // error here

我尝试的所有内容(包括上述内容)似乎都会产生相同的错误消息:

  

JNA:Callback desktop.IDeal@1175f37引发了以下异常:   java.lang.UnsupportedOperationException:此指针不透明:   const @ 0x155f0000 at   com.sun.jna.Pointer $ Opaque.read(Pointer.java:1320)at   com.sun.jna.Pointer.getByteArray(Pointer.java:726)at   desktop.IDeal.callback(IDeal.java:199)at   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     在   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:497)at   com.sun.jna.CallbackReference $ DefaultCallbackProxy.invokeCallback(CallbackReference.java:470)     在   com.sun.jna.CallbackReference $ DefaultCallbackProxy.callback(CallbackReference.java:500)     at com.sun.jna.Native.invokeInt(Native Method)at   com.sun.jna.Function.invoke(Function.java:384)at   com.sun.jna.Function.invoke(Function.java:316)at   com.sun.jna.Library $ Handler.invoke(Library.java:232)at   com.sun.proxy。$ Proxy2.GetMessage(未知来源)at   win32.Window.run(Window.java:59)at   java.lang.Thread.run(Thread.java:745)

我是否正确映射了事物?如果我无法将指针另一端的数据映射到一组Java对象,那么如何使用Pointer对象来访问该数据呢?

2 个答案:

答案 0 :(得分:1)

更改回调的签名以接受IMAGES而不是LPARAM。 JNA将为您处理转换。

您还应该考虑将JNA Structure命名为与您的原生struct完全相同,以避免混淆(使用" ImagesStruct"而不是" IMAGES")

使用基于Structure.read()的构造函数初始化JNA Structure时,调用Pointer也是一种很好的做法。这可确保Java字段在构造函数返回之前与本机内存同步。

答案 1 :(得分:1)

我在JNA Win32WindowDemo中找到了答案:只需使用LPARAM回调并使用YourStructureHere(new Pointer(lParam.longValue()))构造函数创建结构:

public LRESULT callback(HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam) {
    if (commandCompletionMessages.contains(uMsg) || eventMessages.contains(uMsg)){
            WFSRESULT wfsresult = new WFSRESULT(new Pointer(lParam.longValue()));
    (...)
    }       
    return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);