C++二进制到 Java 会"java.lang.Error: Invalid memory access"

C++ binary to Java gets "java.lang.Error: Invalid memory access"

本文关键字:Error Invalid access memory lang java 二进制 Java C++      更新时间:2023-10-16

i具有与天然C DLL的JAVA库接口(通过JNA)。此DLL提供了设置某些硬件事件时被调用的回调的功能。

除一个回调外,所有这些回调都可以使用,即使它具有几乎相同的定义。

这些回调签名和枚举在C 代码中定义:

typedef enum _KEYSTATE
{
  KEYSTATE_NONE = 0, 
  KEYSTATE_UP, 
  KEYSTATE_DOWN, 
  KEYSTATE_HOLD, 
  KEYSTATE_INVALID, 
} KEYSTATETYPE, *P_KEYSTATETYPE;
typedef enum _DKTYPE
{
  DK_NONE = 0,
  DK_1,
  DK_2,
  DK_3,
  DK_4,
  DK_5,
  DK_6,
  DK_7,
  DK_8,
  DK_9,
  DK_10,
  DK_INVALID,
  DK_COUNT = 10
} DKTYPE, *P_DKTYPE;
typedef enum _GESTURETYPE
{
  GESTURE_NONE      = 0x00000000, 
  GESTURE_PRESS     = 0x00000001,
  GESTURE_TAP       = 0x00000002,
  GESTURE_FLICK     = 0x00000004,
  GESTURE_ZOOM      = 0x00000008,
  GESTURE_ROTATE    = 0x00000010,
  GESTURE_MOVE      = 0x00000020,
  GESTURE_HOLD      = 0x00000040,
  GESTURE_RELEASE   = 0x00000080,
  GESTURE_SCROLL    = 0x00000100,
  GESTURE_ALL       = 0xFFFF
} GESTURETYPE, *P_GESTURETYPE;
typedef enum _EVENTTYPE
{
  EVENT_NONE = 0,
  EVENT_ACTIVATED,
  EVENT_DEACTIVATED,
  EVENT_CLOSE,
  EVENT_EXIT,
  EVENT_INVALID,
} EVENTTYPETYPE, *P_EVENTTYPETYPE;
typedef HRESULT (CALLBACK *DynamicKeyCallbackFunctionType)(DKTYPE, KEYSTATETYPE); 
typedef HRESULT (CALLBACK *AppEventCallbackType) (EVENTTYPETYPE, DWORD, DWORD);
typedef HRESULT (CALLBACK *TouchpadGestureCallbackFunctionType)(GESTURETYPE, DWORD, WORD, WORD, WORD);
typedef HRESULT (CALLBACK *KeyboardCallbackFunctionType)(UINT uMsg, WPARAM wParam, LPARAM lParam);

以下接口在Java中定义用于回调:

interface DynamicKeyCallbackFunction extends StdCallLibrary.StdCallCallback {
  int callback(int rawDynamicKeyType, int rawDynamicKeyState);
}
interface AppEventCallbackFunction extends StdCallLibrary.StdCallCallback {
  int callback(int appEventType, WinDef.UINT dwAppMode, WinDef.UINT dwProcessID);
}
interface TouchpadGestureCallbackFunction extends StdCallLibrary.StdCallCallback {
  int callback(int gestureType, WinDef.UINT dwParameters,
               WinDef.USHORT wXPos, WinDef.USHORT wYPos, WinDef.USHORT wZPos);
}
interface KeyboardCallbackFunction extends StdCallLibrary.StdCallCallback {
  int callback(WinDef.UINT uMsg, WinDef.UINT_PTR wParam, WinDef.INT_PTR lParam);
}

在API/Library类/接口中使用这些功能来设置它们:

// These are defined in an RazerAPI.java file as wrappers to simplify usage
// lib is an instance of a RazerLibrary from JNA
public Hresult RzSBAppEventSetCallback(AppEventCallbackFunction callback) {
  return Hresult.getFromApiValue(lib.RzSBAppEventSetCallback(callback));
}
public Hresult RzSBDynamicKeySetCallback(DynamicKeyCallbackFunction callback) {
  return Hresult.getFromApiValue(lib.RzSBDynamicKeySetCallback(callback));
}
public Hresult RzSBKeyboardCaptureSetCallback(KeyboardCallbackFunction callback) {
  return Hresult.getFromApiValue(lib.RzSBKeyboardCaptureSetCallback(callback));
}
public Hresult RzSBGestureSetCallback(TouchpadGestureCallbackFunction callback) {
  return Hresult.getFromApiValue(lib.RzSBGestureSetCallback(callback));
}
// These are the methods in the interface RazerLibrary.java file passed to JNA
int RzSBAppEventSetCallback(RazerAPI.AppEventCallbackFunction callback);
int RzSBDynamicKeySetCallback(RazerAPI.DynamicKeyCallbackFunction callback);
int RzSBKeyboardCaptureSetCallback(RazerAPI.KeyboardCallbackFunction callback);
int RzSBGestureSetCallback(RazerAPI.TouchpadGestureCallbackFunction callback);

注册回调时,使用了类似的东西(简化以免与数百行混乱,帖子结束时指向完整代码文件的链接)。

public class RazerManager implements DynamicKeyCallbackFunction {
  private static DynamicKeyCallbackFunction dkCallback;
  private RazerManager() {
    dkCallback = this;
    RazerAPI api = RazerAPI.INSTANCE;
    api.RzSBDynamicKeySetCallback(dkCallback);
  }
  @Override
  public int callback(int type, int state) {
    System.out.printf("DK Callback: %s %s", type, state);
    return 0; // S_OK
  }
}
public class Touchpad implements TouchpadGestureCallbackFunction {
  private static TouchpadGestureCallbackFunction gestureCallback;
  private Touchpad() {
    gestureCallback = this;
    RazerAPI api = RazerAPI.INSTANCE;
    api.RzSBGestureSetCallback(gestureCallback);
  }
  @Override
  public int callback(int gestureType, UINT param, USHORT x, USHORT y, USHORT z) {
    System.out.printf("Gesture: %s", gestureType);
  }
}

在用于测试的简单摇摆应用的主循环中创建了一个Razermanager的实例,Razermanager在其构造函数中创建了触摸板实例。a时循环用于使用getMessage处理消息,然后进行翻译和dispatchMessage,如下:

public class Main {
  public static void main(String[] args) throws IOException {
    // call javax's invokeLater to run app
  }
  public Main() {
    /* JFrame created here and then shown with setVisible(true); */ 
    RazerManager manager = RazerManager.getInstance();
    // Yes this is horrible, blocking everything but it's simply
    // used to get messages to go through and trigger the callbacks
    WinUser.MSG msg = new WinUser.MSG();
    while (true) {
      int hasMessage = User32.INSTANCE.GetMessage(msg, null, 0, 0);
      if (hasMessage != 0) {
        User32.INSTANCE.TranslateMessage(msg);
        User32.INSTANCE.DispatchMessage(msg);
      }
    }
  }
}

现在,手势事件可以很好地处理,触摸板类中的回调被调用并正确返回。生成动态密钥事件时,在Window Windows消息的While循环处理中会抛出一个例外:

Exception in thread "AWT-EventQueue-0" java.lang.Error: Invalid memory access
  at com.sun.jna.Native.invokeInt(Native Method)
  at com.sun.jna.Function.invoke(Function.java:383)
  at com.sun.jna.Function.invoke(Function.java:315)
  at com.sun.jna.Library$Handler.invoke(Library.java:212)
  at com.sun.proxy.$Proxy11.DispatchMessage(Unknown Source)
  at com.sharparam.jblade.tester.Main.<init>(Main.java:113)
  at com.sharparam.jblade.tester.Main$1.run(Main.java:25)
  at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
  at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
  at java.awt.EventQueue.access$200(EventQueue.java:103)
  at java.awt.EventQueue$3.run(EventQueue.java:694)
  at java.awt.EventQueue$3.run(EventQueue.java:692)
  at java.security.AccessController.doPrivileged(Native Method)
  at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
  at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
  at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
  at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
  at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
  at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
  at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
  at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

这仅发生在动态关键事件中,而不是以手势或狡猾的方式发生。我一生不能理解为什么,因为在C 方面动态键和手势回调非常相似。

编辑:完整的代码可以在github存储库中找到,特别是razerlibrary.java,razerapi.java,razermanager.java和touchpad.java。秋千测试可以找到要点。

,因此事实证明您不能(或至少您必须以不同的方式进行)让一个类实现多个回调接口。创建不同回调接口的明确实现,并将其分配到Razermanager中的回调字段。

这解释了为什么触摸板中的回调是在工作的原因,而Razermanager中的回调不得(TouchPad实现了一个接口,而Razermanager进行了三个接口)。

演示:

public class MyClass {
  private static MyCallbackInterface myCallback;
  private MyClass() {
    myCallback = new CallbackInterface() {
      @Override
      public int callback(/* parameters */) {
        // Do stuff with data here
        return 0;
      }
    }
    nativeLib.SetCallback(myCallback);
  }

当单个类实现多个回调界面时,本地库或JNA似乎在某个地方感到困惑,并且不知道该调用哪一个。因此,它是随机调用一个(或第一个定义的?)。

相关文章: