结构的 JNA 非常量字符串成员

JNA non-const String member of struct

我有一个 C 函数需要一个包含非常量字符串的结构。

typedef struct _A {
  char* str;
} A;

void myFunc(A* aptr) { ... }

我已经尝试了很长时间通过 JNA 传递这个东西,但到目前为止没有成功。

public class A extends Structure {
  public String str;
  protected List getFieldOrder() { ...
}

不起作用,因为 String 将变成 const char* 而不是我需要的 char*。

public class A extends Structure {
  public byte[] str;
  protected List getFieldOrder() { ...
}

不起作用,因为结构中的字节数组变成连续内存而不是指针。

我知道我可以通过使用 Memory 并复制字符串来做到这一点。但我无法想象这是首选的方式。

我也试过

public class NonConstStringMember extends Structure {
  public static class ByReference extends NonConstStringMember implements Structure.ByReference {}        
  public byte[] stringMember;
  protected List getFieldOrder() { ...
}

public class A extends Structure {
  public NonConstStringMember.ByReference str;
}

但它也不起作用,可能是因为对齐问题。

使用 JNA 执行此操作的首选方法是什么?

假设您希望它指向您可以写入的任意缓冲区,请使用 Pointer(如果您正在分配缓冲区,则为其分配一个 Memory 值)。

然后您可以使用 Pointer.getString(0)Pointer.setString(0, s) 来操作缓冲区内容。

编辑 Windows 库通常有大多数函数的 ascii 或 unicode 版本。虽然在大多数情况下您可以定义一个 Structure 用于这两种情况,但有时您需要提供一些额外的处理以确保使用正确的类型。由于这两种模式很少(如果有的话)同时使用,JNA 将选项设置为默认为其中一种(自动映射到正确的函数后缀,并自动将 String 映射到本机 const char*const wchar_t* 取决于模式)。

如果使用 unicode 模式,则使用 setWideString(),否则使用 setString(),或者在 Structure 上设置一些访问器来自动为您处理。例如:

class MyStructure extends Structure {
    private static final boolean ASCII = Boolean.getBoolean("w32.ascii");
    public Pointer stringBuffer = new Memory(X);
    void setStringBuffer(String s) {
        stringBuffer.setString(0, s, ASCII);
    }
    String getStringBuffer() {
        return stringBuffer.getString(0, ASCII);
    }
}

编辑 请注意,在大多数情况下,您应该使用 String 作为字段类型,并依赖 TypeMapper 在适当的情况下在幕后使用 WString(例如 User32 and W32APIOptions.DEFAULT_OPTIONS)。