使用JNA获取void **参数作为char []的函数的结果

时间:2017-05-12 04:36:57

标签: java c macos pointers jna

TL; DR:我使用哪种JNA类型用于void**指针(实际上是char**),如何从中获取结果?

我正在尝试使用this C function从Java中的macOS Keychain获取密码:

OSStatus SecKeychainFindGenericPassword(CFTypeRef keychainOrArray,
        UInt32 serviceNameLength,
        const char *serviceName,
        UInt32 accountNameLength,
        const char *accountName,
        UInt32 *passwordLength,
        void * _Nullable *passwordData,
        SecKeychainItemRef  _Nullable *itemRef);

Usage example.

问题是,我不确定如何处理passwordData参数。我设法从C调用它(见帖子底部)。但是,在Java中,我得到passwordData参数的不确定性和错误结果。这是我尝试从Java调用它:

import com.sun.jna.*;
import com.sun.jna.ptr.*;

public class JnaTest {

    public interface Security extends Library {
        int SecKeychainFindGenericPassword(
                Object keychainOrArray,
                int serviceNameLength,
                String serviceName,
                int accountNameLength,
                String accountName,
                IntByReference passwordLength,
                // I've also tried char[][] and Pointer, which both give errors
                PointerByReference passwordData,
                Object itemRef);
    }

    public static void main(String[] args) {
        Security sec = Native.loadLibrary("Security", Security.class);

        PointerByReference pass = new PointerByReference();
        IntByReference len = new IntByReference();
        int rc = sec.SecKeychainFindGenericPassword(
                null,
                10, "SurfWriter",
                10, "MyUserAcct",
                len, pass,
                null);

        System.out.println(rc); // 0, good
        System.out.println(len.getValue()); // 11, same as in C
        // This prints Unicode characters nondeterministically; buffer overrun?
        System.out.println(new String(pass.getValue().getCharArray(0, len.getValue())));
    }

}

我能够编写这个C程序来做同样的事情,并且它运行正常,所以问题几乎肯定是在JNA中阅读passwordData

#include <Security/Security.h>

int main() {
    unsigned int len;
    void* pass;
    int rc = SecKeychainFindGenericPassword(
            NULL,
            10, "SurfWriter",
            10, "MyUserAcct",
            &len, &pass,
            NULL);
    printf("%d %s\n", len, pass);
}

1 个答案:

答案 0 :(得分:0)

我没有可能测试它(因为我目前在Windows上),但如果你尝试检索密码如下:

String password = new String(pass.getValue().getPointer(0).getCharArray(0, len.getValue()));

这只是一个想法,对于更有用的答案,我需要调试代码。

不过,我很困惑,为什么它的长度为11。