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