简体   繁体   English

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

[英]Getting an opaque struct returned by parameter in JNA

I'm trying to call a method in Apple's Security.h framework that returns a struct by reference, like so: 我试图在Apple的Security.h框架中调用一个通过引用返回结构的方法,如下所示:

int findSomething(SomeStruct *s)

(Specifically, it's this method , and I'm trying to get itemRef . There's a usage example here .) The problem is that I don't know what fields SomeStruct has or how big it is. (具体而言,它的这种方法 ,而我试图获得itemRef 。有一个使用示例在这里 。)的问题是,我不知道哪些字段SomeStruct有或有多大是。 It only exists to be passed to other native library functions. 仅存在要传递给其他本机库函数的情况。 So, I want something like this (Java): 所以,我想要这样的东西(Java):

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

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

If I could do sizeof(SomeStruct) in Java, I could create the pointer using JNAs Memory , I think. 我想,如果我可以在Java中执行sizeof(SomeStruct) ,则可以使用JNAs Memory创建指针。 I could write a native method to return sizeof(SomeStruct) , but I don't want to add a native component to my own code. 我可以编写一个本机方法来返回sizeof(SomeStruct) ,但是我不想在自己的代码中添加本机组件。

This is similar to this question , but it asks about a case where the fields of SomeStruct are known at runtime, whereas, in my case, the fields are obscured intentionally by the library authors. 这类似于此问题 ,但是它询问在运行时知道SomeStruct的字段的情况,而在我的情况下,库作者有意遮盖了这些字段。

The SecKeychainItemRef type is defined to be a pointer to the struct . SecKeychainItemRef类型定义为指向 struct的指针 This means that the SecKeychainFindGenericPassword function actually expects a pointer to a pointer as the itemRef argument, and as such, you can use the JNA PointerByReference class as the argument. 这意味着SecKeychainFindGenericPassword函数实际上希望将指向该指针的指针作为itemRef参数,因此,可以将JNA PointerByReference类用作该参数。

After a successful call, you can use PointerByReference.getValue() to get the opaque pointer. 成功调用之后,可以使用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);
    }
}

If you're calling this method in an actual project, I would suggest creating a class named SecKeychainItemRef which extends the PointerByReference class. 如果在实际项目中调用此方法,建议创建一个名为SecKeychainItemRef的类,该类扩展了PointerByReference类。 This communicates the argument's type to the reader in a clearer fashion, even if it doesn't let you access the internals of the struct. 即使不允许您访问结构的内部结构,这也以更清晰的方式将参数的类型传达给读者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM