获取由 JNA 中的参数返回的不透明结构

Getting an opaque struct returned by parameter in JNA

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

int findSomething(SomeStruct *s)

(具体是this method, and I'm trying to get itemRef. There's a usage example 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 创建指针。我可以为 return sizeof(SomeStruct) 编写本地方法,但我不想将本地组件添加到我自己的代码中。

这类似于 this question,但它询问的是 SomeStruct 的字段在运行时已知的情况,而在我的例子中,这些字段被库作者故意遮盖了.

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

调用成功后,可以使用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 的 class,它扩展了 PointerByReference class。这以更清晰的方式将参数的类型传达给 reader,即使它不允许您访问结构的内部。