/// <summary> /// Get the event delegate for specified method in the source interface. Create a new one if necessary /// </summary> /// <param name="index">Function index</param> /// <returns>The delegate type</returns> public Type GetEventDelegate(InterfaceMemberInfo memberInfo) { TypeInfo type = memberInfo.RefTypeInfo; using (TypeAttr attr = type.GetTypeAttr()) { // Create m_delegateTypes on demand if (m_delegateTypes == null) { m_delegateTypes = new Dictionary <InterfaceMemberInfo, Type>(); } // // Check if we already have a delegate type for method n // if (!m_delegateTypes.ContainsKey(memberInfo)) { // // If not, create a new delegate // FuncDesc func = type.GetFuncDesc(memberInfo.Index); string eventName = type.GetDocumentation(func.memid); string delegateName = m_info.GetRecommendedManagedName(m_convInterface.RefTypeInfo, ConvType.Interface, true) + "_" + type.GetDocumentation(func.memid) + "EventHandler"; // Deal with name collisions delegateName = m_info.GetUniqueManagedName(delegateName); TypeBuilder delegateTypeBuilder = m_info.ModuleBuilder.DefineType( delegateName, TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate) ); // Create constructor for the delegate ConstructorBuilder delegateCtorBuilder = delegateTypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeof(Object), typeof(UIntPtr) }); delegateCtorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); // Create methods for the delegate InterfaceInfo interfaceInfoForDelegate = new InterfaceInfo(m_info, delegateTypeBuilder, false, type, attr, false, true); interfaceInfoForDelegate.AllowNewEnum = !m_convInterface.ImplementsIEnumerable; ConvCommon.CreateMethodForDelegate(interfaceInfoForDelegate, func, memberInfo.Index); // Emit ComVisibleAttribute(false) delegateTypeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComVisible(false)); // Emit TypeLibTypeAttribute(TypeLibTypeFlags.FHidden) to hide it from object browser in VB delegateTypeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForTypeLibType(TypeLibTypeFlags.FHidden)); // Create the delegate m_delegateTypes[memberInfo] = delegateTypeBuilder.CreateType(); } } return(m_delegateTypes[memberInfo]); }
/// <summary> /// Implement methods in parent interfaces /// </summary> private void HandleParentInterface(TypeInfo type, bool bSource, ref bool isConversionLoss, bool isDefault) { using (TypeAttr attr = type.GetTypeAttr()) { InterfaceInfo interfaceInfo = new InterfaceInfo(m_info, m_typeBuilder, ConvCommon.InterfaceSupportsDispatch(type, attr), type, attr, true, bSource, type); interfaceInfo.IsDefaultInterface = isDefault; if (bSource) { // When adding override methods to the interface, we need to use the event interface for source interfaces ConvCommon.CreateEventInterfaceCommon(interfaceInfo); } else { ConvCommon.CreateInterfaceCommon(interfaceInfo); } isConversionLoss |= interfaceInfo.IsConversionLoss; } }
/// <summary> /// Create the event interface /// </summary> public override void OnCreate() { if (m_type != null) return; string name = m_convInterface.ManagedName; m_convInterface.Create(); using (TypeAttr attr = m_convInterface.RefTypeInfo.GetTypeAttr()) { // // Emit attributes // // // Emit [ComEventInterfaceAttribute(...)] // ConstructorInfo ctorComEventInterface = typeof(ComEventInterfaceAttribute).GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Type), typeof(Type) }, null); // // Build the blob manually before creating the event interface / provider types. // We only need to give the name of the types, in order to simplify creation logic and avoid dependency // CustomAttributeBlobBuilder blobBuilder = new CustomAttributeBlobBuilder(); string eventInterfaceFullyQualifiedName = name; if (m_convInterface.ConvScope == ConvScope.External) eventInterfaceFullyQualifiedName = m_convInterface.ManagedType.AssemblyQualifiedName; blobBuilder.AddFixedArg(eventInterfaceFullyQualifiedName); // source interface // Handle event provider name generation collision scenario m_eventProviderName = m_info.GetUniqueManagedName( m_info.GetRecommendedManagedName(m_convInterface.RefTypeInfo, ConvType.Interface, true) + "_EventProvider"); blobBuilder.AddFixedArg(m_eventProviderName); // corresponding event provider m_typeBuilder.SetCustomAttribute(ctorComEventInterface, blobBuilder.GetBlob()); // // Emit ComVisibleAttribute(false) // m_typeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComVisible(false)); // // Emit TypeLibTypeAttribute for TYPEFLAG_FHIDDEN // m_typeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForTypeLibType(TypeLibTypeFlags.FHidden)); bool isConversionLoss = false; // // Verify if the type has any properties // Type interfaceType = m_convInterface.RealManagedType; if (interfaceType.GetProperties().Length > 0) { // Emit a warning and we'll skip the properties m_info.ReportEvent( WarningCode.Wrn_NoPropsInEvents, Resource.FormatString("Wrn_NoPropsInEvents", RefTypeInfo.GetDocumentation())); isConversionLoss = true; } // // Create event interface // InterfaceInfo eventInterfaceInfo = new InterfaceInfo(m_info, m_typeBuilder, false, m_convInterface.RefTypeInfo, attr, false, true); ConvCommon.CreateEventInterfaceCommon(eventInterfaceInfo); isConversionLoss |= eventInterfaceInfo.IsConversionLoss; // // Emit ComConversionLossAttribute if necessary // if (eventInterfaceInfo.IsConversionLoss) { m_typeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComConversionLoss()); } } m_type = m_typeBuilder.CreateType(); }
/// <summary> /// Implement methods in parent interfaces /// </summary> private void HandleParentInterface(TypeInfo type, bool bSource, ref bool isConversionLoss, bool isDefault) { using (TypeAttr attr = type.GetTypeAttr()) { InterfaceInfo interfaceInfo = new InterfaceInfo(m_info, m_typeBuilder, ConvCommon.InterfaceSupportsDispatch(type, attr), type, attr, true, bSource, type); interfaceInfo.IsDefaultInterface = isDefault; if (bSource) // When adding override methods to the interface, we need to use the event interface for source interfaces ConvCommon.CreateEventInterfaceCommon(interfaceInfo); else ConvCommon.CreateInterfaceCommon(interfaceInfo); isConversionLoss |= interfaceInfo.IsConversionLoss; } }
public PropertyInfo(InterfaceInfo info) { m_info = info; Debug.Assert(info != null); }
public static int GetIndexOfFirstMethod(InterfaceInfo info) { TypeInfo type = info.RefTypeInfo; TypeAttr attr = info.RefTypeAttr; return GetIndexOfFirstMethod(type, attr); }
public static void CreateMethodForInterface(InterfaceInfo info, InterfaceMemberInfo memberInfo) { CreateMethod(info, memberInfo, CreateMethodMode.InterfaceMethodMode); }
private static void GetRuledParameterTypeConverters(InterfaceInfo info, InterfaceMemberInfo memInfo, FuncDesc func, out List<TypeConverter> convertToParameterConverterList) { int cParams = func.cParams; convertToParameterConverterList = new List<TypeConverter>(); short n; for (n = 0; n < cParams; ++n) { ElemDesc elem = func.GetElemDesc(n); ParamDesc paramDesc = elem.paramdesc; // "ConvertTo" for basic types and array // Rule Engine Rule convertToRule = null; if (memInfo.Index != -1) { // Is not event delegate. SignatureInfoMatchTarget target = new SignatureInfoMatchTarget( info.RefTypeInfo, memInfo.Index, elem, n + 1); if (info.ConverterInfo.Settings.m_ruleSet != null) { ICategory signatureCategory = SignatureCategory.GetInstance(); AbstractActionManager actionManager = RuleEngine.GetActionManager(); List<Rule> convertToRules = info.ConverterInfo.Settings.m_ruleSet.GetRule( signatureCategory, ConvertToActionDef.GetInstance(), target); if (convertToRules.Count != 0) { if (convertToRules.Count > 1) { Output.WriteWarning( Resource.FormatString("Wrn_RuleMultipleMatch", ConvertToActionDef.GetInstance().GetActionName()), WarningCode.Wrn_RuleMultipleMatch); } convertToRule = convertToRules[convertToRules.Count - 1]; } } if (convertToRule != null) { var convertToAction = convertToRule.Action as ConvertToAction; Type typeReturn; CustomAttributeBuilder customAttribute; ParameterAttributes fixedParameterAttributes; GetTypeFromConvertToAction(target, convertToAction, info.ConverterInfo, info.RefTypeInfo, elem.tdesc, out typeReturn, out customAttribute, out fixedParameterAttributes); convertToParameterConverterList.Add( new TypeConverter(typeReturn, customAttribute, fixedParameterAttributes)); } else { convertToParameterConverterList.Add(null); } } else { convertToParameterConverterList.Add(null); } } }
/// <summary> /// Create methods using the InterfaceInfo /// </summary> private static void CreateMethods(InterfaceInfo info) { // // Stop if info is already IUnknown. Doesn't stop for IDispatch because we want to convert the members of IDispatch // if (WellKnownGuids.IID_IUnknown == info.RefTypeAttr.Guid) return; // // Create methods for parent interface. We need to duplicate them. // if (info.RefTypeAttr.cImplTypes == 1) { TypeInfo parent = info.RefTypeInfo.GetRefType(0); using (TypeAttr parentAttr = parent.GetTypeAttr()) { if (WellKnownGuids.IID_IUnknown != parentAttr.Guid && WellKnownGuids.IID_IDispatch != parentAttr.Guid) { InterfaceInfo parentInterfaceInfo = new InterfaceInfo(info.ConverterInfo, info.TypeBuilder, info.EmitDispId, parent, parentAttr, info.IsCoClass, info.IsSource, info.CurrentImplementingInterface); parentInterfaceInfo.IsDefaultInterface = info.IsDefaultInterface; parentInterfaceInfo.CurrentSlot = info.CurrentSlot; ConvCommon.CreateInterfaceCommon(parentInterfaceInfo); info.CurrentSlot = parentInterfaceInfo.CurrentSlot; /* info.PushType(parent, parentAttr); CreateMethods(info); info.PopType(); */ } else { // Initialize v-table slot for IUnknown/IDispatch info.CurrentSlot = parentAttr.cbSizeVft / parentAttr.cbSizeInstance; } } } // // Create methods for normal methods & property accessors // IConvInterface convInterface = (IConvInterface)info.ConverterInfo.GetTypeRef(ConvType.Interface, info.RefTypeInfo); info.AllowNewEnum = !convInterface.ImplementsIEnumerable; foreach (InterfaceMemberInfo memberInfo in convInterface.AllMembers) { CreateMethodForInterface(info, memberInfo); } // // Generate the properties // info.PropertyInfo.GenerateProperties(); }
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 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 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 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; }
/// <summary> /// /// </summary> /// <param name="info">The interfaceInfo</param> /// <param name="isCreateEventInterface"> /// True if we are creating event interface, false if creating a normal interface /// </param> public static void CreateInterfaceCommonInternal(InterfaceInfo info, bool isCreateEventInterface) { bool bIsIDispatchBasedOnInterface = false; // I finally figured this part out // For dual interfaces, it has a "funky" TKIND_DISPATCH|TKIND_DUAL interface with a parter of TKIND_INTERFACE|TKIND_DUAL interface // The first one is pretty bad and has duplicated all the interface members of its parent, which is not we want // We want the second v-table interface // So, if we indeed has seen this kind of interface, prefer its partner // However, we should not blindly get the partner because those two interfaces partners with each other // So we need to first test to see if the interface is both dispatch & dual, and then get its partner interface if (info.RefTypeAttr.IsDual && info.RefTypeAttr.IsDispatch) { TypeInfo typeReferencedType = info.RefTypeInfo.GetRefTypeNoComThrow(); if (typeReferencedType != null) { using (TypeAttr attrReferencedType = typeReferencedType.GetTypeAttr()) { // Either eliminate the type stack stuff or put PropertyInfo stuff elsewhere // We cannot keep properties on the same interface info as it will cause problems info.PushType(typeReferencedType, attrReferencedType); if (isCreateEventInterface) CreateEventMethods(info); else CreateMethods(info); info.PopType(); bIsIDispatchBasedOnInterface = true; } } } if (!bIsIDispatchBasedOnInterface) { if (isCreateEventInterface) CreateEventMethods(info); else CreateMethods(info); } }
public static void CreateMethodForDelegate(InterfaceInfo info, FuncDesc funcDesc, int index) { InterfaceMemberInfo memberInfo = new InterfaceMemberInfo(info.ConverterInfo, info.RefTypeInfo, index, INVOKE_METHOD, INVOKE_METHOD, InterfaceMemberType.Method, TypeLibTypes.Interop.INVOKEKIND.INVOKE_FUNC, funcDesc.memid, funcDesc, null); CreateMethod(info, memberInfo, CreateMethodMode.EventDelegateMode); }
private static void GetRuledReturnTypeConverter(InterfaceInfo info, InterfaceMemberInfo memInfo, FuncDesc func, out TypeConverter convertToReturnConverter) { convertToReturnConverter = null; Rule convertToRule = null; if (memInfo.Index != -1) { // Is not event delegate. SignatureInfoMatchTarget returnTarget = new SignatureInfoMatchTarget( info.RefTypeInfo, memInfo.Index, func.elemdescFunc, 0); if (info.ConverterInfo.Settings.m_ruleSet != null) { ICategory signatureCategory = SignatureCategory.GetInstance(); AbstractActionManager actionManager = RuleEngine.GetActionManager(); List<Rule> convertToRules = info.ConverterInfo.Settings.m_ruleSet.GetRule( signatureCategory, ConvertToActionDef.GetInstance(), returnTarget); if (convertToRules.Count != 0) { if (convertToRules.Count > 1) { Output.WriteWarning( Resource.FormatString("Wrn_RuleMultipleMatch", ConvertToActionDef.GetInstance().GetActionName()), WarningCode.Wrn_RuleMultipleMatch); } convertToRule = convertToRules[convertToRules.Count - 1]; } } if (convertToRule != null) { var convertToAction = convertToRule.Action as ConvertToAction; Type typeReturn; CustomAttributeBuilder customAttribute; ParameterAttributes fixedParameterAttributes; GetTypeFromConvertToAction(returnTarget, convertToAction, info.ConverterInfo, info.RefTypeInfo, func.elemdescFunc.tdesc, out typeReturn, out customAttribute, out fixedParameterAttributes); convertToReturnConverter = new TypeConverter(typeReturn, customAttribute, fixedParameterAttributes); } } }
/// <summary> /// Figure out types for parameters and return a parameter array /// </summary> /// <returns>TypeConverter[] array for all parameters</returns> public static TypeConverter[] GenerateParameterTypes(InterfaceInfo info, InterfaceMemberInfo memInfo, FuncDesc func, bool isNewEnumMember, int vararg, out int lcidArg, out bool isStandardOleCall, out TypeConverter retTypeConverter, out ReturnKind kind, out int retArgId) { // // Check Lcid Parameter // lcidArg = -1; for (int i = 0; i < func.cParams; ++i) { if (func.GetElemDesc(i).paramdesc.IsLCID) { if (lcidArg >= 0) { info.ConverterInfo.ReportEvent( WarningCode.Wrn_MultipleLcids, Resource.FormatString("Wrn_MultipleLcids", info.RefTypeInfo.GetDocumentation(), info.RefTypeInfo.GetDocumentation(func.memid))); } lcidArg = i; } } // Pre-process for the rule engine // For return value TypeConverter convertToReturnConverter = null; GetRuledReturnTypeConverter(info, memInfo, func, out convertToReturnConverter); // For parameters List<TypeConverter> convertToParameterConverterList; GetRuledParameterTypeConverters(info, memInfo, func, out convertToParameterConverterList); retTypeConverter = GetReturnType(info, memInfo, func, isNewEnumMember, convertToReturnConverter, convertToParameterConverterList, out kind, out isStandardOleCall, out retArgId); if ((retTypeConverter == convertToReturnConverter || convertToParameterConverterList.Contains(retTypeConverter))) { // From convertTo Action. if ((retTypeConverter.ParameterAttributesOverride & ParameterAttributes.In) != ParameterAttributes.None) { Output.WriteWarning(Resource.FormatString("Wrn_ConvertReturnValueToNoneOut", info.RefTypeInfo.GetDocumentation(func.memid)), WarningCode.Wrn_ConvertReturnValueToNoneOut); } retTypeConverter.ParameterAttributesOverride = ParameterAttributes.None; } int cParams = func.cParams; var typeConverterList = new List<TypeConverter>(); short n; for (n = 0; n < cParams; ++n) { ElemDesc elem = func.GetElemDesc(n); ParamDesc paramDesc = elem.paramdesc; // Skip LCID if (paramDesc.IsLCID) continue; // Skip return parameter if (kind == ReturnKind.RetValParameter && n == retArgId) continue; try { ConversionType conversionType; if (n == vararg) conversionType = ConversionType.VarArgParameter; else conversionType = ConversionType.Parameter; if (convertToParameterConverterList[n] != null) { typeConverterList.Add(convertToParameterConverterList[n]); } else { typeConverterList.Add(new TypeConverter( info.ConverterInfo, info.RefTypeInfo, elem.tdesc, paramDesc, false, conversionType)); } } catch (COMException ex) { if ((uint)ex.ErrorCode == HResults.TYPE_E_CANTLOADLIBRARY) { string[] names = info.RefTypeInfo.GetNames(func.memid, func.cParams + 1); string name = names[n + 1]; if (name != String.Empty) { string msg = Resource.FormatString("Wrn_ParamErrorNamed", new object[] { info.RefTypeInfo.GetDocumentation(), name, memInfo.UniqueName }); info.ConverterInfo.ReportEvent(WarningCode.Wrn_ParamErrorNamed, msg); } else { string msg = Resource.FormatString("Wrn_ParamErrorUnnamed", new object[] { info.RefTypeInfo.GetDocumentation(), n, memInfo.UniqueName }); info.ConverterInfo.ReportEvent(WarningCode.Wrn_ParamErrorUnnamed, msg); } } throw; } } return typeConverterList.ToArray(); }
private static bool IsPreserveSigOverride(InterfaceInfo interfaceInfo, int index) { // Check rule engine if (interfaceInfo.ConverterInfo.Settings.m_ruleSet != null) { ICategory functionCategory = FunctionCategory.GetInstance(); FunctionInfoMatchTarget target = new FunctionInfoMatchTarget(interfaceInfo.RefTypeInfo, index); AbstractActionManager actionManager = RuleEngine.GetActionManager(); List<Rule> preserveSigRules = interfaceInfo.ConverterInfo.Settings.m_ruleSet.GetRule( functionCategory, PreserveSigActionDef.GetInstance(), target); if (preserveSigRules.Count != 0) return true; } return false; }
/// <summary> /// Get the return type converter for the function /// </summary> public static TypeConverter GetReturnType(InterfaceInfo info, InterfaceMemberInfo memInfo, FuncDesc func, bool isNewEnumMember, TypeConverter returnConverterOverride, List<TypeConverter> parameterConverterOverrideList, out ReturnKind kind, out bool isStandardOleCall, out int returnArgId) { TypeConverter retType = null; returnArgId = -1; kind = ReturnKind.ReturnValue; isStandardOleCall = false; TypeDesc retTypeDesc = func.elemdescFunc.tdesc; // If /preservesig is specified, we perform the PreserveSig transformation, except for dispatch functions. // Because they are not affected by PreserveSig attribute. if ((!func.IsDispatch) && (info.ConverterInfo.Settings.m_isPreserveSig || IsPreserveSigOverride(info, memInfo.Index))) { if (returnConverterOverride != null) { retType = returnConverterOverride; kind = ReturnKind.ReturnValue; } else if (retTypeDesc.vt == (int)VarEnum.VT_VOID) { retType = s_voidTypeConverter; kind = ReturnKind.NoReturn; } else { retType = new TypeConverter(info.ConverterInfo, info.RefTypeInfo, func.elemdescFunc.tdesc, isNewEnumMember, ConversionType.ReturnValue); kind = ReturnKind.ReturnValue; } return retType; } // Inspect the return value // If the return is HRESULT and PreserveSig switch is not specified, we will do the HRESULT transformation // Otherwise, stick to the original return value and use PreserveSigAttribute if (retTypeDesc.vt == (int)VarEnum.VT_HRESULT) { isStandardOleCall = true; } else { if (retTypeDesc.vt != (int)VarEnum.VT_VOID && retTypeDesc.vt != (int)VarEnum.VT_HRESULT) { if (returnConverterOverride != null) retType = returnConverterOverride; else retType = new TypeConverter(info.ConverterInfo, info.RefTypeInfo, func.elemdescFunc.tdesc, isNewEnumMember, ConversionType.ReturnValue); kind = ReturnKind.ReturnValue; } } if (func.funckind == TypeLibTypes.Interop.FUNCKIND.FUNC_DISPATCH && (!info.ConverterInfo.TransformDispRetVal)) { // Skip RetVal => return value transformation for dispatch interface when TransformDispRetVal is not set } else { for (int i = 0; i < func.cParams; ++i) { ElemDesc ret = func.GetElemDesc(i); // In a COM type library, the return parameter is logical and is the last parameter // whereas it is an explicit separate item in managed. if (IsRetVal(info.ConverterInfo, ret.paramdesc, func)) { // Convert last parameter to return value if (retType == null) { returnArgId = i; if (parameterConverterOverrideList[returnArgId] != null) retType = parameterConverterOverrideList[returnArgId]; else retType = new TypeConverter(info.ConverterInfo, info.RefTypeInfo, ret.tdesc, isNewEnumMember, ConversionType.ParamRetVal); kind = ReturnKind.RetValParameter; } else { info.ConverterInfo.ReportEvent( WarningCode.Wrn_AmbiguousReturn, Resource.FormatString("Wrn_AmbiguousReturn", info.RefTypeInfo.GetDocumentation(), info.RefTypeInfo.GetDocumentation(func.memid))); } break; } } } if (retType == null) { if (returnConverterOverride != null) { retType = returnConverterOverride; kind = ReturnKind.ReturnValue; } else { retType = s_voidTypeConverter; kind = ReturnKind.NoReturn; } } return retType; }
/// <summary> /// Process parameters and apply attributes /// </summary> private static void ProcessParam(InterfaceInfo info, InterfaceMemberInfo memInfo, ElemDesc desc, TypeConverter converter, MethodBuilder methodBuilder, int index, string strname, bool isVarArg, bool isOptionalArg) { ParamDesc param = desc.paramdesc; ParameterAttributes attributes = ParameterAttributes.None; if (converter.ParameterAttributesOverride != ParameterAttributes.None) { attributes = converter.ParameterAttributesOverride; } else { // // Determine in/out/opt // Don't emit [In], [Out] for return type // if (index != 0) { // Always emit in/out information according to type library if (param.IsIn) { attributes |= ParameterAttributes.In; } if (param.IsOut) { attributes |= ParameterAttributes.Out; } if (param.IsOpt || isOptionalArg) { attributes |= ParameterAttributes.Optional; } } } // // Define the parameter // ParameterBuilder parameterBuilder = methodBuilder.DefineParameter(index, attributes, strname); // // Apply MarshalAs attribute // converter.ApplyAttributes(parameterBuilder); // // Support for vararg // if (isVarArg) { parameterBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForParamArray()); } // // Support for default value // if (desc.paramdesc.HasDefault && desc.paramdesc.lpVarValue != IntPtr.Zero) SetDefaultValue(desc, converter.ConvertedType, parameterBuilder); }
/// <summary> /// Generate properties for Functions /// </summary> public void GenerateProperty(InterfaceInfo info, TypeBuilder typebuilder) { // Generate property using unique name string uniqueName = info.GenerateUniqueMemberName( m_propertyInfo.RecommendedName, null, MemberTypes.Property); // // Convert the signature // Type[] paramTypes = null; Type retType = null; if (m_propertyInfo.Kind == PropertyKind.VarProperty) { // Converting variable to property. There are no parameters at all TypeConverter typeConverter = m_propertyInfo.GetPropertyTypeConverter(info.ConverterInfo, info.RefTypeInfo); info.IsConversionLoss |= typeConverter.IsConversionLoss; retType = typeConverter.ConvertedType; } else { // If /preservesig is specified, do not generate property, and only // the getter and setter functions are enough. // Property requires that the property getter must return the real property value, and the first parameter of // the setter must be the property value. While, the /preservesig switch will change the prototype of the setters and // getters, which is different from what the compiler expected. // So we do not support the Property if the /preservesig is specified. if (info.ConverterInfo.Settings.m_isPreserveSig && (m_propertyInfo.BestFuncDesc != null && !m_propertyInfo.BestFuncDesc.IsDispatch)) { if (TlbImpCode.TlbImpCode.s_Options.m_bVerboseMode) FormattedOutput.Output.WriteInfo(Resource.FormatString("Msg_PropertyIsOmitted", m_propertyInfo.RecommendedName, m_propertyInfo.RefTypeInfo.GetDocumentation()), MessageCode.Msg_PropertyIsOmitted); return; } // Converting propget/propput/propputref functions to property. TypeConverter typeConverter = m_propertyInfo.GetPropertyTypeConverter(info.ConverterInfo, info.RefTypeInfo); retType = typeConverter.ConvertedType; info.IsConversionLoss |= typeConverter.IsConversionLoss; FuncDesc bestFuncDesc = m_propertyInfo.BestFuncDesc; // if we have a [vararg] int varArg, firstOptArg, lastOptArg; if (bestFuncDesc.cParamsOpt == -1) ConvCommon.CheckForOptionalArguments(info.ConverterInfo, bestFuncDesc, out varArg, out firstOptArg, out lastOptArg); else varArg = -1; var paramTypeList = new List<Type>(); // Find the index part of the property's signature bool skipLastRetVal = (bestFuncDesc.IsPropertyPut || bestFuncDesc.IsPropertyPutRef); for (int i = 0; i < bestFuncDesc.cParams; ++i) { ElemDesc elemDesc = bestFuncDesc.GetElemDesc(i); ParamDesc paramDesc = elemDesc.paramdesc; // Skip LCID/RetVal if (paramDesc.IsLCID || paramDesc.IsRetval) continue; // Skip the "new value" parameter for putters if (skipLastRetVal) { skipLastRetVal = false; continue; } ConversionType conversionType; if (i == varArg) conversionType = ConversionType.VarArgParameter; else conversionType = ConversionType.Parameter; TypeConverter paramTypeConverter = new TypeConverter(info.ConverterInfo, info.RefTypeInfo, elemDesc.tdesc, conversionType); info.IsConversionLoss |= paramTypeConverter.IsConversionLoss; paramTypeList.Add(paramTypeConverter.ConvertedType); } paramTypes = paramTypeList.ToArray(); } // Define the property PropertyBuilder propertyBuilder = typebuilder.DefineProperty(uniqueName, PropertyAttributes.HasDefault, retType, paramTypes); if (info.IsCoClass && !info.IsDefaultInterface) { // Skip non-default interfaces / implemented interfaces (when we are creating coclass) } else { // Emit dispatch id attribute propertyBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForDispId(m_propertyInfo.DispId)); } // We don't need to emit MarshalAs for properties because the get/set functions should already have them // Emitting MarshalAs for property will hang up CLR!! if (m_methodGet != null) { propertyBuilder.SetGetMethod(m_methodGet); } // Has both propPut & propPutRef? if (m_methodPut != null && m_methodPutRef != null) { propertyBuilder.SetSetMethod(m_methodPutRef); propertyBuilder.AddOtherMethod(m_methodPut); } else { if (m_methodPut != null) { propertyBuilder.SetSetMethod(m_methodPut); } else if (m_methodPutRef != null) { propertyBuilder.SetSetMethod(m_methodPutRef); } } // // Handle DefaultMemberAttribute // if (m_propertyInfo.DispId == WellKnownDispId.DISPID_VALUE) { // DIFF: TlbImpv1 use the type library name while we use the unique name info.ConverterInfo.SetDefaultMember(info.TypeBuilder, uniqueName); } // Handle alias information ConvCommon.HandleAlias(info.ConverterInfo, info.RefTypeInfo, m_propertyInfo.PropertyTypeDesc, propertyBuilder); }
/// <summary> /// Create methods for a event interface /// </summary> /// <param name="eventInterfaceInfo"> /// InterfaceInfo for the source interface, including the type builder for the event interface. /// Note that you can pass whatever type builder you want. /// </param> public static void CreateEventInterfaceCommon(InterfaceInfo eventInterfaceInfo) { CreateInterfaceCommonInternal(eventInterfaceInfo, true); }
/// <summary> /// Create the event interface /// </summary> public override void OnCreate() { if (m_type != null) { return; } string name = m_convInterface.ManagedName; m_convInterface.Create(); using (TypeAttr attr = m_convInterface.RefTypeInfo.GetTypeAttr()) { // // Emit attributes // // // Emit [ComEventInterfaceAttribute(...)] // ConstructorInfo ctorComEventInterface = typeof(ComEventInterfaceAttribute).GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Type), typeof(Type) }, null); // // Build the blob manually before creating the event interface / provider types. // We only need to give the name of the types, in order to simplify creation logic and avoid dependency // CustomAttributeBlobBuilder blobBuilder = new CustomAttributeBlobBuilder(); string eventInterfaceFullyQualifiedName = name; if (m_convInterface.ConvScope == ConvScope.External) { eventInterfaceFullyQualifiedName = m_convInterface.ManagedType.AssemblyQualifiedName; } blobBuilder.AddFixedArg(eventInterfaceFullyQualifiedName); // source interface // Handle event provider name generation collision scenario m_eventProviderName = m_info.GetUniqueManagedName( m_info.GetRecommendedManagedName(m_convInterface.RefTypeInfo, ConvType.Interface, true) + "_EventProvider"); blobBuilder.AddFixedArg(m_eventProviderName); // corresponding event provider m_typeBuilder.SetCustomAttribute(ctorComEventInterface, blobBuilder.GetBlob()); // // Emit ComVisibleAttribute(false) // m_typeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComVisible(false)); // // Emit TypeLibTypeAttribute for TYPEFLAG_FHIDDEN // m_typeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForTypeLibType(TypeLibTypeFlags.FHidden)); bool isConversionLoss = false; // // Verify if the type has any properties // Type interfaceType = m_convInterface.RealManagedType; if (interfaceType.GetProperties().Length > 0) { // Emit a warning and we'll skip the properties m_info.ReportEvent( WarningCode.Wrn_NoPropsInEvents, Resource.FormatString("Wrn_NoPropsInEvents", RefTypeInfo.GetDocumentation())); isConversionLoss = true; } // // Create event interface // InterfaceInfo eventInterfaceInfo = new InterfaceInfo(m_info, m_typeBuilder, false, m_convInterface.RefTypeInfo, attr, false, true); ConvCommon.CreateEventInterfaceCommon(eventInterfaceInfo); isConversionLoss |= eventInterfaceInfo.IsConversionLoss; // // Emit ComConversionLossAttribute if necessary // if (eventInterfaceInfo.IsConversionLoss) { m_typeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComConversionLoss()); } } m_type = m_typeBuilder.CreateType(); }
/// <summary> /// Create methods on event interface recursively /// </summary> /// <param name="eventInterfaceInfo">InterfaceInfo of the event interface</param> public static void CreateEventMethods(InterfaceInfo eventInterfaceInfo) { IConvInterface convInterface = (IConvInterface)eventInterfaceInfo.ConverterInfo.GetInterface(eventInterfaceInfo.RefTypeInfo, eventInterfaceInfo.RefTypeAttr); if (convInterface.EventInterface == null) { convInterface.DefineEventInterface(); } // // If we are creating the co-class, create the real event interface first in case it doesn't exist yet // Note that as event interface doesn't have inheritance, we'll have to do it outside of CreateEventMethodsInternal // if (eventInterfaceInfo.IsCoClass) convInterface.EventInterface.Create(); // Then create the methods CreateEventMethodsInternal(convInterface.EventInterface, eventInterfaceInfo); }
/// <summary> /// Generate properties for Functions /// </summary> public void GenerateProperty(InterfaceInfo info, TypeBuilder typebuilder) { // Generate property using unique name string uniqueName = info.GenerateUniqueMemberName( m_propertyInfo.RecommendedName, null, MemberTypes.Property); // // Convert the signature // Type[] paramTypes = null; Type retType = null; if (m_propertyInfo.Kind == PropertyKind.VarProperty) { // Converting variable to property. There are no parameters at all TypeConverter typeConverter = m_propertyInfo.GetPropertyTypeConverter(info.ConverterInfo, info.RefTypeInfo); info.IsConversionLoss |= typeConverter.IsConversionLoss; retType = typeConverter.ConvertedType; } else { // If /preservesig is specified, do not generate property, and only // the getter and setter functions are enough. // Property requires that the property getter must return the real property value, and the first parameter of // the setter must be the property value. While, the /preservesig switch will change the prototype of the setters and // getters, which is different from what the compiler expected. // So we do not support the Property if the /preservesig is specified. if (info.ConverterInfo.Settings.m_isPreserveSig && (m_propertyInfo.BestFuncDesc != null && !m_propertyInfo.BestFuncDesc.IsDispatch)) { if (TlbImpCode.TlbImpCode.s_Options.m_bVerboseMode) { FormattedOutput.Output.WriteInfo(Resource.FormatString("Msg_PropertyIsOmitted", m_propertyInfo.RecommendedName, m_propertyInfo.RefTypeInfo.GetDocumentation()), MessageCode.Msg_PropertyIsOmitted); } return; } // Converting propget/propput/propputref functions to property. TypeConverter typeConverter = m_propertyInfo.GetPropertyTypeConverter(info.ConverterInfo, info.RefTypeInfo); retType = typeConverter.ConvertedType; info.IsConversionLoss |= typeConverter.IsConversionLoss; FuncDesc bestFuncDesc = m_propertyInfo.BestFuncDesc; // if we have a [vararg] int varArg, firstOptArg, lastOptArg; if (bestFuncDesc.cParamsOpt == -1) { ConvCommon.CheckForOptionalArguments(info.ConverterInfo, bestFuncDesc, out varArg, out firstOptArg, out lastOptArg); } else { varArg = -1; } List <Type> paramTypeList = new List <Type>(); // Find the index part of the property's signature bool skipLastRetVal = (bestFuncDesc.IsPropertyPut || bestFuncDesc.IsPropertyPutRef); for (int i = 0; i < bestFuncDesc.cParams; ++i) { ElemDesc elemDesc = bestFuncDesc.GetElemDesc(i); ParamDesc paramDesc = elemDesc.paramdesc; // Skip LCID/RetVal if (paramDesc.IsLCID || paramDesc.IsRetval) { continue; } // Skip the "new value" parameter for putters if (skipLastRetVal) { skipLastRetVal = false; continue; } ConversionType conversionType; if (i == varArg) { conversionType = ConversionType.VarArgParameter; } else { conversionType = ConversionType.Parameter; } TypeConverter paramTypeConverter = new TypeConverter(info.ConverterInfo, info.RefTypeInfo, elemDesc.tdesc, conversionType); info.IsConversionLoss |= paramTypeConverter.IsConversionLoss; paramTypeList.Add(paramTypeConverter.ConvertedType); } paramTypes = paramTypeList.ToArray(); } // Define the property PropertyBuilder propertyBuilder = typebuilder.DefineProperty(uniqueName, PropertyAttributes.HasDefault, retType, paramTypes); if (info.IsCoClass && !info.IsDefaultInterface) { // Skip non-default interfaces / implemented interfaces (when we are creating coclass) } else { // Emit dispatch id attribute propertyBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForDispId(m_propertyInfo.DispId)); } // We don't need to emit MarshalAs for properties because the get/set functions should already have them // Emitting MarshalAs for property will hang up CLR!! if (m_methodGet != null) { propertyBuilder.SetGetMethod(m_methodGet); } // Has both propPut & propPutRef? if (m_methodPut != null && m_methodPutRef != null) { propertyBuilder.SetSetMethod(m_methodPutRef); propertyBuilder.AddOtherMethod(m_methodPut); } else { if (m_methodPut != null) { propertyBuilder.SetSetMethod(m_methodPut); } else if (m_methodPutRef != null) { propertyBuilder.SetSetMethod(m_methodPutRef); } } // // Handle DefaultMemberAttribute // if (m_propertyInfo.DispId == WellKnownDispId.DISPID_VALUE) { // DIFF: TlbImpv1 use the type library name while we use the unique name info.ConverterInfo.SetDefaultMember(info.TypeBuilder, uniqueName); } // Handle alias information ConvCommon.HandleAlias(info.ConverterInfo, info.RefTypeInfo, m_propertyInfo.PropertyTypeDesc, propertyBuilder); }
public static void CreateEventMethodsInternal(IConvEventInterface convEventInterface, InterfaceInfo eventInterfaceInfo) { // // Stop if info is already IUnknown. Doesn't stop for IDispatch because we want to convert the members of IDispatch // if (WellKnownGuids.IID_IUnknown == eventInterfaceInfo.RefTypeAttr.Guid) return; // // Create methods for parent interface. We need to duplicate them. // if (eventInterfaceInfo.RefTypeAttr.cImplTypes == 1) { TypeInfo parent = eventInterfaceInfo.RefTypeInfo.GetRefType(0); using (TypeAttr parentAttr = parent.GetTypeAttr()) { if (WellKnownGuids.IID_IUnknown != parentAttr.Guid && WellKnownGuids.IID_IDispatch != parentAttr.Guid) { InterfaceInfo parentInterfaceInfo = new InterfaceInfo(eventInterfaceInfo.ConverterInfo, eventInterfaceInfo.TypeBuilder, eventInterfaceInfo.EmitDispId, parent, parentAttr, eventInterfaceInfo.IsCoClass, eventInterfaceInfo.IsSource, eventInterfaceInfo.CurrentImplementingInterface); parentInterfaceInfo.IsDefaultInterface = eventInterfaceInfo.IsDefaultInterface; parentInterfaceInfo.CurrentSlot = eventInterfaceInfo.CurrentSlot; ConvCommon.CreateEventMethodsInternal(convEventInterface, parentInterfaceInfo); eventInterfaceInfo.CurrentSlot = parentInterfaceInfo.CurrentSlot; /* info.PushType(parent, parentAttr); CreateMethods(info); info.PopType(); */ } else { // Initialize v-table slot for IUnknown/IDispatch eventInterfaceInfo.CurrentSlot = parentAttr.cbSizeVft / parentAttr.cbSizeInstance; } } } ConverterInfo converterInfo = eventInterfaceInfo.ConverterInfo; TypeInfo type = eventInterfaceInfo.RefTypeInfo; ModuleBuilder moduleBuilder = eventInterfaceInfo.ConverterInfo.ModuleBuilder; TypeAttr attr = eventInterfaceInfo.RefTypeAttr; // If we are creating the co-class, create the real event interface first in case it doesn't exist yet IConvInterface convInterface = (IConvInterface)converterInfo.GetInterface(type, attr); // For every method in the source interface foreach (InterfaceMemberInfo memInfo in convInterface.AllMembers) { if (memInfo.IsProperty) continue; FuncDesc func = memInfo.RefFuncDesc; // Get/Create the event delegate. Type delegateType = convEventInterface.GetEventDelegate(memInfo); // Need to use the same name as the source interface, otherwise TCEAdapterGenerator will fail string eventName = memInfo.UniqueName; MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; if (!eventInterfaceInfo.IsCoClass) { methodAttributes |= System.Reflection.MethodAttributes.Abstract; } TypeBuilder eventInterfaceType = eventInterfaceInfo.TypeBuilder; Type[] paramTypes = new Type[] { delegateType }; // // Defined add_<Event> method // Note: We are passing null into GenerateUniqueMemberName so that add_XXX/remove_XXX doesn't take overloading into // account. The reason is that we want to keep the add_XXX/remove_XXX methods aligned with the name of the event, // which also doesn't consider overloading // MethodBuilder addMethodBuilder = eventInterfaceType.DefineMethod( // Generate unique name eventInterfaceInfo.GenerateUniqueMemberName("add_" + eventName, null, MemberTypes.Method), methodAttributes, typeof(void), paramTypes ); addMethodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed | MethodImplAttributes.InternalCall); // Do a member override for add_<Event> method if we are creating the method for coclass if (eventInterfaceInfo.IsCoClass) { Debug.Assert(eventInterfaceInfo.CurrentImplementingInterface != null); Type implementingInterfaceType = convEventInterface.RealManagedType; // It is not possible to have a name conflict in event interface, so always use "add_XXX" MethodInfo methodInfo = implementingInterfaceType.GetMethod("add_" + eventName, paramTypes); eventInterfaceInfo.TypeBuilder.DefineMethodOverride(addMethodBuilder, methodInfo); } // // Define remove_<Event> method // Note: We are passing null into GenerateUniqueMemberName so that add_XXX/remove_XXX doesn't take overloading into // account. The reason is that we want to keep the add_XXX/remove_XXX methods aligned with the name of the event, // which also doesn't consider overloading // MethodBuilder removeMethodBuilder = eventInterfaceType.DefineMethod( eventInterfaceInfo.GenerateUniqueMemberName("remove_" + eventName, null, MemberTypes.Method), methodAttributes, typeof(void), paramTypes ); removeMethodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed | MethodImplAttributes.InternalCall); // Do a member override for remove_<Event> method if we are creating the method for coclass if (eventInterfaceInfo.IsCoClass) { Debug.Assert(eventInterfaceInfo.CurrentImplementingInterface != null); Type implementingInterfaceType = convEventInterface.RealManagedType; // It is not possible to have a name conflict in event interface, so always use "remove_XXX" MethodInfo methodInfo = implementingInterfaceType.GetMethod("remove_" + eventName, paramTypes); eventInterfaceType.DefineMethodOverride(removeMethodBuilder, methodInfo); } // // Define event // EventBuilder eventBuilder = eventInterfaceType.DefineEvent( eventInterfaceInfo.GenerateUniqueMemberName(eventName, null, MemberTypes.Event), EventAttributes.None, delegateType); eventBuilder.SetAddOnMethod(addMethodBuilder); eventBuilder.SetRemoveOnMethod(removeMethodBuilder); } }
/// <summary> /// This one should be the entry point as it deals with the funky partner interfaces /// </summary> /// <param name="info"></param> public static void CreateInterfaceCommon(InterfaceInfo info) { CreateInterfaceCommonInternal(info, false); }
/// <summary> /// Get the event delegate for specified method in the source interface. Create a new one if necessary /// </summary> /// <param name="index">Function index</param> /// <returns>The delegate type</returns> public Type GetEventDelegate(InterfaceMemberInfo memberInfo) { TypeInfo type = memberInfo.RefTypeInfo; using (TypeAttr attr = type.GetTypeAttr()) { // Create m_delegateTypes on demand if (m_delegateTypes == null) { m_delegateTypes = new Dictionary<InterfaceMemberInfo, Type>(); } // // Check if we already have a delegate type for method n // if (!m_delegateTypes.ContainsKey(memberInfo)) { // // If not, create a new delegate // FuncDesc func = type.GetFuncDesc(memberInfo.Index); string eventName = type.GetDocumentation(func.memid); string delegateName = m_info.GetRecommendedManagedName(m_convInterface.RefTypeInfo, ConvType.Interface, true) + "_" + type.GetDocumentation(func.memid) + "EventHandler"; // Deal with name collisions delegateName = m_info.GetUniqueManagedName(delegateName); TypeBuilder delegateTypeBuilder = m_info.ModuleBuilder.DefineType( delegateName, TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate) ); // Create constructor for the delegate ConstructorBuilder delegateCtorBuilder = delegateTypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeof(Object), typeof(UIntPtr) }); delegateCtorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); // Create methods for the delegate InterfaceInfo interfaceInfoForDelegate = new InterfaceInfo(m_info, delegateTypeBuilder, false, type, attr, false, true); interfaceInfoForDelegate.AllowNewEnum = !m_convInterface.ImplementsIEnumerable; ConvCommon.CreateMethodForDelegate(interfaceInfoForDelegate, func, memberInfo.Index); // Emit ComVisibleAttribute(false) delegateTypeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComVisible(false)); // Emit TypeLibTypeAttribute(TypeLibTypeFlags.FHidden) to hide it from object browser in VB delegateTypeBuilder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForTypeLibType(TypeLibTypeFlags.FHidden)); // Create the delegate m_delegateTypes[memberInfo] = delegateTypeBuilder.CreateType(); } } return m_delegateTypes[memberInfo]; }