Esempio n. 1
0
        /// <summary>
        /// If the type is aliased, return the ultimated non-aliased type if the type is user-defined, otherwise, return
        /// the aliased type directly. So the result could still be aliased to a built-in type.
        /// If the type is not aliased, just return the type directly
        /// </summary>
        public static void ResolveAlias(TypeInfo type, TypeDesc typeDesc, out TypeInfo realType, out TypeAttr realAttr)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));
            if (typeDesc == null) throw new ArgumentNullException(nameof(typeDesc));
            if ((VarEnum)typeDesc.vt != VarEnum.VT_USERDEFINED)
            {
                // Already resolved
                realType = type;
                realAttr = type.GetTypeAttr();
                return;
            }
            else
            {
                TypeInfo refType = type.GetRefTypeInfo(typeDesc.hreftype);
                TypeAttr refAttr = refType.GetTypeAttr();

                // If the userdefined typeinfo is not itself an alias, then it is what the alias aliases.
                // Also, if the userdefined typeinfo is an alias to a builtin type, then the builtin
                // type is what the alias aliases.
                if (refAttr.typekind != TypeLibTypes.Interop.TYPEKIND.TKIND_ALIAS || (VarEnum)refAttr.tdescAlias.vt != VarEnum.VT_USERDEFINED)
                {
                    // Resolved
                    realType = refType;
                    realAttr = refAttr;
                }
                else
                {
                    // Continue resolving the type
                    ResolveAlias(refType, refAttr.tdescAlias, out realType, out realAttr);
                }
            }
        }
Esempio n. 2
0
        private TypeDesc m_typeDesc; // Type description

        #endregion Fields

        #region Constructors

        public TlbType2String(TypeInfo interfaceType, TypeDesc desc)
        {
            m_interfaceType = interfaceType;
            m_typeDesc = desc;
            m_typeStringBuilder = new StringBuilder();

            // Do the conversion
            _Convert();
        }
Esempio n. 3
0
        private bool m_useDefaultMarshal; // Whether we marshal by default or marshal by UnmanagedType

        #endregion Fields

        #region Constructors

        public TypeConverter(ConverterInfo info, TypeInfo type, TypeDesc desc, ConversionType conversionType)
        {
            m_info = info;
            m_typeInfo = type;
            m_typeDesc = desc;
            m_conversionType = conversionType;

            m_paramDesc = null;
            m_attribute = null;
            m_conversionLoss = false;
            m_convertedType = null;
            m_nativeIndirections = 0;
            m_convertingNewEnumMember = false;

            ResetUnmanagedType();

            // Do the conversion
            _Convert();
        }
Esempio n. 4
0
        /// <summary>
        /// Test whether the typeDesc corresponds to a managed reference type
        /// </summary>
        private bool IsObjectType(TypeInfo typeInfo, TypeDesc typeDesc)
        {
            int nativeIndirection = 0;
            int vt = typeDesc.vt;

            // Strip off leading VT_PTR and VT_BYREF
            while (vt == (int)VarEnum.VT_PTR)
            {
                typeDesc = typeDesc.lptdesc;
                vt = typeDesc.vt;
                nativeIndirection++;
            }

            if ((vt & (int)VarEnum.VT_BYREF) != 0)
            {
                vt &= ~(int)VarEnum.VT_BYREF;
                nativeIndirection++;
            }

            // Determine if the field is/has object type.
            Debug.Assert(vt != (int)VarEnum.VT_PTR);

            switch ((VarEnum)vt)
            {
                // These are object types.
                case VarEnum.VT_BSTR:
                case VarEnum.VT_DISPATCH:
                case VarEnum.VT_VARIANT:
                case VarEnum.VT_UNKNOWN:
                case VarEnum.VT_SAFEARRAY:
                case VarEnum.VT_LPSTR:
                case VarEnum.VT_LPWSTR:
                    return true;

                // A user-defined may or may not be/contain Object type.
                case VarEnum.VT_USERDEFINED:
                    // User defined type.  Get the TypeInfo.
                    TypeInfo refTypeInfo = typeInfo.GetRefTypeInfo(typeDesc.hreftype);
                    TypeAttr refTypeAttr = refTypeInfo.GetTypeAttr();

                    // Some user defined class.  Is it a value class, or a VOS class?
                    switch (refTypeAttr.typekind)
                    {
                        // Alias -- Is the aliased thing an Object type?
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_ALIAS:
                            return IsObjectType(refTypeInfo, refTypeAttr.tdescAlias);

                        // Record/Enum/Union -- Does it contain an Object type?
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_RECORD:
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_ENUM:
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_UNION:
                            // Byref/Ptrto record is Object.  Contained record might be.
                            if (nativeIndirection > 0)
                                return true;
                            else
                                return HasObjectFields(refTypeInfo);

                        // Class/Interface -- An Object Type.
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_INTERFACE:
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_DISPATCH:
                        case TypeLibTypes.Interop.TYPEKIND.TKIND_COCLASS:
                            return true;

                        default:
                            return true;

                    } // switch (psAttrAlias->typekind)

                case VarEnum.VT_CY:
                case VarEnum.VT_DATE:
                case VarEnum.VT_DECIMAL:
                    // Pointer to the value type is an object.  Contained one isn't.
                    if (nativeIndirection > 0)
                        return true;
                    else
                        return false;

                // A fixed array is an Object type.
                case VarEnum.VT_CARRAY:
                    return true;

                // Other types I4, etc., are not Object types.
                default:
                    return false;
            } // switch (vt=pType->vt)
        }
Esempio n. 5
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
            //
            switch (vt)
            {
                case VarEnum.VT_INT:
                    m_typeStringBuilder.Append("INT");
                    break;

                case VarEnum.VT_UINT:
                    m_typeStringBuilder.Append("UINT");
                    break;

                case VarEnum.VT_UI1:
                    m_typeStringBuilder.Append("BYTE");
                    break;

                case VarEnum.VT_UI2:
                    m_typeStringBuilder.Append("USHORT");
                    break;

                case VarEnum.VT_UI4:
                    m_typeStringBuilder.Append("UINT");
                    break;

                case VarEnum.VT_UI8:
                    m_typeStringBuilder.Append("ULONG");
                    break;

                case VarEnum.VT_I1:
                    m_typeStringBuilder.Append("SBYTE");
                    break;

                case VarEnum.VT_I2:
                    m_typeStringBuilder.Append("SHORT");
                    break;

                case VarEnum.VT_I4:
                    m_typeStringBuilder.Append("INT");
                    break;

                case VarEnum.VT_I8:
                    m_typeStringBuilder.Append("LONG");
                    break;

                case VarEnum.VT_R4:
                    m_typeStringBuilder.Append("FLOAT");
                    break;

                case VarEnum.VT_R8:
                    m_typeStringBuilder.Append("DOUBLE");
                    break;

                case VarEnum.VT_ERROR :
                    m_typeStringBuilder.Append("SCODE");
                    break;

                case VarEnum.VT_HRESULT:
                    m_typeStringBuilder.Append("HRESULT");
                    break;

                case VarEnum.VT_VOID:
                    m_typeStringBuilder.Append("void");
                    break;

                case VarEnum.VT_BSTR:
                    m_typeStringBuilder.Append("BSTR");
                    break;

                case VarEnum.VT_DISPATCH:
                    m_typeStringBuilder.Append("IDispatch *");
                    // VT_DISPATCH => IDispatch *
                    break;

                case VarEnum.VT_UNKNOWN:
                    m_typeStringBuilder.Append("IUnknown *");
                    // VT_UNKNOWN => IUnknown *
                    break;

                case VarEnum.VT_LPSTR:
                    m_typeStringBuilder.Append("LPSTR");
                    break;

                case VarEnum.VT_LPWSTR:
                    m_typeStringBuilder.Append("LPWSTR");
                    break;

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

                case VarEnum.VT_VARIANT:
                    m_typeStringBuilder.Append("VARIANT");
                    break;

                case VarEnum.VT_CY:
                    m_typeStringBuilder.Append("CURRENCY");
                    break;

                case VarEnum.VT_DATE:
                    m_typeStringBuilder.Append("DATE");
                    break;

                case VarEnum.VT_DECIMAL:
                    m_typeStringBuilder.Append("DECIMAL");
                    break;

                case VarEnum.VT_BOOL:
                    m_typeStringBuilder.Append("VARIANT_BOOL");
                    break;

                case VarEnum.VT_CARRAY:
                    {
                        TypeDesc elemTypeDesc = m_typeDesc.lptdesc;
                        TlbType2String elemTypeConverter = new TlbType2String(m_interfaceType, elemTypeDesc);
                        string elementTypeString = elemTypeConverter.GetTypeString();

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

                        // SizeConst can only hold Int32.MaxValue
                        m_typeStringBuilder.Append(elementTypeString);
                        m_typeStringBuilder.Append(" [");
                        m_typeStringBuilder.Append(elements);
                        m_typeStringBuilder.Append(']');
                    }
                    break;

                case VarEnum.VT_SAFEARRAY:
                    // TODO(yifeng)
                    m_typeStringBuilder.Append("SAFEARRAY");
                    break;

                case VarEnum.VT_RECORD:
                case VarEnum.VT_USERDEFINED:
                    // Handle structs, interfaces, enums, and unions
                    try
                    {
                        TypeInfo realType = m_typeDesc.GetUserDefinedTypeInfo(m_interfaceType);
                        string typeString = "[" + realType.GetContainingTypeLib().GetDocumentation() +
                            "]" + realType.GetDocumentation();
                        m_typeStringBuilder.Append(typeString);
                        //NativeType2String.AddNativeUserDefinedType(typeString);
                    }
                    catch (Exception)
                    {
                        m_typeStringBuilder.Append("USERDEFINED");
                    }

                    break;

                default:
                    // TODO(yifeng)
                    m_typeStringBuilder.Append("NONE");
                    break;
            }

            for (int i = 0; i < m_nativeIndirections; i++)
                m_typeStringBuilder.Append(" *");
        }
Esempio n. 6
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;
        }
Esempio n. 7
0
        /// <summary>
        /// Used in the customized type conversion
        /// </summary>
        /// <param name="type"></param>
        public TypeConverter(Type type, CustomAttributeBuilder attribute, ParameterAttributes parameterAttributesOverride)
        {
            m_info = null;
            m_typeDesc = null;
            m_typeInfo = null;
            m_paramDesc = null;
            m_attribute = attribute;
            m_conversionLoss = false;
            m_convertedType = type;
            m_nativeIndirections = 0;

            m_parameterAttributesOverride = parameterAttributesOverride;

            ResetUnmanagedType();
        }
Esempio n. 8
0
        /// <summary>
        /// Wrapper for a already converted type
        /// </summary>
        /// <param name="type"></param>
        public TypeConverter(Type type)
        {
            m_info = null;
            m_typeDesc = null;
            m_typeInfo = null;
            m_paramDesc = null;
            m_attribute = null;
            m_conversionLoss = false;
            m_convertedType = type;
            m_nativeIndirections = 0;

            ResetUnmanagedType();
        }
Esempio n. 9
0
 public static void HandleAlias(ConverterInfo info, TypeInfo typeInfo, TypeDesc typeDesc, FieldBuilder builder)
 {
     string aliasName = GetAliasName(info, typeInfo, typeDesc);
     if (aliasName != null)
         builder.SetCustomAttribute(CustomAttributeHelper.GetBuilderForComAliasName(aliasName));
 }
Esempio n. 10
0
        private static void GetTypeFromConvertToAction(SignatureInfoMatchTarget target,
            ConvertToAction convertToAction, ConverterInfo converterInfo, TypeInfo typeInfo,
            TypeDesc typeDesc, out Type typeReturn, out CustomAttributeBuilder customAttribute,
            out ParameterAttributes fixedParameterAttributes)
        {
            typeReturn = null;
            customAttribute = null;
            fixedParameterAttributes = ParameterAttributes.None;
            ParameterDirection direction =
                ConvertToActionConstants.GetParameterDirection(convertToAction.Direction);
            switch (direction)
            {
                case ParameterDirection.IN:
                    fixedParameterAttributes |= ParameterAttributes.In;
                    break;
                case ParameterDirection.OUT:
                    fixedParameterAttributes |= ParameterAttributes.Out;
                    break;
                case ParameterDirection.INOUT:
                    fixedParameterAttributes |= ParameterAttributes.In;
                    fixedParameterAttributes |= ParameterAttributes.Out;
                    break;
            }
            Dictionary<string, string> attributePairDictionary =
                ConvertToAction.GetConvertToAttributeDictionary(convertToAction.Attributes);
            ManagedTypeConvertTo managedType =
                ConvertToActionConstants.GetManagedTypeConvertTo(convertToAction.ManagedTypeConvertTo);
            UnmanagedType marshalAs =
                ConvertToActionConstants.GetMarshalAs(convertToAction.UnmanagedTypeMarshalAs);

            switch (managedType)
            {
                case ManagedTypeConvertTo.LPARRAY:
                    if ((VarEnum)typeDesc.vt == VarEnum.VT_CARRAY || (VarEnum)typeDesc.vt == VarEnum.VT_PTR)
                    {
                        TypeConverter elemTypeConverter = new TypeConverter(converterInfo, typeInfo,
                            typeDesc.lptdesc, ConversionType.Element);
                        Type elemType = elemTypeConverter.ConvertedType;
                        typeReturn = elemType.MakeArrayType();
                        if (attributePairDictionary.ContainsKey(ConvertToActionDef.SizeConst))
                        {
                            customAttribute = CustomAttributeHelper.GetBuilderForMarshalAsConstArray(UnmanagedType.LPArray,
                                Int32.Parse(attributePairDictionary[ConvertToActionDef.SizeConst].ToString()));
                        }
                        else if (attributePairDictionary.ContainsKey(ConvertToActionDef.SizeParamIndex))
                        {
                            customAttribute = CustomAttributeHelper.GetBuilderForMarshalAsConstArrayBySizeParamIndex(
                                UnmanagedType.LPArray,
                                Int16.Parse(attributePairDictionary[ConvertToActionDef.SizeParamIndex].ToString()));
                        }
                        else if (attributePairDictionary.ContainsKey(ConvertToActionDef.SizeParamIndexOffset))
                        {
                            customAttribute = CustomAttributeHelper.GetBuilderForMarshalAsConstArrayBySizeParamIndex(
                                UnmanagedType.LPArray,
                                (short)((target.NativeParameterIndex) - 1 +
                                         Int16.Parse(attributePairDictionary[ConvertToActionDef.SizeParamIndexOffset].ToString())));
                        }
                        else
                        {
                            customAttribute = CustomAttributeHelper.GetBuilderForMarshalAs(UnmanagedType.LPArray);
                        }
                    }
                    else
                    {
                        string targetTypeString = new TlbType2String(typeInfo, typeDesc).GetTypeString();
                        throw new TlbImpGeneralException(Resource.FormatString("Err_ConvertNonArrayToArray", targetTypeString),
                            ErrorCode.Err_ConvertNonArrayToArray);
                    }
                    break;
                case ManagedTypeConvertTo.DECIMAL:
                    typeReturn = typeof(Decimal);
                    if (marshalAs != (UnmanagedType)(-1))
                        customAttribute = CustomAttributeHelper.GetBuilderForMarshalAs(marshalAs);
                    break;
                case ManagedTypeConvertTo.INT:
                    typeReturn = typeof(int);
                    if (marshalAs != (UnmanagedType)(-1))
                        customAttribute = CustomAttributeHelper.GetBuilderForMarshalAs(marshalAs);
                    break;
                case ManagedTypeConvertTo.OBJECT:
                    typeReturn = typeof(object);
                    if (marshalAs != (UnmanagedType)(-1))
                        customAttribute = CustomAttributeHelper.GetBuilderForMarshalAs(marshalAs);
                    break;
                case ManagedTypeConvertTo.STRING:
                    typeReturn = typeof(string);
                    if (marshalAs != (UnmanagedType)(-1))
                        customAttribute = CustomAttributeHelper.GetBuilderForMarshalAs(marshalAs);
                    break;
                case ManagedTypeConvertTo.STRINGBUILDER:
                    typeReturn = typeof(StringBuilder);
                    if (marshalAs != (UnmanagedType)(-1))
                        customAttribute = CustomAttributeHelper.GetBuilderForMarshalAs(marshalAs);
                    break;
            }
            if (convertToAction.ByRef)
            {
                typeReturn = typeReturn.MakeByRefType();
            }
        }
Esempio n. 11
0
        private static string GetAliasName(ConverterInfo info, TypeInfo typeInfo, TypeDesc typeDesc)
        {
            // Drill down to the actual type that is pointed to.
            while (typeDesc.vt == (int)VarEnum.VT_PTR)
                typeDesc = typeDesc.lptdesc;

            // If the parameter is an alias then we need to add a custom attribute to the
            // parameter that describes the alias.
            if (typeDesc.vt == (int)VarEnum.VT_USERDEFINED)
            {
                TypeInfo refTypeInfo = typeInfo.GetRefTypeInfo(typeDesc.hreftype);
                using (TypeAttr refTypeAttr = refTypeInfo.GetTypeAttr())
                {
                    if (refTypeAttr.typekind == TypeLibTypes.Interop.TYPEKIND.TKIND_ALIAS)
                    {
                        return info.GetManagedName(refTypeInfo);
                    }
                }
            }

            return null;
        }