private static MethodBuilder CreateMethodInternal(InterfaceInfo info, VarDesc var, InterfaceMemberInfo memberInfo, CreateMethodMode mode, ref bool isConversionLoss) { bool convertingNewEnumMember = IsNewEnumDispatchProperty(info.ConverterInfo, info.RefTypeInfo, var, memberInfo.Index); Type retType = null; Type[] paramTypes = null; TypeConverter propTypeConverter = new TypeConverter(info.ConverterInfo, info.RefTypeInfo, var.elemdescVar.tdesc, ConversionType.ReturnValue); isConversionLoss |= propTypeConverter.IsConversionLoss; Type propType = propTypeConverter.ConvertedType; int propTypeParamIndex = 0; // The index of the function parameter that represents the property type if (memberInfo.InvokeKind == TypeLibTypes.Interop.INVOKEKIND.INVOKE_PROPERTYGET) { retType = propType; paramTypes = new Type[] { }; propTypeParamIndex = 0; // for Type get_XXX(). Index = 0 } else if (memberInfo.InvokeKind == TypeLibTypes.Interop.INVOKEKIND.INVOKE_PROPERTYPUT) { retType = typeof(void); paramTypes = new Type[] { propType }; propTypeParamIndex = 1; // for void set_XXX(Type arg). Index = 1 } else { Debug.Assert(false, "Should not get here!"); } MethodBuilder methodBuilder = CreateMethodCore(info, memberInfo, convertingNewEnumMember, mode, true, retType, paramTypes); ProcessParam(info, memberInfo, var.elemdescVar, propTypeConverter, methodBuilder, propTypeParamIndex, "", false, false); return methodBuilder; }
private static MethodBuilder CreateMethodCore(InterfaceInfo info, InterfaceMemberInfo memberInfo, bool isNewEnumMember, CreateMethodMode mode, bool isStandardOleCall, Type retType, Type[] paramTypes) { // // vtbl gap support. We only emit vtbl gap for non dispinterfaces // if (!info.IsCoClass && !info.RefTypeAttr.IsDispatch && mode != CreateMethodMode.EventDelegateMode) { int pointerSize = GetPointerSize(info.RefTypeInfo); int slot = memberInfo.RefFuncDesc.oVft / pointerSize; if (slot != info.CurrentSlot) { // Make sure slot numbers are monotonically increasing. if (slot < info.CurrentSlot) { info.ConverterInfo.ReportEvent( WarningCode.Wrn_BadVTable, Resource.FormatString("Wrn_BadVTable", new object[] { memberInfo.UniqueName, info.TypeBuilder.FullName, info.ConverterInfo.ModuleBuilder.Name }) ); throw new TlbImpInvalidTypeConversionException(info.RefTypeInfo); } int gap = slot - info.CurrentSlot; string vtblGapFuncName; if (gap == 1) vtblGapFuncName = string.Format(VTBL_GAP_FORMAT_1, info.CurrentSlot); else vtblGapFuncName = string.Format(VTBL_GAP_FORMAT_N, info.CurrentSlot, gap); MethodBuilder vtblFunc = info.TypeBuilder.DefineMethod( vtblGapFuncName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Abstract); vtblFunc.SetImplementationFlags(MethodImplAttributes.Runtime); info.CurrentSlot = slot; } ++info.CurrentSlot; } MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.Virtual; string methodName; // Determine the name & attributes if (mode == CreateMethodMode.EventDelegateMode) { methodName = INVOKE_METHOD; } else { methodName = info.GenerateUniqueMemberName(memberInfo.RecommendedName, paramTypes, MemberTypes.Method); // Update the name so that we can know the unique member name in the interface later in override if (!info.IsCoClass) { memberInfo.UpdateUniqueName(methodName); } attributes |= System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.NewSlot; if (!info.IsCoClass) { attributes |= System.Reflection.MethodAttributes.Abstract; } } // Is property? If so, add SpecialName to attributes if (!isNewEnumMember && memberInfo.InvokeKind != TypeLibTypes.Interop.INVOKEKIND.INVOKE_FUNC) attributes |= MethodAttributes.SpecialName; MethodBuilder methodBuilder = info.TypeBuilder.DefineMethod( methodName, attributes, CallingConventions.ExplicitThis | CallingConventions.HasThis, retType, paramTypes); // Set implementation flags MethodImplAttributes implAttributes; if (mode == CreateMethodMode.EventDelegateMode) implAttributes = MethodImplAttributes.Managed | MethodImplAttributes.Runtime; else implAttributes = MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime; if (!isStandardOleCall) implAttributes |= MethodImplAttributes.PreserveSig; methodBuilder.SetImplementationFlags(implAttributes); // Add handling for [id(...)] if necessary if (info.EmitDispId || memberInfo.DispIdIsOverridden) { if (info.IsCoClass && !info.IsDefaultInterface) { // Skip non-default interfaces in coclass } else { methodBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForDispId(memberInfo.DispId)); } } if (memberInfo.PropertyInfo != null && memberInfo.PropertyInfo.HasInvalidGetter) { info.ConverterInfo.ReportEvent( WarningCode.Wrn_PropgetWithoutReturn, Resource.FormatString("Wrn_PropgetWithoutReturn", memberInfo.PropertyInfo.RecommendedName, info.TypeBuilder.FullName ) ); } if (memberInfo.IsProperty && !isNewEnumMember) { info.PropertyInfo.SetPropertyInfo(memberInfo, methodBuilder); } // Add a .override instruction for the method for coclass if (info.IsCoClass) { Debug.Assert(info.CurrentImplementingInterface != null); using (TypeAttr implementingInterfaceAttr = info.CurrentImplementingInterface.GetTypeAttr()) { IConvBase convBase = info.ConverterInfo.GetInterface(info.CurrentImplementingInterface, implementingInterfaceAttr); Type interfaceType = convBase.RealManagedType; // Type.GetMethod(Name, ParamList) actually requires all the parameters be loaded (thus created). // Type.GetMethod(Name) won't have this problem. // We can workaround this limitation by having the coclass created after all the other types // Must use UniqueName because it is the right name on the interface. // We should use exact match here. MethodInfo methodInfo = interfaceType.GetMethod(memberInfo.UniqueName, BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Instance, null, paramTypes, null); if (methodInfo == null) { string expectedPrototypeString = FormatMethodPrototype(retType, memberInfo.UniqueName, paramTypes); string msg = Resource.FormatString("Err_OverridedMethodNotFoundInImplementedInterface", new object[] { expectedPrototypeString, interfaceType.FullName, info.TypeBuilder.FullName, info.TypeBuilder.Assembly.FullName }); throw new TlbImpGeneralException(msg, ErrorCode.Err_OverridedMethodNotFoundInImplementedInterface); } info.TypeBuilder.DefineMethodOverride(methodBuilder, methodInfo); } } return methodBuilder; }
private static MethodBuilder CreateMethodInternal(InterfaceInfo info, FuncDesc func, InterfaceMemberInfo memberInfo, CreateMethodMode mode, ref bool isConversionLoss) { bool isNewEnumMember = false; if (info.AllowNewEnum && IsNewEnumFunc(info.ConverterInfo, info.RefTypeInfo, func, memberInfo.Index)) { info.AllowNewEnum = false; isNewEnumMember = true; if (mode == CreateMethodMode.EventDelegateMode) { info.ConverterInfo.ReportEvent( WarningCode.Wrn_EventWithNewEnum, Resource.FormatString("Wrn_EventWithNewEnum", info.RefTypeInfo.GetDocumentation())); } } // // Optional Arguments // int varArg; // index of the vararg argument int firstOptArg; // index of the first optional argument int lastOptArg; // index of the last optional argument CheckForOptionalArguments(info.ConverterInfo, func, out varArg, out firstOptArg, out lastOptArg); // // Figure out types // ReturnKind returnKind; TypeConverter retTypeConverter; Type retType; bool isStandardOleCall; int lcidArg; int retArgId; TypeConverter[] paramTypeConverters = GenerateParameterTypes(info, memberInfo, func, isNewEnumMember, varArg, out lcidArg, out isStandardOleCall, out retTypeConverter, out returnKind, out retArgId); var paramTypes = new Type[paramTypeConverters.Length]; for (int i = 0; i < paramTypeConverters.Length; ++i) paramTypes[i] = paramTypeConverters[i].ConvertedType; if (retTypeConverter != null) retType = retTypeConverter.ConvertedType; else retType = null; MethodBuilder methodBuilder = CreateMethodCore(info, memberInfo, isNewEnumMember, mode, isStandardOleCall, retType, paramTypes); // // Emit LCIDConversionAttribute // if (lcidArg >= 0) methodBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForLCIDConversion(lcidArg)); int cParams = func.cParams; int cParamsIter = cParams; // If there is a return value, skip the last param if (returnKind == ReturnKind.RetValParameter) { ProcessParam(info, memberInfo, func.GetElemDesc(retArgId), retTypeConverter, methodBuilder, 0, "", false, false); isConversionLoss |= retTypeConverter.IsConversionLoss; } else if (returnKind == ReturnKind.ReturnValue) { ProcessParam(info, memberInfo, func.elemdescFunc, retTypeConverter, methodBuilder, 0, "", false, false); isConversionLoss |= retTypeConverter.IsConversionLoss; } // First string is the method name so offset by one String[] saNames = info.RefTypeInfo.GetNames(func.memid, cParams + 1); // // Process parameters // int paramIndex = 0; for (int n = 0; n < cParamsIter; ++n) { ElemDesc elem = func.GetElemDesc(n); // Skip LCID if (elem.paramdesc.IsLCID) continue; // Skip the return parameter if (returnKind == ReturnKind.RetValParameter && n == retArgId) continue; bool isOptionalArg = (n >= firstOptArg && n <= lastOptArg); bool isVarArg = (n == varArg); ProcessParam(info, memberInfo, elem, paramTypeConverters[paramIndex], methodBuilder, paramIndex + 1, saNames[n + 1], isVarArg, isOptionalArg); isConversionLoss |= paramTypeConverters[paramIndex].IsConversionLoss; paramIndex++; } // // Emit TypeLibFuncAttribute if necessary // if (func.wFuncFlags != 0) methodBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForTypeLibFunc((TypeLibFuncFlags)func.wFuncFlags)); // // Handle DefaultMemberAttribute // if (!memberInfo.IsProperty && memberInfo.DispId == WellKnownDispId.DISPID_VALUE) { // DIFF: TlbImpv1 use the type library name while we use the unique name info.ConverterInfo.SetDefaultMember(info.TypeBuilder, methodBuilder.Name); } return methodBuilder; }
private static void CreateMethod(InterfaceInfo info, InterfaceMemberInfo memberInfo, CreateMethodMode mode) { MethodBuilder method = null; bool isConversionLoss = false; switch (memberInfo.MemberType) { // Handle normal methods as well as accesors for properties case InterfaceMemberType.Method: method = CreateMethodInternal(info, memberInfo.RefFuncDesc, memberInfo, mode, ref isConversionLoss); break; // Handle properties in dispatch interfaces defined as variables case InterfaceMemberType.Variable: method = CreateMethodInternal(info, memberInfo.RefVarDesc, memberInfo, mode, ref isConversionLoss); break; default: Debug.Assert(false); break; } if (method == null) return; if (isConversionLoss) { string msg = Resource.FormatString( "Wrn_UnconvertableArgs", info.TypeBuilder.FullName, method.Name); info.ConverterInfo.ReportEvent(WarningCode.Wrn_UnconvertableArgs, msg); } info.IsConversionLoss |= isConversionLoss; }