dbus/mono/ProxyBuilder.cs

609 lines
24 KiB
C#
Raw Normal View History

2004-03-23 12:10:32 +00:00
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 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]);
2004-03-26 15:25:59 +00:00
private static MethodInfo Service_AddSignalCalledMI = typeof(Service).GetMethod("add_SignalCalled",
new Type[] {typeof(Service.SignalCalledHandler)});
2005-03-13 01:13:04 +00:00
private static MethodInfo Service_RemoveSignalCalledMI = typeof(Service).GetMethod("remove_SignalCalled",
new Type[] {typeof(Service.SignalCalledHandler)});
2004-03-26 15:25:59 +00:00
private static MethodInfo Signal_PathNameMI = typeof(Signal).GetMethod("get_PathName",
new Type[0]);
2004-03-23 12:10:32 +00:00
private static MethodInfo Message_ArgumentsMI = typeof(Message).GetMethod("get_Arguments",
new Type[0]);
2004-03-26 15:25:59 +00:00
private static MethodInfo Message_KeyMI = typeof(Message).GetMethod("get_Key",
new Type[0]);
2004-03-23 12:10:32 +00:00
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]);
2004-03-26 15:25:59 +00:00
private static MethodInfo Message_SendMI = typeof(Message).GetMethod("Send",
new Type[0]);
2005-03-08 Joe Shaw <joeshaw@novell.com> Fix a bunch of lifecycle and memory management problems in the mono bindings. * mono/Arguments.cs (Arguments): Implement IDisposable * mono/Bus.cs (Bus): Don't allow public instantiation. This is strictly a static class. * mono/Connection.cs: Move the DBusObjectPathVTable and associated delegates into this file. (Connection): Implement IDisposable. (Dispose): Disconnect the connection and set the raw connection pointer to IntPtr.Zero. (~Connection): Call Dispose(). (RegisterObjectPath): Added. Manages the registration of object paths so we can cleanly disconnect them at dispose/finalize time. (UnregisterObjectPath): Ditto. (set_RawConnection): Unregister all of the object paths when changing the underlying DBusConnection. Add them back onto the new connection, if any. * mono/Handler.cs: Don't implement IDisposable; it doesn't use any more unmanaged resources anymore, so it's not necessary. Move all the DBusObjectPathVTable stuff out of here. (Handler): Save references to our delegates so that they don't get finalized. Call Connection.RegisterObjectPath() instead of dbus_connection_register_object_path() directly. (Message_Called): Dispose the message after we're finished with it. * mono/Message.cs (Message): Implement IDisposable. (Dispose): Dispose the Arguments, and set the RawMessage to IntPtr.Zero. (SendWithReplyAndBlock): We own the ref to the reply that comes back from dbus_connection_send_with_reply_and_block() so add a comment about that and unref it after we've constructed a managed MethodReturn class around it. Fixes a big, big leak. * mono/ProxyBuilder.cs: Reflect into Message to get the Dispose method. (BuildSignalHandler): After we've sent the Signal message, dispose of it. (BuildMethod): Dispose of the method call and reply messages after we've sent the message and extracted the data we want from the reply. * mono/Service.cs (UnregisterObject): Don't call handler.Dispose() anymore. (Service_FilterCalled): Dispose of the message after we're finished with it.
2005-03-09 04:36:15 +00:00
private static MethodInfo Message_DisposeMI = typeof(Message).GetMethod("Dispose",
new Type[0]);
2004-03-23 12:10:32 +00:00
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)});
2004-03-26 15:25:59 +00:00
private static ConstructorInfo Signal_C = typeof(Signal).GetConstructor(new Type[] {typeof(Service),
typeof(string),
typeof(string),
typeof(string)});
private static ConstructorInfo Service_SignalCalledHandlerC = typeof(Service.SignalCalledHandler).GetConstructor(new Type[] {typeof(object),
typeof(System.IntPtr)});
private static MethodInfo String_opEqualityMI = typeof(System.String).GetMethod("op_Equality",
new Type[] {typeof(string),
typeof(string)});
private static MethodInfo MulticastDelegate_opInequalityMI = typeof(System.MulticastDelegate).GetMethod("op_Inequality",
new Type[] {typeof(System.MulticastDelegate),
typeof(System.MulticastDelegate)});
2004-03-23 12:10:32 +00:00
public ProxyBuilder(Service service, Type type, string pathName)
{
this.service = service;
this.pathName = pathName;
this.type = type;
this.introspector = Introspector.GetIntrospector(type);
2004-03-23 12:10:32 +00:00
}
2004-03-26 15:25:59 +00:00
private MethodInfo BuildSignalCalled(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
{
Type[] parTypes = {typeof(Signal)};
MethodBuilder methodBuilder = typeB.DefineMethod("Service_SignalCalled",
MethodAttributes.Private |
MethodAttributes.HideBySig,
typeof(void),
parTypes);
ILGenerator generator = methodBuilder.GetILGenerator();
LocalBuilder enumeratorL = generator.DeclareLocal(typeof(System.Collections.IEnumerator));
enumeratorL.SetLocalSymInfo("enumerator");
Label wrongPath = generator.DefineLabel();
//generator.EmitWriteLine("if (signal.PathName == pathName) {");
generator.Emit(OpCodes.Ldarg_1);
generator.EmitCall(OpCodes.Callvirt, Signal_PathNameMI, null);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, pathF);
generator.EmitCall(OpCodes.Call, String_opEqualityMI, null);
generator.Emit(OpCodes.Brfalse, wrongPath);
int localOffset = 1;
foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
EventInfo eventE = (EventInfo) signalEntry.Value;
// This is really cheeky since we need to grab the event as a private field.
FieldInfo eventF = this.type.GetField(eventE.Name,
BindingFlags.NonPublic|
BindingFlags.Instance);
MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke");
ParameterInfo[] pars = eventHandler_InvokeMI.GetParameters();
parTypes = new Type[pars.Length];
for (int parN = 0; parN < pars.Length; parN++) {
parTypes[parN] = pars[parN].ParameterType;
LocalBuilder parmL = generator.DeclareLocal(parTypes[parN]);
parmL.SetLocalSymInfo(pars[parN].Name);
}
Label skip = generator.DefineLabel();
//generator.EmitWriteLine(" if (SelectedIndexChanged != null) {");
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, eventF);
generator.Emit(OpCodes.Ldnull);
generator.EmitCall(OpCodes.Call, MulticastDelegate_opInequalityMI, null);
generator.Emit(OpCodes.Brfalse, skip);
//generator.EmitWriteLine(" if (signal.Key == 'la i')");
generator.Emit(OpCodes.Ldarg_1);
generator.EmitCall(OpCodes.Callvirt, Message_KeyMI, null);
generator.Emit(OpCodes.Ldstr, eventE.Name + " " + InterfaceProxy.GetSignature(eventHandler_InvokeMI));
generator.EmitCall(OpCodes.Call, String_opEqualityMI, null);
generator.Emit(OpCodes.Brfalse, skip);
//generator.EmitWriteLine("IEnumerator enumerator = signal.Arguments.GetEnumerator()");
generator.Emit(OpCodes.Ldarg_1);
generator.EmitCall(OpCodes.Callvirt, Message_ArgumentsMI, null);
generator.EmitCall(OpCodes.Callvirt, Arguments_GetEnumeratorMI, null);
generator.Emit(OpCodes.Stloc_0);
for (int parN = 0; parN < pars.Length; parN++) {
ParameterInfo par = pars[parN];
if (!par.IsOut) {
EmitSignalIn(generator, par.ParameterType, parN + localOffset, serviceF);
}
}
//generator.EmitWriteLine(" SelectedIndexChanged(selectedIndex)");
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, eventF);
for (int parN = 0; parN < pars.Length; parN++) {
generator.Emit(OpCodes.Ldloc_S, parN + localOffset);
}
generator.EmitCall(OpCodes.Callvirt, eventHandler_InvokeMI, null);
generator.MarkLabel(skip);
//generator.EmitWriteLine(" }");
localOffset += pars.Length;
}
}
generator.MarkLabel(wrongPath);
//generator.EmitWriteLine("}");
//generator.EmitWriteLine("return");
generator.Emit(OpCodes.Ret);
return methodBuilder;
}
private void BuildSignalHandler(EventInfo eventE,
InterfaceProxy interfaceProxy,
ref TypeBuilder typeB,
FieldInfo serviceF,
FieldInfo pathF)
{
MethodInfo eventHandler_InvokeMI = eventE.EventHandlerType.GetMethod("Invoke");
ParameterInfo[] pars = eventHandler_InvokeMI.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("Proxy_" + eventE.Name,
MethodAttributes.Public |
MethodAttributes.HideBySig |
MethodAttributes.Virtual,
typeof(void),
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("signal");
//generator.EmitWriteLine("Signal signal = new Signal(...)");
generator.Emit(OpCodes.Ldsfld, serviceF);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, pathF);
generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName);
generator.Emit(OpCodes.Ldstr, eventE.Name);
generator.Emit(OpCodes.Newobj, Signal_C);
generator.Emit(OpCodes.Stloc_0);
//generator.EmitWriteLine("signal.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, serviceF);
}
}
//generator.EmitWriteLine("signal.Send()");
generator.Emit(OpCodes.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt, Message_SendMI, null);
2005-03-08 Joe Shaw <joeshaw@novell.com> Fix a bunch of lifecycle and memory management problems in the mono bindings. * mono/Arguments.cs (Arguments): Implement IDisposable * mono/Bus.cs (Bus): Don't allow public instantiation. This is strictly a static class. * mono/Connection.cs: Move the DBusObjectPathVTable and associated delegates into this file. (Connection): Implement IDisposable. (Dispose): Disconnect the connection and set the raw connection pointer to IntPtr.Zero. (~Connection): Call Dispose(). (RegisterObjectPath): Added. Manages the registration of object paths so we can cleanly disconnect them at dispose/finalize time. (UnregisterObjectPath): Ditto. (set_RawConnection): Unregister all of the object paths when changing the underlying DBusConnection. Add them back onto the new connection, if any. * mono/Handler.cs: Don't implement IDisposable; it doesn't use any more unmanaged resources anymore, so it's not necessary. Move all the DBusObjectPathVTable stuff out of here. (Handler): Save references to our delegates so that they don't get finalized. Call Connection.RegisterObjectPath() instead of dbus_connection_register_object_path() directly. (Message_Called): Dispose the message after we're finished with it. * mono/Message.cs (Message): Implement IDisposable. (Dispose): Dispose the Arguments, and set the RawMessage to IntPtr.Zero. (SendWithReplyAndBlock): We own the ref to the reply that comes back from dbus_connection_send_with_reply_and_block() so add a comment about that and unref it after we've constructed a managed MethodReturn class around it. Fixes a big, big leak. * mono/ProxyBuilder.cs: Reflect into Message to get the Dispose method. (BuildSignalHandler): After we've sent the Signal message, dispose of it. (BuildMethod): Dispose of the method call and reply messages after we've sent the message and extracted the data we want from the reply. * mono/Service.cs (UnregisterObject): Don't call handler.Dispose() anymore. (Service_FilterCalled): Dispose of the message after we're finished with it.
2005-03-09 04:36:15 +00:00
//generator.EmitWriteLine("signal.Dispose()");
generator.Emit(OpCodes.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt, Message_DisposeMI, null);
2004-03-26 15:25:59 +00:00
//generator.EmitWriteLine("return");
generator.Emit(OpCodes.Ret);
}
2004-03-23 12:10:32 +00:00
private void BuildMethod(MethodInfo method,
InterfaceProxy interfaceProxy,
2004-03-23 12:10:32 +00:00
ref TypeBuilder typeB,
FieldInfo serviceF,
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.Ldstr, interfaceProxy.InterfaceName);
2004-03-23 12:10:32 +00:00
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, serviceF);
2004-03-23 12:10:32 +00:00
}
}
//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);
}
}
2005-03-08 Joe Shaw <joeshaw@novell.com> Fix a bunch of lifecycle and memory management problems in the mono bindings. * mono/Arguments.cs (Arguments): Implement IDisposable * mono/Bus.cs (Bus): Don't allow public instantiation. This is strictly a static class. * mono/Connection.cs: Move the DBusObjectPathVTable and associated delegates into this file. (Connection): Implement IDisposable. (Dispose): Disconnect the connection and set the raw connection pointer to IntPtr.Zero. (~Connection): Call Dispose(). (RegisterObjectPath): Added. Manages the registration of object paths so we can cleanly disconnect them at dispose/finalize time. (UnregisterObjectPath): Ditto. (set_RawConnection): Unregister all of the object paths when changing the underlying DBusConnection. Add them back onto the new connection, if any. * mono/Handler.cs: Don't implement IDisposable; it doesn't use any more unmanaged resources anymore, so it's not necessary. Move all the DBusObjectPathVTable stuff out of here. (Handler): Save references to our delegates so that they don't get finalized. Call Connection.RegisterObjectPath() instead of dbus_connection_register_object_path() directly. (Message_Called): Dispose the message after we're finished with it. * mono/Message.cs (Message): Implement IDisposable. (Dispose): Dispose the Arguments, and set the RawMessage to IntPtr.Zero. (SendWithReplyAndBlock): We own the ref to the reply that comes back from dbus_connection_send_with_reply_and_block() so add a comment about that and unref it after we've constructed a managed MethodReturn class around it. Fixes a big, big leak. * mono/ProxyBuilder.cs: Reflect into Message to get the Dispose method. (BuildSignalHandler): After we've sent the Signal message, dispose of it. (BuildMethod): Dispose of the method call and reply messages after we've sent the message and extracted the data we want from the reply. * mono/Service.cs (UnregisterObject): Don't call handler.Dispose() anymore. (Service_FilterCalled): Dispose of the message after we're finished with it.
2005-03-09 04:36:15 +00:00
// Clean up after ourselves
//generator.EmitWriteLine("methodCall.Dispose()");
generator.Emit(OpCodes.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt, Message_DisposeMI, null);
//generator.EmitWriteLine("reply.Dispose()");
generator.Emit(OpCodes.Ldloc_1);
generator.EmitCall(OpCodes.Callvirt, Message_DisposeMI, null);
2004-03-23 12:10:32 +00:00
if (method.ReturnType != typeof(void)) {
generator.Emit(OpCodes.Ldloc_3);
}
generator.Emit(OpCodes.Ret);
// Generate the method
typeB.DefineMethodOverride(methodBuilder, method);
}
2004-03-26 15:25:59 +00:00
private void EmitSignalIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
{
//generator.EmitWriteLine("enumerator.MoveNext()");
generator.Emit(OpCodes.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt, IEnumerator_MoveNextMI, null);
Type outParType = Arguments.MatchType(parType);
//generator.EmitWriteLine("int selectedIndex = (int) ((DBusType.IDBusType) enumerator.Current).Get(typeof(int))");
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldloc_0);
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, true};
outParType.InvokeMember("EmitMarshalOut", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, pars, null);
generator.Emit(OpCodes.Stloc_S, parN);
}
private void EmitIn(ILGenerator generator, Type parType, int parN, FieldInfo serviceF)
2004-03-23 12:10:32 +00:00
{
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.Ldsfld, serviceF);
2004-03-23 12:10:32 +00:00
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);
}
}
2005-03-13 01:13:04 +00:00
public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF, MethodInfo signalCalledMI, FieldInfo deleF)
2004-03-23 12:10:32 +00:00
{
Type[] pars = {typeof(Service), typeof(string)};
2004-03-23 12:10:32 +00:00
ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName |
MethodAttributes.Public,
CallingConventions.Standard, pars);
ILGenerator generator = constructor.GetILGenerator();
LocalBuilder handlerL = generator.DeclareLocal (typeof (Service.SignalCalledHandler));
handlerL.SetLocalSymInfo ("handler");
2004-03-23 12:10:32 +00:00
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, this.introspector.Constructor);
2004-03-26 15:25:59 +00:00
//generator.EmitWriteLine("service = myService");
2004-03-23 12:10:32 +00:00
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stsfld, serviceF);
2004-03-26 15:25:59 +00:00
//generator.EmitWriteLine("this.pathName = pathName");
2004-03-23 12:10:32 +00:00
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_2);
2004-03-23 12:10:32 +00:00
generator.Emit(OpCodes.Stfld, pathF);
2005-03-13 01:13:04 +00:00
//generator.EmitWriteLine("handler = new Service.SignalCalledHandler(Service_SignalCalled)");
2004-03-26 15:25:59 +00:00
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldftn, signalCalledMI);
generator.Emit(OpCodes.Newobj, Service_SignalCalledHandlerC);
2005-03-13 01:13:04 +00:00
generator.Emit(OpCodes.Stloc_0);
//generator.EmitWriteLine("this.delegate_created = handler");
2005-03-13 01:13:04 +00:00
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Stfld, deleF);
//generator.EmitWriteLine("myService.SignalCalled += handler");
2005-03-13 01:13:04 +00:00
generator.Emit(OpCodes.Ldloc_0);
2004-03-26 15:25:59 +00:00
generator.EmitCall(OpCodes.Callvirt, Service_AddSignalCalledMI, null);
2004-03-23 12:10:32 +00:00
2004-03-26 15:25:59 +00:00
//generator.EmitWriteLine("return");
generator.Emit(OpCodes.Ret);
}
public void BuildSignalConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF)
{
Type[] pars = {typeof(Service), 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.EmitWriteLine("service = myService");
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stsfld, serviceF);
//generator.EmitWriteLine("this.pathName = pathName");
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_2);
generator.Emit(OpCodes.Stfld, pathF);
//generator.EmitWriteLine("return");
2004-03-23 12:10:32 +00:00
generator.Emit(OpCodes.Ret);
}
public void BuildFinalizer (TypeBuilder tb, FieldInfo serviceF, FieldInfo deleF)
2005-03-13 01:13:04 +00:00
{
// Note that this is a *HORRIBLE* example of how to build a finalizer
// It doesn't use the try/finally to chain to Object::Finalize. However,
// because that is always going to be a nop, lets just ignore that here.
// If you are trying to find the right code, look at what mcs does ;-).
MethodBuilder mb = tb.DefineMethod("Finalize",
2005-03-13 01:13:04 +00:00
MethodAttributes.Family |
MethodAttributes.HideBySig |
MethodAttributes.Virtual,
typeof (void),
new Type [0]);
ILGenerator generator = mb.GetILGenerator();
//generator.EmitWriteLine("this.service.SignalCalled -= this.delegate_created");
generator.Emit (OpCodes.Ldarg_0);
generator.Emit (OpCodes.Ldfld, serviceF);
generator.Emit (OpCodes.Ldarg_0);
generator.Emit (OpCodes.Ldfld, deleF);
generator.EmitCall (OpCodes.Callvirt, Service_RemoveSignalCalledMI, null);
2005-03-13 01:13:04 +00:00
generator.Emit (OpCodes.Ret);
}
2004-03-26 15:25:59 +00:00
public object GetSignalProxy()
{
Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".SignalProxy");
if (proxyType == null) {
// Build the type
TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".SignalProxy",
TypeAttributes.Public,
this.type);
FieldBuilder serviceF = typeB.DefineField("service",
typeof(Service),
FieldAttributes.Private |
FieldAttributes.Static);
FieldBuilder pathF = typeB.DefineField("pathName",
typeof(string),
FieldAttributes.Private);
BuildSignalConstructor(ref typeB, serviceF, pathF);
// Build the signal handlers
foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
foreach (DictionaryEntry signalEntry in interfaceProxy.Signals) {
EventInfo eventE = (EventInfo) signalEntry.Value;
BuildSignalHandler(eventE, interfaceProxy, ref typeB, serviceF, pathF);
}
}
proxyType = typeB.CreateType();
2004-03-23 12:10:32 +00:00
2004-03-26 15:25:59 +00:00
// 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.
//Service.ProxyAssembly.Save("proxy.dll");
}
Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
object [] pars = new object[] {Service, pathName};
ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
object instance = constructor.Invoke(pars);
return instance;
}
public object GetProxy()
{
Type proxyType = Service.ProxyAssembly.GetType(ObjectName + ".Proxy");
2004-03-23 12:10:32 +00:00
if (proxyType == null) {
// Build the type
2004-03-26 15:25:59 +00:00
TypeBuilder typeB = Service.Module.DefineType(ObjectName + ".Proxy", TypeAttributes.Public, this.type);
FieldBuilder serviceF = typeB.DefineField("service",
typeof(Service),
FieldAttributes.Private |
FieldAttributes.Static);
FieldBuilder pathF = typeB.DefineField("pathName",
typeof(string),
FieldAttributes.Private);
2005-03-13 01:13:04 +00:00
FieldBuilder deleF = typeB.DefineField("delegate_created",
typeof(Service.SignalCalledHandler),
FieldAttributes.Private);
BuildFinalizer (typeB, serviceF, deleF);
2004-03-26 15:25:59 +00:00
MethodInfo signalCalledMI = BuildSignalCalled(ref typeB, serviceF, pathF);
2005-03-13 01:13:04 +00:00
BuildConstructor(ref typeB, serviceF, pathF, signalCalledMI, deleF);
// Build the methods
foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) {
InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value;
foreach (DictionaryEntry methodEntry in interfaceProxy.Methods) {
MethodInfo method = (MethodInfo) methodEntry.Value;
BuildMethod(method, interfaceProxy, ref typeB, serviceF, pathF);
}
}
proxyType = typeB.CreateType();
2004-03-23 12:10:32 +00:00
// 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.
//Service.ProxyAssembly.Save(Service.Name + ".proxy.dll");
}
Type [] parTypes = new Type[] {typeof(Service), typeof(string)};
object [] pars = new object[] {Service, pathName};
2004-03-23 12:10:32 +00:00
ConstructorInfo constructor = proxyType.GetConstructor(parTypes);
object instance = constructor.Invoke(pars);
return instance;
}
2004-03-26 15:25:59 +00:00
private Service Service
2004-03-23 12:10:32 +00:00
{
get {
return this.service;
}
2004-03-23 12:10:32 +00:00
}
2004-03-26 15:25:59 +00:00
private string ObjectName
2004-03-23 12:10:32 +00:00
{
get {
2004-03-26 15:25:59 +00:00
return this.introspector.ToString();
}
2004-03-23 12:10:32 +00:00
}
}
}