【问题标题】:Getting an opaque struct returned by parameter in JNA获取由 JNA 中的参数返回的不透明结构
【发布时间】:2017-05-17 23:21:34
【问题描述】:

我正在尝试调用 Apple 的 Security.h 框架中的一个方法,该方法通过引用返回一个结构,如下所示:

int findSomething(SomeStruct *s)

(具体是this method,我正在尝试获取itemRef。有一个用法示例here。)问题是我不知道SomeStruct有哪些字段或它有多大是。它只存在以传递给其他本机库函数。所以,我想要这样的东西(Java):

interface SomeLib extends Library {
    int findSomething(Pointer p);
}

...
Pointer p = ... // Not sure how to make this
nativeLib.findSomething(p)
// Do something with p

如果我可以在 Java 中执行 sizeof(SomeStruct),我想我可以使用 JNA Memory 创建指针。我可以编写一个原生方法来返回sizeof(SomeStruct),但我不想在自己的代码中添加原生组件。

这类似于this question,但它询问了SomeStruct 的字段在运行时已知的情况,而在我的情况下,这些字段被库作者有意隐藏了。

【问题讨论】:

  • 如果需要分配空间,只需要Memory。如果您只需要本机对等值,为什么 Pointer 不像您所描述的那样工作?
  • @DanielWiddis 如何创建指针?
  • 感谢您提供更多详细信息。您需要PointerType 或其扩展名之一。 @cubrr 在下面给出了一个很好的答案。

标签: java c pointers struct jna


【解决方案1】:

SecKeychainItemRef 类型 is defined to be a pointer to the struct。这意味着SecKeychainFindGenericPassword 函数实际上需要一个指向指针的指针 作为itemRef 参数,因此,您可以使用JNA PointerByReference 类作为参数。

调用成功后,可以使用PointerByReference.getValue()获取不透明指针。

/* int SecKeychainFindGenericPassword(
 *     Pointer keychainOrArray,
 *     int serviceNameLength,
 *     String serviceName,
 *     int accountNameLength,
 *     String accountName,
 *     IntByReference *passwordLength,
 *     PointerByReference passwordData,
 *     PointerByReference itemRef
 * );
 */

static void main() {
    IntByReference passLength = new IntByReference(0);
    PointerByReference passwordData = new PointerByReference();
    PointerByReference itemRef = new PointerByReference();

    int result = SecKeychainFindGenericPassword(
        keychainOrArray,
        "service name".length(),
        "service name",
        "account".length(),
        "account",
        passLength,
        passwordData,
        itemRef
    );

    if (result == 0) {
        System.out.printf(
            "OSStatus: %d, passDataPtr: 0x%08X, itemRefPtr: 0x%08X%n",
            result,
            Pointer.nativeValue(passwordData.getValue()),
            Pointer.nativeValue(itemRef.getValue())
        );
    } else {
        /* Use SecCopyErrorMessageString to get a human-readable message */
        System.out.printf("An error occurred: %d%n", result);
    }
}

如果您在实际项目中调用此方法,我建议创建一个名为 SecKeychainItemRef 的类,它扩展了 PointerByReference 类。这以更清晰的方式将参数的类型传达给读者,即使它不允许您访问结构的内部。

【讨论】:

  • 扩展PointerByReference而不是简单的PointerType有什么好处?
  • @DanielWiddis PointerByReferencegetValuesetValue 方法 deal with the additional level on indirection automatically。它是一个指向指针的指针PointerType 只是一种指针。也就是说,它只包装了一层间接,而PointerByReference 包装了两层。由于在这种情况下itemRef 是指向指针的指针,我认为使用PointerByReference 在语义上更正确。
  • 另外值得注意的是PointerByReference扩展了ByReference,意思是automatically allocates memory for the pointer
  • 是的,这行得通。唯一奇怪的是PointerByReference 的子类显然需要公开。这是否意味着我在这个问题上接受的答案是错误的:stackoverflow.com/questions/43949920/…
  • @BrianMcCutchon 我不确定你问它是否有误是什么意思。 Java 类必须是public 与此有何关联?
猜你喜欢
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多