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); } } }
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); } }
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)); }
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); } }
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); } } }