/** * Invoke the native function with the given arguments, returning the native result as an Object. */ public Object invoke(Class returnType, Object[] inArgs, Map options) { // Clone the argument array to obtain a scratch space for modified // types/values Object[] args = {}; if (inArgs != null) { if (inArgs.length > MAX_NARGS) { throw new UnsupportedOperationException("Maximum argument count is " + MAX_NARGS); } args = new Object[inArgs.length]; System.arraycopy(inArgs, 0, args, 0, args.length); } TypeMapper mapper = (TypeMapper) options.get(Library.OPTION_TYPE_MAPPER); Method invokingMethod = (Method) options.get(OPTION_INVOKING_METHOD); Class[] paramTypes = invokingMethod != null ? invokingMethod.getParameterTypes() : null; boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS)); boolean isVarArgs = args.length > 0 && invokingMethod != null ? isVarArgs(invokingMethod) : false; for (int i = 0; i < args.length; i++) { Class paramType = invokingMethod != null ? (isVarArgs && i >= paramTypes.length - 1 ? paramTypes[paramTypes.length - 1].getComponentType() : paramTypes[i]) : null; args[i] = convertArgument(args, i, invokingMethod, mapper, allowObjects, paramType); } Class nativeReturnType = returnType; FromNativeConverter resultConverter = null; if (NativeMapped.class.isAssignableFrom(returnType)) { NativeMappedConverter tc = NativeMappedConverter.getInstance(returnType); resultConverter = tc; nativeReturnType = tc.nativeType(); } else if (mapper != null) { resultConverter = mapper.getFromNativeConverter(returnType); if (resultConverter != null) { nativeReturnType = resultConverter.nativeType(); } } Object result = invoke(args, nativeReturnType, allowObjects); // Convert the result to a custom value/type if appropriate if (resultConverter != null) { FromNativeContext context; if (invokingMethod != null) { context = new MethodResultContext(returnType, this, inArgs, invokingMethod); } else { context = new FunctionResultContext(returnType, this, inArgs); } result = resultConverter.fromNative(result, context); } // Sync all memory which might have been modified by the native call if (inArgs != null) { for (int i = 0; i < inArgs.length; i++) { Object inArg = inArgs[i]; if (inArg == null) continue; if (inArg instanceof Structure) { if (!(inArg instanceof Structure.ByValue)) { ((Structure) inArg).autoRead(); } } else if (args[i] instanceof PostCallRead) { ((PostCallRead) args[i]).read(); if (args[i] instanceof PointerArray) { PointerArray array = (PointerArray) args[i]; if (Structure.ByReference[].class.isAssignableFrom(inArg.getClass())) { Class type = inArg.getClass().getComponentType(); Structure[] ss = (Structure[]) inArg; for (int si = 0; si < ss.length; si++) { Pointer p = array.getPointer(Pointer.SIZE * si); ss[si] = Structure.updateStructureByReference(type, ss[si], p); } } } } else if (Structure[].class.isAssignableFrom(inArg.getClass())) { Structure.autoRead((Structure[]) inArg); } } } return result; }