Example #1
0
        public void InvokeMethod(IntPtr m, IntPtr t, IntPtr p, IntPtr r)
        {
            using (var method = new NetMethodInfo(m))
                using (var target = new NetReference(t))
                    using (var parameters = new NetVariantList(p))
                        using (var result = r != IntPtr.Zero ? new NetVariant(r) : null)
                        {
                            CodeGen.CodeGen.InvokeMethodDelegate del;
                            if (!_cachedInvokeMethods.TryGetValue(method.Id, out del))
                            {
                                del = CodeGen.CodeGen.BuildInvokeMethodDelegate(method);
                                _cachedInvokeMethods[method.Id] = del;
                            }

                            Task resultTask = null;
                            del(target, parameters, result, ref resultTask);

                            if (QmlNetConfig.ListenForExceptionsWhenInvokingTasks)
                            {
                                resultTask?.ContinueWith(
                                    task =>
                                {
                                    QmlNetConfig.RaiseUnhandledTaskException(task.Exception);
                                },
                                    TaskContinuationOptions.OnlyOnFaulted);
                            }
                        }
        }
Example #2
0
        public override void InvokeMethod(NetMethodInfo methodInfo, NetInstance target, NetVariantVector parameters,
                                          NetVariant result)
        {
            var handle = (GCHandle)target.GetGCHandle();
            var o      = handle.Target;

            List <object> methodParameters = null;

            if (parameters.Count > 0)
            {
                methodParameters = new List <object>();
                foreach (var parameterInstance in parameters)
                {
                    object v = null;
                    Unpackvalue(ref v, parameterInstance);
                    methodParameters.Add(v);
                }
            }

            var r = o.GetType()
                    .GetMethod(methodInfo.GetMethodName(), BindingFlags.Instance | BindingFlags.Public)
                    .Invoke(o, methodParameters?.ToArray());

            if (result == null)
            {
                // this method doesn't have return type
            }
            else
            {
                PackValue(ref r, result);
            }
        }
Example #3
0
        public static InvokeMethodDelegate BuildInvokeMethodDelegate(NetMethodInfo methodInfo)
        {
            var invokeType     = Type.GetType(methodInfo.ParentType.FullTypeName);
            var parameterTypes = new List <Type>();

            for (var x = 0; x < methodInfo.ParameterCount; x++)
            {
                using (var p = methodInfo.GetParameter(x))
                    using (var t = p.Type)
                    {
                        parameterTypes.Add(Type.GetType(t.FullTypeName));
                    }
            }
            var invokeMethod = invokeType.GetMethod(methodInfo.MethodName, parameterTypes.ToArray());

            return(BuildInvokeMethodDelegate(invokeMethod));
        }
Example #4
0
        public void LoadTypeInfo(IntPtr t)
        {
            using (var type = new NetTypeInfo(t))
            {
                var typeInfo = Type.GetType(type.FullTypeName);
                if (typeInfo == null)
                {
                    throw new InvalidOperationException($"Invalid type {type.FullTypeName}");
                }

                // Don't grab properties and methods for system-level types.
                if (Helpers.IsPrimitive(typeInfo))
                {
                    return;
                }

                if (typeInfo.IsArray)
                {
                    type.IsArray = true;
                }
                else
                {
                    if (typeof(IList).IsAssignableFrom(typeInfo))
                    {
                        type.IsList = true;
                    }
                    else if (typeInfo.IsGenericType)
                    {
                        if (typeof(IList <>).IsAssignableFrom(typeInfo.GetGenericTypeDefinition()))
                        {
                            type.IsList = true;
                        }
                    }
                }

                if (typeof(IQmlComponentCompleted).IsAssignableFrom(typeInfo))
                {
                    type.HasComponentCompleted = true;
                }

                if (typeof(IQmlObjectDestroyed).IsAssignableFrom(typeInfo))
                {
                    type.HasObjectDestroyed = true;
                }

                foreach (var methodInfo in typeInfo.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
                {
                    if (methodInfo.IsGenericMethod)
                    {
                        continue;                             // No generics supported.
                    }
                    if (Helpers.IsPrimitive(methodInfo.DeclaringType))
                    {
                        continue;
                    }

                    if (methodInfo.IsSpecialName)
                    {
                        continue;                           // Ignore the property get/set methods.
                    }
                    NetTypeInfo returnType = null;

                    if (methodInfo.ReturnParameter != null && methodInfo.ReturnParameter.ParameterType != typeof(void))
                    {
                        returnType =
                            NetTypeManager.GetTypeInfo(methodInfo.ReturnParameter.ParameterType);
                    }

                    var method = new NetMethodInfo(type, methodInfo.Name, returnType, methodInfo.IsStatic);

                    foreach (var parameter in methodInfo.GetParameters())
                    {
                        method.AddParameter(parameter.Name, NetTypeManager.GetTypeInfo(parameter.ParameterType));
                    }

                    type.AddMethod(method);
                }

                var signals = new Dictionary <string, NetSignalInfo>();

                foreach (var signalAttribute in typeInfo.GetCustomAttributes(false).OfType <SignalAttribute>())
                {
                    if (string.IsNullOrEmpty(signalAttribute.Name))
                    {
                        throw new InvalidOperationException($"Signal name was null for {typeInfo.Name}");
                    }

                    if (!char.IsLower(signalAttribute.Name[0]))
                    {
                        throw new InvalidOperationException($"Signal {signalAttribute.Name} for {typeInfo.Name} must begin with a lower case letter.");
                    }

                    var signal = new NetSignalInfo(type, signalAttribute.Name);
                    foreach (var parameter in signalAttribute.Parameters)
                    {
                        signal.AddParameter(parameter);
                    }
                    type.AddSignal(signal);
                    signals.Add(signal.Name, signal);
                }

                foreach (var propertyInfo in typeInfo.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
                {
                    if (Helpers.IsPrimitive(propertyInfo.DeclaringType))
                    {
                        continue;
                    }

                    NetSignalInfo notifySignal          = null;
                    var           notifySignalAttribute = propertyInfo.GetCustomAttribute <NotifySignalAttribute>();
                    if (notifySignalAttribute != null)
                    {
                        var name = notifySignalAttribute.Name;
                        if (string.IsNullOrEmpty(name))
                        {
                            name = $"{propertyInfo.Name}Changed";
                            name = char.ToLower(name[0]) + name.Substring(1);
                        }

                        if (signals.ContainsKey(name))
                        {
                            notifySignal = signals[name];

                            // Make sure the signal we are referencing has no parameters.
                            if (notifySignal.ParameterCount != 0)
                            {
                                // TODO: They can actually of parameters, but not implemented yet.
                                throw new Exception("Notify signals must have no parameters.");
                            }
                        }
                        else
                        {
                            if (!char.IsLower(name[0]))
                            {
                                throw new InvalidOperationException($"Signal {name} for {typeInfo.Name} must begin with a lower case letter.");
                            }

                            notifySignal = new NetSignalInfo(type, name);
                            type.AddSignal(notifySignal);
                        }
                    }

                    using (var property = new NetPropertyInfo(
                               type,
                               propertyInfo.Name,
                               NetTypeManager.GetTypeInfo(propertyInfo.PropertyType),
                               propertyInfo.CanRead,
                               propertyInfo.CanWrite,
                               notifySignal))
                    {
                        foreach (var indexParameter in propertyInfo.GetIndexParameters())
                        {
                            property.AddIndexParameter(indexParameter.Name, NetTypeManager.GetTypeInfo(indexParameter.ParameterType));
                        }

                        type.AddProperty(property);
                    }
                }

                // NOTE: This type is going to get a typeInfo object
                // with IsLoading=true and IsLoaded=false. It technically
                // is loaded, but it's misleading.
                InteropBehaviors.OnNetTypeInfoCreated(type, typeInfo);
            }
        }
Example #5
0
        public void InvokeMethod(IntPtr m, IntPtr t, IntPtr p, IntPtr r)
        {
            using (var method = new NetMethodInfo(m))
                using (var target = new NetReference(t))
                    using (var parameters = new NetVariantList(p))
                        using (var result = r != IntPtr.Zero ? new NetVariant(r) : null)
                        {
                            var instance = target.Instance;

                            List <object> methodParameters = null;

                            if (parameters.Count > 0)
                            {
                                methodParameters = new List <object>();
                                var parameterCount = parameters.Count;
                                for (var x = 0; x < parameterCount; x++)
                                {
                                    object v = null;
                                    Helpers.Unpackvalue(ref v, parameters.Get(x));
                                    methodParameters.Add(v);
                                }
                            }

                            MethodInfo methodInfo = null;
                            var        methodName = method.MethodName;
                            var        methods    = instance.GetType()
                                                    .GetMethods(BindingFlags.Instance | BindingFlags.Public)
                                                    .Where(x => x.Name == methodName)
                                                    .ToList();

                            if (methods.Count == 1)
                            {
                                methodInfo = methods[0];
                            }
                            else if (methods.Count > 1)
                            {
                                // This is an overload.

                                // TODO: Make this more performant. https://github.com/pauldotknopf/Qml.Net/issues/39

                                // Get all the parameters for the method we are invoking.
                                var parameterTypes = method.GetAllParameters().Select(x => x.Type.FullTypeName).ToList();

                                // And find a good method to invoke.
                                foreach (var potentialMethod in methods)
                                {
                                    var potentialMethodParameters = potentialMethod.GetParameters();
                                    if (potentialMethodParameters.Length != parameterTypes.Count)
                                    {
                                        continue;
                                    }

                                    bool valid = true;
                                    for (var x = 0; x < potentialMethodParameters.Length; x++)
                                    {
                                        if (potentialMethodParameters[x].ParameterType.AssemblyQualifiedName != parameterTypes[x])
                                        {
                                            valid = false;
                                            break;
                                        }
                                    }

                                    if (valid)
                                    {
                                        methodInfo = potentialMethod;
                                        break;
                                    }
                                }
                            }

                            if (methodInfo == null)
                            {
                                throw new InvalidOperationException($"Invalid method name {method.MethodName}");
                            }

                            var returnObject = methodInfo.Invoke(instance, methodParameters?.ToArray());

                            if (result == null)
                            {
                                // this method doesn't have return type
                            }
                            else
                            {
                                Helpers.PackValue(returnObject, result);
                            }
                        }
        }