summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs')
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs772
1 files changed, 772 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs
new file mode 100644
index 0000000000..2427a5fb39
--- /dev/null
+++ b/src/mscorlib/src/System/Runtime/InteropServices/TCEAdapterGen/EventProviderWriter.cs
@@ -0,0 +1,772 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+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;
+ }
+}