Beispiel #1
0
        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);
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        /// <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));
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        /// <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) + ".");
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }