4 using System.Runtime.InteropServices;
5 using System.Diagnostics;
6 using System.Collections;
7 using System.Threading;
8 using System.Reflection;
9 using System.Reflection.Emit;
11 internal class ProxyBuilder
13 private Service service= null;
14 private string pathName = null;
15 private Type type = null;
16 private Introspector introspector = null;
17 private static AssemblyBuilder proxyAssembly;
19 private static MethodInfo Service_NameMI = typeof(Service).GetMethod("get_Name",
21 private static MethodInfo Service_ConnectionMI = typeof(Service).GetMethod("get_Connection",
23 private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments",
25 private static MethodInfo Arguments_InitAppendingMI = typeof(Arguments).GetMethod("InitAppending",
27 private static MethodInfo Arguments_AppendMI = typeof(Arguments).GetMethod("Append",
28 new Type[] {typeof(DBusType.IDBusType)});
29 private static MethodInfo Message_SendWithReplyAndBlockMI = typeof(Message).GetMethod("SendWithReplyAndBlock",
31 private static MethodInfo Arguments_GetEnumeratorMI = typeof(Arguments).GetMethod("GetEnumerator",
33 private static MethodInfo IEnumerator_MoveNextMI = typeof(System.Collections.IEnumerator).GetMethod("MoveNext",
35 private static MethodInfo IEnumerator_CurrentMI = typeof(System.Collections.IEnumerator).GetMethod("get_Current",
37 private static MethodInfo Type_GetTypeFromHandleMI = typeof(System.Type).GetMethod("GetTypeFromHandle",
38 new Type[] {typeof(System.RuntimeTypeHandle)});
39 private static MethodInfo IDBusType_GetMI = typeof(DBusType.IDBusType).GetMethod("Get",
40 new Type[] {typeof(System.Type)});
41 private static ConstructorInfo MethodCall_C = typeof(MethodCall).GetConstructor(new Type[] {typeof(Service),
48 public ProxyBuilder(Service service, Type type, string pathName)
50 this.service = service;
51 this.pathName = pathName;
53 this.introspector = Introspector.GetIntrospector(type);
56 private void BuildMethod(MethodInfo method,
57 InterfaceProxy interfaceProxy,
58 ref TypeBuilder typeB,
62 ParameterInfo[] pars = method.GetParameters();
63 Type[] parTypes = new Type[pars.Length];
64 for (int parN = 0; parN < pars.Length; parN++) {
65 parTypes[parN] = pars[parN].ParameterType;
69 MethodBuilder methodBuilder = typeB.DefineMethod(method.Name,
70 MethodAttributes.Public |
71 MethodAttributes.HideBySig |
72 MethodAttributes.Virtual,
75 ILGenerator generator = methodBuilder.GetILGenerator();
77 for (int parN = 0; parN < pars.Length; parN++) {
78 methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name);
81 // Generate the locals
82 LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall));
83 methodCallL.SetLocalSymInfo("methodCall");
84 LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn));
85 replyL.SetLocalSymInfo("reply");
86 LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
87 enumeratorL.SetLocalSymInfo("enumerator");
89 if (method.ReturnType != typeof(void)) {
90 LocalBuilder retvalL = generator.DeclareLocal(method.ReturnType);
91 retvalL.SetLocalSymInfo("retval");
94 //generator.EmitWriteLine("MethodCall methodCall = new MethodCall(...)");
95 generator.Emit(OpCodes.Ldsfld, serviceF);
96 generator.Emit(OpCodes.Ldarg_0);
97 generator.Emit(OpCodes.Ldfld, pathF);
98 generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName);
99 generator.Emit(OpCodes.Ldstr, method.Name);
100 generator.Emit(OpCodes.Newobj, MethodCall_C);
101 generator.Emit(OpCodes.Stloc_0);
103 //generator.EmitWriteLine("methodCall.Arguments.InitAppending()");
104 generator.Emit(OpCodes.Ldloc_0);
105 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
106 generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null);
108 for (int parN = 0; parN < pars.Length; parN++) {
109 ParameterInfo par = pars[parN];
111 EmitIn(generator, par.ParameterType, parN, serviceF);
115 //generator.EmitWriteLine("MethodReturn reply = methodCall.SendWithReplyAndBlock()");
116 generator.Emit(OpCodes.Ldloc_0);
117 generator.EmitCall(OpCodes.Callvirt, Message_SendWithReplyAndBlockMI, null);
118 generator.Emit(OpCodes.Stloc_1);
120 //generator.EmitWriteLine("IEnumerator enumeartor = reply.Arguments.GetEnumerator()");
121 generator.Emit(OpCodes.Ldloc_1);
122 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
123 generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
124 generator.Emit(OpCodes.Stloc_2);
126 // handle the return value
127 if (method.ReturnType != typeof(void)) {
128 EmitOut(generator, method.ReturnType, 0);
131 for (int parN = 0; parN < pars.Length; parN++) {
132 ParameterInfo par = pars[parN];
133 if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
134 EmitOut(generator, par.ParameterType, parN);
138 if (method.ReturnType != typeof(void)) {
139 generator.Emit(OpCodes.Ldloc_3);
142 generator.Emit(OpCodes.Ret);
144 // Generate the method
145 typeB.DefineMethodOverride(methodBuilder, method);
148 private void EmitIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
150 Type inParType = Arguments.MatchType(parType);
151 //generator.EmitWriteLine("methodCall.Arguments.Append(...)");
152 generator.Emit(OpCodes.Ldloc_0);
153 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
154 generator.Emit(OpCodes.Ldarg_S, parN + 1);
156 // Call the DBusType EmitMarshalIn to make it emit itself
157 object[] pars = new object[] {generator, parType};
158 inParType.InvokeMember("EmitMarshalIn", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
160 generator.Emit(OpCodes.Ldsfld, serviceF);
161 generator.Emit(OpCodes.Newobj, Arguments.GetDBusTypeConstructor(inParType, parType));
162 generator.EmitCall(OpCodes.Callvirt, Arguments_AppendMI, null);
165 private void EmitOut(ILGenerator generator, Type parType, int parN)
167 Type outParType = Arguments.MatchType(parType);
168 //generator.EmitWriteLine("enumerator.MoveNext()");
169 generator.Emit(OpCodes.Ldloc_2);
170 generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
172 //generator.EmitWriteLine("return (" + parType + ") ((DBusType.IDBusType) enumerator.Current).Get(typeof(" + parType + "))");
173 generator.Emit(OpCodes.Pop);
175 generator.Emit(OpCodes.Ldarg_S, parN + 1);
178 generator.Emit(OpCodes.Ldloc_2);
179 generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null);
180 generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType));
181 generator.Emit(OpCodes.Ldtoken, parType);
182 generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null);
183 generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null);
185 // Call the DBusType EmitMarshalOut to make it emit itself
186 object[] pars = new object[] {generator, parType, parN == 0};
187 outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
190 generator.Emit(OpCodes.Stloc_3);
194 public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
196 Type[] pars = {typeof(Service), typeof(string)};
197 ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName |
198 MethodAttributes.Public,
199 CallingConventions.Standard, pars);
201 ILGenerator generator = constructor.GetILGenerator();
202 generator.Emit(OpCodes.Ldarg_0);
203 generator.Emit(OpCodes.Call, this.introspector.Constructor);
204 generator.Emit(OpCodes.Ldarg_1);
205 generator.Emit(OpCodes.Stsfld, serviceF);
206 generator.Emit(OpCodes.Ldarg_0);
207 generator.Emit(OpCodes.Ldarg_2);
208 generator.Emit(OpCodes.Stfld, pathF);
210 generator.Emit(OpCodes.Ret);
213 public object GetProxy()
216 Type proxyType = ProxyAssembly.GetType(ProxyName);
218 if (proxyType == null) {
220 TypeBuilder typeB = ServiceModuleBuilder.DefineType(ProxyName, TypeAttributes.Public, this.type);
222 FieldBuilder serviceF = typeB.DefineField("service",
224 FieldAttributes.Private |
225 FieldAttributes.Static);
226 FieldBuilder pathF = typeB.DefineField("pathName",
228 FieldAttributes.Private);
230 BuildConstructor(ref typeB, serviceF, pathF);
233 foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
234 InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
235 foreach (DictionaryEntry methodEntry in interfaceProxy.Methods) {
236 MethodInfo method = (MethodInfo) methodEntry.Value;
237 BuildMethod(method, interfaceProxy, ref typeB, serviceF, pathF);
241 proxyType = typeB.CreateType();
243 // Uncomment the following line to produce a DLL of the
244 // constructed assembly which can then be examined using
245 // monodis. Note that in order for this to work you should copy
246 // the client assembly as a dll file so that monodis can pick it
248 //ProxyAssembly.Save("proxy.dll");
251 Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
252 object [] pars = new object[] {Service, pathName};
254 ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
255 object instance = constructor.Invoke(pars);
259 private ModuleBuilder ServiceModuleBuilder
262 if (Service.module == null) {
263 Service.module = ProxyAssembly.DefineDynamicModule(Service.Name, "proxy.dll", true);
266 return Service.module;
270 private Service Service
277 private string ProxyName
280 return this.introspector.ToString() + ".Proxy";
284 private AssemblyBuilder ProxyAssembly
287 if (proxyAssembly == null){
288 AssemblyName assemblyName = new AssemblyName();
289 assemblyName.Name = "DBusProxy";
290 proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName,
291 AssemblyBuilderAccess.RunAndSave);
294 return proxyAssembly;