示例#1
0
        private void CreateField(TypeInfo type, TypeAttr attr, VarDesc var, ref bool isConversionLoss)
        {
            TypeDesc fieldTypeDesc = var.elemdescVar.tdesc;
            TypeConverter typeConverter = new TypeConverter(m_info, type, fieldTypeDesc, ConversionType.Field);
            Type fieldType = typeConverter.ConvertedType;
            string fieldName = type.GetDocumentation(var.memid);
            FieldBuilder field = m_typeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Public);
            typeConverter.ApplyAttributes(field);

            isConversionLoss |= typeConverter.IsConversionLoss;

            //
            // Emit ComConversionLossAttribute for fields if necessary
            //
            if (typeConverter.IsConversionLoss)
            {
                field.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComConversionLoss());

                //
                // Emit Wrn_UnconvertableField warning
                //
                m_info.ReportEvent(
                    WarningCode.Wrn_UnconvertableField,
                    Resource.FormatString("Wrn_UnconvertableField", m_typeBuilder.FullName, fieldName));
            }

            //
            // Emit TypeLibVarAttribute if necessary
            //
            if (var.wVarFlags != 0)
            {
                field.SetCustomAttribute(CustomAttributeHelper.GetBuilderForTypeLibVar((TypeLibVarFlags)var.wVarFlags));
            }
        }
示例#2
0
        /// <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);
        }
示例#3
0
        private void CreateField(TypeInfo type, TypeAttr attr, VarDesc var, ref bool isConversionLoss)
        {
            if (IsObjectType(type, var.elemdescVar.tdesc))
            {
                isConversionLoss = true;
            }
            else
            {

                TypeConverter typeConverter = new TypeConverter(m_info, type, var.elemdescVar.tdesc, ConversionType.Field);
                Type fieldType = typeConverter.ConvertedType;

                // TlbImp2 will only skip reference types, instead of skipping every field
                // Also, TlbImp1 will skip ValueType *, which doesn't make any sense. TlbImp2 will keep ValueType * as IntPtr

                string fieldName = type.GetDocumentation(var.memid);
                // Generates the [FieldOffset(0)] layout declarations that approximate unions in managed code
                FieldBuilder field = m_typeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Public);
                field.SetCustomAttribute(CustomAttributeHelper.GetBuilderForFieldOffset(0));
                typeConverter.ApplyAttributes(field);

                isConversionLoss |= typeConverter.IsConversionLoss;

                //
                // Emit ComConversionLossAttribute for fields if necessary
                //
                if (typeConverter.IsConversionLoss)
                {
                    field.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComConversionLoss());

                    //
                    // Emit Wrn_UnconvertableField warning
                    //
                    m_info.ReportEvent(
                        WarningCode.Wrn_UnconvertableField,
                        Resource.FormatString("Wrn_UnconvertableField", m_typeBuilder.FullName, fieldName));
                }
            }
        }
示例#4
0
        private void _Convert()
        {
            VarEnum vt = (VarEnum)m_typeDesc.vt;

            // Strip out VT_PTR
            while (vt == VarEnum.VT_PTR)
            {
                m_typeDesc = m_typeDesc.lptdesc;
                vt = (VarEnum)m_typeDesc.vt;
                m_nativeIndirections++;
            }

            // Strip out VT_BYREF
            if ((vt & VarEnum.VT_BYREF) != 0)
            {
                vt &= ~VarEnum.VT_BYREF;
                m_nativeIndirections++;
            }

            //
            // Find the corresponding type and save it in result and store the custom attribute in m_attribute
            //
            Type result = null;
            m_attribute = null;
            switch (vt)
            {
                case VarEnum.VT_HRESULT :
                    result = typeof(int);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.Error);
                    SetUnmanagedType(UnmanagedType.Error);
                    break;

                case VarEnum.VT_VOID:
                    result = typeof(void);
                    break;

                case VarEnum.VT_UINT:
                    result = typeof(uint);
                    break;

                case VarEnum.VT_INT:
                    result = typeof(int);
                    break;

                case VarEnum.VT_UI1:
                    result = typeof(byte);
                    break;

                case VarEnum.VT_UI2:
                    result = typeof(ushort);
                    break;

                case VarEnum.VT_UI4:
                    result = typeof(uint);
                    break;

                case VarEnum.VT_UI8:
                    result = typeof(ulong);
                    break;

                case VarEnum.VT_I1:
                    result = typeof(sbyte);
                    break;

                case VarEnum.VT_I2:
                    result = typeof(short);
                    break;

                case VarEnum.VT_I4:
                    result = typeof(int);
                    break;

                case VarEnum.VT_I8:
                    result = typeof(long);
                    break;

                case VarEnum.VT_R4:
                    result = typeof(float);
                    break;

                case VarEnum.VT_R8:
                    result = typeof(double);
                    break;

                case VarEnum.VT_ERROR :
                    result = typeof(int);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.Error);
                    SetUnmanagedType(UnmanagedType.Error);

                    break;

                case VarEnum.VT_BSTR:
                    result = typeof(string);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.BStr);
                    SetUnmanagedType(UnmanagedType.BStr);

                    // BSTR => string is special as BSTR are actually OLECHAR*, so we should add one indirection
                    m_nativeIndirections++;
                    break;

                case VarEnum.VT_DISPATCH:
                    if (m_convertingNewEnumMember)
                    {
                        // When we are creating a new enum member, convert IDispatch to IEnumVariant
                        TryUseCustomMarshaler(WellKnownGuids.IID_IEnumVARIANT, out result);
                    }
                    else
                    {
                        result = typeof(object);
                        m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.IDispatch);
                        SetUnmanagedType(UnmanagedType.IDispatch);
                    }

                    // VT_DISPATCH => IDispatch *
                    m_nativeIndirections++;

                    break;

                case VarEnum.VT_UNKNOWN:
                    if (m_convertingNewEnumMember)
                    {
                        // When we are creating a new enum member, convert IUnknown to IEnumVariant
                        TryUseCustomMarshaler(WellKnownGuids.IID_IEnumVARIANT, out result);
                    }
                    else
                    {
                        result = typeof(object);
                        m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.IUnknown);
                        SetUnmanagedType(UnmanagedType.IUnknown);
                    }

                    // VT_UNKNOWN => IUnknown *
                    m_nativeIndirections++;

                    break;

                case VarEnum.VT_LPSTR:
                    result = typeof(string);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.LPStr);
                    SetUnmanagedType(UnmanagedType.LPStr);
                    m_nativeIndirections++;
                    break;

                case VarEnum.VT_LPWSTR:
                    result = typeof(string);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.LPWStr);
                    SetUnmanagedType(UnmanagedType.LPWStr);
                    m_nativeIndirections++;
                    break;

                case VarEnum.VT_PTR:
                    Debug.Assert(false, "Should not get here");
                    break;

                case VarEnum.VT_SAFEARRAY:
                    {
                        TypeDesc arrayDesc = m_typeDesc.lpadesc.tdescElem;
                        VarEnum arrayVt = (VarEnum)arrayDesc.vt;
                        Type userDefinedType = null;

                        TypeConverter elemTypeConverter = new TypeConverter(m_info, m_typeInfo, arrayDesc, ConversionType.Element);
                        Type elemType = elemTypeConverter.ConvertedType;

                        // Determine the right VT for MarshalAs attribute
                        bool pointerArray = false;
                        if (arrayVt == VarEnum.VT_PTR)
                        {
                            arrayDesc = arrayDesc.lptdesc;
                            arrayVt = (VarEnum)arrayDesc.vt;
                            pointerArray = true;

                            // We don't support marshalling pointers in array except UserType* & void*
                            if (arrayVt != VarEnum.VT_USERDEFINED && arrayVt != VarEnum.VT_VOID)
                            {
                                arrayVt = VarEnum.VT_INT;
                                m_conversionLoss = true;
                            }
                        }

                        //
                        // Emit UserDefinedSubType if necessary
                        //
                        if (arrayVt == VarEnum.VT_USERDEFINED)
                        {
                            if (elemType.IsEnum)
                            {
                                if (pointerArray)
                                {
                                    arrayVt = VarEnum.VT_INT;
                                    m_conversionLoss = true;
                                }
                                else
                                {
                                    // For enums, using VT_RECORD is better than VT_I4
                                    // Within the runtime, if you specify VT_I4 for enums in SafeArray, we treat it the same way as VT_RECORD
                                    // Reflection API also accepts VT_RECORD instead of VT_I4
                                    arrayVt = VarEnum.VT_RECORD;
                                }
                            }
                            else if(elemType.IsValueType)
                            {
                                if (pointerArray)
                                {
                                    arrayVt = VarEnum.VT_INT;
                                    m_conversionLoss = true;
                                }
                                else
                                    arrayVt = VarEnum.VT_RECORD;
                            }
                            else if (elemType.IsInterface)
                            {
                                if (pointerArray)
                                {
                                    // decide VT_UNKNOWN / VT_DISPATCH
                                    if (InterfaceSupportsDispatch(elemType))
                                        arrayVt = VarEnum.VT_DISPATCH;
                                    else
                                        arrayVt = VarEnum.VT_UNKNOWN;
                                }
                                else
                                {
                                    arrayVt = VarEnum.VT_INT;
                                    m_conversionLoss = true;
                                }
                            }
                            else if (elemType == typeof(object) && !elemTypeConverter.UseDefaultMarshal &&
                                     (elemTypeConverter.UnmanagedType == UnmanagedType.IUnknown))
                            {
                                // Special case for object that doesn't have default interface and will be marshalled as IUnknown
                                arrayVt = VarEnum.VT_UNKNOWN;
                            }

                            userDefinedType = elemType;
                        }

                        m_conversionLoss |= elemTypeConverter.IsConversionLoss;

                        // Transform to System.Array if /sysarray is set and not vararg
                        if (((m_info.Settings.m_flags & TypeLibImporterFlags.SafeArrayAsSystemArray) != 0) &&
                            m_conversionType != ConversionType.VarArgParameter)
                            result = typeof(System.Array);
                        else
                        {
                            result = elemType.MakeArrayType();

                            // Don't need SafeArrayUserDefinedSubType for non System.Array case
                            userDefinedType = null;
                        }

                        // TlbImp doesn't have this check for vt == VT_RECORD/VT_UNKNOWN/VT_DISPATCH therefore
                        // it will emit SafeArrayUserDefinedSubType even it is not necessary/not valid
                        // TlbImp2 will take this into account
                        if ((userDefinedType != null) && (arrayVt == VarEnum.VT_RECORD || arrayVt == VarEnum.VT_UNKNOWN || arrayVt == VarEnum.VT_DISPATCH))
                        {
                            // The name of the type would be full name in TlbImp2
                            m_attribute = CustomAttributeHelper.GetBuilderForMarshalAsSafeArrayAndUserDefinedSubType(arrayVt, userDefinedType);
                        }
                        else
                        {
                            // Use I4 for enums when SafeArrayUserDefinedSubType is not specified
                            if (elemType.IsEnum && arrayVt == VarEnum.VT_RECORD)
                                arrayVt = VarEnum.VT_I4;
                            m_attribute = CustomAttributeHelper.GetBuilderForMarshalAsSafeArray(arrayVt);
                        }

                        SetUnmanagedType(UnmanagedType.SafeArray);

                        // SafeArray <=> array is special because SafeArray is similar to Element*
                        m_nativeIndirections++;

                        break;
                    }

                case VarEnum.VT_RECORD:
                case VarEnum.VT_USERDEFINED:
                    {
                        // Handle structs, interfaces, enums, and unions

                        // Check if any ResolveTo Rule applied.
                        TypeInfo refType = m_typeInfo.GetRefTypeInfo(m_typeDesc.hreftype);
                        TypeAttr refAttr = refType.GetTypeAttr();
                        Type resolveToType;
                        if (RuleEngineResolveRedirection(m_info.Settings.m_ruleSet, refType,
                            out resolveToType))
                        {
                            result = resolveToType;
                            break;
                        }

                        // Support for aliasing
                        TypeInfo realType;
                        TypeAttr realAttr;
                        ConvCommon.ResolveAlias(m_typeInfo, m_typeDesc, out realType, out realAttr);

                        // Alias for a built-in type?
                        if (realAttr.typekind == TypeLibTypes.Interop.TYPEKIND.TKIND_ALIAS)
                        {
                            // Recurse to convert the built-in type
                            TypeConverter builtinType = new TypeConverter(m_info, realType, realAttr.tdescAlias, m_conversionType);
                            result = builtinType.ConvertedType;
                            m_attribute = builtinType.m_attribute;
                        }
                        else
                        {
                            // Otherwise, we must have a non-aliased type, and it is a user defined type
                            // We should use the TypeInfo that this TypeDesc refers to
                            realType = m_typeDesc.GetUserDefinedTypeInfo(m_typeInfo);
                            TypeLibTypes.Interop.TYPEKIND typeKind = realAttr.typekind;

                            using (realAttr = realType.GetTypeAttr())
                            {
                                TypeLib typeLib = realType.GetContainingTypeLib();

                                // Convert StdOle2.Guid to System.Guid
                                if (_IsStdOleGuid(realType))
                                {
                                    result = typeof(Guid);
                                    m_attribute = null;
                                    ResetUnmanagedType();
                                }
                                else if (realAttr.Guid == WellKnownGuids.IID_IUnknown)
                                {
                                    // Occasional goto makes sense
                                    // If VT_USERDEFINE *, and the VT_USERDEFINE is actually a VT_UNKNOWN => IUnknown *, we need to decrease the m_nativeIndirections
                                    // to compensate for the m_nativeIndirections++ in VT_UNKNOWN
                                    m_nativeIndirections--;
                                    goto case VarEnum.VT_UNKNOWN;
                                }
                                else if (realAttr.Guid == WellKnownGuids.IID_IDispatch)
                                {
                                    // Occasional goto makes sense
                                    // See the IID_IUnknown case for why we need to --
                                    m_nativeIndirections--;
                                    goto case VarEnum.VT_DISPATCH;
                                }
                                else
                                {
                                    // Need to use CustomMarshaler?
                                    Type customMarshalerResultType;
                                    if (TryUseCustomMarshaler(realAttr.Guid, out customMarshalerResultType))
                                    {
                                        result = customMarshalerResultType;
                                    }
                                    else
                                    {
                                        IConvBase ret = m_info.GetTypeRef(ConvCommon.TypeKindToConvType(typeKind), realType);

                                        if (m_conversionType == ConversionType.Field)
                                        {
                                            // Too bad. Reflection API requires that the field type must be created before creating
                                            // the struct/union type

                                            // Only process indirection = 0 case because > 1 case will be converted to IntPtr
                                            // Otherwise it will leads to a infinite recursion, if you consider the following scenario:
                                            // struct A
                                            // {
                                            //      struct B
                                            //      {
                                            //          struct A *a;
                                            //      } b;
                                            // }
                                            if (ret is ConvUnionLocal && m_nativeIndirections == 0)
                                            {
                                                var convUnion = ret as ConvUnionLocal;
                                                convUnion.Create();
                                            }
                                            else if (ret is ConvStructLocal && m_nativeIndirections == 0)
                                            {
                                                var convStruct = ret as ConvStructLocal;
                                                convStruct.Create();
                                            }
                                            else if (ret is ConvEnumLocal && m_nativeIndirections == 0)
                                            {
                                                var convEnum = ret as ConvEnumLocal;
                                                convEnum.Create();
                                            }
                                        }

                                        result = ret.ManagedType;

                                        // Don't reply on result.IsInterface as we have some weird scenarios like refering to a exported type lib
                                        // which has interfaces that are class interfaces and have the same name as a class.
                                        // For example, manage class M has a class interface _M, and their managed name are both M
                                        if (ret.ConvType == ConvType.Interface || ret.ConvType == ConvType.EventInterface || ret.ConvType == ConvType.ClassInterface)
                                        {
                                            m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.Interface);
                                            SetUnmanagedType(UnmanagedType.Interface);
                                        }

                                        if (ret.ConvType == ConvType.CoClass)
                                        {
                                            // We need to convert CoClass to default interface (could be converted to class interface if it is exclusive) in signatures
                                            Debug.Assert(ret is IConvCoClass);
                                            IConvCoClass convCoClass = ret as IConvCoClass;
                                            if (convCoClass.DefaultInterface != null)
                                            {
                                                // Use the default interface
                                                result = convCoClass.DefaultInterface.ManagedType;
                                                m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.Interface);
                                                SetUnmanagedType(UnmanagedType.Interface);
                                            }
                                            else
                                            {
                                                // The coclass has no default interface (source interface excluded)
                                                // Marshal it as IUnknown
                                                result = typeof(object);
                                                m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.IUnknown);
                                                SetUnmanagedType(UnmanagedType.IUnknown);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    break;

                case VarEnum.VT_VARIANT:
                    result = typeof(object);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.Struct);
                    SetUnmanagedType(UnmanagedType.Struct);

                    // object is special that it will be marshaled to VARIANT
                    // because we'll think object as having one indirection, now we are one indirection less,
                    // so we need add 1 to m_indirections
                    m_nativeIndirections++;
                    break;

                case VarEnum.VT_CY:
                    result = typeof(System.Decimal);
                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.Currency);
                    SetUnmanagedType(UnmanagedType.Currency);

                    break;

                case VarEnum.VT_DATE:
                    result = typeof(System.DateTime);
                    break;

                case VarEnum.VT_DECIMAL:
                    result = typeof(System.Decimal);
                    break;

                case VarEnum.VT_CARRAY:
                    {
                        TypeDesc elemTypeDesc = m_typeDesc.lptdesc;
                        var elemTypeConverter = new TypeConverter(m_info, m_typeInfo, elemTypeDesc, ConversionType.Element);
                        Type elemType = elemTypeConverter.ConvertedType;
                        result = elemType.MakeArrayType();

                        m_conversionLoss |= elemTypeConverter.IsConversionLoss;

                        uint elements = 1;
                        SAFEARRAYBOUND[] bounds = m_typeDesc.lpadesc.Bounds;
                        foreach (SAFEARRAYBOUND bound in bounds)
                        {
                            elements *= bound.cElements;
                        }

                        // SizeConst can only hold Int32.MaxValue
                        if (elements <= Int32.MaxValue)
                        {
                            UnmanagedType arrayType;
                            if (m_conversionType == ConversionType.Field)
                                arrayType = UnmanagedType.ByValArray;
                            else
                                arrayType = UnmanagedType.LPArray;

                            if (elemTypeConverter.UseDefaultMarshal)
                                m_attribute = CustomAttributeHelper.GetBuilderForMarshalAsConstArray(arrayType, (int)elements);
                            else
                            {
                                if (elemTypeConverter.UnmanagedType == UnmanagedType.BStr   ||
                                    elemTypeConverter.UnmanagedType == UnmanagedType.LPStr  ||
                                    elemTypeConverter.UnmanagedType == UnmanagedType.LPWStr ||
                                    elemTypeConverter.UnmanagedType == UnmanagedType.VariantBool)
                                {
                                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAsConstArray(arrayType, (int)elements, elemTypeConverter.UnmanagedType);
                                }
                                else
                                {
                                    m_attribute = CustomAttributeHelper.GetBuilderForMarshalAsConstArray(arrayType, (int)elements);
                                }
                            }

                            SetUnmanagedType(arrayType);
                        }
                        else
                        {
                            m_nativeIndirections = 0;
                            result = typeof(IntPtr);
                            m_attribute = null;
                            ResetUnmanagedType();
                            m_conversionLoss = true;
                        }
                    }
                    break;

                case VarEnum.VT_BOOL:
                    // For VT_BOOL in fields, use short if v2 switch is not specified.
                    if (m_conversionType == ConversionType.Field)
                    {
                        if (m_info.Settings.m_isVersion2)
                        {
                            result = typeof(bool);
                            m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.VariantBool);
                            SetUnmanagedType(UnmanagedType.VariantBool);
                        }
                        else
                        {
                            result = typeof(short);
                        }
                    }
                    else
                    {
                        result = typeof(bool);
                        SetUnmanagedType(UnmanagedType.VariantBool);
                    }
                    break;

                default:
                    m_info.ReportEvent(
                        WarningCode.Wrn_BadVtType,
                        Resource.FormatString("Wrn_BadVtType", (int)vt, m_typeInfo.GetDocumentation()));
                    result = typeof(IntPtr);
                    m_conversionLoss = true;
                    break;
            }

            //
            // String -> StringBuilder special case
            //
            if (result == typeof(string))
            {
                if (_IsParamOut() && m_nativeIndirections == 1 && (m_conversionType == ConversionType.Parameter || m_conversionType == ConversionType.VarArgParameter))
                {
                    // [out] or [in, out] LPSTR/LPWSTR scenario
                    if (vt != VarEnum.VT_BSTR)
                    {
                        // String is immutable and cannot be [out]/[in, out]. We can convert to StringBuilder
                        result = typeof(StringBuilder);
                    }
                    else // VT_BSTR
                    {
                        // VT_BSTR is also immutable. So conversion loss here
                        m_conversionLoss = true;
                        result = typeof(IntPtr);
                        m_attribute = null;
                        m_nativeIndirections = 0;
                        ResetUnmanagedType();
                    }
                }
            }

            // Special rule for void* => IntPtr
            if (result == typeof(void))
            {
                result = typeof(IntPtr);

                switch (m_conversionType)
                {
                    case ConversionType.Element:
                        m_nativeIndirections = 0;
                        break;

                    case ConversionType.Field:
                        m_nativeIndirections = 0;
                        break;

                    default:
                        if (m_nativeIndirections > 1)
                            m_nativeIndirections = 1;
                        else
                            m_nativeIndirections = 0;
                        break;
                }
            }

            //
            // If the type is already a byref type, remove the byref and add extra indirection(s).
            // This is necessary to avoid trying to call MakeByRef on the byref type
            //
            if (result.IsByRef)
            {
                result = result.GetElementType();
                if (result.IsValueType)
                    m_nativeIndirections++;     // Value& = Value *
                else
                    m_nativeIndirections += 2;  // RefType& = RefType**
            }

            //
            // Process indirection
            //
            if (m_nativeIndirections > 0)
            {
                if (result.IsValueType)
                {
                    switch (m_conversionType)
                    {
                        case ConversionType.VarArgParameter:
                        case ConversionType.Parameter:
                            // Decimal/Guid can support extra level of indirection using LpStruct in parameters
                            // LpStruct has no effect in other places and for other types
                            // Only use LpStruct for scenarios like GUID **
                            // This is different from old TlbImp. Old TlbImp will use IntPtr
                            if ((result == typeof(Decimal) || result == typeof(Guid)) && m_nativeIndirections == 2)
                            {
                                m_nativeIndirections--;
                                m_attribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.LPStruct);
                                ResetUnmanagedType();
                                SetUnmanagedType(UnmanagedType.LPStruct);
                            }

                            if (m_nativeIndirections >= 2)
                            {
                                m_conversionLoss = true;
                                result = typeof(IntPtr);
                                m_attribute = null;
                                ResetUnmanagedType();
                            }
                            else if (m_nativeIndirections > 0)
                            {
                                result = result.MakeByRefType();
                            }

                            break;

                        case ConversionType.Field:
                            m_conversionLoss = true;
                            result = typeof(IntPtr);
                            m_attribute = null;
                            ResetUnmanagedType();
                            break;

                        case ConversionType.ParamRetVal:
                            m_nativeIndirections--;
                            goto case ConversionType.ReturnValue;
                            // Fall through to ConversionType.ReturnValue

                        case ConversionType.ReturnValue:
                            if (m_nativeIndirections >= 1)
                            {
                                m_conversionLoss = true;
                                result = typeof(IntPtr);
                                m_attribute = null;
                                ResetUnmanagedType();
                            }
                            break;

                        case ConversionType.Element :
                            m_conversionLoss = true;
                            result = typeof(IntPtr);
                            m_attribute = null;
                            ResetUnmanagedType();
                            break;
                    }
                }
                else
                {
                    switch (m_conversionType)
                    {

                        case ConversionType.Field:
                            // ** => IntPtr, ConversionLoss
                            if (m_nativeIndirections > 1)
                            {
                                result = typeof(IntPtr);
                                m_conversionLoss = true;
                                m_attribute = null;
                                ResetUnmanagedType();
                            }
                            break;

                        case ConversionType.VarArgParameter:
                        case ConversionType.Parameter:
                            if (m_nativeIndirections > 2)
                            {
                                result = typeof(IntPtr);
                                m_conversionLoss = true;
                                m_attribute = null;
                                ResetUnmanagedType();
                            }
                            else if (m_nativeIndirections == 2)
                                result = result.MakeByRefType();
                            break;

                        case ConversionType.ParamRetVal:
                            m_nativeIndirections--;
                            goto case ConversionType.ReturnValue;
                            // Fall through to ConversionType.ReturnValue

                        case ConversionType.ReturnValue:
                            if (m_nativeIndirections > 1)
                            {
                                result = typeof(IntPtr);
                                m_conversionLoss = true;
                                m_attribute = null;
                                ResetUnmanagedType();
                            }
                            break;

                        case ConversionType.Element:
                            if (m_nativeIndirections > 1)
                            {
                                m_conversionLoss = true;
                                result = typeof(IntPtr);
                                m_attribute = null;
                                ResetUnmanagedType();
                            }
                            break;
                    }

                }
            }

            m_convertedType = result;
        }