Пример #1
0
        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, ":");
            }
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
                }
            }
        }
Пример #4
0
        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
        }
Пример #5
0
            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);
            }
Пример #6
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);
        }