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;
18 private static MethodInfo Service_NameMI = typeof(Service).GetMethod("get_Name",
20 private static MethodInfo Service_ConnectionMI = typeof(Service).GetMethod("get_Connection",
22 private static MethodInfo Service_AddSignalCalledMI = typeof(Service).GetMethod("add_SignalCalled",
23 new Type[] {typeof(Service.SignalCalledHandler)});
24 private static MethodInfo Signal_PathNameMI = typeof(Signal).GetMethod("get_PathName",
26 private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments",
28 private static MethodInfo Message_KeyMI = typeof(Message).GetMethod("get_Key",
30 private static MethodInfo Arguments_InitAppendingMI = typeof(Arguments).GetMethod("InitAppending",
32 private static MethodInfo Arguments_AppendMI = typeof(Arguments).GetMethod("Append",
33 new Type[] {typeof(DBusType.IDBusType)});
34 private static MethodInfo Message_SendWithReplyAndBlockMI = typeof(Message).GetMethod("SendWithReplyAndBlock",
36 private static MethodInfo Message_SendMI = typeof(Message).GetMethod("Send",
38 private static MethodInfo Message_DisposeMI = typeof(Message).GetMethod("Dispose",
40 private static MethodInfo Arguments_GetEnumeratorMI = typeof(Arguments).GetMethod("GetEnumerator",
42 private static MethodInfo IEnumerator_MoveNextMI = typeof(System.Collections.IEnumerator).GetMethod("MoveNext",
44 private static MethodInfo IEnumerator_CurrentMI = typeof(System.Collections.IEnumerator).GetMethod("get_Current",
46 private static MethodInfo Type_GetTypeFromHandleMI = typeof(System.Type).GetMethod("GetTypeFromHandle",
47 new Type[] {typeof(System.RuntimeTypeHandle)});
48 private static MethodInfo IDBusType_GetMI = typeof(DBusType.IDBusType).GetMethod("Get",
49 new Type[] {typeof(System.Type)});
50 private static ConstructorInfo MethodCall_C = typeof(MethodCall).GetConstructor(new Type[] {typeof(Service),
54 private static ConstructorInfo Signal_C = typeof(Signal).GetConstructor(new Type[] {typeof(Service),
58 private static ConstructorInfo Service_SignalCalledHandlerC = typeof(Service.SignalCalledHandler).GetConstructor(new Type[] {typeof(object),
59 typeof(System.IntPtr)});
60 private static MethodInfo String_opEqualityMI = typeof(System.String).GetMethod("op_Equality",
61 new Type[] {typeof(string),
63 private static MethodInfo MulticastDelegate_opInequalityMI = typeof(System.MulticastDelegate).GetMethod("op_Inequality",
64 new Type[] {typeof(System.MulticastDelegate),
65 typeof(System.MulticastDelegate)});
68 public ProxyBuilder(Service service, Type type, string pathName)
70 this.service = service;
71 this.pathName = pathName;
73 this.introspector = Introspector.GetIntrospector(type);
76 private MethodInfo BuildSignalCalled(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
78 Type[] parTypes = {typeof(Signal)};
79 MethodBuilder methodBuilder = typeB.DefineMethod("Service_SignalCalled",
80 MethodAttributes.Private |
81 MethodAttributes.HideBySig,
85 ILGenerator generator = methodBuilder.GetILGenerator();
87 LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
88 enumeratorL.SetLocalSymInfo("enumerator");
90 Label wrongPath = generator.DefineLabel();
91 //generator.EmitWriteLine("if (signal.PathName == pathName) {");
92 generator.Emit(OpCodes.Ldarg_1);
93 generator.EmitCall(OpCodes.Callvirt, Signal_PathNameMI, null);
94 generator.Emit(OpCodes.Ldarg_0);
95 generator.Emit(OpCodes.Ldfld, pathF);
96 generator.EmitCall(OpCodes.Call, String_opEqualityMI, null);
97 generator.Emit(OpCodes.Brfalse, wrongPath);
101 foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
102 InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
103 foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
104 EventInfo eventE = (EventInfo) signalEntry.Value;
105 // This is really cheeky since we need to grab the event as a private field.
106 FieldInfo eventF = this.type.GetField(eventE.Name,
107 BindingFlags.NonPublic|
108 BindingFlags.Instance);
110 MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke");
112 ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters();
113 parTypes = new Type[pars.Length];
114 for (int parN = 0; parN < pars.Length; parN++) {
115 parTypes[parN] = pars[parN].ParameterType;
116 LocalBuilder parmL = generator.DeclareLocal(parTypes[parN]);
117 parmL.SetLocalSymInfo(pars[parN].Name);
120 Label skip = generator.DefineLabel();
121 //generator.EmitWriteLine(" if (SelectedIndexChanged != null) {");
122 generator.Emit(OpCodes.Ldarg_0);
123 generator.Emit(OpCodes.Ldfld, eventF);
124 generator.Emit(OpCodes.Ldnull);
125 generator.EmitCall(OpCodes.Call, MulticastDelegate_opInequalityMI, null);
126 generator.Emit(OpCodes.Brfalse, skip);
128 //generator.EmitWriteLine(" if (signal.Key == 'la i')");
129 generator.Emit(OpCodes.Ldarg_1);
130 generator.EmitCall(OpCodes.Callvirt, Message_KeyMI, null);
131 generator.Emit(OpCodes.Ldstr, eventE.Name + " " + InterfaceProxy.GetSignature(eventHandler_InvokeMI));
132 generator.EmitCall(OpCodes.Call, String_opEqualityMI, null);
133 generator.Emit(OpCodes.Brfalse, skip);
135 //generator.EmitWriteLine("IEnumerator enumerator = signal.Arguments.GetEnumerator()");
136 generator.Emit(OpCodes.Ldarg_1);
137 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
138 generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
139 generator.Emit(OpCodes.Stloc_0);
141 for (int parN = 0; parN < pars.Length; parN++) {
142 ParameterInfo par = pars[parN];
144 EmitSignalIn(generator, par.ParameterType, parN + localOffset, serviceF);
148 //generator.EmitWriteLine(" SelectedIndexChanged(selectedIndex)");
149 generator.Emit(OpCodes.Ldarg_0);
150 generator.Emit(OpCodes.Ldfld, eventF);
151 for (int parN = 0; parN < pars.Length; parN++) {
152 generator.Emit(OpCodes.Ldloc_S, parN + localOffset);
155 generator.EmitCall(OpCodes.Callvirt, eventHandler_InvokeMI, null);
157 generator.MarkLabel(skip);
158 //generator.EmitWriteLine(" }");
160 localOffset += pars.Length;
164 generator.MarkLabel(wrongPath);
165 //generator.EmitWriteLine("}");
167 //generator.EmitWriteLine("return");
168 generator.Emit(OpCodes.Ret);
170 return methodBuilder;
173 private void BuildSignalHandler(EventInfo eventE,
174 InterfaceProxy interfaceProxy,
175 ref TypeBuilder typeB,
179 MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke");
180 ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters();
181 Type[] parTypes = new Type[pars.Length];
182 for (int parN = 0; parN < pars.Length; parN++) {
183 parTypes[parN] = pars[parN].ParameterType;
187 MethodBuilder methodBuilder = typeB.DefineMethod("Proxy_" + eventE.Name,
188 MethodAttributes.Public |
189 MethodAttributes.HideBySig |
190 MethodAttributes.Virtual,
193 ILGenerator generator = methodBuilder.GetILGenerator();
195 for (int parN = 0; parN < pars.Length; parN++) {
196 methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name);
199 // Generate the locals
200 LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall));
201 methodCallL.SetLocalSymInfo("signal");
203 //generator.EmitWriteLine("Signal signal = new Signal(...)");
204 generator.Emit(OpCodes.Ldsfld, serviceF);
205 generator.Emit(OpCodes.Ldarg_0);
206 generator.Emit(OpCodes.Ldfld, pathF);
207 generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName);
208 generator.Emit(OpCodes.Ldstr, eventE.Name);
209 generator.Emit(OpCodes.Newobj, Signal_C);
210 generator.Emit(OpCodes.Stloc_0);
212 //generator.EmitWriteLine("signal.Arguments.InitAppending()");
213 generator.Emit(OpCodes.Ldloc_0);
214 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
215 generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null);
217 for (int parN = 0; parN < pars.Length; parN++) {
218 ParameterInfo par = pars[parN];
220 EmitIn(generator, par.ParameterType, parN, serviceF);
224 //generator.EmitWriteLine("signal.Send()");
225 generator.Emit(OpCodes.Ldloc_0);
226 generator.EmitCall(OpCodes.Callvirt, Message_SendMI, null);
228 //generator.EmitWriteLine("signal.Dispose()");
229 generator.Emit(OpCodes.Ldloc_0);
230 generator.EmitCall(OpCodes.Callvirt, Message_DisposeMI, null);
232 //generator.EmitWriteLine("return");
233 generator.Emit(OpCodes.Ret);
236 private void BuildMethod(MethodInfo method,
237 InterfaceProxy interfaceProxy,
238 ref TypeBuilder typeB,
242 ParameterInfo[] pars = method.GetParameters();
243 Type[] parTypes = new Type[pars.Length];
244 for (int parN = 0; parN < pars.Length; parN++) {
245 parTypes[parN] = pars[parN].ParameterType;
249 MethodBuilder methodBuilder = typeB.DefineMethod(method.Name,
250 MethodAttributes.Public |
251 MethodAttributes.HideBySig |
252 MethodAttributes.Virtual,
255 ILGenerator generator = methodBuilder.GetILGenerator();
257 for (int parN = 0; parN < pars.Length; parN++) {
258 methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name);
261 // Generate the locals
262 LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall));
263 methodCallL.SetLocalSymInfo("methodCall");
264 LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn));
265 replyL.SetLocalSymInfo("reply");
266 LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
267 enumeratorL.SetLocalSymInfo("enumerator");
269 if (method.ReturnType != typeof(void)) {
270 LocalBuilder retvalL = generator.DeclareLocal(method.ReturnType);
271 retvalL.SetLocalSymInfo("retval");
274 //generator.EmitWriteLine("MethodCall methodCall = new MethodCall(...)");
275 generator.Emit(OpCodes.Ldsfld, serviceF);
276 generator.Emit(OpCodes.Ldarg_0);
277 generator.Emit(OpCodes.Ldfld, pathF);
278 generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName);
279 generator.Emit(OpCodes.Ldstr, method.Name);
280 generator.Emit(OpCodes.Newobj, MethodCall_C);
281 generator.Emit(OpCodes.Stloc_0);
283 //generator.EmitWriteLine("methodCall.Arguments.InitAppending()");
284 generator.Emit(OpCodes.Ldloc_0);
285 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
286 generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null);
288 for (int parN = 0; parN < pars.Length; parN++) {
289 ParameterInfo par = pars[parN];
291 EmitIn(generator, par.ParameterType, parN, serviceF);
295 //generator.EmitWriteLine("MethodReturn reply = methodCall.SendWithReplyAndBlock()");
296 generator.Emit(OpCodes.Ldloc_0);
297 generator.EmitCall(OpCodes.Callvirt, Message_SendWithReplyAndBlockMI, null);
298 generator.Emit(OpCodes.Stloc_1);
300 //generator.EmitWriteLine("IEnumerator enumeartor = reply.Arguments.GetEnumerator()");
301 generator.Emit(OpCodes.Ldloc_1);
302 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
303 generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
304 generator.Emit(OpCodes.Stloc_2);
306 // handle the return value
307 if (method.ReturnType != typeof(void)) {
308 EmitOut(generator, method.ReturnType, 0);
311 for (int parN = 0; parN < pars.Length; parN++) {
312 ParameterInfo par = pars[parN];
313 if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
314 EmitOut(generator, par.ParameterType, parN);
318 // Clean up after ourselves
319 //generator.EmitWriteLine("methodCall.Dispose()");
320 generator.Emit(OpCodes.Ldloc_0);
321 generator.EmitCall(OpCodes.Callvirt, Message_DisposeMI, null);
323 //generator.EmitWriteLine("reply.Dispose()");
324 generator.Emit(OpCodes.Ldloc_1);
325 generator.EmitCall(OpCodes.Callvirt, Message_DisposeMI, null);
327 if (method.ReturnType != typeof(void)) {
328 generator.Emit(OpCodes.Ldloc_3);
331 generator.Emit(OpCodes.Ret);
333 // Generate the method
334 typeB.DefineMethodOverride(methodBuilder, method);
337 private void EmitSignalIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
339 //generator.EmitWriteLine("enumerator.MoveNext()");
340 generator.Emit(OpCodes.Ldloc_0);
341 generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
343 Type outParType = Arguments.MatchType(parType);
344 //generator.EmitWriteLine("int selectedIndex = (int) ((DBusType.IDBusType) enumerator.Current).Get(typeof(int))");
345 generator.Emit(OpCodes.Pop);
346 generator.Emit(OpCodes.Ldloc_0);
347 generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null);
348 generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType));
349 generator.Emit(OpCodes.Ldtoken, parType);
350 generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null);
351 generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null);
352 // Call the DBusType EmitMarshalOut to make it emit itself
353 object[] pars = new object[] {generator, parType, true};
354 outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
355 generator.Emit(OpCodes.Stloc_S, parN);
359 private void EmitIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
361 Type inParType = Arguments.MatchType(parType);
362 //generator.EmitWriteLine("methodCall.Arguments.Append(...)");
363 generator.Emit(OpCodes.Ldloc_0);
364 generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
365 generator.Emit(OpCodes.Ldarg_S, parN + 1);
367 // Call the DBusType EmitMarshalIn to make it emit itself
368 object[] pars = new object[] {generator, parType};
369 inParType.InvokeMember("EmitMarshalIn", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
371 generator.Emit(OpCodes.Ldsfld, serviceF);
372 generator.Emit(OpCodes.Newobj, Arguments.GetDBusTypeConstructor(inParType, parType));
373 generator.EmitCall(OpCodes.Callvirt, Arguments_AppendMI, null);
376 private void EmitOut(ILGenerator generator, Type parType, int parN)
378 Type outParType = Arguments.MatchType(parType);
379 //generator.EmitWriteLine("enumerator.MoveNext()");
380 generator.Emit(OpCodes.Ldloc_2);
381 generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
383 //generator.EmitWriteLine("return (" + parType + ") ((DBusType.IDBusType) enumerator.Current).Get(typeof(" + parType + "))");
384 generator.Emit(OpCodes.Pop);
386 generator.Emit(OpCodes.Ldarg_S, parN + 1);
389 generator.Emit(OpCodes.Ldloc_2);
390 generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null);
391 generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType));
392 generator.Emit(OpCodes.Ldtoken, parType);
393 generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null);
394 generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null);
396 // Call the DBusType EmitMarshalOut to make it emit itself
397 object[] pars = new object[] {generator, parType, parN == 0};
398 outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
401 generator.Emit(OpCodes.Stloc_3);
405 public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF, MethodInfo signalCalledMI)
407 Type[] pars = {typeof(Service), typeof(string)};
408 ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName |
409 MethodAttributes.Public,
410 CallingConventions.Standard, pars);
412 ILGenerator generator = constructor.GetILGenerator();
413 generator.Emit(OpCodes.Ldarg_0);
414 generator.Emit(OpCodes.Call, this.introspector.Constructor);
415 //generator.EmitWriteLine("service = myService");
416 generator.Emit(OpCodes.Ldarg_1);
417 generator.Emit(OpCodes.Stsfld, serviceF);
418 //generator.EmitWriteLine("this.pathName = pathName");
419 generator.Emit(OpCodes.Ldarg_0);
420 generator.Emit(OpCodes.Ldarg_2);
421 generator.Emit(OpCodes.Stfld, pathF);
423 //generator.EmitWriteLine("myService.SignalCalled += new Service.SignalCalledHandler(Service_SignalCalled)");
424 generator.Emit(OpCodes.Ldarg_1);
425 generator.Emit(OpCodes.Ldarg_0);
426 generator.Emit(OpCodes.Ldftn, signalCalledMI);
427 generator.Emit(OpCodes.Newobj, Service_SignalCalledHandlerC);
428 generator.EmitCall(OpCodes.Callvirt, Service_AddSignalCalledMI, null);
430 //generator.EmitWriteLine("return");
431 generator.Emit(OpCodes.Ret);
434 public void BuildSignalConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
436 Type[] pars = {typeof(Service), typeof(string)};
437 ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName |
438 MethodAttributes.Public,
439 CallingConventions.Standard, pars);
441 ILGenerator generator = constructor.GetILGenerator();
442 generator.Emit(OpCodes.Ldarg_0);
443 generator.Emit(OpCodes.Call, this.introspector.Constructor);
444 //generator.EmitWriteLine("service = myService");
445 generator.Emit(OpCodes.Ldarg_1);
446 generator.Emit(OpCodes.Stsfld, serviceF);
447 //generator.EmitWriteLine("this.pathName = pathName");
448 generator.Emit(OpCodes.Ldarg_0);
449 generator.Emit(OpCodes.Ldarg_2);
450 generator.Emit(OpCodes.Stfld, pathF);
452 //generator.EmitWriteLine("return");
453 generator.Emit(OpCodes.Ret);
456 public object GetSignalProxy()
458 Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".SignalProxy");
460 if (proxyType == null) {
462 TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".SignalProxy",
463 TypeAttributes.Public,
466 FieldBuilder serviceF = typeB.DefineField("service",
468 FieldAttributes.Private |
469 FieldAttributes.Static);
470 FieldBuilder pathF = typeB.DefineField("pathName",
472 FieldAttributes.Private);
474 BuildSignalConstructor(ref typeB, serviceF, pathF);
476 // Build the signal handlers
477 foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
478 InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
479 foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
480 EventInfo eventE = (EventInfo) signalEntry.Value;
481 BuildSignalHandler(eventE, interfaceProxy, ref typeB, serviceF, pathF);
485 proxyType = typeB.CreateType();
487 // Uncomment the following line to produce a DLL of the
488 // constructed assembly which can then be examined using
489 // monodis. Note that in order for this to work you should copy
490 // the client assembly as a dll file so that monodis can pick it
492 //Service.ProxyAssembly.Save("proxy.dll");
495 Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
496 object [] pars = new object[] {Service, pathName};
498 ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
499 object instance = constructor.Invoke(pars);
504 public object GetProxy()
506 Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".Proxy");
508 if (proxyType == null) {
510 TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".Proxy", TypeAttributes.Public, this.type);
512 FieldBuilder serviceF = typeB.DefineField("service",
514 FieldAttributes.Private |
515 FieldAttributes.Static);
516 FieldBuilder pathF = typeB.DefineField("pathName",
518 FieldAttributes.Private);
520 MethodInfo signalCalledMI = BuildSignalCalled(ref typeB, serviceF, pathF);
521 BuildConstructor(ref typeB, serviceF, pathF, signalCalledMI);
524 foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
525 InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
526 foreach (DictionaryEntry methodEntry in interfaceProxy.Methods) {
527 MethodInfo method = (MethodInfo) methodEntry.Value;
528 BuildMethod(method, interfaceProxy, ref typeB, serviceF, pathF);
532 proxyType = typeB.CreateType();
534 // Uncomment the following line to produce a DLL of the
535 // constructed assembly which can then be examined using
536 // monodis. Note that in order for this to work you should copy
537 // the client assembly as a dll file so that monodis can pick it
539 //Service.ProxyAssembly.Save("proxy.dll");
542 Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
543 object [] pars = new object[] {Service, pathName};
545 ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
546 object instance = constructor.Invoke(pars);
550 private Service Service
557 private string ObjectName
560 return this.introspector.ToString();