【问题标题】:how to isolate JNA bindings that are platform specific?如何隔离特定于平台的 JNA 绑定?
【发布时间】:2015-03-04 10:47:34
【问题描述】:

我有一个项目,我为 Windows kernel32 库定义了一个 JNA 包装器,在该项目上我创建了几个对项目并不重要但增加与平台集成的帮助器(即:使用OutputDebugString + 进行系统调试日志记录DebugView 和 Mailslot 消息传递功能)。

这是我的 JNA 定义:

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;

public interface JnaKernel32 extends StdCallLibrary {
    //StdCall is needed for lib kernel32

    @SuppressWarnings("unchecked")
    Map ASCII_OPTIONS = new HashMap(){
        {
            put(OPTION_TYPE_MAPPER, W32APITypeMapper.ASCII);
            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.ASCII);
        }
    };
    @SuppressWarnings("unchecked")
    Map UNICODE_OPTIONS = new HashMap(){
        {
            put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
        }
    };

    Map DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii") ? ASCII_OPTIONS : UNICODE_OPTIONS;

    JnaKernel32 INSTANCE = (JnaKernel32) Native.loadLibrary("kernel32", JnaKernel32.class, DEFAULT_OPTIONS);

    //some system defines
    //...

}

还有 Mailslot 定义:

public class Mailslot {

    static JnaKernel32 kernel32 = JnaKernel32.INSTANCE;
    boolean localMailslot = false;
    int lastError = 0;

    private int hMailslot = JnaKernel32.INVALID_HANDLE_VALUE;

    //...
}

在某些地方我也有

static JnaKernel32 kernel32 = JnaKernel32.INSTANCE; //to call OutputDebugString
//...
kernel32.OutputDebugString("some debug message");

我担心的是项目也可以在 GNU/Linux 或 MacOS X 上使用,但显然 Native.loadLibrary 如果在例如操作系统。

我正在考虑

  • 使用其他 JNA 绑定移植本机功能
  • 或者在另一个平台上运行时简单地禁用现有的 Windows kernel32 绑定,因为它只是方便而不是强制性的帮助程序。

如何隔离特定于平台的功能和进行的调用?我可能正在考虑将 JNA 部分移动到运行时加载的插件中?

【问题讨论】:

    标签: java windows macos jna multiplatform


    【解决方案1】:

    答案确实是通用的软件开发策略。

    1. 确定您的客户端代码需要的 API

      在这种情况下,它可能是MailsSlot.sendMessage(int destID, String msg)

    2. 抽象出该 API 背后的实现细节

      public interface MailSlot { void sendMessage(int destId, String msg); }

    3. 提供一个或多个具体实现以满足 API 合同

      public class Win32MailSlot implements MailSlot { public void sendMessage(int destId, String msg) { // Do stuff here that's windows-specific } }

      public class OSXMailSlot implements MailSlot { public void sendMessage(int destId, String msg) { // Do stuff here that's windows-specific } }

      在运行时选择适当的实现:

      MailSlot mslot = Platform.IS_WINDOWS ? new Win32MailSlot() : new OSXMailSlot();

    在一些实现之后,您可能会发现一些重复的代码,然后您可能会将其重构为在特定平台实现之间共享的抽象基类。

    有关此类策略的示例,请参阅 JNA 平台 FileUtils 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多