2015-04-03 72 views
0

我的Java应用程序使用JNA通过制造商提供的API与设备驱动程序进行通信。 API使用Windows消息进行通信。在执行过程中的一个点上,设备有一组作为LPARAM传递的数据。 LPARAM是指向包含我需要的数据的结构向量的指针。我如何处理JNA中的不透明指针?

在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:回调[email protected]发生以下异常: java.lang.UnsupportedOperationException:该指针是不透明的: 常量@ 0x155f0000在 com.sun.jna.Pointer $ Opaque.read(Pointer.java:1320)在 com.sun.jna.Pointer.getByteArray(Pointer.java:726)在 desktop.IDeal.callback(IDeal.java:199)at sun .reflect.NativeMethodAccessorImpl.invoke0(本机方法)在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect中.Method.invoke(Method.java:497)在 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 $ Handle r.invoke(Library.java:232)at com.sun.proxy $ Proxy2.GetMessage(Unknown Source)at win32.Window.run(Window.java:59)at java.lang.Thread.run( Thread.java:745)

我有东西映射正确吗?如果我没有办法将指针的另一端的数据映射到一组Java对象,那么如何使用Pointer对象来访问该数据?

回答

1

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

您还应该考虑命名您的JNA Structure,就像您的本地struct一样,以避免混淆(使用“ImagesStruct”而不是“IMAGES”)。

使用基于Pointer的构造函数初始化JNA Structure时,最好还是拨打Structure.read()。这确保Java构造函数在构造函数返回之前与本地内存同步。

+0

谢谢你的建议。我添加了以前错过的'read()'的调用,并且仍然得到*指针是不透明*消息。修改回调来取代IMAGES而不是LPARAM会做一些不同于'new IMAGES(lParam.toPointer())'的东西吗? – Cypher 2015-04-07 17:13:52

+0

是的,改变回调签名*会*做一些不同的事情,这就是为什么我首先提出的建议。 – technomage 2015-04-07 17:34:54

+0

我问的原因是因为设备发送了许多消息到这个回调管理的窗口句柄,并且LPARAM经常用于不同类型的数据(主要是int),这些数据不会正确映射到IMAGES对象。因此,如果我无法映射LPARAM - > IMAGES,如果API开发人员确实使用了不透明指针,是否有手动从指针中读取数据的方法?我已经尝试了指针对象上的各种方法,比如read(),getByte()等等,它们都会以相同的异常失败。 – Cypher 2015-04-08 18:11:15

1

我发现在JNA Win32WindowDemo答案:只需使用LPARAM回调,并使用YourStructureHere创建结构(新指针(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);