summaryrefslogtreecommitdiff
path: root/src/md/compiler/custattr_emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/compiler/custattr_emit.cpp')
-rw-r--r--src/md/compiler/custattr_emit.cpp2000
1 files changed, 2000 insertions, 0 deletions
diff --git a/src/md/compiler/custattr_emit.cpp b/src/md/compiler/custattr_emit.cpp
new file mode 100644
index 0000000000..3e23600176
--- /dev/null
+++ b/src/md/compiler/custattr_emit.cpp
@@ -0,0 +1,2000 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// CustAttr_Emit.cpp
+//
+
+//
+// Implementation for the meta data custom attribute emit code (code:IMetaDataEmit).
+//
+//*****************************************************************************
+#include "stdafx.h"
+#include "regmeta.h"
+#include "metadata.h"
+#include "corerror.h"
+#include "mdutil.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include "importhelper.h"
+#include "mdperf.h"
+#include "posterror.h"
+#include "cahlprinternal.h"
+#include "custattr.h"
+#include "corhdr.h"
+#include <metamodelrw.h>
+
+#ifdef FEATURE_METADATA_EMIT
+
+//*****************************************************************************
+//*****************************************************************************
+// Support for "Pseudo Custom Attributes"
+
+
+//*****************************************************************************
+// Enumeration of known custom attributes.
+//*****************************************************************************
+#define KnownCaList() \
+ KnownCa(UNKNOWN) \
+ KnownCa(DllImportAttribute) \
+ KnownCa(GuidAttribute) \
+ KnownCa(ComImportAttribute) \
+ KnownCa(InterfaceTypeAttribute) \
+ KnownCa(ClassInterfaceAttribute) \
+ KnownCa(SerializableAttribute) \
+ KnownCa(NonSerializedAttribute) \
+ KnownCa(MethodImplAttribute1) \
+ KnownCa(MethodImplAttribute2) \
+ KnownCa(MethodImplAttribute3) \
+ KnownCa(MarshalAsAttribute1) \
+ KnownCa(MarshalAsAttribute2) \
+ KnownCa(PreserveSigAttribute) \
+ KnownCa(InAttribute) \
+ KnownCa(OutAttribute) \
+ KnownCa(OptionalAttribute) \
+ KnownCa(StructLayoutAttribute1) \
+ KnownCa(StructLayoutAttribute2) \
+ KnownCa(FieldOffsetAttribute) \
+ KnownCa(TypeLibVersionAttribute) \
+ KnownCa(ComCompatibleVersionAttribute) \
+ KnownCa(SpecialNameAttribute) \
+ KnownCa(AllowPartiallyTrustedCallersAttribute) \
+ KnownCa(WindowsRuntimeImportAttribute) \
+
+// Ids for the CA's. CA_DllImportAttribute, etc.
+#define KnownCa(x) CA_##x,
+enum {
+ KnownCaList()
+ CA_COUNT
+};
+
+
+//*****************************************************************************
+// Properties of the known custom attributes.
+//
+// These tables describe the known custom attributes. For each custom
+// attribute, we know the namespace and name of the custom attribute,
+// the types to which the CA applies, the ctor args, and possible named
+// args. There is a flag which specifies whether the custom attribute
+// should be kept, in addition to any processing done with the data.
+//*****************************************************************************
+const BOOL bKEEPCA = TRUE;
+const BOOL bDONTKEEPCA = FALSE;
+const BOOL bMATCHBYSIG = TRUE;
+const BOOL bMATCHBYNAME = FALSE;
+
+struct KnownCaProp
+{
+ LPCUTF8 szNamespace; // Namespace of the custom attribute.
+ LPCUTF8 szName; // Name of the custom attribute.
+ const mdToken * rTypes; // Types that the CA applies to.
+ BOOL bKeepCa; // Keep the CA after processing?
+ const CaArg * pArgs; // List of ctor argument descriptors.
+ ULONG cArgs; // Count of ctor argument descriptors.
+ const CaNamedArg * pNamedArgs; // List of named arg descriptors.
+ ULONG cNamedArgs; // Count of named arg descriptors.
+ BOOL bMatchBySig; // For overloads; match by sig, not just name.
+ // WARNING: All overloads need the flag!
+};
+
+// Recognized targets for known custom attributes.
+// If Target includes mdtAssembly, then make sure to include mdtTypeRef as well,
+// aLink uses mdtTypeRef target temporarily for assembly target attributes
+const mdToken DllImportTargets[] = {mdtMethodDef, (ULONG32) -1};
+const mdToken GuidTargets[] = {mdtTypeDef, mdtTypeRef, mdtModule, mdtAssembly, (ULONG32) -1};
+const mdToken ComImportTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken InterfaceTypeTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken ClassInterfaceTargets[] = {mdtTypeDef, mdtAssembly, mdtTypeRef, (ULONG32) -1};
+const mdToken SerializableTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken NotInGCHeapTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken NonSerializedTargets[] = {mdtFieldDef, (ULONG32) -1};
+const mdToken MethodImplTargets[] = {mdtMethodDef, (ULONG32) -1};
+const mdToken MarshalTargets[] = {mdtFieldDef, mdtParamDef, mdtProperty, (ULONG32) -1};
+const mdToken PreserveSigTargets[] = {mdtMethodDef, (ULONG32) -1};
+const mdToken InOutTargets[] = {mdtParamDef, (ULONG32) -1};
+const mdToken StructLayoutTargets[] = {mdtTypeDef, (ULONG32) -1};
+const mdToken FieldOffsetTargets[] = {mdtFieldDef, (ULONG32) -1};
+const mdToken TypeLibVersionTargets[] = {mdtAssembly, mdtTypeRef,(ULONG32) -1};
+const mdToken ComCompatibleVersionTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1};
+const mdToken SpecialNameTargets[] = {mdtTypeDef, mdtMethodDef, mdtFieldDef, mdtProperty, mdtEvent, (ULONG32) -1};
+const mdToken AllowPartiallyTrustedCallersTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1};
+const mdToken WindowsRuntimeImportTargets[] = {mdtTypeDef, (ULONG32) -1};
+
+
+//#ifndef CEE_CALLCONV
+// # define CEE_CALLCONV (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS)
+//#endif
+
+#define DEFINE_CA_CTOR_ARGS(NAME) \
+ const CaArg r##NAME##Args[] = \
+ {
+#define DEFINE_CA_CTOR_ARG(TYPE) {{TYPE}},
+#define DEFINE_CA_CTOR_ARGS_END() \
+ };
+
+
+
+#define DEFINE_CA_NAMED_ARGS(NAME) \
+ const CaNamedArg r##NAME##NamedArgs[] = \
+ {
+
+#define DEFINE_CA_NAMED_ARG(NAME, PROPORFIELD, TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME) \
+ { NAME, sizeof(NAME) - 1, PROPORFIELD, { TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME, sizeof(ENUMNAME) - 1 } },
+
+#define DEFINE_CA_NAMED_PROP_I4ENUM(NAME, ENUM) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM)
+#define DEFINE_CA_NAMED_FIELD_I4ENUM(NAME, ENUM) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM)
+#define DEFINE_CA_NAMED_PROP(NAME, TYPE) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "")
+#define DEFINE_CA_NAMED_FIELD(NAME, TYPE) \
+ DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "")
+#define DEFINE_CA_NAMED_PROP_BOOL(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_BOOLEAN)
+#define DEFINE_CA_NAMED_FIELD_BOOL(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_BOOLEAN)
+#define DEFINE_CA_NAMED_PROP_STRING(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_STRING)
+#define DEFINE_CA_NAMED_FIELD_STRING(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_STRING)
+#define DEFINE_CA_NAMED_PROP_TYPE(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_TYPE)
+#define DEFINE_CA_NAMED_FIELD_TYPE(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_TYPE)
+#define DEFINE_CA_NAMED_PROP_I2(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I2)
+#define DEFINE_CA_NAMED_FIELD_I2(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I2)
+#define DEFINE_CA_NAMED_PROP_I4(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I4)
+#define DEFINE_CA_NAMED_FIELD_I4(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I4)
+
+#define DEFINE_CA_NAMED_ARGS_END() \
+ };
+
+//-----------------------------------------------------------------------------
+// index 0 is used as a placeholder.
+const KnownCaProp UNKNOWNProps = {0};
+
+//-----------------------------------------------------------------------------
+// DllImport args, named args, and known attribute properties.
+DEFINE_CA_CTOR_ARGS(DllImportAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING)
+DEFINE_CA_CTOR_ARGS_END()
+
+// NOTE: Keep this enum in sync with the array of named arguments.
+enum DllImportNamedArgs
+{
+ DI_CallingConvention,
+ DI_CharSet,
+ DI_EntryPoint,
+ DI_ExactSpelling,
+ DI_SetLastError,
+ DI_PreserveSig,
+ DI_BestFitMapping,
+ DI_ThrowOnUnmappableChar,
+ DI_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(DllImportAttribute)
+ DEFINE_CA_NAMED_FIELD_I4ENUM("CallingConvention", "System.Runtime.InteropServices.CallingConvention")
+ DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet", "System.Runtime.InteropServices.CharSet")
+ DEFINE_CA_NAMED_FIELD_STRING("EntryPoint")
+ DEFINE_CA_NAMED_FIELD_BOOL("ExactSpelling")
+ DEFINE_CA_NAMED_FIELD_BOOL("SetLastError")
+ DEFINE_CA_NAMED_FIELD_BOOL("PreserveSig")
+ DEFINE_CA_NAMED_FIELD_BOOL("BestFitMapping")
+ DEFINE_CA_NAMED_FIELD_BOOL("ThrowOnUnmappableChar")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp DllImportAttributeProps = {"System.Runtime.InteropServices", "DllImportAttribute", DllImportTargets, bDONTKEEPCA,
+ rDllImportAttributeArgs, lengthof(rDllImportAttributeArgs),
+ rDllImportAttributeNamedArgs, lengthof(rDllImportAttributeNamedArgs)};
+
+//-----------------------------------------------------------------------------
+// GUID args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(GuidAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp GuidAttributeProps = {"System.Runtime.InteropServices", "GuidAttribute", GuidTargets, bKEEPCA,
+ rGuidAttributeArgs, lengthof(rGuidAttributeArgs)};
+
+//-----------------------------------------------------------------------------
+// ComImport args (none), named args (none), and known attribute properties.
+const KnownCaProp ComImportAttributeProps = {"System.Runtime.InteropServices", "ComImportAttribute", ComImportTargets};
+
+//-----------------------------------------------------------------------------
+// Interface type args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(InterfaceTypeAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp InterfaceTypeAttributeProps = {"System.Runtime.InteropServices", "InterfaceTypeAttribute", InterfaceTypeTargets, bKEEPCA,
+ rInterfaceTypeAttributeArgs, lengthof(rInterfaceTypeAttributeArgs)};
+
+//-----------------------------------------------------------------------------
+// Class interface type args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(ClassInterfaceAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp ClassInterfaceAttributeProps = {"System.Runtime.InteropServices", "ClassInterfaceAttribute", ClassInterfaceTargets, bKEEPCA,
+ rClassInterfaceAttributeArgs, lengthof(rClassInterfaceAttributeArgs)};
+
+//-----------------------------------------------------------------------------
+// Serializable args (none), named args (none), and known attribute properties.
+const KnownCaProp SerializableAttributeProps = {"System", "SerializableAttribute", SerializableTargets};
+
+//-----------------------------------------------------------------------------
+// NonSerialized args (none), named args (none), and known attribute properties.
+const KnownCaProp NonSerializedAttributeProps = {"System", "NonSerializedAttribute", NonSerializedTargets};
+
+//-----------------------------------------------------------------------------
+// SpecialName args (none), named args (none), and known attribute properties.
+const KnownCaProp SpecialNameAttributeProps = {"System.Runtime.CompilerServices", "SpecialNameAttribute", SpecialNameTargets, bDONTKEEPCA};
+
+//-----------------------------------------------------------------------------
+// WindowsRuntimeImport args (none), named args (none), and known attribute properties.
+const KnownCaProp WindowsRuntimeImportAttributeProps = {"System.Runtime.InteropServices.WindowsRuntime", "WindowsRuntimeImportAttribute", WindowsRuntimeImportTargets};
+
+
+//-----------------------------------------------------------------------------
+// MethodImpl #1 args (none), named args, and known attribute properties.
+// MethodImpl #2 args (short), named args, and known attribute properties.
+// MethodImpl #3 args (enum), named args, and known attribute properties.
+// Note: first two match by signature; third by name only, because signature matching code is not
+// strong enough for enums.
+DEFINE_CA_CTOR_ARGS(MethodImplAttribute2)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
+DEFINE_CA_CTOR_ARGS_END()
+
+DEFINE_CA_CTOR_ARGS(MethodImplAttribute3)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
+DEFINE_CA_CTOR_ARGS_END()
+
+enum MethodImplAttributeNamedArgs
+{
+ MI_CodeType,
+ MI_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(MethodImplAttribute)
+ DEFINE_CA_NAMED_FIELD_I4ENUM("MethodCodeType", "System.Runtime.CompilerServices.MethodCodeType")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp MethodImplAttribute1Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
+ 0, 0,
+ rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
+ bMATCHBYSIG};
+const KnownCaProp MethodImplAttribute2Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
+ rMethodImplAttribute2Args, lengthof(rMethodImplAttribute2Args),
+ rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
+ bMATCHBYSIG};
+const KnownCaProp MethodImplAttribute3Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
+ rMethodImplAttribute3Args, lengthof(rMethodImplAttribute3Args),
+ rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
+ bMATCHBYNAME};
+
+//-----------------------------------------------------------------------------
+// Marshal args, named args, and known attribute properties.
+DEFINE_CA_CTOR_ARGS(MarshalAsAttribute2)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
+DEFINE_CA_CTOR_ARGS_END()
+
+DEFINE_CA_CTOR_ARGS(MarshalAsAttribute1)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
+DEFINE_CA_CTOR_ARGS_END()
+
+// NOTE: Keep this enum in sync with the array of named arguments.
+enum MarshalNamedArgs
+{
+ M_ArraySubType,
+ M_SafeArraySubType,
+ M_SafeArrayUserDefinedSubType,
+ M_SizeParamIndex,
+ M_SizeConst,
+ M_MarshalType,
+ M_MarshalTypeRef,
+ M_MarshalCookie,
+ M_IidParameterIndex,
+ M_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(MarshalAsAttribute)
+ DEFINE_CA_NAMED_FIELD_I4ENUM("ArraySubType", "System.Runtime.InteropServices.UnmanagedType")
+ DEFINE_CA_NAMED_FIELD_I4ENUM("SafeArraySubType", "System.Runtime.InteropServices.VarEnum")
+ DEFINE_CA_NAMED_FIELD_TYPE("SafeArrayUserDefinedSubType")
+ DEFINE_CA_NAMED_FIELD_I2("SizeParamIndex")
+ DEFINE_CA_NAMED_FIELD_I4("SizeConst")
+ DEFINE_CA_NAMED_FIELD_STRING("MarshalType")
+ DEFINE_CA_NAMED_FIELD_TYPE("MarshalTypeRef")
+ DEFINE_CA_NAMED_FIELD_STRING("MarshalCookie")
+ DEFINE_CA_NAMED_FIELD_I4("IidParameterIndex")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp MarshalAsAttribute1Props = {"System.Runtime.InteropServices", "MarshalAsAttribute", MarshalTargets, bDONTKEEPCA,
+ rMarshalAsAttribute1Args, lengthof(rMarshalAsAttribute1Args),
+ rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs),
+ bMATCHBYSIG};
+
+const KnownCaProp MarshalAsAttribute2Props = {"System.Runtime.InteropServices", "MarshalAsAttribute", MarshalTargets, bDONTKEEPCA,
+ rMarshalAsAttribute2Args, lengthof(rMarshalAsAttribute2Args),
+ rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs),
+ bMATCHBYNAME};
+
+//-----------------------------------------------------------------------------
+// PreserveSignature args, named args (none), and known attribute properties.
+const KnownCaProp PreserveSigAttributeProps = {"System.Runtime.InteropServices", "PreserveSigAttribute", PreserveSigTargets, bDONTKEEPCA};
+
+//-----------------------------------------------------------------------------
+// In args (none), named args (none), and known attribute properties.
+const KnownCaProp InAttributeProps = {"System.Runtime.InteropServices", "InAttribute", InOutTargets};
+
+//-----------------------------------------------------------------------------
+// Out args (none), named args (none), and known attribute properties.
+const KnownCaProp OutAttributeProps = {"System.Runtime.InteropServices", "OutAttribute", InOutTargets};
+
+//-----------------------------------------------------------------------------
+// Optional args (none), named args (none), and known attribute properties.
+const KnownCaProp OptionalAttributeProps = {"System.Runtime.InteropServices", "OptionalAttribute", InOutTargets};
+
+//-----------------------------------------------------------------------------
+// StructLayout args, named args, and known attribute properties.
+DEFINE_CA_CTOR_ARGS(StructLayoutAttribute2)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+DEFINE_CA_CTOR_ARGS_END()
+
+DEFINE_CA_CTOR_ARGS(StructLayoutAttribute1)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
+DEFINE_CA_CTOR_ARGS_END()
+
+// NOTE: Keep this enum in sync with the array of named arguments.
+enum StructLayoutNamedArgs
+{
+ SL_Pack,
+ SL_Size,
+ SL_CharSet,
+ SL_COUNT
+};
+
+DEFINE_CA_NAMED_ARGS(StructLayoutAttribute)
+ DEFINE_CA_NAMED_FIELD_I4("Pack")
+ DEFINE_CA_NAMED_FIELD_I4("Size")
+ DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet", "System.Runtime.InteropServices.CharSet")
+DEFINE_CA_NAMED_ARGS_END()
+
+const KnownCaProp StructLayoutAttribute1Props = {"System.Runtime.InteropServices", "StructLayoutAttribute", StructLayoutTargets, bDONTKEEPCA,
+ rStructLayoutAttribute1Args, lengthof(rStructLayoutAttribute1Args),
+ rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs),
+ bMATCHBYSIG};
+const KnownCaProp StructLayoutAttribute2Props = {"System.Runtime.InteropServices", "StructLayoutAttribute", StructLayoutTargets, bDONTKEEPCA,
+ rStructLayoutAttribute2Args, lengthof(rStructLayoutAttribute2Args),
+ rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs),
+ bMATCHBYNAME};
+
+//-----------------------------------------------------------------------------
+// FieldOffset args, named args (none), and known attribute properties.
+DEFINE_CA_CTOR_ARGS(FieldOffsetAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp FieldOffsetAttributeProps = {"System.Runtime.InteropServices", "FieldOffsetAttribute", FieldOffsetTargets, bDONTKEEPCA,
+ rFieldOffsetAttributeArgs, lengthof(rFieldOffsetAttributeArgs)};
+
+DEFINE_CA_CTOR_ARGS(TypeLibVersionAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp TypeLibVersionAttributeProps = {"System.Runtime.InteropServices", "TypeLibVersionAttribute", TypeLibVersionTargets, bKEEPCA,
+ rTypeLibVersionAttributeArgs, lengthof(rTypeLibVersionAttributeArgs)};
+
+
+DEFINE_CA_CTOR_ARGS(ComCompatibleVersionAttribute)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+ DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
+DEFINE_CA_CTOR_ARGS_END()
+
+const KnownCaProp ComCompatibleVersionAttributeProps = {"System.Runtime.InteropServices", "ComCompatibleVersionAttribute", ComCompatibleVersionTargets, bKEEPCA,
+ rComCompatibleVersionAttributeArgs, lengthof(rComCompatibleVersionAttributeArgs)};
+
+
+//-----------------------------------------------------------------------------
+// APTCA args (none), named args (none), and known attribute properties.
+const KnownCaProp AllowPartiallyTrustedCallersAttributeProps = {"System.Security", "AllowPartiallyTrustedCallersAttribute", AllowPartiallyTrustedCallersTargets, bKEEPCA};
+
+
+
+//-----------------------------------------------------------------------------
+// Array of known custom attribute properties
+#undef KnownCa
+#define KnownCa(x) &x##Props,
+const KnownCaProp * const rKnownCaProps[CA_COUNT] =
+{
+ KnownCaList()
+};
+
+//*****************************************************************************
+// Helper to turn on or off a single bit in a bitmask.
+//*****************************************************************************
+template<class T> FORCEINLINE void SetBitValue(T &bitmask, T bit, int bVal)
+{
+ if (bVal)
+ bitmask |= bit;
+ else
+ bitmask &= ~bit;
+} // template<class T> FORCEINLINE void SetBitValue()
+
+HRESULT ParseEncodedType(
+ CustomAttributeParser &ca,
+ CaType* pCaType)
+{
+ CONTRACTL
+ {
+ PRECONDITION(CheckPointer(pCaType));
+ NOTHROW;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ CorSerializationType* pType = &pCaType->tag;
+
+ IfFailGo(ca.GetTag(pType));
+
+ if (*pType == SERIALIZATION_TYPE_SZARRAY)
+ {
+ IfFailGo(ca.GetTag(&pCaType->arrayType));
+ pType = &pCaType->arrayType;
+ }
+
+ if (*pType == SERIALIZATION_TYPE_ENUM)
+ {
+ // We cannot determine the underlying type without loading the Enum.
+ pCaType->enumType = SERIALIZATION_TYPE_UNDEFINED;
+ IfFailGo(ca.GetNonNullString(&pCaType->szEnumName, &pCaType->cEnumName));
+ }
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Helper to parse the values for the ctor argument list and the named argument list.
+//
+
+HRESULT ParseKnownCaValue(
+ CustomAttributeParser &ca,
+ CaValue* pCaArg,
+ CaType* pCaParam)
+{
+ CONTRACTL
+ {
+ PRECONDITION(CheckPointer(pCaArg));
+ PRECONDITION(CheckPointer(pCaParam));
+ PRECONDITION(pCaParam->tag != SERIALIZATION_TYPE_TAGGED_OBJECT && pCaParam->tag != SERIALIZATION_TYPE_SZARRAY);
+ NOTHROW;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ CorSerializationType underlyingType;
+
+ pCaArg->type = *pCaParam;
+
+ underlyingType = pCaArg->type.tag == SERIALIZATION_TYPE_ENUM ? pCaArg->type.enumType : pCaArg->type.tag;
+
+ // Grab the value.
+ switch (underlyingType)
+ {
+ case SERIALIZATION_TYPE_BOOLEAN:
+ case SERIALIZATION_TYPE_I1:
+ case SERIALIZATION_TYPE_U1:
+ IfFailGo(ca.GetU1(&pCaArg->u1));
+ break;
+
+ case SERIALIZATION_TYPE_CHAR:
+ case SERIALIZATION_TYPE_I2:
+ case SERIALIZATION_TYPE_U2:
+ IfFailGo(ca.GetU2(&pCaArg->u2));
+ break;
+
+ case SERIALIZATION_TYPE_I4:
+ case SERIALIZATION_TYPE_U4:
+ IfFailGo(ca.GetU4(&pCaArg->u4));
+ break;
+
+ case SERIALIZATION_TYPE_I8:
+ case SERIALIZATION_TYPE_U8:
+ IfFailGo(ca.GetU8(&pCaArg->u8));
+ break;
+
+ case SERIALIZATION_TYPE_R4:
+ IfFailGo(ca.GetR4(&pCaArg->r4));
+ break;
+
+ case SERIALIZATION_TYPE_R8:
+ IfFailGo(ca.GetR8(&pCaArg->r8));
+ break;
+
+ case SERIALIZATION_TYPE_STRING:
+ case SERIALIZATION_TYPE_TYPE:
+ IfFailGo(ca.GetString(&pCaArg->str.pStr, &pCaArg->str.cbStr));
+ break;
+
+ default:
+ // The arguments of all known custom attributes are Type, String, Enum, or primitive types.
+ _ASSERTE(!"Unexpected internal error");
+ hr = E_FAIL;
+ break;
+ } // End switch
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Helper to parse the nanmed argument list.
+// This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and
+// should not have any VM dependency.
+//
+
+HRESULT ParseKnownCaNamedArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaNamedArg *pNamedParams, // Array of argument descriptors.
+ ULONG cNamedParams)
+{
+ WRAPPER_NO_CONTRACT;
+
+ HRESULT hr = S_OK;
+ ULONG ixParam;
+ INT32 ixArg;
+ INT16 cActualArgs;
+ CaNamedArgCtor namedArg;
+ CaNamedArg* pNamedParam;
+
+ // Get actual count of named arguments.
+ if (FAILED(ca.GetI2(&cActualArgs)))
+ cActualArgs = 0; // Everett behavior
+
+ for (ixParam = 0; ixParam < cNamedParams; ixParam++)
+ pNamedParams[ixParam].val.type.tag = SERIALIZATION_TYPE_UNDEFINED;
+
+ // For each named argument...
+ for (ixArg = 0; ixArg < cActualArgs; ixArg++)
+ {
+ // Field or property?
+ IfFailGo(ca.GetTag(&namedArg.propertyOrField));
+ if (namedArg.propertyOrField != SERIALIZATION_TYPE_FIELD && namedArg.propertyOrField != SERIALIZATION_TYPE_PROPERTY)
+ IfFailGo(PostError(META_E_CA_INVALID_ARGTYPE));
+
+ // Get argument type information
+ IfFailGo(ParseEncodedType(ca, &namedArg.type));
+
+ // Get name of Arg.
+ if (FAILED(ca.GetNonEmptyString(&namedArg.szName, &namedArg.cName)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+
+ // Match arg by name and type
+ for (ixParam = 0; ixParam < cNamedParams; ixParam++)
+ {
+ pNamedParam = &pNamedParams[ixParam];
+
+ // Match type
+ if (pNamedParam->type.tag != SERIALIZATION_TYPE_TAGGED_OBJECT)
+ {
+ if (namedArg.type.tag != pNamedParam->type.tag)
+ continue;
+
+ // Match array type
+ if (namedArg.type.tag == SERIALIZATION_TYPE_SZARRAY &&
+ pNamedParam->type.arrayType != SERIALIZATION_TYPE_TAGGED_OBJECT &&
+ namedArg.type.arrayType != pNamedParam->type.arrayType)
+ continue;
+ }
+
+ // Match name (and its length to avoid substring matching)
+ if ((pNamedParam->cName != namedArg.cName) ||
+ (strncmp(pNamedParam->szName, namedArg.szName, namedArg.cName) != 0))
+ {
+ continue;
+ }
+
+ // If enum, match enum name.
+ if (pNamedParam->type.tag == SERIALIZATION_TYPE_ENUM ||
+ (pNamedParam->type.tag == SERIALIZATION_TYPE_SZARRAY && pNamedParam->type.arrayType == SERIALIZATION_TYPE_ENUM ))
+ {
+ if (pNamedParam->type.cEnumName > namedArg.type.cEnumName)
+ continue; // name cannot possibly match
+
+ if (strncmp(pNamedParam->type.szEnumName, namedArg.type.szEnumName, pNamedParam->type.cEnumName) != 0 ||
+ (pNamedParam->type.cEnumName < namedArg.type.cEnumName &&
+ namedArg.type.szEnumName[pNamedParam->type.cEnumName] != ','))
+ continue;
+
+ // TODO: For now assume the property\field array size is correct - later we should verify this
+ namedArg.type.enumType = pNamedParam->type.enumType;
+ }
+
+ // Found a match.
+ break;
+ }
+
+ // Better have found an argument.
+ if (ixParam == cNamedParams)
+ {
+ MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
+ IfFailGo(PostError(META_E_CA_UNKNOWN_ARGUMENT, wcslen(pWideStr), pWideStr));
+ }
+
+ // Argument had better not have been seen already.
+ if (pNamedParams[ixParam].val.type.tag != SERIALIZATION_TYPE_UNDEFINED)
+ {
+ MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
+ IfFailGo(PostError(META_E_CA_REPEATED_ARG, wcslen(pWideStr), pWideStr));
+ }
+
+ IfFailGo(ParseKnownCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type));
+ }
+
+ErrExit:
+ return hr;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Helper to parse the ctor argument list.
+// This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and
+// should not have any VM dependency.
+//
+
+HRESULT ParseKnownCaArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaArg* pArgs, // Array of argument descriptors.
+ ULONG cArgs) // Count of argument descriptors.
+{
+ WRAPPER_NO_CONTRACT;
+
+ HRESULT hr = S_OK; // A result.
+ ULONG ix; // Loop control.
+
+ // If there is a blob, check the prolog.
+ if (FAILED(ca.ValidateProlog()))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+
+ // For each expected arg...
+ for (ix=0; ix<cArgs; ++ix)
+ {
+ CaArg* pArg = &pArgs[ix];
+ IfFailGo(ParseKnownCaValue(ca, &pArg->val, &pArg->type));
+ }
+
+ErrExit:
+ return hr;
+} // ParseKnownCaArgs
+
+//*****************************************************************************
+// Create a CustomAttribute record from a blob with the specified parent.
+//*****************************************************************************
+STDMETHODIMP RegMeta::DefineCustomAttribute(
+ mdToken tkOwner, // [IN] The object to put the value on.
+ mdToken tkCtor, // [IN] Constructor of the CustomAttribute type (MemberRef/MethodDef).
+ void const *pCustomAttribute, // [IN] Custom Attribute data.
+ ULONG cbCustomAttribute, // [IN] Size of custom Attribute data.
+ mdCustomAttribute *pcv) // [OUT, OPTIONAL] Put custom Attribute token here.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CustomAttributeRec *pRecord = NULL; // New custom Attribute record.
+ RID iRecord; // New custom Attribute RID.
+ CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
+ int ixKnown; // Index of known custom attribute.
+
+ LOG((LOGMD, "RegMeta::DefineCustomAttribute(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", tkOwner, tkCtor,
+ pCustomAttribute, cbCustomAttribute, pcv));
+ START_MD_PERF();
+ LOCKWRITE();
+
+ _ASSERTE(TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef);
+
+ if (TypeFromToken(tkOwner) == mdtCustomAttribute)
+ IfFailGo(E_INVALIDARG);
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ if (IsNilToken(tkOwner) ||
+ IsNilToken(tkCtor) ||
+ (TypeFromToken(tkCtor) != mdtMethodDef &&
+ TypeFromToken(tkCtor) != mdtMemberRef) )
+ {
+ IfFailGo(E_INVALIDARG);
+ }
+
+ // See if this is a known custom attribute.
+ IfFailGo(_IsKnownCustomAttribute(tkCtor, &ixKnown));
+ if (ixKnown != 0)
+ {
+ int bKeep = false;
+ hr = _HandleKnownCustomAttribute(tkOwner, pCustomAttribute, cbCustomAttribute, ixKnown, &bKeep);
+ if (pcv)
+ *pcv = mdCustomAttributeNil;
+ IfFailGo(hr);
+ if (!bKeep)
+ goto ErrExit;
+ }
+
+ if (((TypeFromToken(tkOwner) == mdtTypeDef) || (TypeFromToken(tkOwner) == mdtMethodDef)) &&
+ (TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef))
+ {
+ CHAR szBuffer[MAX_CLASS_NAME + 1];
+ LPSTR szName = szBuffer;
+ LPCSTR szNamespace;
+ LPCSTR szClass;
+ TypeRefRec *pTypeRefRec = NULL;
+ TypeDefRec *pTypeDefRec = NULL;
+ mdToken tkParent;
+
+ if (TypeFromToken(tkCtor) == mdtMemberRef)
+ {
+ MemberRefRec *pMemberRefRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMemberRefRec));
+ tkParent = pMiniMd->getClassOfMemberRef(pMemberRefRec);
+ if (TypeFromToken(tkParent) == mdtTypeRef)
+ {
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szClass));
+ ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass);
+ }
+ else if (TypeFromToken(tkParent) == mdtTypeDef)
+ {
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+ }
+ else
+ {
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent));
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+
+ if (pTypeDefRec != NULL)
+ {
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szClass));
+ ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass);
+ }
+
+ if ((TypeFromToken(tkOwner) == mdtMethodDef) && strcmp(szName, COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI) == 0)
+ {
+ // Turn REQ_SO attribute into flag bit on the methoddef.
+ MethodRec *pMethod;
+ IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkOwner), &pMethod));
+ pMethod->AddFlags(mdRequireSecObject);
+ IfFailGo(UpdateENCLog(tkOwner));
+ goto ErrExit;
+ }
+ else if (strcmp(szName, COR_SUPPRESS_UNMANAGED_CODE_CHECK_ATTRIBUTE_ANSI) == 0)
+ {
+ // If we spot an unmanged code check suppression attribute, turn on
+ // the bit that says there's declarative security on the
+ // class/method, but still write the attribute itself.
+ if (TypeFromToken(tkOwner) == mdtTypeDef)
+ {
+ IfFailGo(_TurnInternalFlagsOn(tkOwner, tdHasSecurity));
+ }
+ else if (TypeFromToken(tkOwner) == mdtMethodDef)
+ {
+ IfFailGo(_TurnInternalFlagsOn(tkOwner, mdHasSecurity));
+ }
+ IfFailGo(UpdateENCLog(tkOwner));
+ }
+ }
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributeRecord(&pRecord, &iRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecord, tkCtor));
+ IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecord, tkOwner));
+
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute));
+
+ // Give token back to caller.
+ if (pcv != NULL)
+ *pcv = TokenFromRid(iRecord, mdtCustomAttribute);
+
+ IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributesToHash(TokenFromRid(iRecord, mdtCustomAttribute)) );
+
+ IfFailGo(UpdateENCLog(TokenFromRid(iRecord, mdtCustomAttribute)));
+
+ErrExit:
+ STOP_MD_PERF(DefineCustomAttribute);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::DefineCustomAttribute
+
+//*****************************************************************************
+// Replace the blob of an existing custom attribute.
+//*****************************************************************************
+STDMETHODIMP RegMeta::SetCustomAttributeValue( // Return code.
+ mdCustomAttribute tkAttr, // [IN] The object to be Attributed.
+ void const *pCustomAttribute, // [IN] Custom Attribute data.
+ ULONG cbCustomAttribute) // [IN] Size of custom Attribute data.
+{
+#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
+ return E_NOTIMPL;
+#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CustomAttributeRec *pRecord = NULL;// Existing custom Attribute record.
+
+ START_MD_PERF();
+ LOCKWRITE();
+
+ IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
+
+ _ASSERTE(TypeFromToken(tkAttr) == mdtCustomAttribute && !InvalidRid(tkAttr));
+
+ // Retrieve and update the custom value.
+ IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkAttr), &pRecord));
+ IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute));
+
+ IfFailGo(UpdateENCLog(tkAttr));
+ErrExit:
+
+ STOP_MD_PERF(SetCustomAttributeValue);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
+} // RegMeta::SetCustomAttributeValue
+
+//*****************************************************************************
+//*****************************************************************************
+HRESULT RegMeta::_IsKnownCustomAttribute( // S_OK, S_FALSE, or error.
+ mdToken tkCtor, // [IN] Token of custom attribute's constructor.
+ int *pca) // [OUT] Put value from KnownCustAttr enum here.
+{
+ HRESULT hr = S_OK; // A result.
+ CCustAttrHashKey sLookup; // For looking up a custom attribute.
+ CCustAttrHashKey *pFound; // Result of a lookup.
+ LPCSTR szNamespace = ""; // Namespace of custom attribute type.
+ LPCSTR szName = ""; // Name of custom attribute type.
+ TypeDefRec *pTypeDefRec = NULL; // Parent record, when a TypeDef.
+ TypeRefRec *pTypeRefRec = NULL; // Parent record, when a TypeRef.
+ CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
+ int ixCa; // Index of Known CustomAttribute, or 0.
+ int i; // Loop control.
+ mdToken tkParent;
+
+ *pca = 0;
+
+ // Only for Custom Attributes.
+ _ASSERTE(TypeFromToken(tkCtor) != mdtTypeRef && TypeFromToken(tkCtor) != mdtTypeDef);
+
+ sLookup.tkType = tkCtor;
+
+ // See if this custom attribute type has been seen before.
+ if ((pFound = m_caHash.Find(&sLookup)))
+ { // Yes, already seen.
+ *pca = pFound->ca;
+ hr = (pFound->ca == CA_UNKNOWN) ? S_FALSE : S_OK;
+ goto ErrExit;
+ }
+
+ // Hasn't been seen before. See if it is well known.
+
+ // Get the CA name.
+ if (TypeFromToken(tkCtor) == mdtMemberRef)
+ {
+ MemberRefRec *pMember;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember));
+ tkParent = pMiniMd->getClassOfMemberRef(pMember);
+ if (TypeFromToken(tkParent) == mdtTypeRef)
+ {
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
+ }
+ else if (TypeFromToken(tkParent) == mdtTypeDef)
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+ else
+ {
+ IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent));
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
+ }
+
+ if (pTypeDefRec)
+ {
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
+ }
+
+ // Search in list of Known CAs.
+ for (ixCa=0, i=1; i<CA_COUNT; ++i)
+ {
+ if (strcmp(szName, rKnownCaProps[i]->szName) != 0)
+ continue;
+ if (strcmp(szNamespace, rKnownCaProps[i]->szNamespace) == 0)
+ {
+ // Some custom attributes have overloaded ctors. For those,
+ // see if this is the matching overload.
+ if (rKnownCaProps[i]->bMatchBySig)
+ {
+ // Name matches. Does the signature?
+ PCCOR_SIGNATURE pSig = NULL; // Signature of a method.
+ ULONG cbSig = 0; // Size of the signature.
+ ULONG cParams; // Count of signature parameters.
+ ULONG cb; // Size of an element
+ ULONG elem; // Signature element.
+ ULONG j; // Loop control.
+
+ // Get the signature.
+ if (TypeFromToken(tkCtor) == mdtMemberRef)
+ {
+ MemberRefRec *pMember;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember));
+ IfFailGo(pMiniMd->getSignatureOfMemberRef(pMember, &pSig, &cbSig));
+ }
+ else
+ {
+ MethodRec *pMethod;
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkCtor), &pMethod));
+ IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSig, &cbSig));
+ }
+
+ // Skip calling convention.
+ cb = CorSigUncompressData(pSig, &elem);
+ pSig += cb;
+ cbSig -= cb;
+ // Count of params.
+ cb = CorSigUncompressData(pSig, &cParams);
+ pSig += cb;
+ cbSig -= cb;
+
+ // If param count mismatch, not the right CA.
+ if (cParams != rKnownCaProps[i]->cArgs)
+ continue;
+
+ // Count is fine, check each param. Skip return type (better be void).
+ cb = CorSigUncompressData(pSig, &elem);
+ _ASSERTE(elem == ELEMENT_TYPE_VOID);
+ pSig += cb;
+ cbSig -= cb;
+ for (j=0; j<cParams; ++j)
+ {
+ // Get next element from method signature.
+ cb = CorSigUncompressData(pSig, &elem);
+ pSig += cb;
+ cbSig -= cb;
+ if (rKnownCaProps[i]->pArgs[j].type.tag != (CorSerializationType) elem)
+ break;
+ }
+
+ // All matched?
+ if (j != cParams)
+ continue;
+ }
+ // All matched.
+ ixCa = i;
+ break;
+ }
+ }
+
+ // Add to hash.
+ sLookup.ca = ixCa;
+ pFound = m_caHash.Add(&sLookup);
+ IfNullGo(pFound);
+ *pFound = sLookup;
+ *pca = ixCa;
+
+ErrExit:
+ return hr;
+} // RegMeta::_IsKnownCustomAttribute
+
+//*****************************************************************************
+//*****************************************************************************
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::_HandleKnownCustomAttribute( // S_OK or error.
+ mdToken tkObj, // [IN] Object being attributed.
+ const void *pData, // [IN] Custom Attribute data blob.
+ ULONG cbData, // [IN] Count of bytes in the data.
+ int ixCa, // [IN] Value from KnownCustAttr enum.
+ int *bKeep) // [OUT] If true, keep the CA after processing.
+{
+ HRESULT hr = S_OK; // A result.
+ ULONG ixTbl; // Index of table with object.
+ void *pRow; // Whatever sort of record it is.
+ CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
+ mdToken tkObjType; // Type of the object.
+ ULONG ix; // Loop control.
+ KnownCaProp const *props=rKnownCaProps[ixCa]; // For convenience.
+ CustomAttributeParser ca(pData, cbData);
+ CQuickArray<CaArg> qArgs; // Un-named arguments.
+ CQuickArray<CaNamedArg> qNamedArgs; // Named arguments.
+ CQuickArray<BYTE> qNativeType;// Native type string.
+
+ _ASSERTE(ixCa > 0 && ixCa < CA_COUNT);
+ *bKeep = props->bKeepCa || m_bKeepKnownCa;
+
+ // Validate that target is valid for attribute.
+ tkObjType = TypeFromToken(tkObj);
+ for (ix=0; props->rTypes[ix] != (mdToken) -1; ++ix)
+ {
+ if (props->rTypes[ix] == tkObjType)
+ break;
+ }
+ // Was the type found in list of valid targets?
+ if (props->rTypes[ix] == (mdToken) -1)
+ { // No, error.
+ IfFailGo(PostError(META_E_CA_INVALID_TARGET));
+ }
+ // Get the row.
+ ixTbl = pMiniMd->GetTblForToken(tkObj);
+ _ASSERTE(ixTbl >= 0 && ixTbl <= pMiniMd->GetCountTables());
+ IfFailGo(pMiniMd->getRow(ixTbl, RidFromToken(tkObj), &pRow));
+
+ // If this custom attribute expects any args...
+ if (props->cArgs || props->cNamedArgs)
+ { // Initialize array ctor arg descriptors.
+ IfFailGo(qArgs.ReSizeNoThrow(props->cArgs));
+ for (ix=0; ix<props->cArgs; ++ix)
+ qArgs[ix] = props->pArgs[ix];
+ // Parse any ctor args (unnamed, fixed args).
+ IfFailGo(ParseKnownCaArgs(ca, qArgs.Ptr(), props->cArgs));
+
+ // If this custom attribute accepts named args, parse them, or if there
+ // are unused bytes, parse them.
+ if (props->cNamedArgs || ca.BytesLeft() > 0)
+ { // Initialize array of named arg descriptors.
+ IfFailGo(qNamedArgs.ReSizeNoThrow(props->cNamedArgs));
+ for (ix=0; ix<props->cNamedArgs; ++ix)
+ qNamedArgs[ix] = props->pNamedArgs[ix];
+ // Parse named args.
+ IfFailGo(ParseKnownCaNamedArgs(ca, qNamedArgs.Ptr(), props->cNamedArgs));
+ }
+ }
+
+ switch (ixCa)
+ {
+ case CA_DllImportAttribute:
+ {
+ // Validate parameters.
+ if (qArgs[0].val.str.cbStr == 0 || qArgs[0].val.str.pStr == NULL)
+ {
+ // no name for DllImport.
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+
+ // Retrieve / create a ModuleRef on the dll name.
+ mdModuleRef mrModule;
+ CQuickArray<char> qDllName;
+ IfFailGo(qDllName.ReSizeNoThrow(qArgs[0].val.str.cbStr+1));
+ memcpy(qDllName.Ptr(), qArgs[0].val.str.pStr, qArgs[0].val.str.cbStr);
+ qDllName[qArgs[0].val.str.cbStr] = '\0';
+ hr = ImportHelper::FindModuleRef(pMiniMd, qDllName.Ptr(), &mrModule);
+ if (hr != S_OK)
+ {
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzDllName, qDllName.Ptr());
+ if (wzDllName == NULL)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ IfFailGo(_DefineModuleRef(wzDllName, &mrModule));
+ }
+
+ // Create a p/invoke map entry.
+ ULONG dwFlags; dwFlags=0;
+ // Was a calling convention set?
+ if (qNamedArgs[DI_CallingConvention].val.type.tag)
+ { // Calling convention makes no sense on a field.
+ if (TypeFromToken(tkObj) == mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_CallingConvention].szName));
+ // Turn off all callconv bits, then turn on specified value.
+ dwFlags &= ~pmCallConvMask;
+ switch (qNamedArgs[DI_CallingConvention].val.u4)
+ { //<TODO>@future: sigh. keep in sync with System.Runtime.InteropServices.CallingConvention</TODO>
+ case 0: break; // 0 means "do nothing"
+ case 1: dwFlags |= pmCallConvWinapi; break;
+ case 2: dwFlags |= pmCallConvCdecl; break;
+ case 3: dwFlags |= pmCallConvStdcall; break;
+ case 4: dwFlags |= pmCallConvThiscall; break;
+ case 5: dwFlags |= pmCallConvFastcall; break;
+ default:
+ _ASSERTE(!"Flags are out of sync! ");
+ break;
+ }
+ }
+ else
+ if (TypeFromToken(tkObj) == mdtMethodDef)
+ { // No calling convention specified for a method. Default to pmCallConvWinApi.
+ dwFlags = (dwFlags & ~pmCallConvMask) | pmCallConvWinapi;
+ }
+
+ // Charset
+ if (qNamedArgs[DI_CharSet].val.type.tag)
+ { // Turn of all charset bits, then turn on specified bits.
+ dwFlags &= ~pmCharSetMask;
+ switch (qNamedArgs[DI_CharSet].val.u4)
+ { //<TODO>@future: keep in sync with System.Runtime.InteropServices.CharSet</TODO>
+ case 0: break; // 0 means "do nothing"
+ case 1: dwFlags |= pmCharSetNotSpec; break;
+ case 2: dwFlags |= pmCharSetAnsi; break;
+ case 3: dwFlags |= pmCharSetUnicode; break;
+ case 4: dwFlags |= pmCharSetAuto; break;
+ default:
+ _ASSERTE(!"Flags are out of sync! ");
+ break;
+ }
+ }
+ if (qNamedArgs[DI_ExactSpelling].val.u1)
+ dwFlags |= pmNoMangle;
+ if (qNamedArgs[DI_SetLastError].val.type.tag)
+ { // SetLastError makes no sense on a field.
+ if (TypeFromToken(tkObj) == mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_SetLastError].szName));
+ if (qNamedArgs[DI_SetLastError].val.u1)
+ dwFlags |= pmSupportsLastError;
+ }
+
+ // If an entrypoint name was specified, use it, otherrwise grab the name from the member.
+ LPCWSTR wzEntry;
+ if (qNamedArgs[DI_EntryPoint].val.type.tag)
+ {
+ if (qNamedArgs[DI_EntryPoint].val.str.cbStr > 0)
+ {
+ MAKE_WIDEPTR_FROMUTF8N_NOTHROW(wzEntryName, qNamedArgs[DI_EntryPoint].val.str.pStr, qNamedArgs[DI_EntryPoint].val.str.cbStr);
+ if (wzEntryName == NULL)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ wzEntry = wzEntryName;
+ }
+ else
+ wzEntry = W("");
+ }
+ else
+ {
+ LPCUTF8 szMember = NULL;
+ if (TypeFromToken(tkObj) == mdtMethodDef)
+ {
+ IfFailGo(pMiniMd->getNameOfMethod(reinterpret_cast<MethodRec*>(pRow), &szMember));
+ }
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMemberName, szMember);
+ if (wzMemberName == NULL)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ wzEntry = wzMemberName;
+ }
+
+ // Set the miPreserveSig bit based on the value of the preserve sig flag.
+ if (qNamedArgs[DI_PreserveSig].val.type.tag && !qNamedArgs[DI_PreserveSig].val.u1)
+ reinterpret_cast<MethodRec*>(pRow)->RemoveImplFlags(miPreserveSig);
+ else
+ reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig);
+
+ if (qNamedArgs[DI_BestFitMapping].val.type.tag)
+ {
+ if (qNamedArgs[DI_BestFitMapping].val.u1)
+ dwFlags |= pmBestFitEnabled;
+ else
+ dwFlags |= pmBestFitDisabled;
+ }
+
+ if (qNamedArgs[DI_ThrowOnUnmappableChar].val.type.tag)
+ {
+ if (qNamedArgs[DI_ThrowOnUnmappableChar].val.u1)
+ dwFlags |= pmThrowOnUnmappableCharEnabled;
+ else
+ dwFlags |= pmThrowOnUnmappableCharDisabled;
+ }
+
+ // Finally, create the PInvokeMap entry.,
+ IfFailGo(_DefinePinvokeMap(tkObj, dwFlags, wzEntry, mrModule));
+ goto ErrExit;
+ }
+ break;
+
+ case CA_GuidAttribute:
+ { // Just verify the attribute. It still gets stored as a real custom attribute.
+ // format is "{01234567-0123-0123-0123-001122334455}"
+ GUID guid;
+ WCHAR wzGuid[40];
+ int cch = qArgs[0].val.str.cbStr;
+
+ // Guid should be 36 characters; need to add curlies.
+ if (cch == 36)
+ {
+ WszMultiByteToWideChar(CP_UTF8, 0, qArgs[0].val.str.pStr,cch, wzGuid+1,39);
+ wzGuid[0] = '{';
+ wzGuid[37] = '}';
+ wzGuid[38] = 0;
+ hr = IIDFromString(wzGuid, &guid);
+ }
+ else
+ hr = META_E_CA_INVALID_UUID;
+ if (hr != S_OK)
+ IfFailGo(PostError(META_E_CA_INVALID_UUID));
+ goto ErrExit;
+ }
+ break;
+
+ case CA_ComImportAttribute:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdImport);
+ break;
+
+ case CA_InterfaceTypeAttribute:
+ {
+ // Verify the attribute.
+ if (qArgs[0].val.u2 >= ifLast)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+ break;
+
+ case CA_ClassInterfaceAttribute:
+ {
+ // Verify the attribute.
+ if (qArgs[0].val.u2 >= clsIfLast)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+ break;
+
+ case CA_SpecialNameAttribute:
+
+ switch (TypeFromToken(tkObj))
+ {
+ case mdtTypeDef:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSpecialName);
+ break;
+
+ case mdtMethodDef:
+ reinterpret_cast<MethodRec*>(pRow)->AddFlags(mdSpecialName);
+ break;
+
+ case mdtFieldDef:
+ reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdSpecialName);
+ break;
+
+ case mdtProperty:
+ reinterpret_cast<PropertyRec*>(pRow)->AddPropFlags(prSpecialName);
+ break;
+
+ case mdtEvent:
+ reinterpret_cast<EventRec*>(pRow)->AddEventFlags(evSpecialName);
+ break;
+
+ default:
+ _ASSERTE(!"Unfamilar type for SpecialName custom attribute");
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+
+ break;
+ case CA_SerializableAttribute:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSerializable);
+ break;
+
+ case CA_NonSerializedAttribute:
+ reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdNotSerialized);
+ break;
+
+ case CA_InAttribute:
+ reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdIn);
+ break;
+
+ case CA_OutAttribute:
+ reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOut);
+ break;
+
+ case CA_OptionalAttribute:
+ reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOptional);
+ break;
+
+ case CA_MethodImplAttribute2:
+ // Force to wider value.
+ qArgs[0].val.u4 = (unsigned)qArgs[0].val.i2;
+ // Fall through to validation.
+ case CA_MethodImplAttribute3:
+ // Validate bits.
+ if (qArgs[0].val.u4 & ~(miUserMask))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(qArgs[0].val.u4);
+ if (!qNamedArgs[MI_CodeType].val.type.tag)
+ break;
+ // fall through to set the code type.
+ case CA_MethodImplAttribute1:
+ {
+ USHORT usFlags = reinterpret_cast<MethodRec*>(pRow)->GetImplFlags();
+ if (qNamedArgs[MI_CodeType].val.i4 & ~(miCodeTypeMask))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ // Mask out old value, put in new one.
+ usFlags = (usFlags & ~miCodeTypeMask) | qNamedArgs[MI_CodeType].val.i4;
+ reinterpret_cast<MethodRec*>(pRow)->SetImplFlags(usFlags);
+ }
+ break;
+
+ case CA_MarshalAsAttribute1:
+ // Force the U2 to a wider U4 value explicitly.
+ qArgs[0].val.u4 = qArgs[0].val.u2;
+ // Fall through to handle the CA.
+ case CA_MarshalAsAttribute2:
+ IfFailGo(_HandleNativeTypeCustomAttribute(tkObj, qArgs.Ptr(), qNamedArgs.Ptr(), qNativeType));
+ break;
+
+ case CA_PreserveSigAttribute:
+ reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig);
+ break;
+
+ case CA_StructLayoutAttribute1:
+ {
+ // Convert the I2 to a U2, then wide to an I4, then fall through.
+ qArgs[0].val.i4 = static_cast<int>(static_cast<USHORT>(qArgs[0].val.i2));
+ }
+ case CA_StructLayoutAttribute2:
+ {
+ // Get a copy of the flags to work with.
+ ULONG dwFlags;
+ dwFlags = reinterpret_cast<TypeDefRec*>(pRow)->GetFlags();
+ // Class layout. Keep in sync with LayoutKind.
+ switch (qArgs[0].val.i4)
+ {
+ case 0: // tdSequentialLayout:
+ dwFlags = (dwFlags & ~tdLayoutMask) | tdSequentialLayout;
+ break;
+ case 2: // tdExplicitLayout:
+ dwFlags = (dwFlags & ~tdLayoutMask) | tdExplicitLayout;
+ break;
+ case 3: // tdAutoLayout:
+ dwFlags = (dwFlags & ~tdLayoutMask) | tdAutoLayout;
+ break;
+ default:
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+ }
+
+ // Class packing and size.
+ ULONG ulSize, ulPack;
+ ulPack = ulSize = ULONG_MAX;
+ if (qNamedArgs[SL_Pack].val.type.tag)
+ { // Only 1,2,4,8,16,32,64,128 are legal values.
+ ulPack = qNamedArgs[SL_Pack].val.u4;
+ if ((ulPack > 128) ||
+ (ulPack & (ulPack-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ }
+ if (qNamedArgs[SL_Size].val.type.tag)
+ {
+ if (qNamedArgs[SL_Size].val.u4 > INT_MAX)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ ulSize = qNamedArgs[SL_Size].val.u4;
+ }
+ if (ulPack!=ULONG_MAX || ulSize!=ULONG_MAX)
+ IfFailGo(_SetClassLayout(tkObj, ulPack, ulSize));
+
+ // Class character set.
+ if (qNamedArgs[SL_CharSet].val.type.tag)
+ {
+ switch (qNamedArgs[SL_CharSet].val.u4)
+ {
+ //case 1: // Not specified.
+ // IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ // break;
+ case 2: // ANSI
+ dwFlags = (dwFlags & ~tdStringFormatMask) | tdAnsiClass;
+ break;
+ case 3: // Unicode
+ dwFlags = (dwFlags & ~tdStringFormatMask) | tdUnicodeClass;
+ break;
+ case 4: // Auto
+ dwFlags = (dwFlags & ~tdStringFormatMask) | tdAutoClass;
+ break;
+ default:
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+ }
+ }
+
+ // Persist possibly-changed value of flags.
+ reinterpret_cast<TypeDefRec*>(pRow)->SetFlags(dwFlags);
+ }
+ break;
+
+ case CA_FieldOffsetAttribute:
+ if (qArgs[0].val.u4 > INT_MAX)
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ IfFailGo(_SetFieldOffset(tkObj, qArgs[0].val.u4));
+ break;
+
+ case CA_TypeLibVersionAttribute:
+ if ((qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0))
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+
+ case CA_ComCompatibleVersionAttribute:
+ if ( (qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0) || (qArgs[2].val.i4 < 0) || (qArgs[3].val.i4 < 0) )
+ IfFailGo(PostError(META_E_CA_INVALID_VALUE));
+ break;
+
+ case CA_AllowPartiallyTrustedCallersAttribute:
+ break;
+
+ case CA_WindowsRuntimeImportAttribute:
+ reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdWindowsRuntime);
+ break;
+
+ default:
+ _ASSERTE(!"Unexpected custom attribute type");
+ // Turn into ordinary custom attribute.
+ *bKeep = true;
+ hr = S_OK;
+ goto ErrExit;
+ break;
+ }
+
+ IfFailGo(UpdateENCLog(tkObj));
+
+ErrExit:
+ return hr;
+} // RegMeta::_HandleKnownCustomAttribute
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+//*****************************************************************************
+//*****************************************************************************
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
+#endif
+HRESULT RegMeta::_HandleNativeTypeCustomAttribute(// S_OK or error.
+ mdToken tkObj, // The token this CA is applied on.
+ CaArg *pArgs, // Pointer to args.
+ CaNamedArg *pNamedArgs, // Pointer to named args.
+ CQuickArray<BYTE> &qNativeType) // Native type is built here.
+{
+ HRESULT hr = S_OK; // A result.
+ int cch = 0; // Size of a string argument.
+ ULONG cb; // Count of some character operation.
+ ULONG cbNative; // Size of native type string.
+ ULONG cbMax; // Max size of native type string.
+ BYTE *pbNative; // Pointer into native type buffer.
+ mdToken tkObjType; // The type of the token.
+ mdToken tkSetter; // Token for Property setter.
+ mdToken tkGetter; // Token for property getter.
+ mdParamDef tkParam; // Parameter of getter/setter.
+ ULONG cParams; // Count of params for getter/setter.
+ HCORENUM phEnum = 0; // Enumerator for params.
+ ULONG ulSeq; // Sequence of a param.
+
+ // Retrieve the type of the token.
+ tkObjType = TypeFromToken(tkObj);
+
+ // Compute maximum size of the native type.
+ if (pArgs[0].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER)
+ { // N_T_* + 3 string lengths
+ cbMax = sizeof(ULONG) * 4;
+ // Marshal type - name of the type
+ cbMax += pNamedArgs[M_MarshalType].val.str.cbStr;
+ // Marshal type - type of the custom marshaler
+ cbMax += pNamedArgs[M_MarshalTypeRef].val.str.cbStr;
+ // String cookie.
+ cbMax += pNamedArgs[M_MarshalCookie].val.str.cbStr;
+ }
+ else if (pArgs[0].val.i4 == NATIVE_TYPE_SAFEARRAY)
+ { // N_T_* + safe array sub-type + string length.
+ cbMax = sizeof(ULONG) * 3;
+ // Safe array record sub type.
+ cbMax += pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr;
+ }
+ else
+ { // N_T_* + sub-type + size + additive + NativeTypeArrayFlags.
+ cbMax = sizeof(ULONG) * 4 + sizeof(UINT16);
+ }
+
+ // IidParameterIndex.
+ cbMax += sizeof(DWORD);
+
+ // Extra space to prevent buffer overrun.
+ cbMax += 8;
+
+ // Size the array.
+ IfFailGo(qNativeType.ReSizeNoThrow(cbMax));
+ pbNative = qNativeType.Ptr();
+ cbNative = 0;
+
+ //<TODO>@FUTURE: check for valid combinations of args.</TODO>
+
+ // Put in the NativeType.
+ cb = CorSigCompressData(pArgs[0].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in additional information, depending on native type.
+ switch (pArgs[0].val.i4)
+ {
+ case NATIVE_TYPE_INTF:
+ case NATIVE_TYPE_IUNKNOWN:
+ case NATIVE_TYPE_IDISPATCH:
+ // Validate that the IidParameterIndex field is valid if set.
+ if (pNamedArgs[M_IidParameterIndex].val.type.tag)
+ {
+ int iidparam = pNamedArgs[M_IidParameterIndex].val.i4;
+ if (iidparam < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX));
+
+ cb = CorSigCompressData(pNamedArgs[M_IidParameterIndex].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ break;
+
+
+ case NATIVE_TYPE_FIXEDARRAY:
+ // Validate that only fields valid for NATIVE_TYPE_FIXEDARRAY are set.
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // This native type is only applicable on fields.
+ if (tkObjType != mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_NT_FIELDONLY));
+
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ {
+ // Make sure the size is not negative.
+ if (pNamedArgs[M_SizeConst].val.i4 < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
+
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
+ }
+
+ }
+ else
+ {
+ cb = CorSigCompressData(1, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a sub type?
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ {
+ // Put in the sub type.
+ cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ break;
+
+ case NATIVE_TYPE_FIXEDSYSSTRING:
+ // Validate that the required fields are set.
+ if (!pNamedArgs[M_SizeConst].val.type.tag)
+ IfFailGo(PostError(META_E_CA_FIXEDSTR_SIZE_REQUIRED));
+
+ // Validate that other array fields are not set.
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // This native type is only applicable on fields.
+ if (tkObjType != mdtFieldDef)
+ IfFailGo(PostError(META_E_CA_NT_FIELDONLY));
+
+ // Put in the constant value.
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ break;
+
+ case NATIVE_TYPE_BYVALSTR:
+ // This native type is only applicable on parameters.
+ if (tkObjType != mdtParamDef)
+ IfFailGo(PostError(META_E_CA_INVALID_TARGET));
+ break;
+
+ case NATIVE_TYPE_SAFEARRAY:
+ // Validate that other array fields are not set.
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a safe array sub type?
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ {
+ // Put in the safe array sub type.
+ cb = CorSigCompressData(pNamedArgs[M_SafeArraySubType].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // When the SAFEARRAY contains user defined types, the type of the
+ // UDT can be specified in the SafeArrayUserDefinedSubType field.
+ if (pNamedArgs[M_SafeArrayUserDefinedSubType].val.type.tag)
+ {
+ // Validate that this is only set for valid VT's.
+ if (pNamedArgs[M_SafeArraySubType].val.i4 != VT_RECORD &&
+ pNamedArgs[M_SafeArraySubType].val.i4 != VT_DISPATCH &&
+ pNamedArgs[M_SafeArraySubType].val.i4 != VT_UNKNOWN)
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+
+ // Encode the size of the string.
+ cch = pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ cbNative += cb;
+ pbNative += cb;
+
+ // Check that memcpy will fit and then encode the type name itself.
+ if (ovadd_gt(cbNative, cch, cbMax))
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ _ASSERTE(cbNative <= cbMax);
+ }
+ }
+ break;
+
+ case NATIVE_TYPE_ARRAY:
+ // Validate that the array sub type is not set.
+ if (pNamedArgs[M_SafeArraySubType].val.type.tag)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a sub type?
+ if (pNamedArgs[M_ArraySubType].val.type.tag)
+ {
+ // Do some validation on the array sub type.
+ if (pNamedArgs[M_ArraySubType].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the sub type.
+ cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ }
+ else
+ {
+ // Put in the sub type.
+ cb = CorSigCompressData(NATIVE_TYPE_MAX, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ }
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a parameter index?
+ if (pNamedArgs[M_SizeParamIndex].val.type.tag)
+ {
+ // Make sure the parameter index is not negative.
+ if (pNamedArgs[M_SizeParamIndex].val.i4 < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX));
+
+ // Yes, put it in.
+ cb = CorSigCompressData(pNamedArgs[M_SizeParamIndex].val.i2, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Is there a const?
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ {
+ // Make sure the size is not negative.
+ if (pNamedArgs[M_SizeConst].val.i4 < 0)
+ IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
+
+ // Yes, put it in.
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the flag indicating the size param index was specified.
+ cb = CorSigCompressData((UINT16)ntaSizeParamIndexSpecified, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ }
+ else
+ {
+ // Is there a const?
+ if (pNamedArgs[M_SizeConst].val.type.tag)
+ {
+ // Put in a param index of 0.
+ cb = CorSigCompressData(0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the constant value.
+ cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Set the flags field to 0 to indicate the size param index was not specified.
+ cb = CorSigCompressData((UINT16)0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ }
+ }
+ break;
+
+ case NATIVE_TYPE_CUSTOMMARSHALER:
+ // Validate that the marshaler type field is set.
+ if (!pNamedArgs[M_MarshalType].val.type.tag && !pNamedArgs[M_MarshalTypeRef].val.type.tag)
+ IfFailGo(PostError(META_E_CA_CUSTMARSH_TYPE_REQUIRED));
+
+ // Put in the place holder for the unmanaged typelib guid.
+ cb = CorSigCompressData(0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the place holder for the unmanaged type name.
+ cb = CorSigCompressData(0, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ if (cbNative > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+
+ // Put in the marshaler type name.
+ if (pNamedArgs[M_MarshalType].val.type.tag)
+ {
+ cch = pNamedArgs[M_MarshalType].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ cbNative += cb;
+ pbNative += cb;
+ // Check that memcpy will fit.
+ if ((cbNative+cch) > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_MarshalType].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ _ASSERTE(cbNative <= cbMax);
+ }
+ else
+ {
+ cch = pNamedArgs[M_MarshalTypeRef].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ cbNative += cb;
+ pbNative += cb;
+ // Check that memcpy will fit.
+ if ((cbNative+cch) > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_MarshalTypeRef].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ _ASSERTE(cbNative <= cbMax);
+ }
+
+ // Put in the cookie.
+ cch = pNamedArgs[M_MarshalCookie].val.str.cbStr;
+ cb = CorSigCompressData(cch, pbNative);
+ if (cb == ((ULONG)(-1)))
+ {
+ IfFailGo(PostError(META_E_CA_INVALID_BLOB));
+ }
+ cbNative += cb;
+ pbNative += cb;
+ // Check that memcpy will fit.
+ if ((cbNative+cch) > cbMax)
+ IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
+ memcpy(pbNative, pNamedArgs[M_MarshalCookie].val.str.pStr, cch);
+ cbNative += cch;
+ pbNative += cch;
+ break;
+ }
+ _ASSERTE(cbNative <= cbMax);
+
+ // Resize to actual size.
+ IfFailGo(qNativeType.ReSizeNoThrow(cbNative));
+
+ // Now apply the native type to actual token. If it is a property token,
+ // apply to the methods.
+ switch (TypeFromToken(tkObj))
+ {
+ case mdtParamDef:
+ case mdtFieldDef:
+ IfFailGo(_SetFieldMarshal(tkObj, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
+ break;
+
+ case mdtProperty:
+ // Get any setter/getter methods.
+ IfFailGo(GetPropertyProps(tkObj, 0,0,0,0,0,0,0,0,0,0, &tkSetter, &tkGetter, 0,0,0));
+ // For getter, put the field marshal on the return value.
+ if (!IsNilToken(tkGetter))
+ {
+ // Search for first param.
+ mdToken tk;
+ tkParam = mdParamDefNil;
+ do {
+ IfFailGo(EnumParams(&phEnum, tkGetter, &tk, 1, &cParams));
+ if (cParams > 0)
+ {
+ IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0));
+ if (ulSeq == 0)
+ {
+ tkParam = tk;
+ break;
+ }
+ }
+
+ } while (hr == S_OK);
+ if (!IsNilToken(tkParam))
+ IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
+ CloseEnum(phEnum);
+ phEnum = 0;
+ }
+ if (!IsNilToken(tkSetter))
+ {
+ // Determine the last param.
+ PCCOR_SIGNATURE pSig;
+ ULONG cbSig;
+ mdToken tk;
+ ULONG iSeq;
+ IfFailGo(GetMethodProps(tkSetter, 0,0,0,0,0, &pSig,&cbSig, 0,0));
+ tkParam = mdParamDefNil;
+ CorSigUncompressData(pSig+1, &iSeq);
+ // Search for last param.
+ if (iSeq != 0)
+ {
+ do {
+ IfFailGo(EnumParams(&phEnum, tkSetter, &tk, 1, &cParams));
+ if (cParams > 0)
+ {
+ IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0));
+ if (ulSeq == iSeq)
+ {
+ tkParam = tk;
+ break;
+ }
+ }
+ } while (hr == S_OK);
+ }
+ // If found one that is not return value
+ if (!IsNilToken(tkParam))
+ IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
+ CloseEnum(phEnum);
+ phEnum = 0;
+ }
+ break;
+
+ default:
+ _ASSERTE(!"Should not have this token type in _HandleNativeTypeCustomAttribute()");
+ break;
+ }
+
+ErrExit:
+ if (phEnum)
+ CloseEnum(phEnum);
+ return hr;
+} // RegMeta::_HandleNativeTypeCustomAttribute
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+#endif //FEATURE_METADATA_EMIT