| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | //***************************************************************************** |
| 5 | // CustAttr_Emit.cpp |
| 6 | // |
| 7 | |
| 8 | // |
| 9 | // Implementation for the meta data custom attribute emit code (code:IMetaDataEmit). |
| 10 | // |
| 11 | //***************************************************************************** |
| 12 | #include "stdafx.h" |
| 13 | #include "regmeta.h" |
| 14 | #include "metadata.h" |
| 15 | #include "corerror.h" |
| 16 | #include "mdutil.h" |
| 17 | #include "rwutil.h" |
| 18 | #include "mdlog.h" |
| 19 | #include "importhelper.h" |
| 20 | #include "mdperf.h" |
| 21 | #include "posterror.h" |
| 22 | #include "cahlprinternal.h" |
| 23 | #include "custattr.h" |
| 24 | #include "corhdr.h" |
| 25 | #include <metamodelrw.h> |
| 26 | |
| 27 | #ifdef FEATURE_METADATA_EMIT |
| 28 | |
| 29 | //***************************************************************************** |
| 30 | //***************************************************************************** |
| 31 | // Support for "Pseudo Custom Attributes" |
| 32 | |
| 33 | |
| 34 | //***************************************************************************** |
| 35 | // Enumeration of known custom attributes. |
| 36 | //***************************************************************************** |
| 37 | #define KnownCaList() \ |
| 38 | KnownCa(UNKNOWN) \ |
| 39 | KnownCa(DllImportAttribute) \ |
| 40 | KnownCa(GuidAttribute) \ |
| 41 | KnownCa(ComImportAttribute) \ |
| 42 | KnownCa(InterfaceTypeAttribute) \ |
| 43 | KnownCa(ClassInterfaceAttribute) \ |
| 44 | KnownCa(SerializableAttribute) \ |
| 45 | KnownCa(NonSerializedAttribute) \ |
| 46 | KnownCa(MethodImplAttribute1) \ |
| 47 | KnownCa(MethodImplAttribute2) \ |
| 48 | KnownCa(MethodImplAttribute3) \ |
| 49 | KnownCa(MarshalAsAttribute1) \ |
| 50 | KnownCa(MarshalAsAttribute2) \ |
| 51 | KnownCa(PreserveSigAttribute) \ |
| 52 | KnownCa(InAttribute) \ |
| 53 | KnownCa(OutAttribute) \ |
| 54 | KnownCa(OptionalAttribute) \ |
| 55 | KnownCa(StructLayoutAttribute1) \ |
| 56 | KnownCa(StructLayoutAttribute2) \ |
| 57 | KnownCa(FieldOffsetAttribute) \ |
| 58 | KnownCa(TypeLibVersionAttribute) \ |
| 59 | KnownCa(ComCompatibleVersionAttribute) \ |
| 60 | KnownCa(SpecialNameAttribute) \ |
| 61 | KnownCa(AllowPartiallyTrustedCallersAttribute) \ |
| 62 | KnownCa(WindowsRuntimeImportAttribute) \ |
| 63 | |
| 64 | // Ids for the CA's. CA_DllImportAttribute, etc. |
| 65 | #define KnownCa(x) CA_##x, |
| 66 | enum { |
| 67 | KnownCaList() |
| 68 | CA_COUNT |
| 69 | }; |
| 70 | |
| 71 | |
| 72 | //***************************************************************************** |
| 73 | // Properties of the known custom attributes. |
| 74 | // |
| 75 | // These tables describe the known custom attributes. For each custom |
| 76 | // attribute, we know the namespace and name of the custom attribute, |
| 77 | // the types to which the CA applies, the ctor args, and possible named |
| 78 | // args. There is a flag which specifies whether the custom attribute |
| 79 | // should be kept, in addition to any processing done with the data. |
| 80 | //***************************************************************************** |
| 81 | const BOOL bKEEPCA = TRUE; |
| 82 | const BOOL bDONTKEEPCA = FALSE; |
| 83 | const BOOL bMATCHBYSIG = TRUE; |
| 84 | const BOOL bMATCHBYNAME = FALSE; |
| 85 | |
| 86 | struct KnownCaProp |
| 87 | { |
| 88 | LPCUTF8 szNamespace; // Namespace of the custom attribute. |
| 89 | LPCUTF8 szName; // Name of the custom attribute. |
| 90 | const mdToken * rTypes; // Types that the CA applies to. |
| 91 | BOOL bKeepCa; // Keep the CA after processing? |
| 92 | const CaArg * pArgs; // List of ctor argument descriptors. |
| 93 | ULONG cArgs; // Count of ctor argument descriptors. |
| 94 | const CaNamedArg * pNamedArgs; // List of named arg descriptors. |
| 95 | ULONG cNamedArgs; // Count of named arg descriptors. |
| 96 | BOOL bMatchBySig; // For overloads; match by sig, not just name. |
| 97 | // WARNING: All overloads need the flag! |
| 98 | }; |
| 99 | |
| 100 | // Recognized targets for known custom attributes. |
| 101 | // If Target includes mdtAssembly, then make sure to include mdtTypeRef as well, |
| 102 | // aLink uses mdtTypeRef target temporarily for assembly target attributes |
| 103 | const mdToken DllImportTargets[] = {mdtMethodDef, (ULONG32) -1}; |
| 104 | const mdToken GuidTargets[] = {mdtTypeDef, mdtTypeRef, mdtModule, mdtAssembly, (ULONG32) -1}; |
| 105 | const mdToken ComImportTargets[] = {mdtTypeDef, (ULONG32) -1}; |
| 106 | const mdToken InterfaceTypeTargets[] = {mdtTypeDef, (ULONG32) -1}; |
| 107 | const mdToken ClassInterfaceTargets[] = {mdtTypeDef, mdtAssembly, mdtTypeRef, (ULONG32) -1}; |
| 108 | const mdToken SerializableTargets[] = {mdtTypeDef, (ULONG32) -1}; |
| 109 | const mdToken NotInGCHeapTargets[] = {mdtTypeDef, (ULONG32) -1}; |
| 110 | const mdToken NonSerializedTargets[] = {mdtFieldDef, (ULONG32) -1}; |
| 111 | const mdToken MethodImplTargets[] = {mdtMethodDef, (ULONG32) -1}; |
| 112 | const mdToken MarshalTargets[] = {mdtFieldDef, mdtParamDef, mdtProperty, (ULONG32) -1}; |
| 113 | const mdToken PreserveSigTargets[] = {mdtMethodDef, (ULONG32) -1}; |
| 114 | const mdToken InOutTargets[] = {mdtParamDef, (ULONG32) -1}; |
| 115 | const mdToken StructLayoutTargets[] = {mdtTypeDef, (ULONG32) -1}; |
| 116 | const mdToken FieldOffsetTargets[] = {mdtFieldDef, (ULONG32) -1}; |
| 117 | const mdToken TypeLibVersionTargets[] = {mdtAssembly, mdtTypeRef,(ULONG32) -1}; |
| 118 | const mdToken ComCompatibleVersionTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1}; |
| 119 | const mdToken SpecialNameTargets[] = {mdtTypeDef, mdtMethodDef, mdtFieldDef, mdtProperty, mdtEvent, (ULONG32) -1}; |
| 120 | const mdToken AllowPartiallyTrustedCallersTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1}; |
| 121 | const mdToken WindowsRuntimeImportTargets[] = {mdtTypeDef, (ULONG32) -1}; |
| 122 | |
| 123 | |
| 124 | //#ifndef CEE_CALLCONV |
| 125 | // # define CEE_CALLCONV (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS) |
| 126 | //#endif |
| 127 | |
| 128 | #define DEFINE_CA_CTOR_ARGS(NAME) \ |
| 129 | const CaArg r##NAME##Args[] = \ |
| 130 | { |
| 131 | #define DEFINE_CA_CTOR_ARG(TYPE) {{TYPE}}, |
| 132 | #define DEFINE_CA_CTOR_ARGS_END() \ |
| 133 | }; |
| 134 | |
| 135 | |
| 136 | |
| 137 | #define DEFINE_CA_NAMED_ARGS(NAME) \ |
| 138 | const CaNamedArg r##NAME##NamedArgs[] = \ |
| 139 | { |
| 140 | |
| 141 | #define DEFINE_CA_NAMED_ARG(NAME, PROPORFIELD, TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME) \ |
| 142 | { NAME, sizeof(NAME) - 1, PROPORFIELD, { TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME, sizeof(ENUMNAME) - 1 } }, |
| 143 | |
| 144 | #define DEFINE_CA_NAMED_PROP_I4ENUM(NAME, ENUM) \ |
| 145 | DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM) |
| 146 | #define DEFINE_CA_NAMED_FIELD_I4ENUM(NAME, ENUM) \ |
| 147 | DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM) |
| 148 | #define DEFINE_CA_NAMED_PROP(NAME, TYPE) \ |
| 149 | DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "") |
| 150 | #define DEFINE_CA_NAMED_FIELD(NAME, TYPE) \ |
| 151 | DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "") |
| 152 | #define DEFINE_CA_NAMED_PROP_BOOL(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_BOOLEAN) |
| 153 | #define DEFINE_CA_NAMED_FIELD_BOOL(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_BOOLEAN) |
| 154 | #define DEFINE_CA_NAMED_PROP_STRING(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_STRING) |
| 155 | #define DEFINE_CA_NAMED_FIELD_STRING(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_STRING) |
| 156 | #define DEFINE_CA_NAMED_PROP_TYPE(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_TYPE) |
| 157 | #define DEFINE_CA_NAMED_FIELD_TYPE(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_TYPE) |
| 158 | #define DEFINE_CA_NAMED_PROP_I2(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I2) |
| 159 | #define DEFINE_CA_NAMED_FIELD_I2(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I2) |
| 160 | #define DEFINE_CA_NAMED_PROP_I4(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I4) |
| 161 | #define DEFINE_CA_NAMED_FIELD_I4(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I4) |
| 162 | |
| 163 | #define DEFINE_CA_NAMED_ARGS_END() \ |
| 164 | }; |
| 165 | |
| 166 | //----------------------------------------------------------------------------- |
| 167 | // index 0 is used as a placeholder. |
| 168 | const KnownCaProp UNKNOWNProps = {0}; |
| 169 | |
| 170 | //----------------------------------------------------------------------------- |
| 171 | // DllImport args, named args, and known attribute properties. |
| 172 | DEFINE_CA_CTOR_ARGS(DllImportAttribute) |
| 173 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING) |
| 174 | DEFINE_CA_CTOR_ARGS_END() |
| 175 | |
| 176 | // NOTE: Keep this enum in sync with the array of named arguments. |
| 177 | enum DllImportNamedArgs |
| 178 | { |
| 179 | DI_CallingConvention, |
| 180 | DI_CharSet, |
| 181 | DI_EntryPoint, |
| 182 | DI_ExactSpelling, |
| 183 | DI_SetLastError, |
| 184 | DI_PreserveSig, |
| 185 | DI_BestFitMapping, |
| 186 | DI_ThrowOnUnmappableChar, |
| 187 | DI_COUNT |
| 188 | }; |
| 189 | |
| 190 | DEFINE_CA_NAMED_ARGS(DllImportAttribute) |
| 191 | DEFINE_CA_NAMED_FIELD_I4ENUM("CallingConvention" , "System.Runtime.InteropServices.CallingConvention" ) |
| 192 | DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet" , "System.Runtime.InteropServices.CharSet" ) |
| 193 | DEFINE_CA_NAMED_FIELD_STRING("EntryPoint" ) |
| 194 | DEFINE_CA_NAMED_FIELD_BOOL("ExactSpelling" ) |
| 195 | DEFINE_CA_NAMED_FIELD_BOOL("SetLastError" ) |
| 196 | DEFINE_CA_NAMED_FIELD_BOOL("PreserveSig" ) |
| 197 | DEFINE_CA_NAMED_FIELD_BOOL("BestFitMapping" ) |
| 198 | DEFINE_CA_NAMED_FIELD_BOOL("ThrowOnUnmappableChar" ) |
| 199 | DEFINE_CA_NAMED_ARGS_END() |
| 200 | |
| 201 | const KnownCaProp DllImportAttributeProps = {"System.Runtime.InteropServices" , "DllImportAttribute" , DllImportTargets, bDONTKEEPCA, |
| 202 | rDllImportAttributeArgs, lengthof(rDllImportAttributeArgs), |
| 203 | rDllImportAttributeNamedArgs, lengthof(rDllImportAttributeNamedArgs)}; |
| 204 | |
| 205 | //----------------------------------------------------------------------------- |
| 206 | // GUID args, named args (none), and known attribute properties. |
| 207 | DEFINE_CA_CTOR_ARGS(GuidAttribute) |
| 208 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING) |
| 209 | DEFINE_CA_CTOR_ARGS_END() |
| 210 | |
| 211 | const KnownCaProp GuidAttributeProps = {"System.Runtime.InteropServices" , "GuidAttribute" , GuidTargets, bKEEPCA, |
| 212 | rGuidAttributeArgs, lengthof(rGuidAttributeArgs)}; |
| 213 | |
| 214 | //----------------------------------------------------------------------------- |
| 215 | // ComImport args (none), named args (none), and known attribute properties. |
| 216 | const KnownCaProp ComImportAttributeProps = {"System.Runtime.InteropServices" , "ComImportAttribute" , ComImportTargets}; |
| 217 | |
| 218 | //----------------------------------------------------------------------------- |
| 219 | // Interface type args, named args (none), and known attribute properties. |
| 220 | DEFINE_CA_CTOR_ARGS(InterfaceTypeAttribute) |
| 221 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2) |
| 222 | DEFINE_CA_CTOR_ARGS_END() |
| 223 | |
| 224 | const KnownCaProp InterfaceTypeAttributeProps = {"System.Runtime.InteropServices" , "InterfaceTypeAttribute" , InterfaceTypeTargets, bKEEPCA, |
| 225 | rInterfaceTypeAttributeArgs, lengthof(rInterfaceTypeAttributeArgs)}; |
| 226 | |
| 227 | //----------------------------------------------------------------------------- |
| 228 | // Class interface type args, named args (none), and known attribute properties. |
| 229 | DEFINE_CA_CTOR_ARGS(ClassInterfaceAttribute) |
| 230 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2) |
| 231 | DEFINE_CA_CTOR_ARGS_END() |
| 232 | |
| 233 | const KnownCaProp ClassInterfaceAttributeProps = {"System.Runtime.InteropServices" , "ClassInterfaceAttribute" , ClassInterfaceTargets, bKEEPCA, |
| 234 | rClassInterfaceAttributeArgs, lengthof(rClassInterfaceAttributeArgs)}; |
| 235 | |
| 236 | //----------------------------------------------------------------------------- |
| 237 | // Serializable args (none), named args (none), and known attribute properties. |
| 238 | const KnownCaProp SerializableAttributeProps = {"System" , "SerializableAttribute" , SerializableTargets}; |
| 239 | |
| 240 | //----------------------------------------------------------------------------- |
| 241 | // NonSerialized args (none), named args (none), and known attribute properties. |
| 242 | const KnownCaProp NonSerializedAttributeProps = {"System" , "NonSerializedAttribute" , NonSerializedTargets}; |
| 243 | |
| 244 | //----------------------------------------------------------------------------- |
| 245 | // SpecialName args (none), named args (none), and known attribute properties. |
| 246 | const KnownCaProp SpecialNameAttributeProps = {"System.Runtime.CompilerServices" , "SpecialNameAttribute" , SpecialNameTargets, bDONTKEEPCA}; |
| 247 | |
| 248 | //----------------------------------------------------------------------------- |
| 249 | // WindowsRuntimeImport args (none), named args (none), and known attribute properties. |
| 250 | const KnownCaProp WindowsRuntimeImportAttributeProps = {"System.Runtime.InteropServices.WindowsRuntime" , "WindowsRuntimeImportAttribute" , WindowsRuntimeImportTargets}; |
| 251 | |
| 252 | |
| 253 | //----------------------------------------------------------------------------- |
| 254 | // MethodImpl #1 args (none), named args, and known attribute properties. |
| 255 | // MethodImpl #2 args (short), named args, and known attribute properties. |
| 256 | // MethodImpl #3 args (enum), named args, and known attribute properties. |
| 257 | // Note: first two match by signature; third by name only, because signature matching code is not |
| 258 | // strong enough for enums. |
| 259 | DEFINE_CA_CTOR_ARGS(MethodImplAttribute2) |
| 260 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2) |
| 261 | DEFINE_CA_CTOR_ARGS_END() |
| 262 | |
| 263 | DEFINE_CA_CTOR_ARGS(MethodImplAttribute3) |
| 264 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4) |
| 265 | DEFINE_CA_CTOR_ARGS_END() |
| 266 | |
| 267 | enum MethodImplAttributeNamedArgs |
| 268 | { |
| 269 | MI_CodeType, |
| 270 | MI_COUNT |
| 271 | }; |
| 272 | |
| 273 | DEFINE_CA_NAMED_ARGS(MethodImplAttribute) |
| 274 | DEFINE_CA_NAMED_FIELD_I4ENUM("MethodCodeType" , "System.Runtime.CompilerServices.MethodCodeType" ) |
| 275 | DEFINE_CA_NAMED_ARGS_END() |
| 276 | |
| 277 | const KnownCaProp MethodImplAttribute1Props = {"System.Runtime.CompilerServices" , "MethodImplAttribute" , MethodImplTargets, bDONTKEEPCA, |
| 278 | 0, 0, |
| 279 | rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs), |
| 280 | bMATCHBYSIG}; |
| 281 | const KnownCaProp MethodImplAttribute2Props = {"System.Runtime.CompilerServices" , "MethodImplAttribute" , MethodImplTargets, bDONTKEEPCA, |
| 282 | rMethodImplAttribute2Args, lengthof(rMethodImplAttribute2Args), |
| 283 | rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs), |
| 284 | bMATCHBYSIG}; |
| 285 | const KnownCaProp MethodImplAttribute3Props = {"System.Runtime.CompilerServices" , "MethodImplAttribute" , MethodImplTargets, bDONTKEEPCA, |
| 286 | rMethodImplAttribute3Args, lengthof(rMethodImplAttribute3Args), |
| 287 | rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs), |
| 288 | bMATCHBYNAME}; |
| 289 | |
| 290 | //----------------------------------------------------------------------------- |
| 291 | // Marshal args, named args, and known attribute properties. |
| 292 | DEFINE_CA_CTOR_ARGS(MarshalAsAttribute2) |
| 293 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4) |
| 294 | DEFINE_CA_CTOR_ARGS_END() |
| 295 | |
| 296 | DEFINE_CA_CTOR_ARGS(MarshalAsAttribute1) |
| 297 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2) |
| 298 | DEFINE_CA_CTOR_ARGS_END() |
| 299 | |
| 300 | // NOTE: Keep this enum in sync with the array of named arguments. |
| 301 | enum MarshalNamedArgs |
| 302 | { |
| 303 | M_ArraySubType, |
| 304 | M_SafeArraySubType, |
| 305 | M_SafeArrayUserDefinedSubType, |
| 306 | M_SizeParamIndex, |
| 307 | M_SizeConst, |
| 308 | M_MarshalType, |
| 309 | M_MarshalTypeRef, |
| 310 | M_MarshalCookie, |
| 311 | M_IidParameterIndex, |
| 312 | M_COUNT |
| 313 | }; |
| 314 | |
| 315 | DEFINE_CA_NAMED_ARGS(MarshalAsAttribute) |
| 316 | DEFINE_CA_NAMED_FIELD_I4ENUM("ArraySubType" , "System.Runtime.InteropServices.UnmanagedType" ) |
| 317 | DEFINE_CA_NAMED_FIELD_I4ENUM("SafeArraySubType" , "System.Runtime.InteropServices.VarEnum" ) |
| 318 | DEFINE_CA_NAMED_FIELD_TYPE("SafeArrayUserDefinedSubType" ) |
| 319 | DEFINE_CA_NAMED_FIELD_I2("SizeParamIndex" ) |
| 320 | DEFINE_CA_NAMED_FIELD_I4("SizeConst" ) |
| 321 | DEFINE_CA_NAMED_FIELD_STRING("MarshalType" ) |
| 322 | DEFINE_CA_NAMED_FIELD_TYPE("MarshalTypeRef" ) |
| 323 | DEFINE_CA_NAMED_FIELD_STRING("MarshalCookie" ) |
| 324 | DEFINE_CA_NAMED_FIELD_I4("IidParameterIndex" ) |
| 325 | DEFINE_CA_NAMED_ARGS_END() |
| 326 | |
| 327 | const KnownCaProp MarshalAsAttribute1Props = {"System.Runtime.InteropServices" , "MarshalAsAttribute" , MarshalTargets, bDONTKEEPCA, |
| 328 | rMarshalAsAttribute1Args, lengthof(rMarshalAsAttribute1Args), |
| 329 | rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs), |
| 330 | bMATCHBYSIG}; |
| 331 | |
| 332 | const KnownCaProp MarshalAsAttribute2Props = {"System.Runtime.InteropServices" , "MarshalAsAttribute" , MarshalTargets, bDONTKEEPCA, |
| 333 | rMarshalAsAttribute2Args, lengthof(rMarshalAsAttribute2Args), |
| 334 | rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs), |
| 335 | bMATCHBYNAME}; |
| 336 | |
| 337 | //----------------------------------------------------------------------------- |
| 338 | // PreserveSignature args, named args (none), and known attribute properties. |
| 339 | const KnownCaProp PreserveSigAttributeProps = {"System.Runtime.InteropServices" , "PreserveSigAttribute" , PreserveSigTargets, bDONTKEEPCA}; |
| 340 | |
| 341 | //----------------------------------------------------------------------------- |
| 342 | // In args (none), named args (none), and known attribute properties. |
| 343 | const KnownCaProp InAttributeProps = {"System.Runtime.InteropServices" , "InAttribute" , InOutTargets}; |
| 344 | |
| 345 | //----------------------------------------------------------------------------- |
| 346 | // Out args (none), named args (none), and known attribute properties. |
| 347 | const KnownCaProp OutAttributeProps = {"System.Runtime.InteropServices" , "OutAttribute" , InOutTargets}; |
| 348 | |
| 349 | //----------------------------------------------------------------------------- |
| 350 | // Optional args (none), named args (none), and known attribute properties. |
| 351 | const KnownCaProp OptionalAttributeProps = {"System.Runtime.InteropServices" , "OptionalAttribute" , InOutTargets}; |
| 352 | |
| 353 | //----------------------------------------------------------------------------- |
| 354 | // StructLayout args, named args, and known attribute properties. |
| 355 | DEFINE_CA_CTOR_ARGS(StructLayoutAttribute2) |
| 356 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 357 | DEFINE_CA_CTOR_ARGS_END() |
| 358 | |
| 359 | DEFINE_CA_CTOR_ARGS(StructLayoutAttribute1) |
| 360 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2) |
| 361 | DEFINE_CA_CTOR_ARGS_END() |
| 362 | |
| 363 | // NOTE: Keep this enum in sync with the array of named arguments. |
| 364 | enum StructLayoutNamedArgs |
| 365 | { |
| 366 | SL_Pack, |
| 367 | SL_Size, |
| 368 | SL_CharSet, |
| 369 | SL_COUNT |
| 370 | }; |
| 371 | |
| 372 | DEFINE_CA_NAMED_ARGS(StructLayoutAttribute) |
| 373 | DEFINE_CA_NAMED_FIELD_I4("Pack" ) |
| 374 | DEFINE_CA_NAMED_FIELD_I4("Size" ) |
| 375 | DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet" , "System.Runtime.InteropServices.CharSet" ) |
| 376 | DEFINE_CA_NAMED_ARGS_END() |
| 377 | |
| 378 | const KnownCaProp StructLayoutAttribute1Props = {"System.Runtime.InteropServices" , "StructLayoutAttribute" , StructLayoutTargets, bDONTKEEPCA, |
| 379 | rStructLayoutAttribute1Args, lengthof(rStructLayoutAttribute1Args), |
| 380 | rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs), |
| 381 | bMATCHBYSIG}; |
| 382 | const KnownCaProp StructLayoutAttribute2Props = {"System.Runtime.InteropServices" , "StructLayoutAttribute" , StructLayoutTargets, bDONTKEEPCA, |
| 383 | rStructLayoutAttribute2Args, lengthof(rStructLayoutAttribute2Args), |
| 384 | rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs), |
| 385 | bMATCHBYNAME}; |
| 386 | |
| 387 | //----------------------------------------------------------------------------- |
| 388 | // FieldOffset args, named args (none), and known attribute properties. |
| 389 | DEFINE_CA_CTOR_ARGS(FieldOffsetAttribute) |
| 390 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4) |
| 391 | DEFINE_CA_CTOR_ARGS_END() |
| 392 | |
| 393 | const KnownCaProp FieldOffsetAttributeProps = {"System.Runtime.InteropServices" , "FieldOffsetAttribute" , FieldOffsetTargets, bDONTKEEPCA, |
| 394 | rFieldOffsetAttributeArgs, lengthof(rFieldOffsetAttributeArgs)}; |
| 395 | |
| 396 | DEFINE_CA_CTOR_ARGS(TypeLibVersionAttribute) |
| 397 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 398 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 399 | DEFINE_CA_CTOR_ARGS_END() |
| 400 | |
| 401 | const KnownCaProp TypeLibVersionAttributeProps = {"System.Runtime.InteropServices" , "TypeLibVersionAttribute" , TypeLibVersionTargets, bKEEPCA, |
| 402 | rTypeLibVersionAttributeArgs, lengthof(rTypeLibVersionAttributeArgs)}; |
| 403 | |
| 404 | |
| 405 | DEFINE_CA_CTOR_ARGS(ComCompatibleVersionAttribute) |
| 406 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 407 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 408 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 409 | DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4) |
| 410 | DEFINE_CA_CTOR_ARGS_END() |
| 411 | |
| 412 | const KnownCaProp ComCompatibleVersionAttributeProps = {"System.Runtime.InteropServices" , "ComCompatibleVersionAttribute" , ComCompatibleVersionTargets, bKEEPCA, |
| 413 | rComCompatibleVersionAttributeArgs, lengthof(rComCompatibleVersionAttributeArgs)}; |
| 414 | |
| 415 | |
| 416 | //----------------------------------------------------------------------------- |
| 417 | // APTCA args (none), named args (none), and known attribute properties. |
| 418 | const KnownCaProp AllowPartiallyTrustedCallersAttributeProps = {"System.Security" , "AllowPartiallyTrustedCallersAttribute" , AllowPartiallyTrustedCallersTargets, bKEEPCA}; |
| 419 | |
| 420 | |
| 421 | |
| 422 | //----------------------------------------------------------------------------- |
| 423 | // Array of known custom attribute properties |
| 424 | #undef KnownCa |
| 425 | #define KnownCa(x) &x##Props, |
| 426 | const KnownCaProp * const rKnownCaProps[CA_COUNT] = |
| 427 | { |
| 428 | KnownCaList() |
| 429 | }; |
| 430 | |
| 431 | //***************************************************************************** |
| 432 | // Helper to turn on or off a single bit in a bitmask. |
| 433 | //***************************************************************************** |
| 434 | template<class T> FORCEINLINE void SetBitValue(T &bitmask, T bit, int bVal) |
| 435 | { |
| 436 | if (bVal) |
| 437 | bitmask |= bit; |
| 438 | else |
| 439 | bitmask &= ~bit; |
| 440 | } // template<class T> FORCEINLINE void SetBitValue() |
| 441 | |
| 442 | HRESULT ParseEncodedType( |
| 443 | CustomAttributeParser &ca, |
| 444 | CaType* pCaType) |
| 445 | { |
| 446 | CONTRACTL |
| 447 | { |
| 448 | PRECONDITION(CheckPointer(pCaType)); |
| 449 | NOTHROW; |
| 450 | } |
| 451 | CONTRACTL_END; |
| 452 | |
| 453 | HRESULT hr = S_OK; |
| 454 | |
| 455 | CorSerializationType* pType = &pCaType->tag; |
| 456 | |
| 457 | IfFailGo(ca.GetTag(pType)); |
| 458 | |
| 459 | if (*pType == SERIALIZATION_TYPE_SZARRAY) |
| 460 | { |
| 461 | IfFailGo(ca.GetTag(&pCaType->arrayType)); |
| 462 | pType = &pCaType->arrayType; |
| 463 | } |
| 464 | |
| 465 | if (*pType == SERIALIZATION_TYPE_ENUM) |
| 466 | { |
| 467 | // We cannot determine the underlying type without loading the Enum. |
| 468 | pCaType->enumType = SERIALIZATION_TYPE_UNDEFINED; |
| 469 | IfFailGo(ca.GetNonNullString(&pCaType->szEnumName, &pCaType->cEnumName)); |
| 470 | } |
| 471 | |
| 472 | ErrExit: |
| 473 | return hr; |
| 474 | } |
| 475 | |
| 476 | //--------------------------------------------------------------------------------------- |
| 477 | // |
| 478 | // Helper to parse the values for the ctor argument list and the named argument list. |
| 479 | // |
| 480 | |
| 481 | HRESULT ParseKnownCaValue( |
| 482 | CustomAttributeParser &ca, |
| 483 | CaValue* pCaArg, |
| 484 | CaType* pCaParam) |
| 485 | { |
| 486 | CONTRACTL |
| 487 | { |
| 488 | PRECONDITION(CheckPointer(pCaArg)); |
| 489 | PRECONDITION(CheckPointer(pCaParam)); |
| 490 | PRECONDITION(pCaParam->tag != SERIALIZATION_TYPE_TAGGED_OBJECT && pCaParam->tag != SERIALIZATION_TYPE_SZARRAY); |
| 491 | NOTHROW; |
| 492 | } |
| 493 | CONTRACTL_END; |
| 494 | |
| 495 | HRESULT hr = S_OK; |
| 496 | CorSerializationType underlyingType; |
| 497 | |
| 498 | pCaArg->type = *pCaParam; |
| 499 | |
| 500 | underlyingType = pCaArg->type.tag == SERIALIZATION_TYPE_ENUM ? pCaArg->type.enumType : pCaArg->type.tag; |
| 501 | |
| 502 | // Grab the value. |
| 503 | switch (underlyingType) |
| 504 | { |
| 505 | case SERIALIZATION_TYPE_BOOLEAN: |
| 506 | case SERIALIZATION_TYPE_I1: |
| 507 | case SERIALIZATION_TYPE_U1: |
| 508 | IfFailGo(ca.GetU1(&pCaArg->u1)); |
| 509 | break; |
| 510 | |
| 511 | case SERIALIZATION_TYPE_CHAR: |
| 512 | case SERIALIZATION_TYPE_I2: |
| 513 | case SERIALIZATION_TYPE_U2: |
| 514 | IfFailGo(ca.GetU2(&pCaArg->u2)); |
| 515 | break; |
| 516 | |
| 517 | case SERIALIZATION_TYPE_I4: |
| 518 | case SERIALIZATION_TYPE_U4: |
| 519 | IfFailGo(ca.GetU4(&pCaArg->u4)); |
| 520 | break; |
| 521 | |
| 522 | case SERIALIZATION_TYPE_I8: |
| 523 | case SERIALIZATION_TYPE_U8: |
| 524 | IfFailGo(ca.GetU8(&pCaArg->u8)); |
| 525 | break; |
| 526 | |
| 527 | case SERIALIZATION_TYPE_R4: |
| 528 | IfFailGo(ca.GetR4(&pCaArg->r4)); |
| 529 | break; |
| 530 | |
| 531 | case SERIALIZATION_TYPE_R8: |
| 532 | IfFailGo(ca.GetR8(&pCaArg->r8)); |
| 533 | break; |
| 534 | |
| 535 | case SERIALIZATION_TYPE_STRING: |
| 536 | case SERIALIZATION_TYPE_TYPE: |
| 537 | IfFailGo(ca.GetString(&pCaArg->str.pStr, &pCaArg->str.cbStr)); |
| 538 | break; |
| 539 | |
| 540 | default: |
| 541 | // The arguments of all known custom attributes are Type, String, Enum, or primitive types. |
| 542 | _ASSERTE(!"Unexpected internal error" ); |
| 543 | hr = E_FAIL; |
| 544 | break; |
| 545 | } // End switch |
| 546 | |
| 547 | ErrExit: |
| 548 | return hr; |
| 549 | } |
| 550 | |
| 551 | //--------------------------------------------------------------------------------------- |
| 552 | // |
| 553 | // Helper to parse the nanmed argument list. |
| 554 | // This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and |
| 555 | // should not have any VM dependency. |
| 556 | // |
| 557 | |
| 558 | HRESULT ParseKnownCaNamedArgs( |
| 559 | CustomAttributeParser &ca, // The Custom Attribute blob. |
| 560 | CaNamedArg *pNamedParams, // Array of argument descriptors. |
| 561 | ULONG cNamedParams) |
| 562 | { |
| 563 | WRAPPER_NO_CONTRACT; |
| 564 | |
| 565 | HRESULT hr = S_OK; |
| 566 | ULONG ixParam; |
| 567 | INT32 ixArg; |
| 568 | INT16 cActualArgs; |
| 569 | CaNamedArgCtor namedArg; |
| 570 | CaNamedArg* pNamedParam; |
| 571 | |
| 572 | // Get actual count of named arguments. |
| 573 | if (FAILED(ca.GetI2(&cActualArgs))) |
| 574 | cActualArgs = 0; // Everett behavior |
| 575 | |
| 576 | for (ixParam = 0; ixParam < cNamedParams; ixParam++) |
| 577 | pNamedParams[ixParam].val.type.tag = SERIALIZATION_TYPE_UNDEFINED; |
| 578 | |
| 579 | // For each named argument... |
| 580 | for (ixArg = 0; ixArg < cActualArgs; ixArg++) |
| 581 | { |
| 582 | // Field or property? |
| 583 | IfFailGo(ca.GetTag(&namedArg.propertyOrField)); |
| 584 | if (namedArg.propertyOrField != SERIALIZATION_TYPE_FIELD && namedArg.propertyOrField != SERIALIZATION_TYPE_PROPERTY) |
| 585 | IfFailGo(PostError(META_E_CA_INVALID_ARGTYPE)); |
| 586 | |
| 587 | // Get argument type information |
| 588 | IfFailGo(ParseEncodedType(ca, &namedArg.type)); |
| 589 | |
| 590 | // Get name of Arg. |
| 591 | if (FAILED(ca.GetNonEmptyString(&namedArg.szName, &namedArg.cName))) |
| 592 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 593 | |
| 594 | // Match arg by name and type |
| 595 | for (ixParam = 0; ixParam < cNamedParams; ixParam++) |
| 596 | { |
| 597 | pNamedParam = &pNamedParams[ixParam]; |
| 598 | |
| 599 | // Match type |
| 600 | if (pNamedParam->type.tag != SERIALIZATION_TYPE_TAGGED_OBJECT) |
| 601 | { |
| 602 | if (namedArg.type.tag != pNamedParam->type.tag) |
| 603 | continue; |
| 604 | |
| 605 | // Match array type |
| 606 | if (namedArg.type.tag == SERIALIZATION_TYPE_SZARRAY && |
| 607 | pNamedParam->type.arrayType != SERIALIZATION_TYPE_TAGGED_OBJECT && |
| 608 | namedArg.type.arrayType != pNamedParam->type.arrayType) |
| 609 | continue; |
| 610 | } |
| 611 | |
| 612 | // Match name (and its length to avoid substring matching) |
| 613 | if ((pNamedParam->cName != namedArg.cName) || |
| 614 | (strncmp(pNamedParam->szName, namedArg.szName, namedArg.cName) != 0)) |
| 615 | { |
| 616 | continue; |
| 617 | } |
| 618 | |
| 619 | // If enum, match enum name. |
| 620 | if (pNamedParam->type.tag == SERIALIZATION_TYPE_ENUM || |
| 621 | (pNamedParam->type.tag == SERIALIZATION_TYPE_SZARRAY && pNamedParam->type.arrayType == SERIALIZATION_TYPE_ENUM )) |
| 622 | { |
| 623 | if (pNamedParam->type.cEnumName > namedArg.type.cEnumName) |
| 624 | continue; // name cannot possibly match |
| 625 | |
| 626 | if (strncmp(pNamedParam->type.szEnumName, namedArg.type.szEnumName, pNamedParam->type.cEnumName) != 0 || |
| 627 | (pNamedParam->type.cEnumName < namedArg.type.cEnumName && |
| 628 | namedArg.type.szEnumName[pNamedParam->type.cEnumName] != ',')) |
| 629 | continue; |
| 630 | |
| 631 | // TODO: For now assume the property\field array size is correct - later we should verify this |
| 632 | namedArg.type.enumType = pNamedParam->type.enumType; |
| 633 | } |
| 634 | |
| 635 | // Found a match. |
| 636 | break; |
| 637 | } |
| 638 | |
| 639 | // Better have found an argument. |
| 640 | if (ixParam == cNamedParams) |
| 641 | { |
| 642 | MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName) |
| 643 | IfFailGo(PostError(META_E_CA_UNKNOWN_ARGUMENT, wcslen(pWideStr), pWideStr)); |
| 644 | } |
| 645 | |
| 646 | // Argument had better not have been seen already. |
| 647 | if (pNamedParams[ixParam].val.type.tag != SERIALIZATION_TYPE_UNDEFINED) |
| 648 | { |
| 649 | MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName) |
| 650 | IfFailGo(PostError(META_E_CA_REPEATED_ARG, wcslen(pWideStr), pWideStr)); |
| 651 | } |
| 652 | |
| 653 | IfFailGo(ParseKnownCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type)); |
| 654 | } |
| 655 | |
| 656 | ErrExit: |
| 657 | return hr; |
| 658 | } |
| 659 | |
| 660 | //--------------------------------------------------------------------------------------- |
| 661 | // |
| 662 | // Helper to parse the ctor argument list. |
| 663 | // This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and |
| 664 | // should not have any VM dependency. |
| 665 | // |
| 666 | |
| 667 | HRESULT ParseKnownCaArgs( |
| 668 | CustomAttributeParser &ca, // The Custom Attribute blob. |
| 669 | CaArg* pArgs, // Array of argument descriptors. |
| 670 | ULONG cArgs) // Count of argument descriptors. |
| 671 | { |
| 672 | WRAPPER_NO_CONTRACT; |
| 673 | |
| 674 | HRESULT hr = S_OK; // A result. |
| 675 | ULONG ix; // Loop control. |
| 676 | |
| 677 | // If there is a blob, check the prolog. |
| 678 | if (FAILED(ca.ValidateProlog())) |
| 679 | { |
| 680 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 681 | } |
| 682 | |
| 683 | // For each expected arg... |
| 684 | for (ix=0; ix<cArgs; ++ix) |
| 685 | { |
| 686 | CaArg* pArg = &pArgs[ix]; |
| 687 | IfFailGo(ParseKnownCaValue(ca, &pArg->val, &pArg->type)); |
| 688 | } |
| 689 | |
| 690 | ErrExit: |
| 691 | return hr; |
| 692 | } // ParseKnownCaArgs |
| 693 | |
| 694 | //***************************************************************************** |
| 695 | // Create a CustomAttribute record from a blob with the specified parent. |
| 696 | //***************************************************************************** |
| 697 | STDMETHODIMP RegMeta::DefineCustomAttribute( |
| 698 | mdToken tkOwner, // [IN] The object to put the value on. |
| 699 | mdToken tkCtor, // [IN] Constructor of the CustomAttribute type (MemberRef/MethodDef). |
| 700 | void const *pCustomAttribute, // [IN] Custom Attribute data. |
| 701 | ULONG cbCustomAttribute, // [IN] Size of custom Attribute data. |
| 702 | mdCustomAttribute *pcv) // [OUT, OPTIONAL] Put custom Attribute token here. |
| 703 | { |
| 704 | #ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER |
| 705 | return E_NOTIMPL; |
| 706 | #else //!FEATURE_METADATA_EMIT_IN_DEBUGGER |
| 707 | HRESULT hr = S_OK; |
| 708 | |
| 709 | BEGIN_ENTRYPOINT_NOTHROW; |
| 710 | |
| 711 | CustomAttributeRec *pRecord = NULL; // New custom Attribute record. |
| 712 | RID iRecord; // New custom Attribute RID. |
| 713 | CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd; |
| 714 | int ixKnown; // Index of known custom attribute. |
| 715 | |
| 716 | LOG((LOGMD, "RegMeta::DefineCustomAttribute(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n" , tkOwner, tkCtor, |
| 717 | pCustomAttribute, cbCustomAttribute, pcv)); |
| 718 | START_MD_PERF(); |
| 719 | LOCKWRITE(); |
| 720 | |
| 721 | _ASSERTE(TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef); |
| 722 | |
| 723 | if (TypeFromToken(tkOwner) == mdtCustomAttribute) |
| 724 | IfFailGo(E_INVALIDARG); |
| 725 | |
| 726 | IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); |
| 727 | |
| 728 | if (IsNilToken(tkOwner) || |
| 729 | IsNilToken(tkCtor) || |
| 730 | (TypeFromToken(tkCtor) != mdtMethodDef && |
| 731 | TypeFromToken(tkCtor) != mdtMemberRef) ) |
| 732 | { |
| 733 | IfFailGo(E_INVALIDARG); |
| 734 | } |
| 735 | |
| 736 | // See if this is a known custom attribute. |
| 737 | IfFailGo(_IsKnownCustomAttribute(tkCtor, &ixKnown)); |
| 738 | if (ixKnown != 0) |
| 739 | { |
| 740 | int bKeep = false; |
| 741 | hr = _HandleKnownCustomAttribute(tkOwner, pCustomAttribute, cbCustomAttribute, ixKnown, &bKeep); |
| 742 | if (pcv) |
| 743 | *pcv = mdCustomAttributeNil; |
| 744 | IfFailGo(hr); |
| 745 | if (!bKeep) |
| 746 | goto ErrExit; |
| 747 | } |
| 748 | |
| 749 | if (((TypeFromToken(tkOwner) == mdtTypeDef) || (TypeFromToken(tkOwner) == mdtMethodDef)) && |
| 750 | (TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef)) |
| 751 | { |
| 752 | CHAR szBuffer[MAX_CLASS_NAME + 1]; |
| 753 | LPSTR szName = szBuffer; |
| 754 | LPCSTR szNamespace; |
| 755 | LPCSTR szClass; |
| 756 | TypeRefRec *pTypeRefRec = NULL; |
| 757 | TypeDefRec *pTypeDefRec = NULL; |
| 758 | mdToken tkParent; |
| 759 | |
| 760 | if (TypeFromToken(tkCtor) == mdtMemberRef) |
| 761 | { |
| 762 | MemberRefRec *pMemberRefRec; |
| 763 | IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMemberRefRec)); |
| 764 | tkParent = pMiniMd->getClassOfMemberRef(pMemberRefRec); |
| 765 | if (TypeFromToken(tkParent) == mdtTypeRef) |
| 766 | { |
| 767 | IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec)); |
| 768 | IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace)); |
| 769 | IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szClass)); |
| 770 | ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass); |
| 771 | } |
| 772 | else if (TypeFromToken(tkParent) == mdtTypeDef) |
| 773 | { |
| 774 | IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec)); |
| 775 | } |
| 776 | } |
| 777 | else |
| 778 | { |
| 779 | IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent)); |
| 780 | IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec)); |
| 781 | } |
| 782 | |
| 783 | if (pTypeDefRec != NULL) |
| 784 | { |
| 785 | IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace)); |
| 786 | IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szClass)); |
| 787 | ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass); |
| 788 | } |
| 789 | |
| 790 | if ((TypeFromToken(tkOwner) == mdtMethodDef) && strcmp(szName, COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI) == 0) |
| 791 | { |
| 792 | // Turn REQ_SO attribute into flag bit on the methoddef. |
| 793 | MethodRec *pMethod; |
| 794 | IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkOwner), &pMethod)); |
| 795 | pMethod->AddFlags(mdRequireSecObject); |
| 796 | IfFailGo(UpdateENCLog(tkOwner)); |
| 797 | goto ErrExit; |
| 798 | } |
| 799 | else if (strcmp(szName, COR_SUPPRESS_UNMANAGED_CODE_CHECK_ATTRIBUTE_ANSI) == 0) |
| 800 | { |
| 801 | // If we spot an unmanged code check suppression attribute, turn on |
| 802 | // the bit that says there's declarative security on the |
| 803 | // class/method, but still write the attribute itself. |
| 804 | if (TypeFromToken(tkOwner) == mdtTypeDef) |
| 805 | { |
| 806 | IfFailGo(_TurnInternalFlagsOn(tkOwner, tdHasSecurity)); |
| 807 | } |
| 808 | else if (TypeFromToken(tkOwner) == mdtMethodDef) |
| 809 | { |
| 810 | IfFailGo(_TurnInternalFlagsOn(tkOwner, mdHasSecurity)); |
| 811 | } |
| 812 | IfFailGo(UpdateENCLog(tkOwner)); |
| 813 | } |
| 814 | } |
| 815 | |
| 816 | IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributeRecord(&pRecord, &iRecord)); |
| 817 | IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecord, tkCtor)); |
| 818 | IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecord, tkOwner)); |
| 819 | |
| 820 | IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute)); |
| 821 | |
| 822 | // Give token back to caller. |
| 823 | if (pcv != NULL) |
| 824 | *pcv = TokenFromRid(iRecord, mdtCustomAttribute); |
| 825 | |
| 826 | IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributesToHash(TokenFromRid(iRecord, mdtCustomAttribute)) ); |
| 827 | |
| 828 | IfFailGo(UpdateENCLog(TokenFromRid(iRecord, mdtCustomAttribute))); |
| 829 | |
| 830 | ErrExit: |
| 831 | STOP_MD_PERF(DefineCustomAttribute); |
| 832 | END_ENTRYPOINT_NOTHROW; |
| 833 | |
| 834 | return hr; |
| 835 | #endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER |
| 836 | } // RegMeta::DefineCustomAttribute |
| 837 | |
| 838 | //***************************************************************************** |
| 839 | // Replace the blob of an existing custom attribute. |
| 840 | //***************************************************************************** |
| 841 | STDMETHODIMP RegMeta::SetCustomAttributeValue( // Return code. |
| 842 | mdCustomAttribute tkAttr, // [IN] The object to be Attributed. |
| 843 | void const *pCustomAttribute, // [IN] Custom Attribute data. |
| 844 | ULONG cbCustomAttribute) // [IN] Size of custom Attribute data. |
| 845 | { |
| 846 | #ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER |
| 847 | return E_NOTIMPL; |
| 848 | #else //!FEATURE_METADATA_EMIT_IN_DEBUGGER |
| 849 | HRESULT hr; |
| 850 | |
| 851 | BEGIN_ENTRYPOINT_NOTHROW; |
| 852 | |
| 853 | CustomAttributeRec *pRecord = NULL;// Existing custom Attribute record. |
| 854 | |
| 855 | START_MD_PERF(); |
| 856 | LOCKWRITE(); |
| 857 | |
| 858 | IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); |
| 859 | |
| 860 | _ASSERTE(TypeFromToken(tkAttr) == mdtCustomAttribute && !InvalidRid(tkAttr)); |
| 861 | |
| 862 | // Retrieve and update the custom value. |
| 863 | IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkAttr), &pRecord)); |
| 864 | IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute)); |
| 865 | |
| 866 | IfFailGo(UpdateENCLog(tkAttr)); |
| 867 | ErrExit: |
| 868 | |
| 869 | STOP_MD_PERF(SetCustomAttributeValue); |
| 870 | END_ENTRYPOINT_NOTHROW; |
| 871 | |
| 872 | return hr; |
| 873 | #endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER |
| 874 | } // RegMeta::SetCustomAttributeValue |
| 875 | |
| 876 | //***************************************************************************** |
| 877 | //***************************************************************************** |
| 878 | HRESULT RegMeta::_IsKnownCustomAttribute( // S_OK, S_FALSE, or error. |
| 879 | mdToken tkCtor, // [IN] Token of custom attribute's constructor. |
| 880 | int *pca) // [OUT] Put value from KnownCustAttr enum here. |
| 881 | { |
| 882 | HRESULT hr = S_OK; // A result. |
| 883 | CCustAttrHashKey sLookup; // For looking up a custom attribute. |
| 884 | CCustAttrHashKey *pFound; // Result of a lookup. |
| 885 | LPCSTR szNamespace = "" ; // Namespace of custom attribute type. |
| 886 | LPCSTR szName = "" ; // Name of custom attribute type. |
| 887 | TypeDefRec *pTypeDefRec = NULL; // Parent record, when a TypeDef. |
| 888 | TypeRefRec *pTypeRefRec = NULL; // Parent record, when a TypeRef. |
| 889 | CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd; |
| 890 | int ixCa; // Index of Known CustomAttribute, or 0. |
| 891 | int i; // Loop control. |
| 892 | mdToken tkParent; |
| 893 | |
| 894 | *pca = 0; |
| 895 | |
| 896 | // Only for Custom Attributes. |
| 897 | _ASSERTE(TypeFromToken(tkCtor) != mdtTypeRef && TypeFromToken(tkCtor) != mdtTypeDef); |
| 898 | |
| 899 | sLookup.tkType = tkCtor; |
| 900 | |
| 901 | // See if this custom attribute type has been seen before. |
| 902 | if ((pFound = m_caHash.Find(&sLookup))) |
| 903 | { // Yes, already seen. |
| 904 | *pca = pFound->ca; |
| 905 | hr = (pFound->ca == CA_UNKNOWN) ? S_FALSE : S_OK; |
| 906 | goto ErrExit; |
| 907 | } |
| 908 | |
| 909 | // Hasn't been seen before. See if it is well known. |
| 910 | |
| 911 | // Get the CA name. |
| 912 | if (TypeFromToken(tkCtor) == mdtMemberRef) |
| 913 | { |
| 914 | MemberRefRec *pMember; |
| 915 | IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember)); |
| 916 | tkParent = pMiniMd->getClassOfMemberRef(pMember); |
| 917 | if (TypeFromToken(tkParent) == mdtTypeRef) |
| 918 | { |
| 919 | IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec)); |
| 920 | IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace)); |
| 921 | IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName)); |
| 922 | } |
| 923 | else if (TypeFromToken(tkParent) == mdtTypeDef) |
| 924 | IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec)); |
| 925 | } |
| 926 | else |
| 927 | { |
| 928 | IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent)); |
| 929 | IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec)); |
| 930 | } |
| 931 | |
| 932 | if (pTypeDefRec) |
| 933 | { |
| 934 | IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace)); |
| 935 | IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName)); |
| 936 | } |
| 937 | |
| 938 | // Search in list of Known CAs. |
| 939 | for (ixCa=0, i=1; i<CA_COUNT; ++i) |
| 940 | { |
| 941 | if (strcmp(szName, rKnownCaProps[i]->szName) != 0) |
| 942 | continue; |
| 943 | if (strcmp(szNamespace, rKnownCaProps[i]->szNamespace) == 0) |
| 944 | { |
| 945 | // Some custom attributes have overloaded ctors. For those, |
| 946 | // see if this is the matching overload. |
| 947 | if (rKnownCaProps[i]->bMatchBySig) |
| 948 | { |
| 949 | // Name matches. Does the signature? |
| 950 | PCCOR_SIGNATURE pSig = NULL; // Signature of a method. |
| 951 | ULONG cbSig = 0; // Size of the signature. |
| 952 | ULONG cParams; // Count of signature parameters. |
| 953 | ULONG cb; // Size of an element |
| 954 | ULONG elem; // Signature element. |
| 955 | ULONG j; // Loop control. |
| 956 | |
| 957 | // Get the signature. |
| 958 | if (TypeFromToken(tkCtor) == mdtMemberRef) |
| 959 | { |
| 960 | MemberRefRec *pMember; |
| 961 | IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember)); |
| 962 | IfFailGo(pMiniMd->getSignatureOfMemberRef(pMember, &pSig, &cbSig)); |
| 963 | } |
| 964 | else |
| 965 | { |
| 966 | MethodRec *pMethod; |
| 967 | IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkCtor), &pMethod)); |
| 968 | IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSig, &cbSig)); |
| 969 | } |
| 970 | |
| 971 | // Skip calling convention. |
| 972 | cb = CorSigUncompressData(pSig, &elem); |
| 973 | pSig += cb; |
| 974 | cbSig -= cb; |
| 975 | // Count of params. |
| 976 | cb = CorSigUncompressData(pSig, &cParams); |
| 977 | pSig += cb; |
| 978 | cbSig -= cb; |
| 979 | |
| 980 | // If param count mismatch, not the right CA. |
| 981 | if (cParams != rKnownCaProps[i]->cArgs) |
| 982 | continue; |
| 983 | |
| 984 | // Count is fine, check each param. Skip return type (better be void). |
| 985 | cb = CorSigUncompressData(pSig, &elem); |
| 986 | _ASSERTE(elem == ELEMENT_TYPE_VOID); |
| 987 | pSig += cb; |
| 988 | cbSig -= cb; |
| 989 | for (j=0; j<cParams; ++j) |
| 990 | { |
| 991 | // Get next element from method signature. |
| 992 | cb = CorSigUncompressData(pSig, &elem); |
| 993 | pSig += cb; |
| 994 | cbSig -= cb; |
| 995 | if (rKnownCaProps[i]->pArgs[j].type.tag != (CorSerializationType) elem) |
| 996 | break; |
| 997 | } |
| 998 | |
| 999 | // All matched? |
| 1000 | if (j != cParams) |
| 1001 | continue; |
| 1002 | } |
| 1003 | // All matched. |
| 1004 | ixCa = i; |
| 1005 | break; |
| 1006 | } |
| 1007 | } |
| 1008 | |
| 1009 | // Add to hash. |
| 1010 | sLookup.ca = ixCa; |
| 1011 | pFound = m_caHash.Add(&sLookup); |
| 1012 | IfNullGo(pFound); |
| 1013 | *pFound = sLookup; |
| 1014 | *pca = ixCa; |
| 1015 | |
| 1016 | ErrExit: |
| 1017 | return hr; |
| 1018 | } // RegMeta::_IsKnownCustomAttribute |
| 1019 | |
| 1020 | //***************************************************************************** |
| 1021 | //***************************************************************************** |
| 1022 | #ifdef _PREFAST_ |
| 1023 | #pragma warning(push) |
| 1024 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
| 1025 | #endif |
| 1026 | HRESULT RegMeta::_HandleKnownCustomAttribute( // S_OK or error. |
| 1027 | mdToken tkObj, // [IN] Object being attributed. |
| 1028 | const void *pData, // [IN] Custom Attribute data blob. |
| 1029 | ULONG cbData, // [IN] Count of bytes in the data. |
| 1030 | int ixCa, // [IN] Value from KnownCustAttr enum. |
| 1031 | int *bKeep) // [OUT] If true, keep the CA after processing. |
| 1032 | { |
| 1033 | HRESULT hr = S_OK; // A result. |
| 1034 | ULONG ixTbl; // Index of table with object. |
| 1035 | void *pRow; // Whatever sort of record it is. |
| 1036 | CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd; |
| 1037 | mdToken tkObjType; // Type of the object. |
| 1038 | ULONG ix; // Loop control. |
| 1039 | KnownCaProp const *props=rKnownCaProps[ixCa]; // For convenience. |
| 1040 | CustomAttributeParser ca(pData, cbData); |
| 1041 | CQuickArray<CaArg> qArgs; // Un-named arguments. |
| 1042 | CQuickArray<CaNamedArg> qNamedArgs; // Named arguments. |
| 1043 | CQuickArray<BYTE> qNativeType;// Native type string. |
| 1044 | |
| 1045 | _ASSERTE(ixCa > 0 && ixCa < CA_COUNT); |
| 1046 | *bKeep = props->bKeepCa || m_bKeepKnownCa; |
| 1047 | |
| 1048 | // Validate that target is valid for attribute. |
| 1049 | tkObjType = TypeFromToken(tkObj); |
| 1050 | for (ix=0; props->rTypes[ix] != (mdToken) -1; ++ix) |
| 1051 | { |
| 1052 | if (props->rTypes[ix] == tkObjType) |
| 1053 | break; |
| 1054 | } |
| 1055 | // Was the type found in list of valid targets? |
| 1056 | if (props->rTypes[ix] == (mdToken) -1) |
| 1057 | { // No, error. |
| 1058 | IfFailGo(PostError(META_E_CA_INVALID_TARGET)); |
| 1059 | } |
| 1060 | // Get the row. |
| 1061 | ixTbl = pMiniMd->GetTblForToken(tkObj); |
| 1062 | _ASSERTE(ixTbl >= 0 && ixTbl <= pMiniMd->GetCountTables()); |
| 1063 | IfFailGo(pMiniMd->getRow(ixTbl, RidFromToken(tkObj), &pRow)); |
| 1064 | |
| 1065 | // If this custom attribute expects any args... |
| 1066 | if (props->cArgs || props->cNamedArgs) |
| 1067 | { // Initialize array ctor arg descriptors. |
| 1068 | IfFailGo(qArgs.ReSizeNoThrow(props->cArgs)); |
| 1069 | for (ix=0; ix<props->cArgs; ++ix) |
| 1070 | qArgs[ix] = props->pArgs[ix]; |
| 1071 | // Parse any ctor args (unnamed, fixed args). |
| 1072 | IfFailGo(ParseKnownCaArgs(ca, qArgs.Ptr(), props->cArgs)); |
| 1073 | |
| 1074 | // If this custom attribute accepts named args, parse them, or if there |
| 1075 | // are unused bytes, parse them. |
| 1076 | if (props->cNamedArgs || ca.BytesLeft() > 0) |
| 1077 | { // Initialize array of named arg descriptors. |
| 1078 | IfFailGo(qNamedArgs.ReSizeNoThrow(props->cNamedArgs)); |
| 1079 | for (ix=0; ix<props->cNamedArgs; ++ix) |
| 1080 | qNamedArgs[ix] = props->pNamedArgs[ix]; |
| 1081 | // Parse named args. |
| 1082 | IfFailGo(ParseKnownCaNamedArgs(ca, qNamedArgs.Ptr(), props->cNamedArgs)); |
| 1083 | } |
| 1084 | } |
| 1085 | |
| 1086 | switch (ixCa) |
| 1087 | { |
| 1088 | case CA_DllImportAttribute: |
| 1089 | { |
| 1090 | // Validate parameters. |
| 1091 | if (qArgs[0].val.str.cbStr == 0 || qArgs[0].val.str.pStr == NULL) |
| 1092 | { |
| 1093 | // no name for DllImport. |
| 1094 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1095 | } |
| 1096 | |
| 1097 | // Retrieve / create a ModuleRef on the dll name. |
| 1098 | mdModuleRef mrModule; |
| 1099 | CQuickArray<char> qDllName; |
| 1100 | IfFailGo(qDllName.ReSizeNoThrow(qArgs[0].val.str.cbStr+1)); |
| 1101 | memcpy(qDllName.Ptr(), qArgs[0].val.str.pStr, qArgs[0].val.str.cbStr); |
| 1102 | qDllName[qArgs[0].val.str.cbStr] = '\0'; |
| 1103 | hr = ImportHelper::FindModuleRef(pMiniMd, qDllName.Ptr(), &mrModule); |
| 1104 | if (hr != S_OK) |
| 1105 | { |
| 1106 | MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzDllName, qDllName.Ptr()); |
| 1107 | if (wzDllName == NULL) |
| 1108 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1109 | IfFailGo(_DefineModuleRef(wzDllName, &mrModule)); |
| 1110 | } |
| 1111 | |
| 1112 | // Create a p/invoke map entry. |
| 1113 | ULONG dwFlags; dwFlags=0; |
| 1114 | // Was a calling convention set? |
| 1115 | if (qNamedArgs[DI_CallingConvention].val.type.tag) |
| 1116 | { // Calling convention makes no sense on a field. |
| 1117 | if (TypeFromToken(tkObj) == mdtFieldDef) |
| 1118 | IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_CallingConvention].szName)); |
| 1119 | // Turn off all callconv bits, then turn on specified value. |
| 1120 | dwFlags &= ~pmCallConvMask; |
| 1121 | switch (qNamedArgs[DI_CallingConvention].val.u4) |
| 1122 | { //<TODO>@future: sigh. keep in sync with System.Runtime.InteropServices.CallingConvention</TODO> |
| 1123 | case 0: break; // 0 means "do nothing" |
| 1124 | case 1: dwFlags |= pmCallConvWinapi; break; |
| 1125 | case 2: dwFlags |= pmCallConvCdecl; break; |
| 1126 | case 3: dwFlags |= pmCallConvStdcall; break; |
| 1127 | case 4: dwFlags |= pmCallConvThiscall; break; |
| 1128 | case 5: dwFlags |= pmCallConvFastcall; break; |
| 1129 | default: |
| 1130 | _ASSERTE(!"Flags are out of sync! " ); |
| 1131 | break; |
| 1132 | } |
| 1133 | } |
| 1134 | else |
| 1135 | if (TypeFromToken(tkObj) == mdtMethodDef) |
| 1136 | { // No calling convention specified for a method. Default to pmCallConvWinApi. |
| 1137 | dwFlags = (dwFlags & ~pmCallConvMask) | pmCallConvWinapi; |
| 1138 | } |
| 1139 | |
| 1140 | // Charset |
| 1141 | if (qNamedArgs[DI_CharSet].val.type.tag) |
| 1142 | { // Turn of all charset bits, then turn on specified bits. |
| 1143 | dwFlags &= ~pmCharSetMask; |
| 1144 | switch (qNamedArgs[DI_CharSet].val.u4) |
| 1145 | { //<TODO>@future: keep in sync with System.Runtime.InteropServices.CharSet</TODO> |
| 1146 | case 0: break; // 0 means "do nothing" |
| 1147 | case 1: dwFlags |= pmCharSetNotSpec; break; |
| 1148 | case 2: dwFlags |= pmCharSetAnsi; break; |
| 1149 | case 3: dwFlags |= pmCharSetUnicode; break; |
| 1150 | case 4: dwFlags |= pmCharSetAuto; break; |
| 1151 | default: |
| 1152 | _ASSERTE(!"Flags are out of sync! " ); |
| 1153 | break; |
| 1154 | } |
| 1155 | } |
| 1156 | if (qNamedArgs[DI_ExactSpelling].val.u1) |
| 1157 | dwFlags |= pmNoMangle; |
| 1158 | if (qNamedArgs[DI_SetLastError].val.type.tag) |
| 1159 | { // SetLastError makes no sense on a field. |
| 1160 | if (TypeFromToken(tkObj) == mdtFieldDef) |
| 1161 | IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_SetLastError].szName)); |
| 1162 | if (qNamedArgs[DI_SetLastError].val.u1) |
| 1163 | dwFlags |= pmSupportsLastError; |
| 1164 | } |
| 1165 | |
| 1166 | // If an entrypoint name was specified, use it, otherwise grab the name from the member. |
| 1167 | LPCWSTR wzEntry; |
| 1168 | if (qNamedArgs[DI_EntryPoint].val.type.tag) |
| 1169 | { |
| 1170 | if (qNamedArgs[DI_EntryPoint].val.str.cbStr > 0) |
| 1171 | { |
| 1172 | MAKE_WIDEPTR_FROMUTF8N_NOTHROW(wzEntryName, qNamedArgs[DI_EntryPoint].val.str.pStr, qNamedArgs[DI_EntryPoint].val.str.cbStr); |
| 1173 | if (wzEntryName == NULL) |
| 1174 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1175 | wzEntry = wzEntryName; |
| 1176 | } |
| 1177 | else |
| 1178 | wzEntry = W("" ); |
| 1179 | } |
| 1180 | else |
| 1181 | { |
| 1182 | LPCUTF8 szMember = NULL; |
| 1183 | if (TypeFromToken(tkObj) == mdtMethodDef) |
| 1184 | { |
| 1185 | IfFailGo(pMiniMd->getNameOfMethod(reinterpret_cast<MethodRec*>(pRow), &szMember)); |
| 1186 | } |
| 1187 | MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMemberName, szMember); |
| 1188 | if (wzMemberName == NULL) |
| 1189 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1190 | wzEntry = wzMemberName; |
| 1191 | } |
| 1192 | |
| 1193 | // Set the miPreserveSig bit based on the value of the preserve sig flag. |
| 1194 | if (qNamedArgs[DI_PreserveSig].val.type.tag && !qNamedArgs[DI_PreserveSig].val.u1) |
| 1195 | reinterpret_cast<MethodRec*>(pRow)->RemoveImplFlags(miPreserveSig); |
| 1196 | else |
| 1197 | reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig); |
| 1198 | |
| 1199 | if (qNamedArgs[DI_BestFitMapping].val.type.tag) |
| 1200 | { |
| 1201 | if (qNamedArgs[DI_BestFitMapping].val.u1) |
| 1202 | dwFlags |= pmBestFitEnabled; |
| 1203 | else |
| 1204 | dwFlags |= pmBestFitDisabled; |
| 1205 | } |
| 1206 | |
| 1207 | if (qNamedArgs[DI_ThrowOnUnmappableChar].val.type.tag) |
| 1208 | { |
| 1209 | if (qNamedArgs[DI_ThrowOnUnmappableChar].val.u1) |
| 1210 | dwFlags |= pmThrowOnUnmappableCharEnabled; |
| 1211 | else |
| 1212 | dwFlags |= pmThrowOnUnmappableCharDisabled; |
| 1213 | } |
| 1214 | |
| 1215 | // Finally, create the PInvokeMap entry., |
| 1216 | IfFailGo(_DefinePinvokeMap(tkObj, dwFlags, wzEntry, mrModule)); |
| 1217 | goto ErrExit; |
| 1218 | } |
| 1219 | break; |
| 1220 | |
| 1221 | case CA_GuidAttribute: |
| 1222 | { // Just verify the attribute. It still gets stored as a real custom attribute. |
| 1223 | // format is "{01234567-0123-0123-0123-001122334455}" |
| 1224 | GUID guid; |
| 1225 | WCHAR wzGuid[40]; |
| 1226 | int cch = qArgs[0].val.str.cbStr; |
| 1227 | |
| 1228 | // Guid should be 36 characters; need to add curlies. |
| 1229 | if (cch == 36) |
| 1230 | { |
| 1231 | WszMultiByteToWideChar(CP_UTF8, 0, qArgs[0].val.str.pStr,cch, wzGuid+1,39); |
| 1232 | wzGuid[0] = '{'; |
| 1233 | wzGuid[37] = '}'; |
| 1234 | wzGuid[38] = 0; |
| 1235 | hr = IIDFromString(wzGuid, &guid); |
| 1236 | } |
| 1237 | else |
| 1238 | hr = META_E_CA_INVALID_UUID; |
| 1239 | if (hr != S_OK) |
| 1240 | IfFailGo(PostError(META_E_CA_INVALID_UUID)); |
| 1241 | goto ErrExit; |
| 1242 | } |
| 1243 | break; |
| 1244 | |
| 1245 | case CA_ComImportAttribute: |
| 1246 | reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdImport); |
| 1247 | break; |
| 1248 | |
| 1249 | case CA_InterfaceTypeAttribute: |
| 1250 | { |
| 1251 | // Verify the attribute. |
| 1252 | if (qArgs[0].val.u2 >= ifLast) |
| 1253 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1254 | } |
| 1255 | break; |
| 1256 | |
| 1257 | case CA_ClassInterfaceAttribute: |
| 1258 | { |
| 1259 | // Verify the attribute. |
| 1260 | if (qArgs[0].val.u2 >= clsIfLast) |
| 1261 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1262 | } |
| 1263 | break; |
| 1264 | |
| 1265 | case CA_SpecialNameAttribute: |
| 1266 | |
| 1267 | switch (TypeFromToken(tkObj)) |
| 1268 | { |
| 1269 | case mdtTypeDef: |
| 1270 | reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSpecialName); |
| 1271 | break; |
| 1272 | |
| 1273 | case mdtMethodDef: |
| 1274 | reinterpret_cast<MethodRec*>(pRow)->AddFlags(mdSpecialName); |
| 1275 | break; |
| 1276 | |
| 1277 | case mdtFieldDef: |
| 1278 | reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdSpecialName); |
| 1279 | break; |
| 1280 | |
| 1281 | case mdtProperty: |
| 1282 | reinterpret_cast<PropertyRec*>(pRow)->AddPropFlags(prSpecialName); |
| 1283 | break; |
| 1284 | |
| 1285 | case mdtEvent: |
| 1286 | reinterpret_cast<EventRec*>(pRow)->AddEventFlags(evSpecialName); |
| 1287 | break; |
| 1288 | |
| 1289 | default: |
| 1290 | _ASSERTE(!"Unfamilar type for SpecialName custom attribute" ); |
| 1291 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1292 | } |
| 1293 | |
| 1294 | break; |
| 1295 | case CA_SerializableAttribute: |
| 1296 | reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSerializable); |
| 1297 | break; |
| 1298 | |
| 1299 | case CA_NonSerializedAttribute: |
| 1300 | reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdNotSerialized); |
| 1301 | break; |
| 1302 | |
| 1303 | case CA_InAttribute: |
| 1304 | reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdIn); |
| 1305 | break; |
| 1306 | |
| 1307 | case CA_OutAttribute: |
| 1308 | reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOut); |
| 1309 | break; |
| 1310 | |
| 1311 | case CA_OptionalAttribute: |
| 1312 | reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOptional); |
| 1313 | break; |
| 1314 | |
| 1315 | case CA_MethodImplAttribute2: |
| 1316 | // Force to wider value. |
| 1317 | qArgs[0].val.u4 = (unsigned)qArgs[0].val.i2; |
| 1318 | // Fall through to validation. |
| 1319 | case CA_MethodImplAttribute3: |
| 1320 | // Validate bits. |
| 1321 | if (qArgs[0].val.u4 & ~(miUserMask)) |
| 1322 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1323 | reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(qArgs[0].val.u4); |
| 1324 | if (!qNamedArgs[MI_CodeType].val.type.tag) |
| 1325 | break; |
| 1326 | // fall through to set the code type. |
| 1327 | case CA_MethodImplAttribute1: |
| 1328 | { |
| 1329 | USHORT usFlags = reinterpret_cast<MethodRec*>(pRow)->GetImplFlags(); |
| 1330 | if (qNamedArgs[MI_CodeType].val.i4 & ~(miCodeTypeMask)) |
| 1331 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1332 | // Mask out old value, put in new one. |
| 1333 | usFlags = (usFlags & ~miCodeTypeMask) | qNamedArgs[MI_CodeType].val.i4; |
| 1334 | reinterpret_cast<MethodRec*>(pRow)->SetImplFlags(usFlags); |
| 1335 | } |
| 1336 | break; |
| 1337 | |
| 1338 | case CA_MarshalAsAttribute1: |
| 1339 | // Force the U2 to a wider U4 value explicitly. |
| 1340 | qArgs[0].val.u4 = qArgs[0].val.u2; |
| 1341 | // Fall through to handle the CA. |
| 1342 | case CA_MarshalAsAttribute2: |
| 1343 | IfFailGo(_HandleNativeTypeCustomAttribute(tkObj, qArgs.Ptr(), qNamedArgs.Ptr(), qNativeType)); |
| 1344 | break; |
| 1345 | |
| 1346 | case CA_PreserveSigAttribute: |
| 1347 | reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig); |
| 1348 | break; |
| 1349 | |
| 1350 | case CA_StructLayoutAttribute1: |
| 1351 | { |
| 1352 | // Convert the I2 to a U2, then wide to an I4, then fall through. |
| 1353 | qArgs[0].val.i4 = static_cast<int>(static_cast<USHORT>(qArgs[0].val.i2)); |
| 1354 | } |
| 1355 | case CA_StructLayoutAttribute2: |
| 1356 | { |
| 1357 | // Get a copy of the flags to work with. |
| 1358 | ULONG dwFlags; |
| 1359 | dwFlags = reinterpret_cast<TypeDefRec*>(pRow)->GetFlags(); |
| 1360 | // Class layout. Keep in sync with LayoutKind. |
| 1361 | switch (qArgs[0].val.i4) |
| 1362 | { |
| 1363 | case 0: // tdSequentialLayout: |
| 1364 | dwFlags = (dwFlags & ~tdLayoutMask) | tdSequentialLayout; |
| 1365 | break; |
| 1366 | case 2: // tdExplicitLayout: |
| 1367 | dwFlags = (dwFlags & ~tdLayoutMask) | tdExplicitLayout; |
| 1368 | break; |
| 1369 | case 3: // tdAutoLayout: |
| 1370 | dwFlags = (dwFlags & ~tdLayoutMask) | tdAutoLayout; |
| 1371 | break; |
| 1372 | default: |
| 1373 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1374 | break; |
| 1375 | } |
| 1376 | |
| 1377 | // Class packing and size. |
| 1378 | ULONG ulSize, ulPack; |
| 1379 | ulPack = ulSize = ULONG_MAX; |
| 1380 | if (qNamedArgs[SL_Pack].val.type.tag) |
| 1381 | { // Only 1,2,4,8,16,32,64,128 are legal values. |
| 1382 | ulPack = qNamedArgs[SL_Pack].val.u4; |
| 1383 | if ((ulPack > 128) || |
| 1384 | (ulPack & (ulPack-1))) |
| 1385 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1386 | } |
| 1387 | if (qNamedArgs[SL_Size].val.type.tag) |
| 1388 | { |
| 1389 | if (qNamedArgs[SL_Size].val.u4 > INT_MAX) |
| 1390 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1391 | ulSize = qNamedArgs[SL_Size].val.u4; |
| 1392 | } |
| 1393 | if (ulPack!=ULONG_MAX || ulSize!=ULONG_MAX) |
| 1394 | IfFailGo(_SetClassLayout(tkObj, ulPack, ulSize)); |
| 1395 | |
| 1396 | // Class character set. |
| 1397 | if (qNamedArgs[SL_CharSet].val.type.tag) |
| 1398 | { |
| 1399 | switch (qNamedArgs[SL_CharSet].val.u4) |
| 1400 | { |
| 1401 | //case 1: // Not specified. |
| 1402 | // IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1403 | // break; |
| 1404 | case 2: // ANSI |
| 1405 | dwFlags = (dwFlags & ~tdStringFormatMask) | tdAnsiClass; |
| 1406 | break; |
| 1407 | case 3: // Unicode |
| 1408 | dwFlags = (dwFlags & ~tdStringFormatMask) | tdUnicodeClass; |
| 1409 | break; |
| 1410 | case 4: // Auto |
| 1411 | dwFlags = (dwFlags & ~tdStringFormatMask) | tdAutoClass; |
| 1412 | break; |
| 1413 | default: |
| 1414 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1415 | break; |
| 1416 | } |
| 1417 | } |
| 1418 | |
| 1419 | // Persist possibly-changed value of flags. |
| 1420 | reinterpret_cast<TypeDefRec*>(pRow)->SetFlags(dwFlags); |
| 1421 | } |
| 1422 | break; |
| 1423 | |
| 1424 | case CA_FieldOffsetAttribute: |
| 1425 | if (qArgs[0].val.u4 > INT_MAX) |
| 1426 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1427 | IfFailGo(_SetFieldOffset(tkObj, qArgs[0].val.u4)); |
| 1428 | break; |
| 1429 | |
| 1430 | case CA_TypeLibVersionAttribute: |
| 1431 | if ((qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0)) |
| 1432 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1433 | break; |
| 1434 | |
| 1435 | case CA_ComCompatibleVersionAttribute: |
| 1436 | if ( (qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0) || (qArgs[2].val.i4 < 0) || (qArgs[3].val.i4 < 0) ) |
| 1437 | IfFailGo(PostError(META_E_CA_INVALID_VALUE)); |
| 1438 | break; |
| 1439 | |
| 1440 | case CA_AllowPartiallyTrustedCallersAttribute: |
| 1441 | break; |
| 1442 | |
| 1443 | case CA_WindowsRuntimeImportAttribute: |
| 1444 | reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdWindowsRuntime); |
| 1445 | break; |
| 1446 | |
| 1447 | default: |
| 1448 | _ASSERTE(!"Unexpected custom attribute type" ); |
| 1449 | // Turn into ordinary custom attribute. |
| 1450 | *bKeep = true; |
| 1451 | hr = S_OK; |
| 1452 | goto ErrExit; |
| 1453 | break; |
| 1454 | } |
| 1455 | |
| 1456 | IfFailGo(UpdateENCLog(tkObj)); |
| 1457 | |
| 1458 | ErrExit: |
| 1459 | return hr; |
| 1460 | } // RegMeta::_HandleKnownCustomAttribute |
| 1461 | #ifdef _PREFAST_ |
| 1462 | #pragma warning(pop) |
| 1463 | #endif |
| 1464 | |
| 1465 | //***************************************************************************** |
| 1466 | //***************************************************************************** |
| 1467 | #ifdef _PREFAST_ |
| 1468 | #pragma warning(push) |
| 1469 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
| 1470 | #endif |
| 1471 | HRESULT RegMeta::_HandleNativeTypeCustomAttribute(// S_OK or error. |
| 1472 | mdToken tkObj, // The token this CA is applied on. |
| 1473 | CaArg *pArgs, // Pointer to args. |
| 1474 | CaNamedArg *pNamedArgs, // Pointer to named args. |
| 1475 | CQuickArray<BYTE> &qNativeType) // Native type is built here. |
| 1476 | { |
| 1477 | HRESULT hr = S_OK; // A result. |
| 1478 | int cch = 0; // Size of a string argument. |
| 1479 | ULONG cb; // Count of some character operation. |
| 1480 | ULONG cbNative; // Size of native type string. |
| 1481 | ULONG cbMax; // Max size of native type string. |
| 1482 | BYTE *pbNative; // Pointer into native type buffer. |
| 1483 | mdToken tkObjType; // The type of the token. |
| 1484 | mdToken tkSetter; // Token for Property setter. |
| 1485 | mdToken tkGetter; // Token for property getter. |
| 1486 | mdParamDef tkParam; // Parameter of getter/setter. |
| 1487 | ULONG cParams; // Count of params for getter/setter. |
| 1488 | HCORENUM phEnum = 0; // Enumerator for params. |
| 1489 | ULONG ulSeq; // Sequence of a param. |
| 1490 | |
| 1491 | // Retrieve the type of the token. |
| 1492 | tkObjType = TypeFromToken(tkObj); |
| 1493 | |
| 1494 | // Compute maximum size of the native type. |
| 1495 | if (pArgs[0].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER) |
| 1496 | { // N_T_* + 3 string lengths |
| 1497 | cbMax = sizeof(ULONG) * 4; |
| 1498 | // Marshal type - name of the type |
| 1499 | cbMax += pNamedArgs[M_MarshalType].val.str.cbStr; |
| 1500 | // Marshal type - type of the custom marshaler |
| 1501 | cbMax += pNamedArgs[M_MarshalTypeRef].val.str.cbStr; |
| 1502 | // String cookie. |
| 1503 | cbMax += pNamedArgs[M_MarshalCookie].val.str.cbStr; |
| 1504 | } |
| 1505 | else if (pArgs[0].val.i4 == NATIVE_TYPE_SAFEARRAY) |
| 1506 | { // N_T_* + safe array sub-type + string length. |
| 1507 | cbMax = sizeof(ULONG) * 3; |
| 1508 | // Safe array record sub type. |
| 1509 | cbMax += pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr; |
| 1510 | } |
| 1511 | else |
| 1512 | { // N_T_* + sub-type + size + additive + NativeTypeArrayFlags. |
| 1513 | cbMax = sizeof(ULONG) * 4 + sizeof(UINT16); |
| 1514 | } |
| 1515 | |
| 1516 | // IidParameterIndex. |
| 1517 | cbMax += sizeof(DWORD); |
| 1518 | |
| 1519 | // Extra space to prevent buffer overrun. |
| 1520 | cbMax += 8; |
| 1521 | |
| 1522 | // Size the array. |
| 1523 | IfFailGo(qNativeType.ReSizeNoThrow(cbMax)); |
| 1524 | pbNative = qNativeType.Ptr(); |
| 1525 | cbNative = 0; |
| 1526 | |
| 1527 | //<TODO>@FUTURE: check for valid combinations of args.</TODO> |
| 1528 | |
| 1529 | // Put in the NativeType. |
| 1530 | cb = CorSigCompressData(pArgs[0].val.i4, pbNative); |
| 1531 | if (cb == ((ULONG)(-1))) |
| 1532 | { |
| 1533 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1534 | } |
| 1535 | |
| 1536 | cbNative += cb; |
| 1537 | pbNative += cb; |
| 1538 | if (cbNative > cbMax) |
| 1539 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1540 | |
| 1541 | // Put in additional information, depending on native type. |
| 1542 | switch (pArgs[0].val.i4) |
| 1543 | { |
| 1544 | case NATIVE_TYPE_INTF: |
| 1545 | case NATIVE_TYPE_IUNKNOWN: |
| 1546 | case NATIVE_TYPE_IDISPATCH: |
| 1547 | // Validate that the IidParameterIndex field is valid if set. |
| 1548 | if (pNamedArgs[M_IidParameterIndex].val.type.tag) |
| 1549 | { |
| 1550 | int iidparam = pNamedArgs[M_IidParameterIndex].val.i4; |
| 1551 | if (iidparam < 0) |
| 1552 | IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX)); |
| 1553 | |
| 1554 | cb = CorSigCompressData(pNamedArgs[M_IidParameterIndex].val.i4, pbNative); |
| 1555 | if (cb == ((ULONG)(-1))) |
| 1556 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1557 | |
| 1558 | cbNative += cb; |
| 1559 | pbNative += cb; |
| 1560 | if (cbNative > cbMax) |
| 1561 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1562 | } |
| 1563 | break; |
| 1564 | |
| 1565 | |
| 1566 | case NATIVE_TYPE_FIXEDARRAY: |
| 1567 | // Validate that only fields valid for NATIVE_TYPE_FIXEDARRAY are set. |
| 1568 | if (pNamedArgs[M_SafeArraySubType].val.type.tag) |
| 1569 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1570 | |
| 1571 | if (pNamedArgs[M_SizeParamIndex].val.type.tag) |
| 1572 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1573 | |
| 1574 | // This native type is only applicable on fields. |
| 1575 | if (tkObjType != mdtFieldDef) |
| 1576 | IfFailGo(PostError(META_E_CA_NT_FIELDONLY)); |
| 1577 | |
| 1578 | if (pNamedArgs[M_SizeConst].val.type.tag) |
| 1579 | { |
| 1580 | // Make sure the size is not negative. |
| 1581 | if (pNamedArgs[M_SizeConst].val.i4 < 0) |
| 1582 | IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE)); |
| 1583 | |
| 1584 | cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative); |
| 1585 | if (cb == ((ULONG)(-1))) |
| 1586 | { |
| 1587 | IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE)); |
| 1588 | } |
| 1589 | |
| 1590 | } |
| 1591 | else |
| 1592 | { |
| 1593 | cb = CorSigCompressData(1, pbNative); |
| 1594 | if (cb == ((ULONG)(-1))) |
| 1595 | { |
| 1596 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1597 | } |
| 1598 | } |
| 1599 | cbNative += cb; |
| 1600 | pbNative += cb; |
| 1601 | if (cbNative > cbMax) |
| 1602 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1603 | |
| 1604 | // Is there a sub type? |
| 1605 | if (pNamedArgs[M_ArraySubType].val.type.tag) |
| 1606 | { |
| 1607 | // Put in the sub type. |
| 1608 | cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative); |
| 1609 | if (cb == ((ULONG)(-1))) |
| 1610 | { |
| 1611 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1612 | } |
| 1613 | cbNative += cb; |
| 1614 | pbNative += cb; |
| 1615 | if (cbNative > cbMax) |
| 1616 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1617 | } |
| 1618 | break; |
| 1619 | |
| 1620 | case NATIVE_TYPE_FIXEDSYSSTRING: |
| 1621 | // Validate that the required fields are set. |
| 1622 | if (!pNamedArgs[M_SizeConst].val.type.tag) |
| 1623 | IfFailGo(PostError(META_E_CA_FIXEDSTR_SIZE_REQUIRED)); |
| 1624 | |
| 1625 | // Validate that other array fields are not set. |
| 1626 | if (pNamedArgs[M_ArraySubType].val.type.tag) |
| 1627 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1628 | if (pNamedArgs[M_SizeParamIndex].val.type.tag) |
| 1629 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1630 | if (pNamedArgs[M_SafeArraySubType].val.type.tag) |
| 1631 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1632 | |
| 1633 | // This native type is only applicable on fields. |
| 1634 | if (tkObjType != mdtFieldDef) |
| 1635 | IfFailGo(PostError(META_E_CA_NT_FIELDONLY)); |
| 1636 | |
| 1637 | // Put in the constant value. |
| 1638 | cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative); |
| 1639 | if (cb == ((ULONG)(-1))) |
| 1640 | { |
| 1641 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1642 | } |
| 1643 | cbNative += cb; |
| 1644 | pbNative += cb; |
| 1645 | if (cbNative > cbMax) |
| 1646 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1647 | break; |
| 1648 | |
| 1649 | case NATIVE_TYPE_BYVALSTR: |
| 1650 | // This native type is only applicable on parameters. |
| 1651 | if (tkObjType != mdtParamDef) |
| 1652 | IfFailGo(PostError(META_E_CA_INVALID_TARGET)); |
| 1653 | break; |
| 1654 | |
| 1655 | case NATIVE_TYPE_SAFEARRAY: |
| 1656 | // Validate that other array fields are not set. |
| 1657 | if (pNamedArgs[M_ArraySubType].val.type.tag) |
| 1658 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1659 | if (pNamedArgs[M_SizeParamIndex].val.type.tag) |
| 1660 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1661 | if (pNamedArgs[M_SizeConst].val.type.tag) |
| 1662 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1663 | |
| 1664 | // Is there a safe array sub type? |
| 1665 | if (pNamedArgs[M_SafeArraySubType].val.type.tag) |
| 1666 | { |
| 1667 | // Put in the safe array sub type. |
| 1668 | cb = CorSigCompressData(pNamedArgs[M_SafeArraySubType].val.i4, pbNative); |
| 1669 | if (cb == ((ULONG)(-1))) |
| 1670 | { |
| 1671 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1672 | } |
| 1673 | cbNative += cb; |
| 1674 | pbNative += cb; |
| 1675 | if (cbNative > cbMax) |
| 1676 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1677 | |
| 1678 | // When the SAFEARRAY contains user defined types, the type of the |
| 1679 | // UDT can be specified in the SafeArrayUserDefinedSubType field. |
| 1680 | if (pNamedArgs[M_SafeArrayUserDefinedSubType].val.type.tag) |
| 1681 | { |
| 1682 | // Validate that this is only set for valid VT's. |
| 1683 | if (pNamedArgs[M_SafeArraySubType].val.i4 != VT_RECORD && |
| 1684 | pNamedArgs[M_SafeArraySubType].val.i4 != VT_DISPATCH && |
| 1685 | pNamedArgs[M_SafeArraySubType].val.i4 != VT_UNKNOWN) |
| 1686 | { |
| 1687 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1688 | } |
| 1689 | |
| 1690 | // Encode the size of the string. |
| 1691 | cch = pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr; |
| 1692 | cb = CorSigCompressData(cch, pbNative); |
| 1693 | if (cb == ((ULONG)(-1))) |
| 1694 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1695 | cbNative += cb; |
| 1696 | pbNative += cb; |
| 1697 | |
| 1698 | // Check that memcpy will fit and then encode the type name itself. |
| 1699 | if (ovadd_gt(cbNative, cch, cbMax)) |
| 1700 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1701 | memcpy(pbNative, pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.pStr, cch); |
| 1702 | cbNative += cch; |
| 1703 | pbNative += cch; |
| 1704 | _ASSERTE(cbNative <= cbMax); |
| 1705 | } |
| 1706 | } |
| 1707 | break; |
| 1708 | |
| 1709 | case NATIVE_TYPE_ARRAY: |
| 1710 | // Validate that the array sub type is not set. |
| 1711 | if (pNamedArgs[M_SafeArraySubType].val.type.tag) |
| 1712 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1713 | |
| 1714 | // Is there a sub type? |
| 1715 | if (pNamedArgs[M_ArraySubType].val.type.tag) |
| 1716 | { |
| 1717 | // Do some validation on the array sub type. |
| 1718 | if (pNamedArgs[M_ArraySubType].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER) |
| 1719 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1720 | |
| 1721 | // Put in the sub type. |
| 1722 | cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative); |
| 1723 | if (cb == ((ULONG)(-1))) |
| 1724 | { |
| 1725 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1726 | } |
| 1727 | cbNative += cb; |
| 1728 | pbNative += cb; |
| 1729 | } |
| 1730 | else |
| 1731 | { |
| 1732 | // Put in the sub type. |
| 1733 | cb = CorSigCompressData(NATIVE_TYPE_MAX, pbNative); |
| 1734 | if (cb == ((ULONG)(-1))) |
| 1735 | { |
| 1736 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1737 | } |
| 1738 | cbNative += cb; |
| 1739 | pbNative += cb; |
| 1740 | } |
| 1741 | if (cbNative > cbMax) |
| 1742 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1743 | |
| 1744 | // Is there a parameter index? |
| 1745 | if (pNamedArgs[M_SizeParamIndex].val.type.tag) |
| 1746 | { |
| 1747 | // Make sure the parameter index is not negative. |
| 1748 | if (pNamedArgs[M_SizeParamIndex].val.i4 < 0) |
| 1749 | IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX)); |
| 1750 | |
| 1751 | // Yes, put it in. |
| 1752 | cb = CorSigCompressData(pNamedArgs[M_SizeParamIndex].val.i2, pbNative); |
| 1753 | if (cb == ((ULONG)(-1))) |
| 1754 | { |
| 1755 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1756 | } |
| 1757 | cbNative += cb; |
| 1758 | pbNative += cb; |
| 1759 | if (cbNative > cbMax) |
| 1760 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1761 | |
| 1762 | // Is there a const? |
| 1763 | if (pNamedArgs[M_SizeConst].val.type.tag) |
| 1764 | { |
| 1765 | // Make sure the size is not negative. |
| 1766 | if (pNamedArgs[M_SizeConst].val.i4 < 0) |
| 1767 | IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE)); |
| 1768 | |
| 1769 | // Yes, put it in. |
| 1770 | cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative); |
| 1771 | if (cb == ((ULONG)(-1))) |
| 1772 | { |
| 1773 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1774 | } |
| 1775 | cbNative += cb; |
| 1776 | pbNative += cb; |
| 1777 | if (cbNative > cbMax) |
| 1778 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1779 | |
| 1780 | // Put in the flag indicating the size param index was specified. |
| 1781 | cb = CorSigCompressData((UINT16)ntaSizeParamIndexSpecified, pbNative); |
| 1782 | if (cb == ((ULONG)(-1))) |
| 1783 | { |
| 1784 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1785 | } |
| 1786 | cbNative += cb; |
| 1787 | pbNative += cb; |
| 1788 | if (cbNative > cbMax) |
| 1789 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1790 | } |
| 1791 | } |
| 1792 | else |
| 1793 | { |
| 1794 | // Is there a const? |
| 1795 | if (pNamedArgs[M_SizeConst].val.type.tag) |
| 1796 | { |
| 1797 | // Put in a param index of 0. |
| 1798 | cb = CorSigCompressData(0, pbNative); |
| 1799 | if (cb == ((ULONG)(-1))) |
| 1800 | { |
| 1801 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1802 | } |
| 1803 | cbNative += cb; |
| 1804 | pbNative += cb; |
| 1805 | if (cbNative > cbMax) |
| 1806 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1807 | |
| 1808 | // Put in the constant value. |
| 1809 | cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative); |
| 1810 | if (cb == ((ULONG)(-1))) |
| 1811 | { |
| 1812 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1813 | } |
| 1814 | cbNative += cb; |
| 1815 | pbNative += cb; |
| 1816 | if (cbNative > cbMax) |
| 1817 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1818 | |
| 1819 | // Set the flags field to 0 to indicate the size param index was not specified. |
| 1820 | cb = CorSigCompressData((UINT16)0, pbNative); |
| 1821 | if (cb == ((ULONG)(-1))) |
| 1822 | { |
| 1823 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1824 | } |
| 1825 | cbNative += cb; |
| 1826 | pbNative += cb; |
| 1827 | if (cbNative > cbMax) |
| 1828 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1829 | } |
| 1830 | } |
| 1831 | break; |
| 1832 | |
| 1833 | case NATIVE_TYPE_CUSTOMMARSHALER: |
| 1834 | // Validate that the marshaler type field is set. |
| 1835 | if (!pNamedArgs[M_MarshalType].val.type.tag && !pNamedArgs[M_MarshalTypeRef].val.type.tag) |
| 1836 | IfFailGo(PostError(META_E_CA_CUSTMARSH_TYPE_REQUIRED)); |
| 1837 | |
| 1838 | // Put in the place holder for the unmanaged typelib guid. |
| 1839 | cb = CorSigCompressData(0, pbNative); |
| 1840 | if (cb == ((ULONG)(-1))) |
| 1841 | { |
| 1842 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1843 | } |
| 1844 | cbNative += cb; |
| 1845 | pbNative += cb; |
| 1846 | if (cbNative > cbMax) |
| 1847 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1848 | |
| 1849 | // Put in the place holder for the unmanaged type name. |
| 1850 | cb = CorSigCompressData(0, pbNative); |
| 1851 | if (cb == ((ULONG)(-1))) |
| 1852 | { |
| 1853 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1854 | } |
| 1855 | cbNative += cb; |
| 1856 | pbNative += cb; |
| 1857 | if (cbNative > cbMax) |
| 1858 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1859 | |
| 1860 | // Put in the marshaler type name. |
| 1861 | if (pNamedArgs[M_MarshalType].val.type.tag) |
| 1862 | { |
| 1863 | cch = pNamedArgs[M_MarshalType].val.str.cbStr; |
| 1864 | cb = CorSigCompressData(cch, pbNative); |
| 1865 | if (cb == ((ULONG)(-1))) |
| 1866 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1867 | cbNative += cb; |
| 1868 | pbNative += cb; |
| 1869 | // Check that memcpy will fit. |
| 1870 | if ((cbNative+cch) > cbMax) |
| 1871 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1872 | memcpy(pbNative, pNamedArgs[M_MarshalType].val.str.pStr, cch); |
| 1873 | cbNative += cch; |
| 1874 | pbNative += cch; |
| 1875 | _ASSERTE(cbNative <= cbMax); |
| 1876 | } |
| 1877 | else |
| 1878 | { |
| 1879 | cch = pNamedArgs[M_MarshalTypeRef].val.str.cbStr; |
| 1880 | cb = CorSigCompressData(cch, pbNative); |
| 1881 | if (cb == ((ULONG)(-1))) |
| 1882 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1883 | cbNative += cb; |
| 1884 | pbNative += cb; |
| 1885 | // Check that memcpy will fit. |
| 1886 | if ((cbNative+cch) > cbMax) |
| 1887 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1888 | memcpy(pbNative, pNamedArgs[M_MarshalTypeRef].val.str.pStr, cch); |
| 1889 | cbNative += cch; |
| 1890 | pbNative += cch; |
| 1891 | _ASSERTE(cbNative <= cbMax); |
| 1892 | } |
| 1893 | |
| 1894 | // Put in the cookie. |
| 1895 | cch = pNamedArgs[M_MarshalCookie].val.str.cbStr; |
| 1896 | cb = CorSigCompressData(cch, pbNative); |
| 1897 | if (cb == ((ULONG)(-1))) |
| 1898 | { |
| 1899 | IfFailGo(PostError(META_E_CA_INVALID_BLOB)); |
| 1900 | } |
| 1901 | cbNative += cb; |
| 1902 | pbNative += cb; |
| 1903 | // Check that memcpy will fit. |
| 1904 | if ((cbNative+cch) > cbMax) |
| 1905 | IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS)); |
| 1906 | memcpy(pbNative, pNamedArgs[M_MarshalCookie].val.str.pStr, cch); |
| 1907 | cbNative += cch; |
| 1908 | pbNative += cch; |
| 1909 | break; |
| 1910 | } |
| 1911 | _ASSERTE(cbNative <= cbMax); |
| 1912 | |
| 1913 | // Resize to actual size. |
| 1914 | IfFailGo(qNativeType.ReSizeNoThrow(cbNative)); |
| 1915 | |
| 1916 | // Now apply the native type to actual token. If it is a property token, |
| 1917 | // apply to the methods. |
| 1918 | switch (TypeFromToken(tkObj)) |
| 1919 | { |
| 1920 | case mdtParamDef: |
| 1921 | case mdtFieldDef: |
| 1922 | IfFailGo(_SetFieldMarshal(tkObj, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size())); |
| 1923 | break; |
| 1924 | |
| 1925 | case mdtProperty: |
| 1926 | // Get any setter/getter methods. |
| 1927 | IfFailGo(GetPropertyProps(tkObj, 0,0,0,0,0,0,0,0,0,0, &tkSetter, &tkGetter, 0,0,0)); |
| 1928 | // For getter, put the field marshal on the return value. |
| 1929 | if (!IsNilToken(tkGetter)) |
| 1930 | { |
| 1931 | // Search for first param. |
| 1932 | mdToken tk; |
| 1933 | tkParam = mdParamDefNil; |
| 1934 | do { |
| 1935 | IfFailGo(EnumParams(&phEnum, tkGetter, &tk, 1, &cParams)); |
| 1936 | if (cParams > 0) |
| 1937 | { |
| 1938 | IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0)); |
| 1939 | if (ulSeq == 0) |
| 1940 | { |
| 1941 | tkParam = tk; |
| 1942 | break; |
| 1943 | } |
| 1944 | } |
| 1945 | |
| 1946 | } while (hr == S_OK); |
| 1947 | if (!IsNilToken(tkParam)) |
| 1948 | IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size())); |
| 1949 | CloseEnum(phEnum); |
| 1950 | phEnum = 0; |
| 1951 | } |
| 1952 | if (!IsNilToken(tkSetter)) |
| 1953 | { |
| 1954 | // Determine the last param. |
| 1955 | PCCOR_SIGNATURE pSig; |
| 1956 | ULONG cbSig; |
| 1957 | mdToken tk; |
| 1958 | ULONG iSeq; |
| 1959 | IfFailGo(GetMethodProps(tkSetter, 0,0,0,0,0, &pSig,&cbSig, 0,0)); |
| 1960 | tkParam = mdParamDefNil; |
| 1961 | CorSigUncompressData(pSig+1, &iSeq); |
| 1962 | // Search for last param. |
| 1963 | if (iSeq != 0) |
| 1964 | { |
| 1965 | do { |
| 1966 | IfFailGo(EnumParams(&phEnum, tkSetter, &tk, 1, &cParams)); |
| 1967 | if (cParams > 0) |
| 1968 | { |
| 1969 | IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0)); |
| 1970 | if (ulSeq == iSeq) |
| 1971 | { |
| 1972 | tkParam = tk; |
| 1973 | break; |
| 1974 | } |
| 1975 | } |
| 1976 | } while (hr == S_OK); |
| 1977 | } |
| 1978 | // If found one that is not return value |
| 1979 | if (!IsNilToken(tkParam)) |
| 1980 | IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size())); |
| 1981 | CloseEnum(phEnum); |
| 1982 | phEnum = 0; |
| 1983 | } |
| 1984 | break; |
| 1985 | |
| 1986 | default: |
| 1987 | _ASSERTE(!"Should not have this token type in _HandleNativeTypeCustomAttribute()" ); |
| 1988 | break; |
| 1989 | } |
| 1990 | |
| 1991 | ErrExit: |
| 1992 | if (phEnum) |
| 1993 | CloseEnum(phEnum); |
| 1994 | return hr; |
| 1995 | } // RegMeta::_HandleNativeTypeCustomAttribute |
| 1996 | #ifdef _PREFAST_ |
| 1997 | #pragma warning(pop) |
| 1998 | #endif |
| 1999 | |
| 2000 | #endif //FEATURE_METADATA_EMIT |
| 2001 | |