internal Native(IntPtr target, Selector selector, IntPtr imp, MethodSignature sig) { Contract.Requires(selector != null, "selector is null"); Contract.Requires(target == IntPtr.Zero || imp != IntPtr.Zero, "imp is null"); m_target = target; if (m_target != IntPtr.Zero) { if (ms_stackFrames == null) { ms_stackFrames = new Dictionary <MethodSignature, StackFrame>(); // note that we have to do this here so each thread gets its own dictionary } m_selector = selector; m_imp = imp; m_sig = sig ?? new MethodSignature(target, (IntPtr)selector); if (!ms_stackFrames.TryGetValue(m_sig, out m_stackFrame)) { m_stackFrame = new StackFrame(m_sig); ms_stackFrames.Add(m_sig, m_stackFrame); } Ffi.FillBuffer(m_stackFrame.ArgBuffers[0], target, "@"); Ffi.FillBuffer(m_stackFrame.ArgBuffers[1], m_selector, ":"); } }
/// <summary>Calls the native method using the arguments which were set by <c>SetArgs</c>.</summary> public object Invoke() { object result = new NSObject(IntPtr.Zero); if (m_target != IntPtr.Zero) { Ffi.Call(m_stackFrame.Cif, m_imp, m_stackFrame.ResultBuffer, m_stackFrame.ArgBuffers); result = Ffi.DrainReturnBuffer(m_stackFrame.ResultBuffer, m_stackFrame.ReturnEncoding); } return(result); }
/// <summary>Note that this may be be called once and <c>Invoke</c> many times.</summary> public void SetArgs(params object[] args) { Contract.Requires(args != null, "args is null"); if (m_target != IntPtr.Zero) { if (m_sig.GetNumArgs() != 2 + args.Length) { throw new InvalidCallException(string.Format("{0} takes {1} arguments but was called with {2} arguments", m_selector, m_sig.GetNumArgs() - 2, args.Length)); } for (int i = 0; i < args.Length; ++i) { string encoding = m_sig.GetArgEncoding(i + 2); Ffi.FillBuffer(m_stackFrame.ArgBuffers[i + 2], args[i], encoding); } } }
private static IntPtr DoCreateCif(MethodInfo info) { IntPtr resultType = Ffi.GetFfiType(info.ReturnType); ParameterInfo[] parms = info.GetParameters(); int numArgs = parms.Length; PtrArray argTypes = new PtrArray(numArgs + 3); argTypes[0] = Ffi.GetFfiType(typeof(NSObject)); argTypes[1] = Ffi.GetFfiType(typeof(Selector)); for (int i = 0; i < numArgs; ++i) { Type type = parms[i].ParameterType; argTypes[i + 2] = Ffi.GetFfiType(type); } argTypes[numArgs + 2] = IntPtr.Zero; return(Ffi.AllocCif(resultType, argTypes)); // note that we don't want to free argTypes }
public StackFrame(MethodSignature sig) { m_returnEncoding = sig.GetReturnEncoding(); IntPtr resultType = Ffi.GetFfiType(m_returnEncoding); m_resultBuffer = Ffi.CreateBuffer(m_returnEncoding); int numArgs = sig.GetNumArgs(); m_argBuffers = new PtrArray(numArgs); m_argTypes = new PtrArray(numArgs + 1); for (int i = 0; i < numArgs; ++i) { string encoding = sig.GetArgEncoding(i); m_argBuffers[i] = Ffi.CreateBuffer(encoding); m_argTypes[i] = Ffi.GetFfiType(encoding); } m_argTypes[numArgs] = IntPtr.Zero; m_cif = Ffi.AllocCif(resultType, m_argTypes); }
internal IntPtr Call(IntPtr dummy, IntPtr resultBuffer, IntPtr argBuffers) { Unused.Value = dummy; IntPtr exception = IntPtr.Zero; try { // Get the this pointer for the method we're calling. PtrArray argArray = new PtrArray(argBuffers, m_signature.GetNumArgs() + 2); NSObject instance = (NSObject)Ffi.DrainBuffer(argArray[0], "@"); // Get the selector for the method that was called. // Get the method arguments. string encoding; object[] args = new object[m_signature.GetNumArgs() - 2]; for (int i = 0; i < args.Length; ++i) { encoding = m_signature.GetArgEncoding(i + 2); if (encoding == "@") { args[i] = (NSObject)Ffi.DrainBuffer(argArray[i + 2], encoding); } else { args[i] = Ffi.DrainBuffer(argArray[i + 2], encoding); } // Native code doesn't distinguish between unsigned short and unichar // so we need to fix things up here. Type ptype = m_info.GetParameters()[i].ParameterType; if (ptype == typeof(char)) { args[i] = (char)(UInt16)args[i]; } else if (ptype != typeof(NSObject) && typeof(NSObject).IsAssignableFrom(ptype)) { IntPtr ip = (IntPtr)(NSObject)args[i]; args[i] = NSObject.Lookup(ip); if (args[i] == null && ip != IntPtr.Zero) { throw new InvalidCallException(string.Format("Couldn't create a {0} when calling {1}. Is {0} registered or exported?", ptype, m_info.Name)); } } // Provide a better error message than the uber lame: "parameters". if (args[i] != null && !ptype.IsAssignableFrom(args[i].GetType())) { throw new InvalidCallException(string.Format("Expected a {0} when calling {1} but have a {2}.", ptype, m_info.Name, args[i].GetType())); } } // Call the method, object value = m_info.Invoke(instance, args); // and marshal the result. encoding = m_signature.GetReturnEncoding(); if (encoding == "c" || encoding == "C" || encoding == "s" || encoding == "S") // per 'man ffi_call' small results must be stuffed into "storage that is sizeof(long) or larger" { int r = Convert.ToInt32(value); Ffi.FillBuffer(resultBuffer, r, "l"); } else if (encoding != "v" && encoding != "Vv") { Ffi.FillBuffer(resultBuffer, value, encoding); } } catch (TargetInvocationException ie) { if (LogException != null) { LogException(ie); } else { DoLogException(ie); } exception = DoCreateNativeException(ie.InnerException); } catch (Exception e) { if (LogException != null) { LogException(e); } else { DoLogException(e); } exception = DoCreateNativeException(e); } return(exception); }