private static Hashtable GetTargetMethods(Object BaseObject) { Type baseType = BaseObject.GetType(); Hashtable retVal = new Hashtable(); foreach (Type itf in baseType.GetInterfaces()) { InterfaceMapping imap = baseType.GetInterfaceMap(itf); for (int i = 0; i < imap.InterfaceMethods.Length; i++) { MethodInfo trueTarget; if (imap.TargetMethods[i].IsPublic) { // We can invoke the true target // so the mapping will be directly to the target method. // Note that I don't care if it's final or not. trueTarget = imap.TargetMethods[i]; } else { trueTarget = imap.InterfaceMethods[i]; } MethodMappings itfMM = (MethodMappings)retVal[trueTarget]; if (null == itfMM) { itfMM = new MethodMappings(trueTarget, true); retVal.Add(trueTarget, itfMM); } itfMM.MappedMethods.Add(imap.InterfaceMethods[i]); } } foreach (MethodInfo mi in baseType.GetMethods()) { if (mi.IsPublic && mi.IsVirtual && !mi.IsFinal) { // Let's see if we already have it // from the interface mapping. MethodMappings baseMM = (MethodMappings)retVal[mi]; if (null == baseMM) { // This method doesn't override // any itf. methods, so add it. baseMM = new MethodMappings(mi, false); retVal.Add(mi, baseMM); baseMM.MappedMethods.Add(mi); } } } return(retVal); }
private static void BuildTargetMethods(TypeBuilder BaseProxy, MethodInfo InvokeMethod, FieldBuilder WrappedObject, Hashtable TargetMethods) { #region Variable Declarations Type[] argTypes = null; LocalBuilder argValues = null; MethodAttributes methodAttribs; LocalBuilder methodCxtInfo = null; MethodInfo mi = null; Type paramRetType = null; String paramRetTypeName = null; Type paramType = null; String paramTypeName = null; ParameterInfo pi = null; MethodBuilder proxyMethod = null; ILGenerator proxyMthIL = null; LocalBuilder retVal = null; LocalBuilder targetMethod = null; LocalBuilder tempRetVal = null; LocalBuilder wrappedType = null; #endregion /* * methodAttribs = MethodAttributes.HideBySig | * MethodAttributes.NewSlot | MethodAttributes.Virtual | * MethodAttributes.Private; */ methodAttribs = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Private; foreach (DictionaryEntry de in TargetMethods) { mi = (MethodInfo)de.Key; argTypes = new Type[mi.GetParameters().Length]; for (int i = 0; i < mi.GetParameters().Length; i++) { argTypes[i] = mi.GetParameters()[i].ParameterType; } proxyMethod = BaseProxy.DefineMethod(mi.Name + mi.GetHashCode(), methodAttribs, mi.ReturnType, argTypes); // Determine if this method should override // the mapped method (OverridesInterfaceMethods == false) // or a number of itf. methods (OverridesInterfaceMethods == true) MethodMappings mm = (MethodMappings)de.Value; if (false == mm.OverridesInterfaceMethods) { BaseProxy.DefineMethodOverride(proxyMethod, mi); } else { for (int itfs = 0; itfs < mm.MappedMethods.Count; itfs++) { MethodInfo itfMth = (MethodInfo)mm.MappedMethods[itfs]; BaseProxy.DefineMethodOverride(proxyMethod, itfMth); } } proxyMthIL = proxyMethod.GetILGenerator(); // These are always there. argValues = proxyMthIL.DeclareLocal(typeof(Object[])); methodCxtInfo = proxyMthIL.DeclareLocal(typeof(MethodContextInfo)); targetMethod = proxyMthIL.DeclareLocal(typeof(MethodInfo)); wrappedType = proxyMthIL.DeclareLocal(typeof(Type)); // Check for a return value. if (typeof(void) != mi.ReturnType) { tempRetVal = proxyMthIL.DeclareLocal(typeof(Object)); retVal = proxyMthIL.DeclareLocal(mi.ReturnType); } proxyMthIL.Emit(OpCodes.Ldc_I4, mi.GetParameters().Length); proxyMthIL.Emit(OpCodes.Newarr, typeof(Object)); // Set up the arg array if (0 == mi.GetParameters().Length) { // Store in argValues - there's no values // to put into the array. proxyMthIL.Emit(OpCodes.Stloc, argValues); } else { proxyMthIL.Emit(OpCodes.Stloc, argValues); for (int argLoad = 0; argLoad < mi.GetParameters().Length; argLoad++) { proxyMthIL.Emit(OpCodes.Ldloc, argValues); proxyMthIL.Emit(OpCodes.Ldc_I4, argLoad); proxyMthIL.Emit(OpCodes.Ldarg, argLoad + 1); pi = mi.GetParameters()[argLoad]; paramTypeName = pi.ParameterType.ToString(); paramTypeName = paramTypeName.Replace("&", ""); paramType = Type.GetType(paramTypeName); if (pi.ParameterType.IsByRef) { proxyMthIL.Emit(OpCodes.Ldobj, paramType); } if (paramType.IsValueType) { proxyMthIL.Emit(OpCodes.Box, paramType); } proxyMthIL.Emit(OpCodes.Stelem_Ref); } } // Get the target method. proxyMthIL.Emit(OpCodes.Ldtoken, mi); proxyMthIL.Emit(OpCodes.Call, typeof(MethodBase).GetMethod(GET_METHOD_FROM_HANDLE)); proxyMthIL.Emit(OpCodes.Castclass, typeof(MethodInfo)); proxyMthIL.Emit(OpCodes.Stloc, targetMethod); // Set up the method context object. proxyMthIL.Emit(OpCodes.Ldloca, methodCxtInfo); proxyMthIL.Emit(OpCodes.Ldarg_0); proxyMthIL.Emit(OpCodes.Ldfld, WrappedObject); proxyMthIL.Emit(OpCodes.Callvirt, typeof(Object).GetMethod(GET_TYPE)); proxyMthIL.Emit(OpCodes.Stloc, wrappedType); proxyMthIL.Emit(OpCodes.Ldloc, wrappedType); proxyMthIL.Emit(OpCodes.Callvirt, typeof(Type).GetMethod(GET_ASSEMBLY_PROP)); proxyMthIL.Emit(OpCodes.Callvirt, typeof(Assembly).GetMethod(GET_NAME, Type.EmptyTypes)); proxyMthIL.Emit(OpCodes.Ldloc, wrappedType); proxyMthIL.Emit(OpCodes.Callvirt, typeof(Type).GetMethod(GET_FULL_NAME_PROP)); proxyMthIL.Emit(OpCodes.Ldloc, targetMethod); proxyMthIL.Emit(OpCodes.Callvirt, typeof(MemberInfo).GetMethod(GET_NAME_PROP)); argTypes = new Type[3]; argTypes[0] = typeof(AssemblyName); argTypes[1] = typeof(String); argTypes[2] = typeof(String); proxyMthIL.Emit(OpCodes.Call, typeof(MethodContextInfo).GetConstructor(argTypes)); // "invokeMethod()". proxyMthIL.Emit(OpCodes.Ldarg_0); proxyMthIL.Emit(OpCodes.Ldloc, targetMethod); proxyMthIL.Emit(OpCodes.Ldloca, argValues); proxyMthIL.Emit(OpCodes.Ldloc, methodCxtInfo); proxyMthIL.Emit(OpCodes.Call, InvokeMethod); // Set the method value (if any exists). if (typeof(void) != mi.ReturnType) { // Need to be careful here. If the return type // is null, then we leave retVal as-is. Label retIsNull = proxyMthIL.DefineLabel(); proxyMthIL.Emit(OpCodes.Stloc, tempRetVal); proxyMthIL.Emit(OpCodes.Ldloc, tempRetVal); proxyMthIL.Emit(OpCodes.Brfalse, retIsNull); proxyMthIL.Emit(OpCodes.Ldloc, tempRetVal); if (mi.ReturnType.IsValueType) { // Unbox whatever is on the stack. proxyMthIL.Emit(OpCodes.Unbox, mi.ReturnType); // Note: See pg. 72 of Partition III to see why // I chose the general ldobj over ldind. proxyMthIL.Emit(OpCodes.Ldobj, mi.ReturnType); } else { proxyMthIL.Emit(OpCodes.Castclass, mi.ReturnType); } proxyMthIL.Emit(OpCodes.Stloc, retVal); proxyMthIL.MarkLabel(retIsNull); } else { proxyMthIL.Emit(OpCodes.Pop); } // Move the ByRef or out arg values from the array // to the arg values. foreach (ParameterInfo argValueByRef in mi.GetParameters()) { if (argValueByRef.ParameterType.IsByRef || argValueByRef.IsOut) { paramRetTypeName = argValueByRef.ParameterType.ToString(); paramRetTypeName = paramRetTypeName.Replace("&", ""); paramRetType = Type.GetType(paramRetTypeName); proxyMthIL.Emit(OpCodes.Ldarg, argValueByRef.Position + 1); proxyMthIL.Emit(OpCodes.Ldloc, argValues); proxyMthIL.Emit(OpCodes.Ldc_I4, argValueByRef.Position); proxyMthIL.Emit(OpCodes.Ldelem_Ref); if (paramRetType.IsValueType) { proxyMthIL.Emit(OpCodes.Unbox, paramRetType); proxyMthIL.Emit(OpCodes.Ldobj, paramRetType); proxyMthIL.Emit(OpCodes.Stobj, paramRetType); } else { if (paramRetType != typeof(Object)) { proxyMthIL.Emit(OpCodes.Castclass, paramRetType); } proxyMthIL.Emit(OpCodes.Stind_Ref); } } } // Finally...return. if (typeof(void) != mi.ReturnType) { proxyMthIL.Emit(OpCodes.Ldloc, retVal); } proxyMthIL.Emit(OpCodes.Ret); } }