Example #1
0
        public string description()
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            if (m_instance != IntPtr.Zero)
            {
                IntPtr exception = IntPtr.Zero;
                IntPtr str       = DirectCalls.Callp(this, Selector.Description, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }

                IntPtr utf8 = DirectCalls.Callp(str, Selector.UTF8String, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }

                return(Marshal.PtrToStringAuto(utf8));
            }
            else
            {
                return("nil");
            }
        }
Example #2
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);
        }
Example #3
0
        private SignatureInfo DoEncodingToSig(string encoding)
        {
            SignatureInfo info;

            lock (ms_lock)
            {
                if (!ms_encodedTable.TryGetValue(encoding, out info))
                {
                    Class klass = new Class("NSMethodSignature");

                    IntPtr exception = IntPtr.Zero;
                    IntPtr instance  = DirectCalls.Callpp(klass, signatureWithObjCTypes, Marshal.StringToHGlobalAnsi(encoding), ref exception);
                    if (exception != IntPtr.Zero)
                    {
                        CocoaException.Raise(exception);
                    }

                    if (instance == IntPtr.Zero)
                    {
                        throw new InvalidCallException(string.Format("Couldn't find the method signature for {0}", encoding));
                    }

                    info = new SignatureInfo(instance);
                    ms_encodedTable.Add(encoding, info);
                    klass.release();
                }
            }

            return(info);
        }
Example #4
0
        // Call imp where args points to buffers containing the arguments and result
        // is a buffer where the result will be written.
        public static void Call(IntPtr cif, IntPtr imp, IntPtr result, PtrArray args)
        {
            IntPtr exception = IntPtr.Zero;

            FfiCall(cif, imp, result, args.ToIntPtr(), ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }
        }
Example #5
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));
        }
Example #6
0
        /// <exclude/>
        public NSObject retain()
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            IntPtr exception = IntPtr.Zero;

            Unused.Value = DirectCalls.Callp(m_instance, Selector.Retain, ref exception);
            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            return(this);
        }
Example #7
0
        /// <exclude/>
        public void autorelease()
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            if (m_instance != IntPtr.Zero)
            {
                IntPtr exception = IntPtr.Zero;
                Unused.Value = DirectCalls.Callp(this, Selector.Autorelease, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }
            }
        }
Example #8
0
        /// <summary>Creates a new uninitialized unmanaged object with a reference count of one.</summary>
        /// <param name = "name">The class name, e.g. "MyView".</param>
        /// <remarks>This is commonly used with exported types which can be created via managed code
        /// (as opposed to via Interface Builder).</remarks>
        public static IntPtr AllocInstance(string name)
        {
            Class klass = new Class(name);

            IntPtr exception = IntPtr.Zero;
            IntPtr instance  = DirectCalls.Callp(klass, Selector.Alloc, ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            return(instance);
        }
Example #9
0
        // Note that if we don't do all of this caching the memory tests fail.
        private SignatureInfo DoClassSelectorToSig(IntPtr target, IntPtr selector)
        {
            SignatureInfo info = null;

            IntPtr exception = IntPtr.Zero;
            IntPtr id        = DirectCalls.Callp(target, klass, ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            lock (ms_lock)
            {
                KeyValuePair <IntPtr, IntPtr> key = new KeyValuePair <IntPtr, IntPtr>(id, selector);
                if (!ms_selectorTable.TryGetValue(key, out info))
                {
                    // If target's class is itself then target is a class and we need to use
                    // methodSignatureForSelector to get the class method. Otherwise we'll use
                    // instanceMethodSignatureForSelector to see if the class has an instance
                    // method. If that fails we'll fall back on DoInstanceSelectorToSig to see
                    // if the instance has the method.
                    IntPtr instance;
                    if (id == target)
                    {
                        instance = DirectCalls.Callpp(id, methodSignatureForSelector, selector, ref exception);
                    }
                    else
                    {
                        instance = DirectCalls.Callpp(id, instanceMethodSignatureForSelector, selector, ref exception);
                    }

                    if (exception != IntPtr.Zero)
                    {
                        CocoaException.Raise(exception);
                    }

                    if (instance != IntPtr.Zero)
                    {
                        info = new SignatureInfo(instance);
                        ms_selectorTable.Add(key, info);
                    }
                }
            }

            return(info);
        }
Example #10
0
        public int hash()
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            int hash = 0;

            if (m_instance != IntPtr.Zero)
            {
                IntPtr exception = IntPtr.Zero;
                hash = DirectCalls.Calli(this, Selector.Hash, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }
            }

            return(hash);
        }
Example #11
0
        /// <exclude/>
        public uint retainCount()
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            uint count = uint.MaxValue;

            if (m_instance != IntPtr.Zero)
            {
                IntPtr exception = IntPtr.Zero;
                count = unchecked ((uint)DirectCalls.Calli(m_instance, Selector.RetainCount, ref exception));
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }
            }

            return(count);
        }
Example #12
0
        /// <exclude/>
        public void release()
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            uint oldCount = retainCount();

            IntPtr exception = IntPtr.Zero;

            Unused.Value = DirectCalls.Callp(m_instance, Selector.Release, ref exception);
            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            if (oldCount == 1)
            {
                m_deallocated = true;                           // OnDealloc won't be called for registered types so we'll go ahead and set dealloced here
            }
        }
Example #13
0
        private SignatureInfo DoInstanceSelectorToSig(IntPtr target, IntPtr selector)
        {
            IntPtr exception = IntPtr.Zero;
            IntPtr instance  = DirectCalls.Callpp(target, methodSignatureForSelector, selector, ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            if (instance == IntPtr.Zero)
            {
                string cn = new NSObject(target).class_().Name;
                string sn = new Selector(selector).Name;
                throw new InvalidCallException(string.Format("Couldn't find the method signature for {0} {1}", cn, sn));
            }

            return(new SignatureInfo(instance));
        }
Example #14
0
        public bool isEqual(NSObject rhs)
        {
            Contract.Requires(!m_deallocated, "ref count is zero");

            bool equal = m_instance == (IntPtr)rhs;

            if (!equal && m_instance != IntPtr.Zero)
            {
                IntPtr exception = IntPtr.Zero;
                byte   result    = DirectCalls.CallCp(this, Selector.IsEqual, rhs, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }

                equal = result != 0;
            }

            return(equal);
        }
Example #15
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);
        }
Example #16
0
        public SignatureInfo(IntPtr sig)
        {
            Contract.Requires(sig != IntPtr.Zero, "sig is nil");

            // Get the return encoding.
            IntPtr exception = IntPtr.Zero;
            IntPtr buffer    = DirectCalls.Callp(sig, methodReturnType, ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            m_return = Marshal.PtrToStringAnsi(buffer);

            // Get the number of arguments.
            int count = DirectCalls.Calli(sig, numberOfArguments, ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            // Get the encodings for each argument.
            m_args = new string[count];
            for (int i = 0; i < count; ++i)
            {
                buffer = DirectCalls.Callpi(sig, getArgumentTypeAtIndex, i, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }

                m_args[i] = Marshal.PtrToStringAnsi(buffer);
            }
        }
Example #17
0
        private static void DoInitClass(string name, string baseName, Type type, string outlets)
        {
            Class superClass = new Class(baseName);

            IntPtr exception = IntPtr.Zero;
            IntPtr klass     = CreateClass(superClass, name, ref exception);

            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }

            if (outlets != null)
            {
                string[] ivnames = outlets.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                int  size      = Marshal.SizeOf(typeof(IntPtr));
                byte alignment = (byte)Math.Log(size, 2);
                foreach (string ivname in ivnames)
                {
                    byte added = class_addIvar(klass, ivname, new IntPtr(size), alignment, "@");
                    if (added == 0)
                    {
                        throw new ArgumentException(string.Format("Couldn't add outlet {0} to {1}. Is there already an outlet with that name?", ivname, name));
                    }
                }
            }

            BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;

            foreach (MethodInfo info in type.GetMethods(flags))
            {
                if (!info.IsSpecialName && info.DeclaringType.Name != "NSObject")
                {
                    if (info.Name == "dealloc")
                    {
                        throw new ArgumentException(string.Format("Instead of using {0}::{1}, override OnDealloc.", type, info.Name));
                    }

                    RegisterAttribute attr = Attribute.GetCustomAttribute(info, typeof(RegisterAttribute), false) as RegisterAttribute;
                    if (attr != null)
                    {
                        DoAddMethod(name, info, attr.Name ?? info.Name, klass, superClass);
                    }
                    else if (char.IsLower(info.Name[0]))
                    {
                        if (info.GetParameters().Length == 0)
                        {
                            DoAddMethod(name, info, info.Name, klass, superClass);
                        }

                        else if (info.GetParameters().Length == 1)
                        {
                            DoAddMethod(name, info, info.Name + ":", klass, superClass);
                        }

                        else if (info.GetParameters().Length >= 2 && info.Name.Contains("_"))
                        {
                            DoAddMethod(name, info, info.Name.Replace('_', ':') + ":", klass, superClass);
                        }

                        else
                        {
                            DoAddMethod(name, info, info.Name, klass, superClass);
                        }
                    }
                }
            }

            MethodInfo info2 = typeof(NSObject).GetMethod("Deallocated", BindingFlags.Instance | BindingFlags.NonPublic);

            DoAddMethod(name, info2, "dealloc", klass, superClass);

            RegisterClass(klass, ref exception);
            if (exception != IntPtr.Zero)
            {
                CocoaException.Raise(exception);
            }
        }
Example #18
0
        /// <summary>Get or set an ivar.</summary>
        /// <remarks>Usually these will be Interface Builder outlets.</remarks>
        public NSObject this[string ivarName]
        {
            get
            {
                Contract.Requires(!string.IsNullOrEmpty(ivarName), "ivarName is null or empty");
                Contract.Requires(!m_deallocated, "ref count is zero");

                NSObject result;

                if (m_instance != IntPtr.Zero)
                {
                    IntPtr value = IntPtr.Zero;
                    IntPtr ivar  = object_getInstanceVariable(m_instance, ivarName, ref value);

                    if (ivar == IntPtr.Zero)
                    {
                        throw new ArgumentException(ivarName + " isn't a valid instance variable");
                    }

                    result = Lookup(value);
                }
                else
                {
                    result = new NSObject(IntPtr.Zero);
                }

                return(result);
            }

            set
            {
                Contract.Requires(!string.IsNullOrEmpty(ivarName), "ivarName is null or empty");
                Contract.Requires(!m_deallocated, "ref count is zero");

                if (m_instance != IntPtr.Zero)
                {
                    // Retain the new value (if any).
                    IntPtr exception = IntPtr.Zero, dummy = IntPtr.Zero;
                    if (!NSObject.IsNullOrNil(value))
                    {
                        Unused.Value = DirectCalls.Callp(value, Selector.Retain, ref exception);
                        if (exception != IntPtr.Zero)
                        {
                            CocoaException.Raise(exception);
                        }
                    }

                    // Release the old value (if any).
                    IntPtr oldValue = IntPtr.Zero;
                    IntPtr ivar     = object_getInstanceVariable(m_instance, ivarName, ref oldValue);
                    if (ivar == IntPtr.Zero)
                    {
                        Unused.Value = DirectCalls.Callp(value, Selector.Release, ref dummy);
                        throw new ArgumentException(ivarName + " isn't a valid instance variable");
                    }

                    if (oldValue != IntPtr.Zero)
                    {
                        Unused.Value = DirectCalls.Callp(oldValue, Selector.Release, ref exception);
                        if (exception != IntPtr.Zero)
                        {
                            Unused.Value = DirectCalls.Callp(value, Selector.Release, ref dummy);
                            CocoaException.Raise(exception);
                        }
                    }

                    // Set the value.
                    ivar = object_setInstanceVariable(m_instance, ivarName, value);
                }
            }
        }
Example #19
0
        /// <summary>Constructs a managed object which is associated with an unmanaged object.</summary>
        /// <remarks>In general multiple NSObject instances can be associated with the same unmanaged object.
        /// The exception is that only one <see cref = "ExportClassAttribute">ExportClassAttribute</see> object can be associated with an
        /// unmanaged object. If an attempt is made to construct two NSObjects pointing to the same
        /// exported object an exception will be thrown. (The reason for this is that exported instances may
        /// have managed state which should be associated with one and only one unmanaged instance).</remarks>
        public NSObject(IntPtr instance)
        {
            m_instance = instance;                                      // note that it's legal to send messages to nil
            m_class    = IntPtr.Zero;

            if (m_instance != IntPtr.Zero)
            {
                // It's a little inefficient to always grab this information, but it makes
                // dumping objects much easier because we can safely do it even when ref
                // counts are zero.
                IntPtr exception = IntPtr.Zero;
                m_class = DirectCalls.Callp(m_instance, Selector.Class, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }

                m_baseClass = DirectCalls.Callp(m_class, Selector.SuperClass, ref exception);
                if (exception != IntPtr.Zero)
                {
                    CocoaException.Raise(exception);
                }

#if DEBUG
                if (SaveStackTraces)
                {
                    var stack = new System.Diagnostics.StackTrace(1);
                    StackTrace = new string[stack.FrameCount];
                    for (int i = 0; i < stack.FrameCount; ++i)                          // TODO: provide a MaxStackDepth method?
                    {
                        StackFrame frame = stack.GetFrame(i);

                        if (!string.IsNullOrEmpty(frame.GetFileName()))
                        {
                            StackTrace[i] = string.Format("{0}|{1} {2}:{3}", frame.GetMethod().DeclaringType, frame.GetMethod(), frame.GetFileName(), frame.GetFileLineNumber());
                        }
                        else
                        {
                            StackTrace[i] = string.Format("{0}|{1}", frame.GetMethod().DeclaringType, frame.GetMethod());
                        }
                    }
                }
#endif

                lock (ms_instancesLock)
                {
                    bool exported;
                    Type type = GetType();
                    if (!ms_exports.TryGetValue(type, out exported))                            // GetCustomAttribute turns out to be very slow
                    {
                        ExportClassAttribute attr = Attribute.GetCustomAttribute(type, typeof(ExportClassAttribute)) as ExportClassAttribute;
                        exported = attr != null;
                        ms_exports.Add(type, exported);
                    }

                    if (exported)
                    {
                        if (ms_instances.ContainsKey(instance))
                        {
                            throw new InvalidOperationException(type + " is being constructed twice with the same id, try using the Lookup method.");
                        }

                        ms_instances.Add(instance, this);
                    }
                }
#if DEBUG
                ms_refs.Add(this);
#endif
            }
        }