2 Copyright (C) 2008, 2010 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 // TODO use binary search?
42 for (int i = 0; i < module.FieldMarshal.records.Length; i++)
44 if (module.FieldMarshal.records[i].Parent == token)
46 ByteReader blob = module.GetBlob(module.FieldMarshal.records[i].NativeType);
47 UnmanagedType unmanagedType = (UnmanagedType)blob.ReadCompressedInt();
48 UnmanagedType? arraySubType = null;
49 short? sizeParamIndex = null;
50 int? sizeConst = null;
51 VarEnum? safeArraySubType = null;
52 Type safeArrayUserDefinedSubType = null;
53 int? iidParameterIndex = null;
54 string marshalType = null;
55 string marshalCookie = null;
56 Type marshalTypeRef = null;
57 if (unmanagedType == UnmanagedType.LPArray)
59 arraySubType = (UnmanagedType)blob.ReadCompressedInt();
60 if (arraySubType == NATIVE_TYPE_MAX)
66 sizeParamIndex = (short)blob.ReadCompressedInt();
69 sizeConst = blob.ReadCompressedInt();
70 if (blob.Length != 0 && blob.ReadCompressedInt() == 0)
72 sizeParamIndex = null;
77 else if (unmanagedType == UnmanagedType.SafeArray)
81 safeArraySubType = (VarEnum)blob.ReadCompressedInt();
84 safeArrayUserDefinedSubType = ReadType(module, blob);
88 else if (unmanagedType == UnmanagedType.ByValArray)
90 sizeConst = blob.ReadCompressedInt();
93 arraySubType = (UnmanagedType)blob.ReadCompressedInt();
96 else if (unmanagedType == UnmanagedType.ByValTStr)
98 sizeConst = blob.ReadCompressedInt();
100 else if (unmanagedType == UnmanagedType.Interface
101 || unmanagedType == UnmanagedType.IDispatch
102 || unmanagedType == UnmanagedType.IUnknown)
104 if (blob.Length != 0)
106 iidParameterIndex = blob.ReadCompressedInt();
109 else if (unmanagedType == UnmanagedType.CustomMarshaler)
111 blob.ReadCompressedInt();
112 blob.ReadCompressedInt();
113 marshalType = ReadString(blob);
114 marshalCookie = ReadString(blob);
115 marshalTypeRef = module.Assembly.GetType(marshalType) ?? module.universe.GetType(marshalType);
118 Type typeofMarshalAs = module.universe.System_Runtime_InteropServices_MarshalAsAttribute;
119 Type typeofUnmanagedType = module.universe.System_Runtime_InteropServices_UnmanagedType;
120 Type typeofVarEnum = module.universe.System_Runtime_InteropServices_VarEnum;
121 Type typeofType = module.universe.System_Type;
122 List<CustomAttributeNamedArgument> named = new List<CustomAttributeNamedArgument>();
123 if (arraySubType != null)
125 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("ArraySubType"), new CustomAttributeTypedArgument(typeofUnmanagedType, arraySubType.Value)));
127 if (sizeParamIndex != null)
129 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SizeParamIndex"), new CustomAttributeTypedArgument(module.universe.System_Int16, sizeParamIndex.Value)));
131 if (sizeConst != null)
133 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SizeConst"), new CustomAttributeTypedArgument(module.universe.System_Int32, sizeConst.Value)));
135 if (safeArraySubType != null)
137 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SafeArraySubType"), new CustomAttributeTypedArgument(typeofVarEnum, safeArraySubType.Value)));
139 if (safeArrayUserDefinedSubType != null)
141 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SafeArrayUserDefinedSubType"), new CustomAttributeTypedArgument(typeofType, safeArrayUserDefinedSubType)));
143 if (iidParameterIndex != null)
145 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("IidParameterIndex"), new CustomAttributeTypedArgument(module.universe.System_Int32, iidParameterIndex.Value)));
147 if (marshalType != null)
149 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("MarshalType"), new CustomAttributeTypedArgument(module.universe.System_String, marshalType)));
151 if (marshalTypeRef != null)
153 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("MarshalTypeRef"), new CustomAttributeTypedArgument(module.universe.System_Type, marshalTypeRef)));
155 if (marshalCookie != null)
157 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("MarshalCookie"), new CustomAttributeTypedArgument(module.universe.System_String, marshalCookie)));
159 ConstructorInfo constructor = typeofMarshalAs.GetConstructor(new Type[] { typeofUnmanagedType });
160 return new CustomAttributeData(constructor, new object[] { unmanagedType }, named);
163 throw new BadImageFormatException();
166 internal static void SetMarshalAsAttribute(ModuleBuilder module, int token, CustomAttributeBuilder attribute)
168 attribute = attribute.DecodeBlob(module.Assembly);
169 FieldMarshalTable.Record rec = new FieldMarshalTable.Record();
171 rec.NativeType = WriteMarshallingDescriptor(module, attribute);
172 module.FieldMarshal.AddRecord(rec);
175 private static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute)
177 UnmanagedType unmanagedType;
178 object val = attribute.GetConstructorArgument(0);
181 unmanagedType = (UnmanagedType)(short)val;
185 unmanagedType = (UnmanagedType)(int)val;
189 unmanagedType = (UnmanagedType)val;
192 ByteBuffer bb = new ByteBuffer(5);
193 bb.WriteCompressedInt((int)unmanagedType);
195 if (unmanagedType == UnmanagedType.LPArray)
197 UnmanagedType arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType") ?? NATIVE_TYPE_MAX;
198 bb.WriteCompressedInt((int)arraySubType);
199 int? sizeParamIndex = attribute.GetFieldValue<short>("SizeParamIndex");
200 int? sizeConst = attribute.GetFieldValue<int>("SizeConst");
201 if (sizeParamIndex != null)
203 bb.WriteCompressedInt(sizeParamIndex.Value);
204 if (sizeConst != null)
206 bb.WriteCompressedInt(sizeConst.Value);
207 bb.WriteCompressedInt(1); // flag that says that SizeParamIndex was specified
210 else if (sizeConst != null)
212 bb.WriteCompressedInt(0); // SizeParamIndex
213 bb.WriteCompressedInt(sizeConst.Value);
214 bb.WriteCompressedInt(0); // flag that says that SizeParamIndex was not specified
217 else if (unmanagedType == UnmanagedType.SafeArray)
219 VarEnum? safeArraySubType = attribute.GetFieldValue<VarEnum>("SafeArraySubType");
220 if (safeArraySubType != null)
222 bb.WriteCompressedInt((int)safeArraySubType);
223 Type safeArrayUserDefinedSubType = (Type)attribute.GetFieldValue("SafeArrayUserDefinedSubType");
224 if (safeArrayUserDefinedSubType != null)
226 WriteType(module, bb, safeArrayUserDefinedSubType);
230 else if (unmanagedType == UnmanagedType.ByValArray)
232 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst") ?? 1);
233 UnmanagedType? arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType");
234 if (arraySubType != null)
236 bb.WriteCompressedInt((int)arraySubType);
239 else if (unmanagedType == UnmanagedType.ByValTStr)
241 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst").Value);
243 else if (unmanagedType == UnmanagedType.Interface
244 || unmanagedType == UnmanagedType.IDispatch
245 || unmanagedType == UnmanagedType.IUnknown)
247 int? iidParameterIndex = attribute.GetFieldValue<int>("IidParameterIndex");
248 if (iidParameterIndex != null)
250 bb.WriteCompressedInt(iidParameterIndex.Value);
253 else if (unmanagedType == UnmanagedType.CustomMarshaler)
255 bb.WriteCompressedInt(0);
256 bb.WriteCompressedInt(0);
257 string marshalType = (string)attribute.GetFieldValue("MarshalType");
258 if (marshalType != null)
260 WriteString(bb, marshalType);
264 WriteType(module, bb, (Type)attribute.GetFieldValue("MarshalTypeRef"));
266 WriteString(bb, (string)attribute.GetFieldValue("MarshalCookie") ?? "");
269 return module.Blobs.Add(bb);
272 private static Type ReadType(Module module, ByteReader br)
274 string str = ReadString(br);
279 return module.Assembly.GetType(str) ?? module.universe.GetType(str, true);
282 private static void WriteType(Module module, ByteBuffer bb, Type type)
284 WriteString(bb, type.Assembly == module.Assembly ? type.FullName : type.AssemblyQualifiedName);
287 private static string ReadString(ByteReader br)
289 return Encoding.UTF8.GetString(br.ReadBytes(br.ReadCompressedInt()));
292 private static void WriteString(ByteBuffer bb, string str)
294 byte[] buf = Encoding.UTF8.GetBytes(str);
295 bb.WriteCompressedInt(buf.Length);