// this function takes a pointer to a templated array (ie. a pointer to a list of Types, and a length) // and returns an array of that object type, and cleans up the memory if specified. public static object GetTemplatedArray(IntPtr sourcePtr, Type structureType, bool freeMem) { templated_array arr = (templated_array)Marshal.PtrToStructure(sourcePtr, typeof(templated_array)); if (structureType == typeof(byte)) { byte[] val = new byte[arr.count]; if (val.Length > 0) { Marshal.Copy(arr.elems, val, 0, val.Length); } return(val); } else { Array val = Array.CreateInstance(structureType, arr.count); int sizeInBytes = SizeOf(structureType); for (int i = 0; i < val.Length; i++) { IntPtr p = new IntPtr((arr.elems.ToInt64() + i * sizeInBytes)); val.SetValue(PtrToStructure(p, structureType, freeMem), i); } if (freeMem) { RENDERDOC_FreeArrayMem(arr.elems); } return(val); } }
// specific versions of the above GetTemplatedArray for convenience. public static string TemplatedArrayToString(IntPtr sourcePtr, bool freeMem) { templated_array arr = (templated_array)Marshal.PtrToStructure(sourcePtr, typeof(templated_array)); string val = PtrToStringUTF8(arr.elems, arr.count); if (freeMem) { RENDERDOC_FreeArrayMem(arr.elems); } return(val); }
public static string[] TemplatedArrayToStringArray(IntPtr sourcePtr, bool freeMem) { templated_array arr = (templated_array)Marshal.PtrToStructure(sourcePtr, typeof(templated_array)); int arrSize = SizeOf(typeof(templated_array)); string[] ret = new string[arr.count]; for (int i = 0; i < arr.count; i++) { IntPtr ptr = new IntPtr((arr.elems.ToInt64() + i * arrSize)); ret[i] = TemplatedArrayToString(ptr, freeMem); } if (freeMem) { RENDERDOC_FreeArrayMem(arr.elems); } return(ret); }
// take a pointer to a C++ structure of a given type, and convert it into the managed equivalent, // while handling alignment etc and freeing memory returned if it should be caller-freed private static object PtrToStructure(IntPtr sourcePtr, Type structureType, bool freeMem, bool isUnion) { if (sourcePtr == IntPtr.Zero) { return(null); } // Get instance fields of the structure type. FieldInfo[] fields = structureType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); object ret = Activator.CreateInstance(structureType); try { for (int fieldIdx = 0; fieldIdx < fields.Length; fieldIdx++) { FieldInfo field = fields[fieldIdx]; IntPtr fieldPtr = isUnion ? sourcePtr : OffsetPtr(structureType, fields, fieldIdx, sourcePtr); var arrayType = NonArrayType(field.FieldType); int sizeInBytes = SizeOf(arrayType); // no custom attribute, so just use the regular Marshal code var cma = GetCustomAttr(structureType, fields, fieldIdx); if (cma == null) { if (field.FieldType.IsEnum) { field.SetValue(ret, (VarType)Marshal.ReadInt32(fieldPtr)); } else { field.SetValue(ret, Marshal.PtrToStructure(fieldPtr, field.FieldType)); } } else { switch (cma.CustomType) { case CustomUnmanagedType.CustomClass: field.SetValue(ret, PtrToStructure(fieldPtr, field.FieldType, freeMem)); break; case CustomUnmanagedType.CustomClassPointer: IntPtr ptr = Marshal.ReadIntPtr(fieldPtr); if (ptr == IntPtr.Zero) { field.SetValue(ret, null); } else { field.SetValue(ret, PtrToStructure(ptr, field.FieldType, freeMem)); } break; case CustomUnmanagedType.Union: field.SetValue(ret, PtrToStructure(fieldPtr, field.FieldType, freeMem, true)); break; case CustomUnmanagedType.Skip: break; case CustomUnmanagedType.FixedArray: { if (cma.FixedType == CustomFixedType.Float) { float[] val = new float[cma.FixedLength]; Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); field.SetValue(ret, val); } else if (cma.FixedType == CustomFixedType.UInt16) { Int16[] val = new Int16[cma.FixedLength]; Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); UInt16[] realval = new UInt16[cma.FixedLength]; for (int i = 0; i < val.Length; i++) { realval[i] = unchecked ((UInt16)val[i]); } field.SetValue(ret, val); } else if (cma.FixedType == CustomFixedType.Int32) { Int32[] val = new Int32[cma.FixedLength]; Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); field.SetValue(ret, val); } else if (cma.FixedType == CustomFixedType.Double) { double[] val = new double[cma.FixedLength]; Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); field.SetValue(ret, val); } else if (cma.FixedType == CustomFixedType.UInt32) { Int32[] val = new Int32[cma.FixedLength]; Marshal.Copy(fieldPtr, val, 0, cma.FixedLength); UInt32[] realval = new UInt32[cma.FixedLength]; for (int i = 0; i < val.Length; i++) { realval[i] = unchecked ((UInt32)val[i]); } field.SetValue(ret, realval); } else { Array val = Array.CreateInstance(arrayType, cma.FixedLength); for (int i = 0; i < val.Length; i++) { IntPtr p = new IntPtr((fieldPtr.ToInt64() + i * sizeInBytes)); val.SetValue(PtrToStructure(p, arrayType, freeMem), i); } field.SetValue(ret, val); } break; } case CustomUnmanagedType.UTF8TemplatedString: case CustomUnmanagedType.TemplatedArray: { // templated_array must be pointer-aligned long alignment = fieldPtr.ToInt64() % IntPtr.Size; if (alignment != 0) { fieldPtr = new IntPtr(fieldPtr.ToInt64() + IntPtr.Size - alignment); } templated_array arr = (templated_array)Marshal.PtrToStructure(fieldPtr, typeof(templated_array)); if (field.FieldType == typeof(string)) { if (arr.elems == IntPtr.Zero) { field.SetValue(ret, ""); } else { field.SetValue(ret, PtrToStringUTF8(arr.elems, arr.count)); } } else { if (field.FieldType.IsArray && arrayType == typeof(byte)) { byte[] val = new byte[arr.count]; if (val.Length > 0) { Marshal.Copy(arr.elems, val, 0, val.Length); } field.SetValue(ret, val); } else if (field.FieldType.IsArray) { Array val = Array.CreateInstance(arrayType, arr.count); for (int i = 0; i < val.Length; i++) { IntPtr p = new IntPtr((arr.elems.ToInt64() + i * sizeInBytes)); val.SetValue(PtrToStructure(p, arrayType, freeMem), i); } field.SetValue(ret, val); } else { throw new NotImplementedException("non-array element marked to marshal as TemplatedArray"); } } if (freeMem) { RENDERDOC_FreeArrayMem(arr.elems); } break; } default: throw new NotImplementedException("Unexpected attribute"); } } } MethodInfo postMarshal = structureType.GetMethod("PostMarshal", BindingFlags.NonPublic | BindingFlags.Instance); if (postMarshal != null) { postMarshal.Invoke(ret, new object[] { }); } } catch (Exception ex) { System.Diagnostics.Debug.Fail(ex.Message); } return(ret); }