internal static object Call(IntPtr instance, string name, object[] args) { Contract.Requires(instance != IntPtr.Zero, "instance is zero"); object result; if (name == "alloc" && args.Length == 0) // need this so we can create an auto release pool without leaking NSMethodSignature { IntPtr exception = IntPtr.Zero; IntPtr ip = DirectCalls.Callp(instance, Selector.Alloc, ref exception); if (exception != IntPtr.Zero) { CocoaException.Raise(exception); } result = NSObject.Lookup(ip); } else { Selector selector = new Selector(name); MethodSignature sig = new MethodSignature(instance, (IntPtr)selector); Native native = new Native(instance, selector, sig); native.SetArgs(args); result = native.Invoke(); } return(result); }
/// <remarks>The first argument of the delegate must be an IntPtr for the /// (normally implicit) block argument.</remarks> public ExtendedBlock(Delegate callback) { this.callback = callback; IntPtr fp = Marshal.GetFunctionPointerForDelegate(callback); this.block = NSObject.Lookup(CreateBlock(fp)); }
/// <exclude/> public NSObject init() { IntPtr exception = IntPtr.Zero; IntPtr instance = DirectCalls.Callp(this, Selector.Init, ref exception); if (exception != IntPtr.Zero) { CocoaException.Raise(exception); } return(NSObject.Lookup(instance)); }
/// <summary>Allows Call expressions to be chained.</summary> public static object Call(this object instance, Selector selector, params object[] args) { Contract.Requires(selector != null, "selector is null"); Contract.Requires(args != null, "args is null"); object result = new NSObject(IntPtr.Zero); if (instance != null) { IntPtr ptr; if (instance.GetType() == typeof(IntPtr)) { ptr = (IntPtr)instance; } else { ptr = (IntPtr)(NSObject)instance; } if (selector.Name == "init" && args.Length == 0) { IntPtr exception = IntPtr.Zero; IntPtr ip = DirectCalls.Callp(ptr, Selector.Init, ref exception); if (exception != IntPtr.Zero) { CocoaException.Raise(exception); } result = NSObject.Lookup(ip); } else { Native invoke = new Native(ptr, selector); invoke.SetArgs(args); result = invoke.Invoke(); } } return(result); }
/// <summary>Used to cast the return value of a native call to something useful.</summary> /// <remarks>This is better than a C# cast because it will produce a decent error message /// if there are problems and it will convert native IntPtr objects to the corresponding managed /// object.</remarks> public static T To <T>(this object value) { // If the value is null then return some form of null. if (value == null || value.Equals(IntPtr.Zero)) { if (typeof(T).IsValueType) { throw new InvalidCastException("Value is null"); } else if (typeof(T) == typeof(NSObject)) { return((T)(object)new NSObject(IntPtr.Zero)); } else if (typeof(NSObject).IsAssignableFrom(typeof(T))) { return((T)Activator.CreateInstance(typeof(T), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, new object[] { IntPtr.Zero }, null)); } else { return(default(T)); } } // If T matches the value type then just cast value to that type. Type type = value.GetType(); if (type == typeof(T)) { return((T)value); } // If T is bool then allow value to be an sbyte. if (typeof(T) == typeof(bool) && type == typeof(sbyte)) { return((T)(object)((sbyte)value != 0)); } // If T is NSObject, a derived class, or IntPtr then do a lookup and // return the correct managed class. if (type == typeof(IntPtr) || typeof(NSObject).IsAssignableFrom(typeof(T))) { IntPtr instance = IntPtr.Zero; if (type == typeof(IntPtr)) { instance = (IntPtr)value; } else { instance = (IntPtr)(NSObject)value; } NSObject obj = NSObject.Lookup(instance); if (obj == null) { return(default(T)); } else if (typeof(T).IsAssignableFrom(obj.GetType())) { return((T)(object)obj); } else { throw new InvalidCastException("Can't cast from " + obj.class_().Name + " to " + typeof(T) + "."); } } throw new InvalidCastException("Can't cast from " + type + " to " + typeof(T) + "."); }
private static object DoDrainBuffer(IntPtr buffer, string encoding) { object result; switch (encoding) { case "i": result = Marshal.ReadInt32(buffer); break; case "l": result = Marshal.ReadInt32(buffer); break; case "q": result = Marshal.ReadInt64(buffer); break; case "I": result = unchecked ((UInt32)Marshal.ReadInt32(buffer)); break; case "L": result = unchecked ((UInt32)Marshal.ReadInt32(buffer)); break; case "Q": result = unchecked ((UInt64)Marshal.ReadInt64(buffer)); break; case "f": result = Marshal.PtrToStructure(buffer, typeof(float)); break; case "d": result = Marshal.PtrToStructure(buffer, typeof(double)); break; case "v": case "Vv": result = null; break; case "@": IntPtr ip = Marshal.ReadIntPtr(buffer); result = NSObject.Lookup(ip); break; case "#": result = new Class(Marshal.ReadIntPtr(buffer)); break; case ":": result = new Selector(Marshal.ReadIntPtr(buffer)); break; default: result = DoDrainPtrBuffer(buffer, encoding); if (result == null) { result = DoDrainStructBuffer(buffer, encoding); } if (result == null) { throw new ArgumentException("Don't know how to read buffer of: " + encoding); } break; } return(result); }
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); }