From c916037773d7d3d8d37ca2c5a8899b7b728e377d Mon Sep 17 00:00:00 2001 From: Owen Fraser-Green Date: Tue, 23 Mar 2004 12:10:32 +0000 Subject: First checkin of the Mono bindings. --- mono/ProxyBuilder.cs | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 mono/ProxyBuilder.cs (limited to 'mono/ProxyBuilder.cs') diff --git a/mono/ProxyBuilder.cs b/mono/ProxyBuilder.cs new file mode 100644 index 00000000..8e170c74 --- /dev/null +++ b/mono/ProxyBuilder.cs @@ -0,0 +1,301 @@ +namespace DBus +{ + using System; + using System.Runtime.InteropServices; + using System.Diagnostics; + using System.Collections; + using System.Threading; + using System.Reflection; + using System.Reflection.Emit; + + internal class ProxyBuilder + { + private Service service= null; + private string pathName = null; + private Type type = null; + private Introspector introspector = null; + private AssemblyBuilder proxyAssembly; + + private static MethodInfo Service_NameMI = typeof(Service).GetMethod("get_Name", + new Type[0]); + private static MethodInfo Service_ConnectionMI = typeof(Service).GetMethod("get_Connection", + new Type[0]); + private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments", + new Type[0]); + private static MethodInfo Arguments_InitAppendingMI = typeof(Arguments).GetMethod("InitAppending", + new Type[0]); + private static MethodInfo Arguments_AppendMI = typeof(Arguments).GetMethod("Append", + new Type[] {typeof(DBusType.IDBusType)}); + private static MethodInfo Message_SendWithReplyAndBlockMI = typeof(Message).GetMethod("SendWithReplyAndBlock", + new Type[0]); + private static MethodInfo Arguments_GetEnumeratorMI = typeof(Arguments).GetMethod("GetEnumerator", + new Type[0]); + private static MethodInfo IEnumerator_MoveNextMI = typeof(System.Collections.IEnumerator).GetMethod("MoveNext", + new Type[0]); + private static MethodInfo IEnumerator_CurrentMI = typeof(System.Collections.IEnumerator).GetMethod("get_Current", + new Type[0]); + private static MethodInfo Type_GetTypeFromHandleMI = typeof(System.Type).GetMethod("GetTypeFromHandle", + new Type[] {typeof(System.RuntimeTypeHandle)}); + private static MethodInfo IDBusType_GetMI = typeof(DBusType.IDBusType).GetMethod("Get", + new Type[] {typeof(System.Type)}); + private static ConstructorInfo MethodCall_C = typeof(MethodCall).GetConstructor(new Type[] {typeof(Service), + typeof(string), + typeof(string), + typeof(string)}); + + + + public ProxyBuilder(Service service, Type type, string pathName) + { + this.service = service; + this.pathName = pathName; + this.type = type; + this.introspector = new Introspector(type); + } + + private void BuildMethod(MethodInfo method, + ref TypeBuilder typeB, + FieldInfo serviceF, + FieldInfo interfaceF, + FieldInfo pathF) + { + ParameterInfo[] pars = method.GetParameters(); + Type[] parTypes = new Type[pars.Length]; + for (int parN = 0; parN < pars.Length; parN++) { + parTypes[parN] = pars[parN].ParameterType; + } + + // Generate the code + MethodBuilder methodBuilder = typeB.DefineMethod(method.Name, + MethodAttributes.Public | + MethodAttributes.HideBySig | + MethodAttributes.Virtual, + method.ReturnType, + parTypes); + ILGenerator generator = methodBuilder.GetILGenerator(); + + for (int parN = 0; parN < pars.Length; parN++) { + methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name); + } + + // Generate the locals + LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall)); + methodCallL.SetLocalSymInfo("methodCall"); + LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn)); + replyL.SetLocalSymInfo("reply"); + LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator)); + enumeratorL.SetLocalSymInfo("enumerator"); + + if (method.ReturnType != typeof(void)) { + LocalBuilder retvalL = generator.DeclareLocal(method.ReturnType); + retvalL.SetLocalSymInfo("retval"); + } + + //generator.EmitWriteLine("MethodCall methodCall = new MethodCall(...)"); + generator.Emit(OpCodes.Ldsfld, serviceF); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, pathF); + generator.Emit(OpCodes.Ldsfld, interfaceF); + generator.Emit(OpCodes.Ldstr, method.Name); + generator.Emit(OpCodes.Newobj, MethodCall_C); + generator.Emit(OpCodes.Stloc_0); + + //generator.EmitWriteLine("methodCall.Arguments.InitAppending()"); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null); + generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null); + + for (int parN = 0; parN < pars.Length; parN++) { + ParameterInfo par = pars[parN]; + if (!par.IsOut) { + EmitIn(generator, par.ParameterType, parN); + } + } + + //generator.EmitWriteLine("MethodReturn reply = methodCall.SendWithReplyAndBlock()"); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, Message_SendWithReplyAndBlockMI, null); + generator.Emit(OpCodes.Stloc_1); + + //generator.EmitWriteLine("IEnumerator enumeartor = reply.Arguments.GetEnumerator()"); + generator.Emit(OpCodes.Ldloc_1); + generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null); + generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null); + generator.Emit(OpCodes.Stloc_2); + + // handle the return value + if (method.ReturnType != typeof(void)) { + EmitOut(generator, method.ReturnType, 0); + } + + for (int parN = 0; parN < pars.Length; parN++) { + ParameterInfo par = pars[parN]; + if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) { + EmitOut(generator, par.ParameterType, parN); + } + } + + if (method.ReturnType != typeof(void)) { + generator.Emit(OpCodes.Ldloc_3); + } + + generator.Emit(OpCodes.Ret); + + // Generate the method + typeB.DefineMethodOverride(methodBuilder, method); + } + + private void EmitIn(ILGenerator generator, Type parType, int parN) + { + Type inParType = Arguments.MatchType(parType); + //generator.EmitWriteLine("methodCall.Arguments.Append(...)"); + generator.Emit(OpCodes.Ldloc_0); + generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null); + generator.Emit(OpCodes.Ldarg_S, parN + 1); + + // Call the DBusType EmitMarshalIn to make it emit itself + object[] pars = new object[] {generator, parType}; + inParType.InvokeMember("EmitMarshalIn", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null); + + generator.Emit(OpCodes.Newobj, Arguments.GetDBusTypeConstructor(inParType, parType)); + generator.EmitCall(OpCodes.Callvirt, Arguments_AppendMI, null); + } + + private void EmitOut(ILGenerator generator, Type parType, int parN) + { + Type outParType = Arguments.MatchType(parType); + //generator.EmitWriteLine("enumerator.MoveNext()"); + generator.Emit(OpCodes.Ldloc_2); + generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null); + + //generator.EmitWriteLine("return (" + parType + ") ((DBusType.IDBusType) enumerator.Current).Get(typeof(" + parType + "))"); + generator.Emit(OpCodes.Pop); + if (parN > 0) { + generator.Emit(OpCodes.Ldarg_S, parN + 1); + } + + generator.Emit(OpCodes.Ldloc_2); + generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null); + generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType)); + generator.Emit(OpCodes.Ldtoken, parType); + generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null); + generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null); + + // Call the DBusType EmitMarshalOut to make it emit itself + object[] pars = new object[] {generator, parType, parN == 0}; + outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null); + + if (parN == 0) { + generator.Emit(OpCodes.Stloc_3); + } + } + + public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo interfaceF, FieldInfo pathF) + { + Type[] pars = {typeof(Service), typeof(string), typeof(string)}; + ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | + MethodAttributes.Public, + CallingConventions.Standard, pars); + + ILGenerator generator = constructor.GetILGenerator(); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Call, this.introspector.Constructor); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Stsfld, serviceF); + generator.Emit(OpCodes.Ldarg_2); + generator.Emit(OpCodes.Stsfld, interfaceF); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_3); + generator.Emit(OpCodes.Stfld, pathF); + + generator.Emit(OpCodes.Ret); + } + + public object GetProxy() + { + + // Build the type + TypeBuilder typeB = ServiceModuleBuilder.DefineType(ProxyName, TypeAttributes.Public, this.type); + //type.AddInterfaceImplementation(typeof(IProxy)); + + FieldBuilder serviceF = typeB.DefineField("service", + typeof(Service), + FieldAttributes.Private | + FieldAttributes.Static); + FieldBuilder interfaceF = typeB.DefineField("interfaceName", + typeof(string), + FieldAttributes.Private | + FieldAttributes.Static); + FieldBuilder pathF = typeB.DefineField("pathName", + typeof(string), + FieldAttributes.Private); + + BuildConstructor(ref typeB, serviceF, interfaceF, pathF); + + // Build the methods + foreach (MethodInfo method in this.introspector.Methods) { + BuildMethod(method, ref typeB, serviceF, interfaceF, pathF); + } + + Type [] parTypes = new Type[] {typeof(Service), typeof(string), typeof(string)}; + object [] pars = new object[] {Service, this.introspector.InterfaceName, pathName}; + + Type proxyType = typeB.CreateType(); + + // Uncomment the following line to produce a DLL of the + // constructed assembly which can then be examined using + // monodis. Note that in order for this to work you should copy + // the client assembly as a dll file so that monodis can pick it + // up. + //ProxyAssembly.Save("proxy.dll"); + + ConstructorInfo constructor = proxyType.GetConstructor(parTypes); + object instance = constructor.Invoke(pars); + return instance; + } + + private ModuleBuilder ServiceModuleBuilder + { + get + { + if (Service.module == null) { + Service.module = ProxyAssembly.DefineDynamicModule(Service.Name, "proxy.dll", true); + } + + return Service.module; + } + } + + private Service Service + { + get + { + return this.service; + } + } + + private string ProxyName + { + get + { + return this.introspector.InterfaceName + ".Proxy"; + } + } + + private AssemblyBuilder ProxyAssembly + { + get + { + if (this.proxyAssembly == null){ + AssemblyName assemblyName = new AssemblyName(); + assemblyName.Name = "DBusProxy"; + this.proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, + AssemblyBuilderAccess.RunAndSave); + } + + return this.proxyAssembly; + } + } + } +} + -- cgit