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 | |