|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
namespace System.Runtime.InteropServices.TCEAdapterGen {
using System.Runtime.InteropServices.ComTypes;
using ubyte = System.Byte;
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Threading;
using System.Diagnostics.Contracts;
internal class EventProviderWriter
{
private const BindingFlags DefaultLookup = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
private readonly Type[] MonitorEnterParamTypes = new Type[] { typeof(Object), Type.GetType("System.Boolean&") };
public EventProviderWriter( ModuleBuilder OutputModule, String strDestTypeName, Type EventItfType, Type SrcItfType, Type SinkHelperType )
{
m_OutputModule = OutputModule;
m_strDestTypeName = strDestTypeName;
m_EventItfType = EventItfType;
m_SrcItfType = SrcItfType;
m_SinkHelperType = SinkHelperType;
}
public Type Perform()
{
// Create the event provider class.
TypeBuilder OutputTypeBuilder = m_OutputModule.DefineType(
m_strDestTypeName,
TypeAttributes.Sealed | TypeAttributes.NotPublic,
typeof(Object),
new Type[]{m_EventItfType, typeof(IDisposable)}
);
// Create the event source field.
FieldBuilder fbCPC = OutputTypeBuilder.DefineField(
"m_ConnectionPointContainer",
typeof(IConnectionPointContainer),
FieldAttributes.Private
);
// Create array of event sink helpers.
FieldBuilder fbSinkHelper = OutputTypeBuilder.DefineField(
"m_aEventSinkHelpers",
typeof(ArrayList),
FieldAttributes.Private
);
// Define the connection point field.
FieldBuilder fbEventCP = OutputTypeBuilder.DefineField(
"m_ConnectionPoint",
typeof(IConnectionPoint),
FieldAttributes.Private
);
// Define the InitXXX method.
MethodBuilder InitSrcItfMethodBuilder =
DefineInitSrcItfMethod( OutputTypeBuilder, m_SrcItfType, fbSinkHelper, fbEventCP, fbCPC );
// Process all the methods in the event interface.
MethodInfo[] aMethods = TCEAdapterGenerator.GetNonPropertyMethods(m_SrcItfType);
for ( int cMethods = 0; cMethods < aMethods.Length; cMethods++ )
{
if ( m_SrcItfType == aMethods[cMethods].DeclaringType )
{
// Define the add_XXX method.
MethodBuilder AddEventMethodBuilder = DefineAddEventMethod(
OutputTypeBuilder, aMethods[cMethods], m_SinkHelperType, fbSinkHelper, fbEventCP, InitSrcItfMethodBuilder );
// Define the remove_XXX method.
MethodBuilder RemoveEventMethodBuilder = DefineRemoveEventMethod(
OutputTypeBuilder, aMethods[cMethods], m_SinkHelperType, fbSinkHelper, fbEventCP );
}
}
// Define the constructor.
DefineConstructor( OutputTypeBuilder, fbCPC );
// Define the finalize method.
MethodBuilder FinalizeMethod = DefineFinalizeMethod( OutputTypeBuilder, m_SinkHelperType, fbSinkHelper, fbEventCP );
// Define the Dispose method.
DefineDisposeMethod( OutputTypeBuilder, FinalizeMethod);
return OutputTypeBuilder.CreateType();
}
private MethodBuilder DefineAddEventMethod( TypeBuilder OutputTypeBuilder, MethodInfo SrcItfMethod, Type SinkHelperClass, FieldBuilder fbSinkHelperArray, FieldBuilder fbEventCP, MethodBuilder mbInitSrcItf )
{
Type[] aParamTypes;
// Find the delegate on the event sink helper.
FieldInfo DelegateField = SinkHelperClass.GetField( "m_" + SrcItfMethod.Name + "Delegate" );
Contract.Assert(DelegateField != null, "Unable to find the field m_" + SrcItfMethod.Name + "Delegate on the sink helper");
// Find the cookie on the event sink helper.
FieldInfo CookieField = SinkHelperClass.GetField( "m_dwCookie" );
Contract.Assert(CookieField != null, "Unable to find the field m_dwCookie on the sink helper");
// Retrieve the sink helper's constructor.
ConstructorInfo SinkHelperCons = SinkHelperClass.GetConstructor(EventProviderWriter.DefaultLookup | BindingFlags.NonPublic, null, new Type[0], null );
Contract.Assert(SinkHelperCons != null, "Unable to find the constructor for the sink helper");
// Retrieve the IConnectionPoint.Advise method.
MethodInfo CPAdviseMethod = typeof(IConnectionPoint).GetMethod( "Advise" );
Contract.Assert(CPAdviseMethod != null, "Unable to find the method ConnectionPoint.Advise");
// Retrieve the ArrayList.Add method.
aParamTypes = new Type[1];
aParamTypes[0] = typeof(Object);
MethodInfo ArrayListAddMethod = typeof(ArrayList).GetMethod( "Add", aParamTypes, null );
Contract.Assert(ArrayListAddMethod != null, "Unable to find the method ArrayList.Add");
// Retrieve the Monitor.Enter() method.
MethodInfo MonitorEnterMethod = typeof(Monitor).GetMethod( "Enter", MonitorEnterParamTypes, null );
Contract.Assert(MonitorEnterMethod != null, "Unable to find the method Monitor.Enter()");
// Retrieve the Monitor.Exit() method.
aParamTypes[0] = typeof(Object);
MethodInfo MonitorExitMethod = typeof(Monitor).GetMethod( "Exit", aParamTypes, null );
Contract.Assert(MonitorExitMethod != null, "Unable to find the method Monitor.Exit()");
// Define the add_XXX method.
Type[] parameterTypes;
parameterTypes = new Type[1];
parameterTypes[0] = DelegateField.FieldType;
MethodBuilder Meth = OutputTypeBuilder.DefineMethod(
"add_" + SrcItfMethod.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
null,
parameterTypes );
ILGenerator il = Meth.GetILGenerator();
// Define a label for the m_IFooEventsCP comparision.
Label EventCPNonNullLabel = il.DefineLabel();
// Declare the local variables.
LocalBuilder ltSinkHelper = il.DeclareLocal( SinkHelperClass );
LocalBuilder ltCookie = il.DeclareLocal( typeof(Int32) );
LocalBuilder ltLockTaken = il.DeclareLocal( typeof(bool) );
// Generate the following code:
// try {
il.BeginExceptionBlock();
// Generate the following code:
// Monitor.Enter(this, ref lockTaken);
il.Emit(OpCodes.Ldarg, (short)0);
il.Emit(OpCodes.Ldloca_S, ltLockTaken);
il.Emit(OpCodes.Call, MonitorEnterMethod);
// Generate the following code:
// if ( m_IFooEventsCP != null ) goto EventCPNonNullLabel;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Brtrue, EventCPNonNullLabel );
// Generate the following code:
// InitIFooEvents();
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Call, mbInitSrcItf );
// Mark this as label to jump to if the CP is not null.
il.MarkLabel( EventCPNonNullLabel );
// Generate the following code:
// IFooEvents_SinkHelper SinkHelper = new IFooEvents_SinkHelper;
il.Emit( OpCodes.Newobj, SinkHelperCons );
il.Emit( OpCodes.Stloc, ltSinkHelper );
// Generate the following code:
// dwCookie = 0;
il.Emit( OpCodes.Ldc_I4_0 );
il.Emit( OpCodes.Stloc, ltCookie );
// Generate the following code:
// m_IFooEventsCP.Advise( SinkHelper, dwCookie );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Ldloc, ltSinkHelper );
il.Emit( OpCodes.Castclass, typeof(Object) );
il.Emit( OpCodes.Ldloca, ltCookie );
il.Emit( OpCodes.Callvirt, CPAdviseMethod );
// Generate the following code:
// SinkHelper.m_dwCookie = dwCookie;
il.Emit( OpCodes.Ldloc, ltSinkHelper );
il.Emit( OpCodes.Ldloc, ltCookie );
il.Emit( OpCodes.Stfld, CookieField );
// Generate the following code:
// SinkHelper.m_FooDelegate = d;
il.Emit( OpCodes.Ldloc, ltSinkHelper );
il.Emit( OpCodes.Ldarg, (short)1 );
il.Emit( OpCodes.Stfld, DelegateField );
// Generate the following code:
// m_aIFooEventsHelpers.Add( SinkHelper );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelperArray );
il.Emit( OpCodes.Ldloc, ltSinkHelper );
il.Emit( OpCodes.Castclass, typeof(Object) );
il.Emit( OpCodes.Callvirt, ArrayListAddMethod );
il.Emit( OpCodes.Pop );
// Generate the following code:
// } finally {
il.BeginFinallyBlock();
// Generate the following code:
// if (lockTaken)
// Monitor.Exit(this);
Label skipExit = il.DefineLabel();
il.Emit( OpCodes.Ldloc, ltLockTaken );
il.Emit( OpCodes.Brfalse_S, skipExit );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Call, MonitorExitMethod );
il.MarkLabel(skipExit);
// Generate the following code:
// }
il.EndExceptionBlock();
// Generate the return opcode.
il.Emit( OpCodes.Ret );
return Meth;
}
private MethodBuilder DefineRemoveEventMethod( TypeBuilder OutputTypeBuilder, MethodInfo SrcItfMethod, Type SinkHelperClass, FieldBuilder fbSinkHelperArray, FieldBuilder fbEventCP )
{
Type[] aParamTypes;
// Find the delegate on the event sink helper.
FieldInfo DelegateField = SinkHelperClass.GetField( "m_" + SrcItfMethod.Name + "Delegate" );
Contract.Assert(DelegateField != null, "Unable to find the field m_" + SrcItfMethod.Name + "Delegate on the sink helper");
// Find the cookie on the event sink helper.
FieldInfo CookieField = SinkHelperClass.GetField( "m_dwCookie" );
Contract.Assert(CookieField != null, "Unable to find the field m_dwCookie on the sink helper");
// Retrieve the ArrayList.RemoveAt method.
aParamTypes = new Type[1];
aParamTypes[0] = typeof(Int32);
MethodInfo ArrayListRemoveMethod = typeof(ArrayList).GetMethod( "RemoveAt", aParamTypes, null );
Contract.Assert(ArrayListRemoveMethod != null, "Unable to find the method ArrayList.RemoveAt()");
// Retrieve the ArrayList.Item property get method.
PropertyInfo ArrayListItemProperty = typeof(ArrayList).GetProperty( "Item" );
Contract.Assert(ArrayListItemProperty != null, "Unable to find the property ArrayList.Item");
MethodInfo ArrayListItemGetMethod = ArrayListItemProperty.GetGetMethod();
Contract.Assert(ArrayListItemGetMethod != null, "Unable to find the get method for property ArrayList.Item");
// Retrieve the ArrayList.Count property get method.
PropertyInfo ArrayListSizeProperty = typeof(ArrayList).GetProperty( "Count" );
Contract.Assert(ArrayListSizeProperty != null, "Unable to find the property ArrayList.Count");
MethodInfo ArrayListSizeGetMethod = ArrayListSizeProperty.GetGetMethod();
Contract.Assert(ArrayListSizeGetMethod != null, "Unable to find the get method for property ArrayList.Count");
// Retrieve the Delegate.Equals() method.
aParamTypes[0] = typeof(Delegate);
MethodInfo DelegateEqualsMethod = typeof(Delegate).GetMethod( "Equals", aParamTypes, null );
Contract.Assert(DelegateEqualsMethod != null, "Unable to find the method Delegate.Equlals()");
// Retrieve the Monitor.Enter() method.
MethodInfo MonitorEnterMethod = typeof(Monitor).GetMethod("Enter", MonitorEnterParamTypes, null);
Contract.Assert(MonitorEnterMethod != null, "Unable to find the method Monitor.Enter()");
// Retrieve the Monitor.Exit() method.
aParamTypes[0] = typeof(Object);
MethodInfo MonitorExitMethod = typeof(Monitor).GetMethod( "Exit", aParamTypes, null );
Contract.Assert(MonitorExitMethod != null, "Unable to find the method Monitor.Exit()");
// Retrieve the ConnectionPoint.Unadvise() method.
MethodInfo CPUnadviseMethod = typeof(IConnectionPoint).GetMethod( "Unadvise" );
Contract.Assert(CPUnadviseMethod != null, "Unable to find the method ConnectionPoint.Unadvise()");
// Retrieve the Marshal.ReleaseComObject() method.
MethodInfo ReleaseComObjectMethod = typeof(Marshal).GetMethod( "ReleaseComObject" );
Contract.Assert(ReleaseComObjectMethod != null, "Unable to find the method Marshal.ReleaseComObject()");
// Define the remove_XXX method.
Type[] parameterTypes;
parameterTypes = new Type[1];
parameterTypes[0] = DelegateField.FieldType;
MethodBuilder Meth = OutputTypeBuilder.DefineMethod(
"remove_" + SrcItfMethod.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
null,
parameterTypes );
ILGenerator il = Meth.GetILGenerator();
// Declare the local variables.
LocalBuilder ltNumSinkHelpers = il.DeclareLocal( typeof(Int32) );
LocalBuilder ltSinkHelperCounter = il.DeclareLocal( typeof(Int32) );
LocalBuilder ltCurrSinkHelper = il.DeclareLocal( SinkHelperClass );
LocalBuilder ltLockTaken = il.DeclareLocal(typeof(bool));
// Generate the labels for the for loop.
Label ForBeginLabel = il.DefineLabel();
Label ForEndLabel = il.DefineLabel();
Label FalseIfLabel = il.DefineLabel();
Label MonitorExitLabel = il.DefineLabel();
// Generate the following code:
// try {
il.BeginExceptionBlock();
// Generate the following code:
// Monitor.Enter(this, ref lockTaken);
il.Emit(OpCodes.Ldarg, (short)0);
il.Emit(OpCodes.Ldloca_S, ltLockTaken);
il.Emit(OpCodes.Call, MonitorEnterMethod);
// Generate the following code:
// if ( m_aIFooEventsHelpers == null ) goto ForEndLabel;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelperArray );
il.Emit( OpCodes.Brfalse, ForEndLabel );
// Generate the following code:
// int NumEventHelpers = m_aIFooEventsHelpers.Count;
// int cEventHelpers = 0;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelperArray );
il.Emit( OpCodes.Callvirt, ArrayListSizeGetMethod );
il.Emit( OpCodes.Stloc, ltNumSinkHelpers );
il.Emit( OpCodes.Ldc_I4, 0 );
il.Emit( OpCodes.Stloc, ltSinkHelperCounter );
// Generate the following code:
// if ( 0 >= NumEventHelpers ) goto ForEndLabel;
il.Emit( OpCodes.Ldc_I4, 0 );
il.Emit( OpCodes.Ldloc, ltNumSinkHelpers );
il.Emit( OpCodes.Bge, ForEndLabel );
// Mark this as the beginning of the for loop's body.
il.MarkLabel( ForBeginLabel );
// Generate the following code:
// CurrentHelper = (IFooEvents_SinkHelper)m_aIFooEventsHelpers.Get( cEventHelpers );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelperArray );
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Callvirt, ArrayListItemGetMethod );
il.Emit( OpCodes.Castclass, SinkHelperClass );
il.Emit( OpCodes.Stloc, ltCurrSinkHelper );
// Generate the following code:
// if ( CurrentHelper.m_FooDelegate )
il.Emit( OpCodes.Ldloc, ltCurrSinkHelper );
il.Emit( OpCodes.Ldfld, DelegateField );
il.Emit( OpCodes.Ldnull );
il.Emit( OpCodes.Beq, FalseIfLabel );
// Generate the following code:
// if ( CurrentHelper.m_FooDelegate.Equals( d ) )
il.Emit( OpCodes.Ldloc, ltCurrSinkHelper );
il.Emit( OpCodes.Ldfld, DelegateField );
il.Emit( OpCodes.Ldarg, (short)1 );
il.Emit( OpCodes.Castclass, typeof(Object) );
il.Emit( OpCodes.Callvirt, DelegateEqualsMethod );
il.Emit( OpCodes.Ldc_I4, 0xff );
il.Emit( OpCodes.And );
il.Emit( OpCodes.Ldc_I4, 0 );
il.Emit( OpCodes.Beq, FalseIfLabel );
// Generate the following code:
// m_aIFooEventsHelpers.RemoveAt( cEventHelpers );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelperArray );
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Callvirt, ArrayListRemoveMethod );
// Generate the following code:
// m_IFooEventsCP.Unadvise( CurrentHelper.m_dwCookie );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Ldloc, ltCurrSinkHelper );
il.Emit( OpCodes.Ldfld, CookieField );
il.Emit( OpCodes.Callvirt, CPUnadviseMethod );
// Generate the following code:
// if ( NumEventHelpers > 1) break;
il.Emit( OpCodes.Ldloc, ltNumSinkHelpers );
il.Emit( OpCodes.Ldc_I4, 1 );
il.Emit( OpCodes.Bgt, ForEndLabel );
// Generate the following code:
// Marshal.ReleaseComObject(m_IFooEventsCP);
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Call, ReleaseComObjectMethod );
il.Emit( OpCodes.Pop );
// Generate the following code:
// m_IFooEventsCP = null;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldnull );
il.Emit( OpCodes.Stfld, fbEventCP );
// Generate the following code:
// m_aIFooEventsHelpers = null;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldnull );
il.Emit( OpCodes.Stfld, fbSinkHelperArray );
// Generate the following code:
// break;
il.Emit( OpCodes.Br, ForEndLabel );
// Mark this as the label to jump to when the if statement is false.
il.MarkLabel( FalseIfLabel );
// Generate the following code:
// cEventHelpers++;
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Ldc_I4, 1 );
il.Emit( OpCodes.Add );
il.Emit( OpCodes.Stloc, ltSinkHelperCounter );
// Generate the following code:
// if ( cEventHelpers < NumEventHelpers ) goto ForBeginLabel;
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Ldloc, ltNumSinkHelpers );
il.Emit( OpCodes.Blt, ForBeginLabel );
// Mark this as the end of the for loop's body.
il.MarkLabel( ForEndLabel );
// Generate the following code:
// } finally {
il.BeginFinallyBlock();
// Generate the following code:
// if (lockTaken)
// Monitor.Exit(this);
Label skipExit = il.DefineLabel();
il.Emit(OpCodes.Ldloc, ltLockTaken);
il.Emit(OpCodes.Brfalse_S, skipExit);
il.Emit(OpCodes.Ldarg, (short)0);
il.Emit(OpCodes.Call, MonitorExitMethod);
il.MarkLabel(skipExit);
// Generate the following code:
// }
il.EndExceptionBlock();
// Generate the return opcode.
il.Emit( OpCodes.Ret );
return Meth;
}
private MethodBuilder DefineInitSrcItfMethod( TypeBuilder OutputTypeBuilder, Type SourceInterface, FieldBuilder fbSinkHelperArray, FieldBuilder fbEventCP, FieldBuilder fbCPC )
{
// Retrieve the constructor info for the array list's default constructor.
ConstructorInfo DefaultArrayListCons = typeof(ArrayList).GetConstructor(EventProviderWriter.DefaultLookup, null, new Type[0], null );
Contract.Assert(DefaultArrayListCons != null, "Unable to find the constructor for class ArrayList");
// Temp byte array for Guid
ubyte[] rgByteGuid = new ubyte[16];
// Retrieve the constructor info for the Guid constructor.
Type[] aParamTypes = new Type[1];
aParamTypes[0] = typeof(Byte[]);
ConstructorInfo ByteArrayGUIDCons = typeof(Guid).GetConstructor(EventProviderWriter.DefaultLookup, null, aParamTypes, null );
Contract.Assert(ByteArrayGUIDCons != null, "Unable to find the constructor for GUID that accepts a string as argument");
// Retrieve the IConnectionPointContainer.FindConnectionPoint() method.
MethodInfo CPCFindCPMethod = typeof(IConnectionPointContainer).GetMethod( "FindConnectionPoint" );
Contract.Assert(CPCFindCPMethod != null, "Unable to find the method ConnectionPointContainer.FindConnectionPoint()");
// Define the Init method itself.
MethodBuilder Meth = OutputTypeBuilder.DefineMethod(
"Init",
MethodAttributes.Private,
null,
null );
ILGenerator il = Meth.GetILGenerator();
// Declare the local variables.
LocalBuilder ltCP = il.DeclareLocal( typeof(IConnectionPoint) );
LocalBuilder ltEvGuid = il.DeclareLocal( typeof(Guid) );
LocalBuilder ltByteArrayGuid = il.DeclareLocal( typeof(Byte[]) );
// Generate the following code:
// IConnectionPoint CP = NULL;
il.Emit( OpCodes.Ldnull );
il.Emit( OpCodes.Stloc, ltCP );
// Get unsigned byte array for the GUID of the event interface.
rgByteGuid = SourceInterface.GUID.ToByteArray();
// Generate the following code:
// ubyte rgByteArray[] = new ubyte [16];
il.Emit( OpCodes.Ldc_I4, 0x10 );
il.Emit( OpCodes.Newarr, typeof(Byte) );
il.Emit( OpCodes.Stloc, ltByteArrayGuid );
// Generate the following code:
// rgByteArray[i] = rgByteGuid[i];
for (int i = 0; i < 16; i++ )
{
il.Emit( OpCodes.Ldloc, ltByteArrayGuid );
il.Emit( OpCodes.Ldc_I4, i );
il.Emit( OpCodes.Ldc_I4, (int) (rgByteGuid[i]) );
il.Emit( OpCodes.Stelem_I1);
}
// Generate the following code:
// EventItfGuid = Guid( ubyte b[] );
il.Emit( OpCodes.Ldloca, ltEvGuid );
il.Emit( OpCodes.Ldloc, ltByteArrayGuid );
il.Emit( OpCodes.Call, ByteArrayGUIDCons );
// Generate the following code:
// m_ConnectionPointContainer.FindConnectionPoint( EventItfGuid, CP );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbCPC );
il.Emit( OpCodes.Ldloca, ltEvGuid );
il.Emit( OpCodes.Ldloca, ltCP );
il.Emit( OpCodes.Callvirt, CPCFindCPMethod );
// Generate the following code:
// m_ConnectionPoint = (IConnectionPoint)CP;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldloc, ltCP );
il.Emit( OpCodes.Castclass, typeof(IConnectionPoint) );
il.Emit( OpCodes.Stfld, fbEventCP );
// Generate the following code:
// m_aEventSinkHelpers = new ArrayList;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Newobj, DefaultArrayListCons );
il.Emit( OpCodes.Stfld, fbSinkHelperArray );
// Generate the return opcode.
il.Emit( OpCodes.Ret );
return Meth;
}
private void DefineConstructor( TypeBuilder OutputTypeBuilder, FieldBuilder fbCPC )
{
// Retrieve the constructor info for the base class's constructor.
ConstructorInfo DefaultBaseClsCons = typeof(Object).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null );
Contract.Assert(DefaultBaseClsCons != null, "Unable to find the object's public default constructor");
// Define the default constructor.
MethodAttributes ctorAttributes = MethodAttributes.SpecialName | (DefaultBaseClsCons.Attributes & MethodAttributes.MemberAccessMask);
MethodBuilder Cons = OutputTypeBuilder.DefineMethod(
".ctor",
ctorAttributes,
null,
new Type[]{typeof(Object)} );
ILGenerator il = Cons.GetILGenerator();
// Generate the call to the base class constructor.
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Call, DefaultBaseClsCons );
// Generate the following code:
// m_ConnectionPointContainer = (IConnectionPointContainer)EventSource;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldarg, (short)1 );
il.Emit( OpCodes.Castclass, typeof(IConnectionPointContainer) );
il.Emit( OpCodes.Stfld, fbCPC );
// Generate the return opcode.
il.Emit( OpCodes.Ret );
}
private MethodBuilder DefineFinalizeMethod( TypeBuilder OutputTypeBuilder, Type SinkHelperClass, FieldBuilder fbSinkHelper, FieldBuilder fbEventCP )
{
// Find the cookie on the event sink helper.
FieldInfo CookieField = SinkHelperClass.GetField( "m_dwCookie" );
Contract.Assert(CookieField != null, "Unable to find the field m_dwCookie on the sink helper");
// Retrieve the ArrayList.Item property get method.
PropertyInfo ArrayListItemProperty = typeof(ArrayList).GetProperty( "Item" );
Contract.Assert(ArrayListItemProperty != null, "Unable to find the property ArrayList.Item");
MethodInfo ArrayListItemGetMethod = ArrayListItemProperty.GetGetMethod();
Contract.Assert(ArrayListItemGetMethod != null, "Unable to find the get method for property ArrayList.Item");
// Retrieve the ArrayList.Count property get method.
PropertyInfo ArrayListSizeProperty = typeof(ArrayList).GetProperty( "Count" );
Contract.Assert(ArrayListSizeProperty != null, "Unable to find the property ArrayList.Count");
MethodInfo ArrayListSizeGetMethod = ArrayListSizeProperty.GetGetMethod();
Contract.Assert(ArrayListSizeGetMethod != null, "Unable to find the get method for property ArrayList.Count");
// Retrieve the ConnectionPoint.Unadvise() method.
MethodInfo CPUnadviseMethod = typeof(IConnectionPoint).GetMethod( "Unadvise" );
Contract.Assert(CPUnadviseMethod != null, "Unable to find the method ConnectionPoint.Unadvise()");
// Retrieve the Marshal.ReleaseComObject() method.
MethodInfo ReleaseComObjectMethod = typeof(Marshal).GetMethod( "ReleaseComObject" );
Contract.Assert(ReleaseComObjectMethod != null, "Unable to find the method Marshal.ReleaseComObject()");
// Retrieve the Monitor.Enter() method.
MethodInfo MonitorEnterMethod = typeof(Monitor).GetMethod("Enter", MonitorEnterParamTypes, null);
Contract.Assert(MonitorEnterMethod != null, "Unable to find the method Monitor.Enter()");
// Retrieve the Monitor.Exit() method.
Type[] aParamTypes = new Type[1];
aParamTypes[0] = typeof(Object);
MethodInfo MonitorExitMethod = typeof(Monitor).GetMethod( "Exit", aParamTypes, null );
Contract.Assert(MonitorExitMethod != null, "Unable to find the method Monitor.Exit()");
// Define the Finalize method itself.
MethodBuilder Meth = OutputTypeBuilder.DefineMethod( "Finalize", MethodAttributes.Public | MethodAttributes.Virtual, null, null );
ILGenerator il = Meth.GetILGenerator();
// Declare the local variables.
LocalBuilder ltNumSinkHelpers = il.DeclareLocal( typeof(Int32) );
LocalBuilder ltSinkHelperCounter = il.DeclareLocal( typeof(Int32) );
LocalBuilder ltCurrSinkHelper = il.DeclareLocal( SinkHelperClass );
LocalBuilder ltLockTaken = il.DeclareLocal(typeof(bool));
// Generate the following code:
// try {
il.BeginExceptionBlock();
// Generate the following code:
// Monitor.Enter(this, ref lockTaken);
il.Emit(OpCodes.Ldarg, (short)0);
il.Emit(OpCodes.Ldloca_S, ltLockTaken);
il.Emit(OpCodes.Call, MonitorEnterMethod);
// Generate the labels.
Label ForBeginLabel = il.DefineLabel();
Label ReleaseComObjectLabel = il.DefineLabel();
Label AfterReleaseComObjectLabel = il.DefineLabel();
// Generate the following code:
// if ( m_IFooEventsCP == null ) goto AfterReleaseComObjectLabel;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Brfalse, AfterReleaseComObjectLabel );
// Generate the following code:
// int NumEventHelpers = m_aIFooEventsHelpers.Count;
// int cEventHelpers = 0;
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelper );
il.Emit( OpCodes.Callvirt, ArrayListSizeGetMethod );
il.Emit( OpCodes.Stloc, ltNumSinkHelpers );
il.Emit( OpCodes.Ldc_I4, 0 );
il.Emit( OpCodes.Stloc, ltSinkHelperCounter );
// Generate the following code:
// if ( 0 >= NumEventHelpers ) goto ReleaseComObjectLabel;
il.Emit( OpCodes.Ldc_I4, 0 );
il.Emit( OpCodes.Ldloc, ltNumSinkHelpers );
il.Emit( OpCodes.Bge, ReleaseComObjectLabel );
// Mark this as the beginning of the for loop's body.
il.MarkLabel( ForBeginLabel );
// Generate the following code:
// CurrentHelper = (IFooEvents_SinkHelper)m_aIFooEventsHelpers.Get( cEventHelpers );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbSinkHelper );
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Callvirt, ArrayListItemGetMethod );
il.Emit( OpCodes.Castclass, SinkHelperClass );
il.Emit( OpCodes.Stloc, ltCurrSinkHelper );
// Generate the following code:
// m_IFooEventsCP.Unadvise( CurrentHelper.m_dwCookie );
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Ldloc, ltCurrSinkHelper );
il.Emit( OpCodes.Ldfld, CookieField );
il.Emit( OpCodes.Callvirt, CPUnadviseMethod );
// Generate the following code:
// cEventHelpers++;
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Ldc_I4, 1 );
il.Emit( OpCodes.Add );
il.Emit( OpCodes.Stloc, ltSinkHelperCounter );
// Generate the following code:
// if ( cEventHelpers < NumEventHelpers ) goto ForBeginLabel;
il.Emit( OpCodes.Ldloc, ltSinkHelperCounter );
il.Emit( OpCodes.Ldloc, ltNumSinkHelpers );
il.Emit( OpCodes.Blt, ForBeginLabel );
// Mark this as the end of the for loop's body.
il.MarkLabel( ReleaseComObjectLabel );
// Generate the following code:
// Marshal.ReleaseComObject(m_IFooEventsCP);
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Ldfld, fbEventCP );
il.Emit( OpCodes.Call, ReleaseComObjectMethod );
il.Emit( OpCodes.Pop );
// Mark this as the end of the for loop's body.
il.MarkLabel( AfterReleaseComObjectLabel );
// Generate the following code:
// } catch {
il.BeginCatchBlock(typeof(System.Exception));
il.Emit( OpCodes.Pop );
// Generate the following code:
// } finally {
il.BeginFinallyBlock();
// Generate the following code:
// if (lockTaken)
// Monitor.Exit(this);
Label skipExit = il.DefineLabel();
il.Emit(OpCodes.Ldloc, ltLockTaken);
il.Emit(OpCodes.Brfalse_S, skipExit);
il.Emit(OpCodes.Ldarg, (short)0);
il.Emit(OpCodes.Call, MonitorExitMethod);
il.MarkLabel(skipExit);
// Generate the following code:
// }
il.EndExceptionBlock();
// Generate the return opcode.
il.Emit( OpCodes.Ret );
return Meth;
}
private void DefineDisposeMethod( TypeBuilder OutputTypeBuilder, MethodBuilder FinalizeMethod )
{
// Retrieve the method info for GC.SuppressFinalize().
MethodInfo SuppressFinalizeMethod = typeof(GC).GetMethod("SuppressFinalize");
Contract.Assert(SuppressFinalizeMethod != null, "Unable to find the GC.SuppressFinalize");
// Define the Finalize method itself.
MethodBuilder Meth = OutputTypeBuilder.DefineMethod( "Dispose", MethodAttributes.Public | MethodAttributes.Virtual, null, null );
ILGenerator il = Meth.GetILGenerator();
// Generate the following code:
// Finalize()
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Callvirt, FinalizeMethod );
// Generate the following code:
// GC.SuppressFinalize()
il.Emit( OpCodes.Ldarg, (short)0 );
il.Emit( OpCodes.Call, SuppressFinalizeMethod );
// Generate the return opcode.
il.Emit( OpCodes.Ret );
}
private ModuleBuilder m_OutputModule;
private String m_strDestTypeName;
private Type m_EventItfType;
private Type m_SrcItfType;
private Type m_SinkHelperType;
}
}
|