2 Copyright (C) 2008-2011 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using System.Collections.Generic;
26 using System.Runtime.InteropServices;
28 using IKVM.Reflection.Emit;
29 using IKVM.Reflection.Reader;
30 using IKVM.Reflection.Writer;
31 using IKVM.Reflection.Metadata;
33 namespace IKVM.Reflection
35 static class MarshalSpec
37 private const UnmanagedType NATIVE_TYPE_MAX = (UnmanagedType)0x50;
39 internal static CustomAttributeData GetMarshalAsAttribute(Module module, int token)
41 foreach (int i in module.FieldMarshal.Filter(token))
43 ByteReader blob = module.GetBlob(module.FieldMarshal.records[i].NativeType);
44 UnmanagedType unmanagedType = (UnmanagedType)blob.ReadCompressedInt();
45 UnmanagedType? arraySubType = null;
46 short? sizeParamIndex = null;
47 int? sizeConst = null;
48 VarEnum? safeArraySubType = null;
49 Type safeArrayUserDefinedSubType = null;
50 int? iidParameterIndex = null;
51 string marshalType = null;
52 string marshalCookie = null;
53 Type marshalTypeRef = null;
54 if (unmanagedType == UnmanagedType.LPArray)
56 arraySubType = (UnmanagedType)blob.ReadCompressedInt();
57 if (arraySubType == NATIVE_TYPE_MAX)
63 sizeParamIndex = (short)blob.ReadCompressedInt();
66 sizeConst = blob.ReadCompressedInt();
67 if (blob.Length != 0 && blob.ReadCompressedInt() == 0)
69 sizeParamIndex = null;
74 else if (unmanagedType == UnmanagedType.SafeArray)
78 safeArraySubType = (VarEnum)blob.ReadCompressedInt();
81 safeArrayUserDefinedSubType = ReadType(module, blob);
85 else if (unmanagedType == UnmanagedType.ByValArray)
87 sizeConst = blob.ReadCompressedInt();
90 arraySubType = (UnmanagedType)blob.ReadCompressedInt();
93 else if (unmanagedType == UnmanagedType.ByValTStr)
95 sizeConst = blob.ReadCompressedInt();
97 else if (unmanagedType == UnmanagedType.Interface
98 || unmanagedType == UnmanagedType.IDispatch
99 || unmanagedType == UnmanagedType.IUnknown)
101 if (blob.Length != 0)
103 iidParameterIndex = blob.ReadCompressedInt();
106 else if (unmanagedType == UnmanagedType.CustomMarshaler)
108 blob.ReadCompressedInt();
109 blob.ReadCompressedInt();
110 marshalType = ReadString(blob);
111 marshalCookie = ReadString(blob);
113 TypeNameParser parser = TypeNameParser.Parse(marshalType, false);
116 marshalTypeRef = parser.GetType(module.universe, module.Assembly, false, marshalType, false, false);
120 Type typeofMarshalAs = module.universe.System_Runtime_InteropServices_MarshalAsAttribute;
121 Type typeofUnmanagedType = module.universe.System_Runtime_InteropServices_UnmanagedType;
122 Type typeofVarEnum = module.universe.System_Runtime_InteropServices_VarEnum;
123 Type typeofType = module.universe.System_Type;
124 List<CustomAttributeNamedArgument> named = new List<CustomAttributeNamedArgument>();
125 if (arraySubType != null)
127 AddNamedArgument(named, typeofMarshalAs, "ArraySubType", typeofUnmanagedType, arraySubType.Value);
129 if (sizeParamIndex != null)
131 AddNamedArgument(named, typeofMarshalAs, "SizeParamIndex", module.universe.System_Int16, sizeParamIndex.Value);
133 if (sizeConst != null)
135 AddNamedArgument(named, typeofMarshalAs, "SizeConst", module.universe.System_Int32, sizeConst.Value);
137 if (safeArraySubType != null)
139 AddNamedArgument(named, typeofMarshalAs, "SafeArraySubType", typeofVarEnum, safeArraySubType.Value);
141 if (safeArrayUserDefinedSubType != null)
143 AddNamedArgument(named, typeofMarshalAs, "SafeArrayUserDefinedSubType", typeofType, safeArrayUserDefinedSubType);
145 if (iidParameterIndex != null)
147 AddNamedArgument(named, typeofMarshalAs, "IidParameterIndex", module.universe.System_Int32, iidParameterIndex.Value);
149 if (marshalType != null)
151 AddNamedArgument(named, typeofMarshalAs, "MarshalType", module.universe.System_String, marshalType);
153 if (marshalTypeRef != null)
155 AddNamedArgument(named, typeofMarshalAs, "MarshalTypeRef", module.universe.System_Type, marshalTypeRef);
157 if (marshalCookie != null)
159 AddNamedArgument(named, typeofMarshalAs, "MarshalCookie", module.universe.System_String, marshalCookie);
161 ConstructorInfo constructor = typeofMarshalAs.GetPseudoCustomAttributeConstructor(typeofUnmanagedType);
162 return new CustomAttributeData(module, constructor, new object[] { unmanagedType }, named);
164 throw new BadImageFormatException();
167 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type attributeType, string fieldName, Type valueType, object value)
169 // some fields are not available on the .NET Compact Framework version of MarshalAsAttribute
170 FieldInfo field = attributeType.FindField(fieldName, FieldSignature.Create(valueType, new CustomModifiers()));
173 list.Add(new CustomAttributeNamedArgument(field, new CustomAttributeTypedArgument(valueType, value)));
177 internal static void SetMarshalAsAttribute(ModuleBuilder module, int token, CustomAttributeBuilder attribute)
179 attribute = attribute.DecodeBlob(module.Assembly);
180 FieldMarshalTable.Record rec = new FieldMarshalTable.Record();
182 rec.NativeType = WriteMarshallingDescriptor(module, attribute);
183 module.FieldMarshal.AddRecord(rec);
186 private static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute)
188 UnmanagedType unmanagedType;
189 object val = attribute.GetConstructorArgument(0);
192 unmanagedType = (UnmanagedType)(short)val;
196 unmanagedType = (UnmanagedType)(int)val;
200 unmanagedType = (UnmanagedType)val;
203 ByteBuffer bb = new ByteBuffer(5);
204 bb.WriteCompressedInt((int)unmanagedType);
206 if (unmanagedType == UnmanagedType.LPArray)
208 UnmanagedType arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType") ?? NATIVE_TYPE_MAX;
209 bb.WriteCompressedInt((int)arraySubType);
210 int? sizeParamIndex = attribute.GetFieldValue<short>("SizeParamIndex");
211 int? sizeConst = attribute.GetFieldValue<int>("SizeConst");
212 if (sizeParamIndex != null)
214 bb.WriteCompressedInt(sizeParamIndex.Value);
215 if (sizeConst != null)
217 bb.WriteCompressedInt(sizeConst.Value);
218 bb.WriteCompressedInt(1); // flag that says that SizeParamIndex was specified
221 else if (sizeConst != null)
223 bb.WriteCompressedInt(0); // SizeParamIndex
224 bb.WriteCompressedInt(sizeConst.Value);
225 bb.WriteCompressedInt(0); // flag that says that SizeParamIndex was not specified
228 else if (unmanagedType == UnmanagedType.SafeArray)
230 VarEnum? safeArraySubType = attribute.GetFieldValue<VarEnum>("SafeArraySubType");
231 if (safeArraySubType != null)
233 bb.WriteCompressedInt((int)safeArraySubType);
234 Type safeArrayUserDefinedSubType = (Type)attribute.GetFieldValue("SafeArrayUserDefinedSubType");
235 if (safeArrayUserDefinedSubType != null)
237 WriteType(module, bb, safeArrayUserDefinedSubType);
241 else if (unmanagedType == UnmanagedType.ByValArray)
243 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst") ?? 1);
244 UnmanagedType? arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType");
245 if (arraySubType != null)
247 bb.WriteCompressedInt((int)arraySubType);
250 else if (unmanagedType == UnmanagedType.ByValTStr)
252 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst").Value);
254 else if (unmanagedType == UnmanagedType.Interface
255 || unmanagedType == UnmanagedType.IDispatch
256 || unmanagedType == UnmanagedType.IUnknown)
258 int? iidParameterIndex = attribute.GetFieldValue<int>("IidParameterIndex");
259 if (iidParameterIndex != null)
261 bb.WriteCompressedInt(iidParameterIndex.Value);
264 else if (unmanagedType == UnmanagedType.CustomMarshaler)
266 bb.WriteCompressedInt(0);
267 bb.WriteCompressedInt(0);
268 string marshalType = (string)attribute.GetFieldValue("MarshalType");
269 if (marshalType != null)
271 WriteString(bb, marshalType);
275 WriteType(module, bb, (Type)attribute.GetFieldValue("MarshalTypeRef"));
277 WriteString(bb, (string)attribute.GetFieldValue("MarshalCookie") ?? "");
280 return module.Blobs.Add(bb);
283 private static Type ReadType(Module module, ByteReader br)
285 string str = ReadString(br);
290 return module.Assembly.GetType(str) ?? module.universe.GetType(str, true);
293 private static void WriteType(Module module, ByteBuffer bb, Type type)
295 WriteString(bb, type.Assembly == module.Assembly ? type.FullName : type.AssemblyQualifiedName);
298 private static string ReadString(ByteReader br)
300 return Encoding.UTF8.GetString(br.ReadBytes(br.ReadCompressedInt()));
303 private static void WriteString(ByteBuffer bb, string str)
305 byte[] buf = Encoding.UTF8.GetBytes(str);
306 bb.WriteCompressedInt(buf.Length);