Added signal support.
[platform/upstream/dbus.git] / mono / ProxyBuilder.cs
1 namespace DBus
2 {
3   using System;
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;
10
11   internal class ProxyBuilder
12   {
13     private Service service= null;
14     private string pathName = null;
15     private Type type = null;
16     private Introspector introspector = null;
17     
18     private static MethodInfo Service_NameMI = typeof(Service).GetMethod("get_Name", 
19                                                                             new Type[0]);
20     private static MethodInfo Service_ConnectionMI = typeof(Service).GetMethod("get_Connection",
21                                                                                   new Type[0]);
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",
25                                                                            new Type[0]);
26     private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments",
27                                                                                  new Type[0]);
28     private static MethodInfo Message_KeyMI = typeof(Message).GetMethod("get_Key",
29                                                                         new Type[0]);
30     private static MethodInfo Arguments_InitAppendingMI = typeof(Arguments).GetMethod("InitAppending",
31                                                                                           new Type[0]);
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",
35                                                                                              new Type[0]);
36     private static MethodInfo Message_SendMI = typeof(Message).GetMethod("Send",
37                                                                          new Type[0]);
38     private static MethodInfo Arguments_GetEnumeratorMI = typeof(Arguments).GetMethod("GetEnumerator",
39                                                                                           new Type[0]);
40     private static MethodInfo IEnumerator_MoveNextMI = typeof(System.Collections.IEnumerator).GetMethod("MoveNext",
41                                                                                                         new Type[0]);
42     private static MethodInfo IEnumerator_CurrentMI = typeof(System.Collections.IEnumerator).GetMethod("get_Current",
43                                                                                                        new Type[0]);
44     private static MethodInfo Type_GetTypeFromHandleMI = typeof(System.Type).GetMethod("GetTypeFromHandle",
45                                                                                        new Type[] {typeof(System.RuntimeTypeHandle)});
46     private static MethodInfo IDBusType_GetMI = typeof(DBusType.IDBusType).GetMethod("Get",
47                                                                                      new Type[] {typeof(System.Type)});
48     private static ConstructorInfo MethodCall_C = typeof(MethodCall).GetConstructor(new Type[] {typeof(Service),
49                                                                                                 typeof(string),
50                                                                                                 typeof(string),
51                                                                                                 typeof(string)});
52     private static ConstructorInfo Signal_C = typeof(Signal).GetConstructor(new Type[] {typeof(Service),
53                                                                                         typeof(string),
54                                                                                         typeof(string),
55                                                                                         typeof(string)});
56     private static ConstructorInfo Service_SignalCalledHandlerC = typeof(Service.SignalCalledHandler).GetConstructor(new Type[] {typeof(object),
57                                                                                                                                  typeof(System.IntPtr)});
58     private static MethodInfo String_opEqualityMI = typeof(System.String).GetMethod("op_Equality",
59                                                                                     new Type[] {typeof(string),
60                                                                                                 typeof(string)});                                                                                                            
61     private static MethodInfo MulticastDelegate_opInequalityMI = typeof(System.MulticastDelegate).GetMethod("op_Inequality",
62                                                                                     new Type[] {typeof(System.MulticastDelegate),
63                                                                                                 typeof(System.MulticastDelegate)});
64     
65
66     public ProxyBuilder(Service service, Type type, string pathName)
67     {
68       this.service = service;
69       this.pathName = pathName;
70       this.type = type;
71       this.introspector = Introspector.GetIntrospector(type);
72     }
73
74     private MethodInfo BuildSignalCalled(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
75     {
76       Type[] parTypes = {typeof(Signal)};
77       MethodBuilder methodBuilder = typeB.DefineMethod("Service_SignalCalled",
78                                                        MethodAttributes.Private |
79                                                        MethodAttributes.HideBySig,
80                                                        typeof(void),
81                                                        parTypes);
82       
83       ILGenerator generator = methodBuilder.GetILGenerator();
84
85       LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
86       enumeratorL.SetLocalSymInfo("enumerator");
87
88       Label wrongPath = generator.DefineLabel();
89       //generator.EmitWriteLine("if (signal.PathName == pathName) {");
90       generator.Emit(OpCodes.Ldarg_1);
91       generator.EmitCall(OpCodes.Callvirt, Signal_PathNameMI, null);
92       generator.Emit(OpCodes.Ldarg_0);
93       generator.Emit(OpCodes.Ldfld, pathF);
94       generator.EmitCall(OpCodes.Call, String_opEqualityMI, null);
95       generator.Emit(OpCodes.Brfalse, wrongPath);
96
97       int localOffset = 1;
98
99       foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
100         InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
101         foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
102           EventInfo eventE = (EventInfo) signalEntry.Value;
103           // This is really cheeky since we need to grab the event as a private field.
104           FieldInfo eventF = this.type.GetField(eventE.Name,
105                                                 BindingFlags.NonPublic|
106                                                 BindingFlags.Instance);
107
108           MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke");
109
110           ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters();
111           parTypes = new Type[pars.Length];
112           for (int parN = 0; parN < pars.Length; parN++) {
113             parTypes[parN] = pars[parN].ParameterType;
114             LocalBuilder parmL = generator.DeclareLocal(parTypes[parN]);
115             parmL.SetLocalSymInfo(pars[parN].Name);
116           }
117           
118           Label skip = generator.DefineLabel();      
119           //generator.EmitWriteLine("  if (SelectedIndexChanged != null) {");
120           generator.Emit(OpCodes.Ldarg_0);
121           generator.Emit(OpCodes.Ldfld, eventF);
122           generator.Emit(OpCodes.Ldnull);
123           generator.EmitCall(OpCodes.Call, MulticastDelegate_opInequalityMI, null);
124           generator.Emit(OpCodes.Brfalse, skip);
125           
126           //generator.EmitWriteLine("    if (signal.Key == 'la i')");
127           generator.Emit(OpCodes.Ldarg_1);
128           generator.EmitCall(OpCodes.Callvirt, Message_KeyMI, null);
129           generator.Emit(OpCodes.Ldstr, eventE.Name + " " + InterfaceProxy.GetSignature(eventHandler_InvokeMI));
130           generator.EmitCall(OpCodes.Call, String_opEqualityMI, null);
131           generator.Emit(OpCodes.Brfalse, skip);
132
133           //generator.EmitWriteLine("IEnumerator enumerator = signal.Arguments.GetEnumerator()");
134           generator.Emit(OpCodes.Ldarg_1);
135           generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
136           generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
137           generator.Emit(OpCodes.Stloc_0);
138           
139           for (int parN = 0; parN < pars.Length; parN++) {
140             ParameterInfo par = pars[parN];
141             if (!par.IsOut) {
142               EmitSignalIn(generator, par.ParameterType, parN + localOffset, serviceF);
143             }
144           }
145           
146           //generator.EmitWriteLine("    SelectedIndexChanged(selectedIndex)");
147           generator.Emit(OpCodes.Ldarg_0);
148           generator.Emit(OpCodes.Ldfld, eventF);
149           for (int parN = 0; parN < pars.Length; parN++) {
150             generator.Emit(OpCodes.Ldloc_S, parN + localOffset);
151           }
152           
153           generator.EmitCall(OpCodes.Callvirt, eventHandler_InvokeMI, null);
154           
155           generator.MarkLabel(skip);
156           //generator.EmitWriteLine("  }");
157           
158           localOffset += pars.Length;
159         }
160       }
161
162       generator.MarkLabel(wrongPath);
163       //generator.EmitWriteLine("}");
164
165       //generator.EmitWriteLine("return");
166       generator.Emit(OpCodes.Ret);
167
168       return methodBuilder;
169     }
170     
171     private void BuildSignalHandler(EventInfo eventE, 
172                                     InterfaceProxy interfaceProxy,
173                                     ref TypeBuilder typeB, 
174                                     FieldInfo serviceF,
175                                     FieldInfo pathF)
176     {
177       MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke");
178       ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters();
179       Type[] parTypes = new Type[pars.Length];
180       for (int parN = 0; parN < pars.Length; parN++) {
181         parTypes[parN] = pars[parN].ParameterType;
182       }
183
184       // Generate the code
185       MethodBuilder methodBuilder = typeB.DefineMethod("Proxy_" + eventE.Name, 
186                                                        MethodAttributes.Public |
187                                                        MethodAttributes.HideBySig |
188                                                        MethodAttributes.Virtual, 
189                                                        typeof(void),
190                                                        parTypes);
191       ILGenerator generator = methodBuilder.GetILGenerator();
192
193       for (int parN = 0; parN < pars.Length; parN++) {
194         methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name);
195       }
196
197       // Generate the locals
198       LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall));
199       methodCallL.SetLocalSymInfo("signal");
200       LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn));
201
202       //generator.EmitWriteLine("Signal signal = new Signal(...)");
203       generator.Emit(OpCodes.Ldsfld, serviceF);
204       generator.Emit(OpCodes.Ldarg_0);
205       generator.Emit(OpCodes.Ldfld, pathF);
206       generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName);
207       generator.Emit(OpCodes.Ldstr, eventE.Name);
208       generator.Emit(OpCodes.Newobj, Signal_C);
209       generator.Emit(OpCodes.Stloc_0);
210
211       //generator.EmitWriteLine("signal.Arguments.InitAppending()");
212       generator.Emit(OpCodes.Ldloc_0);
213       generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
214       generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null);
215
216       for (int parN = 0; parN < pars.Length; parN++) {
217         ParameterInfo par = pars[parN];
218         if (!par.IsOut) {
219           EmitIn(generator, par.ParameterType, parN, serviceF);
220         }
221       }
222       
223       //generator.EmitWriteLine("signal.Send()");
224       generator.Emit(OpCodes.Ldloc_0);
225       generator.EmitCall(OpCodes.Callvirt, Message_SendMI, null); 
226
227       //generator.EmitWriteLine("return");
228       generator.Emit(OpCodes.Ret);
229     }
230
231     private void BuildMethod(MethodInfo method, 
232                              InterfaceProxy interfaceProxy,
233                              ref TypeBuilder typeB, 
234                              FieldInfo serviceF,
235                              FieldInfo pathF)
236     {
237       ParameterInfo[] pars = method.GetParameters();
238       Type[] parTypes = new Type[pars.Length];
239       for (int parN = 0; parN < pars.Length; parN++) {
240         parTypes[parN] = pars[parN].ParameterType;
241       }
242
243       // Generate the code
244       MethodBuilder methodBuilder = typeB.DefineMethod(method.Name, 
245                                                        MethodAttributes.Public |
246                                                        MethodAttributes.HideBySig |
247                                                        MethodAttributes.Virtual, 
248                                                        method.ReturnType, 
249                                                        parTypes);
250       ILGenerator generator = methodBuilder.GetILGenerator();
251
252       for (int parN = 0; parN < pars.Length; parN++) {
253         methodBuilder.DefineParameter(parN + 1, pars[parN].Attributes, pars[parN].Name);
254       }
255
256       // Generate the locals
257       LocalBuilder methodCallL = generator.DeclareLocal(typeof(MethodCall));
258       methodCallL.SetLocalSymInfo("methodCall");
259       LocalBuilder replyL = generator.DeclareLocal(typeof(MethodReturn));
260       replyL.SetLocalSymInfo("reply");
261       LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
262       enumeratorL.SetLocalSymInfo("enumerator");
263
264       if (method.ReturnType != typeof(void)) {
265         LocalBuilder retvalL = generator.DeclareLocal(method.ReturnType);
266         retvalL.SetLocalSymInfo("retval");
267       }
268
269       //generator.EmitWriteLine("MethodCall methodCall = new MethodCall(...)");
270       generator.Emit(OpCodes.Ldsfld, serviceF);
271       generator.Emit(OpCodes.Ldarg_0);
272       generator.Emit(OpCodes.Ldfld, pathF);
273       generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName);
274       generator.Emit(OpCodes.Ldstr, method.Name);
275       generator.Emit(OpCodes.Newobj, MethodCall_C);
276       generator.Emit(OpCodes.Stloc_0);
277
278       //generator.EmitWriteLine("methodCall.Arguments.InitAppending()");
279       generator.Emit(OpCodes.Ldloc_0);
280       generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
281       generator.EmitCall(OpCodes.Callvirt, Arguments_InitAppendingMI, null);
282
283       for (int parN = 0; parN < pars.Length; parN++) {
284         ParameterInfo par = pars[parN];
285         if (!par.IsOut) {
286           EmitIn(generator, par.ParameterType, parN, serviceF);
287         }
288       }
289       
290       //generator.EmitWriteLine("MethodReturn reply = methodCall.SendWithReplyAndBlock()");
291       generator.Emit(OpCodes.Ldloc_0);
292       generator.EmitCall(OpCodes.Callvirt, Message_SendWithReplyAndBlockMI, null);      
293       generator.Emit(OpCodes.Stloc_1);
294
295       //generator.EmitWriteLine("IEnumerator enumeartor = reply.Arguments.GetEnumerator()");
296       generator.Emit(OpCodes.Ldloc_1);
297       generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
298       generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
299       generator.Emit(OpCodes.Stloc_2);
300
301       // handle the return value
302       if (method.ReturnType != typeof(void)) {
303         EmitOut(generator, method.ReturnType, 0);
304       }
305
306       for (int parN = 0; parN < pars.Length; parN++) {
307         ParameterInfo par = pars[parN];
308         if (par.IsOut || par.ParameterType.ToString().EndsWith("&")) {
309           EmitOut(generator, par.ParameterType, parN);
310         }
311       }
312
313       if (method.ReturnType != typeof(void)) {
314         generator.Emit(OpCodes.Ldloc_3);
315       }
316       
317       generator.Emit(OpCodes.Ret);
318
319       // Generate the method
320       typeB.DefineMethodOverride(methodBuilder, method);
321     }
322
323     private void EmitSignalIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
324     {
325         //generator.EmitWriteLine("enumerator.MoveNext()");
326         generator.Emit(OpCodes.Ldloc_0);
327         generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
328         
329         Type outParType = Arguments.MatchType(parType);
330         //generator.EmitWriteLine("int selectedIndex = (int) ((DBusType.IDBusType) enumerator.Current).Get(typeof(int))");
331         generator.Emit(OpCodes.Pop);
332         generator.Emit(OpCodes.Ldloc_0);
333         generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null);
334         generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType));
335         generator.Emit(OpCodes.Ldtoken, parType);
336         generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null);
337         generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null);
338         // Call the DBusType EmitMarshalOut to make it emit itself
339         object[] pars = new object[] {generator, parType, true};
340         outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
341         generator.Emit(OpCodes.Stloc_S, parN);
342     }
343     
344
345     private void EmitIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
346     {
347       Type inParType = Arguments.MatchType(parType);
348       //generator.EmitWriteLine("methodCall.Arguments.Append(...)");
349       generator.Emit(OpCodes.Ldloc_0);
350       generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
351       generator.Emit(OpCodes.Ldarg_S, parN + 1);
352
353       // Call the DBusType EmitMarshalIn to make it emit itself
354       object[] pars = new object[] {generator, parType};
355       inParType.InvokeMember("EmitMarshalIn", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
356
357       generator.Emit(OpCodes.Ldsfld, serviceF);
358       generator.Emit(OpCodes.Newobj, Arguments.GetDBusTypeConstructor(inParType, parType));
359       generator.EmitCall(OpCodes.Callvirt, Arguments_AppendMI, null);
360     }
361
362     private void EmitOut(ILGenerator generator, Type parType, int parN)
363     {
364       Type outParType = Arguments.MatchType(parType);
365       //generator.EmitWriteLine("enumerator.MoveNext()");
366       generator.Emit(OpCodes.Ldloc_2);
367       generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
368
369       //generator.EmitWriteLine("return (" + parType + ") ((DBusType.IDBusType) enumerator.Current).Get(typeof(" + parType + "))");
370       generator.Emit(OpCodes.Pop);
371       if (parN > 0) {
372         generator.Emit(OpCodes.Ldarg_S, parN + 1);
373       }
374       
375       generator.Emit(OpCodes.Ldloc_2);
376       generator.EmitCall(OpCodes.Callvirt, IEnumerator_CurrentMI, null);
377       generator.Emit(OpCodes.Castclass, typeof(DBusType.IDBusType));
378       generator.Emit(OpCodes.Ldtoken, parType);
379       generator.EmitCall(OpCodes.Call, Type_GetTypeFromHandleMI, null);
380       generator.EmitCall(OpCodes.Callvirt, IDBusType_GetMI, null);
381
382       // Call the DBusType EmitMarshalOut to make it emit itself
383       object[] pars = new object[] {generator, parType, parN == 0};
384       outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
385       
386       if (parN == 0) {
387         generator.Emit(OpCodes.Stloc_3);
388       }
389     }
390     
391     public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF, MethodInfo signalCalledMI)
392     {
393       Type[] pars = {typeof(Service), typeof(string)};
394       ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | 
395                                                                MethodAttributes.Public,
396                                                                CallingConventions.Standard, pars);
397
398       ILGenerator generator = constructor.GetILGenerator();
399       generator.Emit(OpCodes.Ldarg_0);
400       generator.Emit(OpCodes.Call, this.introspector.Constructor);
401       //generator.EmitWriteLine("service = myService");
402       generator.Emit(OpCodes.Ldarg_1);
403       generator.Emit(OpCodes.Stsfld, serviceF);
404       //generator.EmitWriteLine("this.pathName = pathName");
405       generator.Emit(OpCodes.Ldarg_0);
406       generator.Emit(OpCodes.Ldarg_2);
407       generator.Emit(OpCodes.Stfld, pathF);
408       
409       //generator.EmitWriteLine("myService.SignalCalled += new Service.SignalCalledHandler(Service_SignalCalled)");
410       generator.Emit(OpCodes.Ldarg_1);
411       generator.Emit(OpCodes.Ldarg_0);
412       generator.Emit(OpCodes.Ldftn, signalCalledMI);
413       generator.Emit(OpCodes.Newobj, Service_SignalCalledHandlerC);
414       generator.EmitCall(OpCodes.Callvirt, Service_AddSignalCalledMI, null);
415
416       //generator.EmitWriteLine("return");
417       generator.Emit(OpCodes.Ret);
418     }
419
420     public void BuildSignalConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
421     {
422       Type[] pars = {typeof(Service), typeof(string)};
423       ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | 
424                                                                MethodAttributes.Public,
425                                                                CallingConventions.Standard, pars);
426
427       ILGenerator generator = constructor.GetILGenerator();
428       generator.Emit(OpCodes.Ldarg_0);
429       generator.Emit(OpCodes.Call, this.introspector.Constructor);
430       //generator.EmitWriteLine("service = myService");
431       generator.Emit(OpCodes.Ldarg_1);
432       generator.Emit(OpCodes.Stsfld, serviceF);
433       //generator.EmitWriteLine("this.pathName = pathName");
434       generator.Emit(OpCodes.Ldarg_0);
435       generator.Emit(OpCodes.Ldarg_2);
436       generator.Emit(OpCodes.Stfld, pathF);
437       
438       //generator.EmitWriteLine("return");
439       generator.Emit(OpCodes.Ret);
440     }
441     
442     public object GetSignalProxy()
443     {
444       Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".SignalProxy");
445
446       if (proxyType == null) {
447         // Build the type
448         TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".SignalProxy", 
449                                                       TypeAttributes.Public, 
450                                                       this.type);
451         
452         FieldBuilder serviceF = typeB.DefineField("service", 
453                                                   typeof(Service), 
454                                                   FieldAttributes.Private | 
455                                                   FieldAttributes.Static);
456         FieldBuilder pathF = typeB.DefineField("pathName", 
457                                                typeof(string), 
458                                                FieldAttributes.Private);
459
460         BuildSignalConstructor(ref typeB, serviceF, pathF);
461         
462         // Build the signal handlers
463         foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
464           InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
465           foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
466             EventInfo eventE = (EventInfo) signalEntry.Value;
467             BuildSignalHandler(eventE, interfaceProxy, ref typeB, serviceF, pathF);
468           }
469         }
470         
471         proxyType = typeB.CreateType();
472       
473         // Uncomment the following line to produce a DLL of the
474         // constructed assembly which can then be examined using
475         // monodis. Note that in order for this to work you should copy
476         // the client assembly as a dll file so that monodis can pick it
477         // up.
478         //Service.ProxyAssembly.Save("proxy.dll");
479       }
480
481       Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
482       object [] pars = new object[] {Service, pathName};
483       
484       ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
485       object instance = constructor.Invoke(pars);
486       return instance;
487     }
488       
489     
490     public object GetProxy() 
491     { 
492       Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".Proxy");
493       
494       if (proxyType == null) {
495         // Build the type
496         TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".Proxy", TypeAttributes.Public, this.type);
497         
498         FieldBuilder serviceF = typeB.DefineField("service", 
499                                                   typeof(Service), 
500                                                   FieldAttributes.Private | 
501                                                   FieldAttributes.Static);
502         FieldBuilder pathF = typeB.DefineField("pathName", 
503                                                typeof(string), 
504                                                FieldAttributes.Private);
505         
506         MethodInfo signalCalledMI = BuildSignalCalled(ref typeB, serviceF, pathF);
507         BuildConstructor(ref typeB, serviceF, pathF, signalCalledMI);
508         
509         // Build the methods
510         foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
511           InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
512           foreach (DictionaryEntry methodEntry in interfaceProxy.Methods) {
513             MethodInfo method = (MethodInfo) methodEntry.Value;
514             BuildMethod(method, interfaceProxy, ref typeB, serviceF, pathF);
515           }
516         }
517         
518         proxyType = typeB.CreateType();
519       
520         // Uncomment the following line to produce a DLL of the
521         // constructed assembly which can then be examined using
522         // monodis. Note that in order for this to work you should copy
523         // the client assembly as a dll file so that monodis can pick it
524         // up.
525         //Service.ProxyAssembly.Save("proxy.dll");
526       }
527
528       Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
529       object [] pars = new object[] {Service, pathName};
530       
531       ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
532       object instance = constructor.Invoke(pars);
533       return instance;
534     }
535     
536     private Service Service
537     {
538       get {
539         return this.service;
540       }
541     }
542
543     private string ObjectName
544     {
545       get {
546         return this.introspector.ToString();
547       }
548     }
549   }
550 }
551