I'm trying to call a method in Apple's Security.h
framework that returns a struct by reference, like so:
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. It only exists to be passed to other native library functions. So, I want something like this (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. I could write a native method to return sizeof(SomeStruct)
, but I don't want to add a native component to my own code.
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.
The SecKeychainItemRef
type is defined to be a pointer to the 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.
After a successful call, you can use PointerByReference.getValue()
to get the opaque pointer.
/* 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. 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.