/// <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); } } }
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(); }
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(); }
/// <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) }
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(" *"); }
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; }
/// <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(); }
/// <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(); }
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)); }
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(); } }
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; }