summaryrefslogtreecommitdiffstats
path: root/mono/ProxyBuilder.cs
diff options
context:
space:
mode:
authorOwen Fraser-Green <owen@discobabe.net>2004-03-23 12:10:32 +0000
committerOwen Fraser-Green <owen@discobabe.net>2004-03-23 12:10:32 +0000
commitc916037773d7d3d8d37ca2c5a8899b7b728e377d (patch)
tree21c37372ab9795583e724e8459578b7fe0be330b /mono/ProxyBuilder.cs
parent2195cf0dbde2ae26b5a684c6d914c1711f44c28d (diff)
First checkin of the Mono bindings.
Diffstat (limited to 'mono/ProxyBuilder.cs')
-rw-r--r--mono/ProxyBuilder.cs301
1 files changed, 301 insertions, 0 deletions
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;
+ }
+ }
+ }
+}
+