// ReSharper disable once InconsistentNaming public static IntPtr MarshalCLRToV8(object clrObject, out V8Type v8Type) { if (clrObject == null) { v8Type = V8Type.Null; return IntPtr.Zero; } else if (clrObject is string) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi((string) clrObject); } else if (clrObject is char) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi(clrObject.ToString()); } else if (clrObject is bool) { v8Type = V8Type.Boolean; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (int)); Marshal.WriteInt32(memoryLocation, ((bool) clrObject) ? 1 : 0); return memoryLocation; } else if (clrObject is Guid) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi(clrObject.ToString()); } else if (clrObject is DateTime) { v8Type = V8Type.Date; DateTime dateTime = (DateTime) clrObject; if (dateTime.Kind == DateTimeKind.Local) { dateTime = dateTime.ToUniversalTime(); } else if (dateTime.Kind == DateTimeKind.Unspecified) { dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc); } long ticks = (dateTime.Ticks - MinDateTimeTicks)/10000; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (double)); WriteDouble(memoryLocation, ticks); return memoryLocation; } else if (clrObject is DateTimeOffset) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi(clrObject.ToString()); } else if (clrObject is Uri) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi(clrObject.ToString()); } else if (clrObject is short) { v8Type = V8Type.Int32; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (int)); Marshal.WriteInt32(memoryLocation, Convert.ToInt32(clrObject)); return memoryLocation; } else if (clrObject is int) { v8Type = V8Type.Int32; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (int)); Marshal.WriteInt32(memoryLocation, (int) clrObject); return memoryLocation; } else if (clrObject is long) { v8Type = V8Type.Number; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (double)); WriteDouble(memoryLocation, Convert.ToDouble((long) clrObject)); return memoryLocation; } else if (clrObject is double) { v8Type = V8Type.Number; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (double)); WriteDouble(memoryLocation, (double) clrObject); return memoryLocation; } else if (clrObject is float) { v8Type = V8Type.Number; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof (double)); WriteDouble(memoryLocation, Convert.ToDouble((Single) clrObject)); return memoryLocation; } else if (clrObject is decimal) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi(clrObject.ToString()); } else if (clrObject is Enum) { v8Type = V8Type.String; return Marshal.StringToHGlobalAnsi(clrObject.ToString()); } else if (clrObject is byte[] || clrObject is IEnumerable<byte>) { v8Type = V8Type.Buffer; V8BufferData bufferData = new V8BufferData(); byte[] buffer; if (clrObject is byte[]) { buffer = (byte[]) clrObject; } else { buffer = ((IEnumerable<byte>) clrObject).ToArray(); } bufferData.bufferLength = buffer.Length; bufferData.buffer = Marshal.AllocHGlobal(buffer.Length*sizeof (byte)); Marshal.Copy(buffer, 0, bufferData.buffer, bufferData.bufferLength); IntPtr destinationPointer = Marshal.AllocHGlobal(V8BufferDataSize); Marshal.StructureToPtr(bufferData, destinationPointer, false); return destinationPointer; } else if (clrObject is IDictionary || clrObject is ExpandoObject) { v8Type = V8Type.Object; IEnumerable keys; int keyCount; Func<object, object> getValue; if (clrObject is ExpandoObject) { IDictionary<string, object> objectDictionary = (IDictionary<string, object>) clrObject; keys = objectDictionary.Keys; keyCount = objectDictionary.Keys.Count; getValue = index => objectDictionary[index.ToString()]; } else { IDictionary objectDictionary = (IDictionary) clrObject; keys = objectDictionary.Keys; keyCount = objectDictionary.Keys.Count; getValue = index => objectDictionary[index]; } V8ObjectData objectData = new V8ObjectData(); int counter = 0; objectData.propertiesCount = keyCount; objectData.propertyNames = Marshal.AllocHGlobal(PointerSize*keyCount); objectData.propertyTypes = Marshal.AllocHGlobal(sizeof (int)*keyCount); objectData.propertyValues = Marshal.AllocHGlobal(PointerSize*keyCount); foreach (object key in keys) { Marshal.WriteIntPtr(objectData.propertyNames, counter*PointerSize, Marshal.StringToHGlobalAnsi(key.ToString())); V8Type propertyType; Marshal.WriteIntPtr(objectData.propertyValues, counter*PointerSize, MarshalCLRToV8(getValue(key), out propertyType)); Marshal.WriteInt32(objectData.propertyTypes, counter*sizeof (int), (int) propertyType); counter++; } IntPtr destinationPointer = Marshal.AllocHGlobal(V8ObjectDataSize); Marshal.StructureToPtr(objectData, destinationPointer, false); return destinationPointer; } else if (clrObject is IEnumerable) { v8Type = V8Type.Array; V8ArrayData arrayData = new V8ArrayData(); List<IntPtr> itemValues = new List<IntPtr>(); List<int> itemTypes = new List<int>(); foreach (object item in (IEnumerable) clrObject) { V8Type itemType; itemValues.Add(MarshalCLRToV8(item, out itemType)); itemTypes.Add((int) itemType); } arrayData.arrayLength = itemValues.Count; arrayData.itemTypes = Marshal.AllocHGlobal(sizeof (int)*arrayData.arrayLength); arrayData.itemValues = Marshal.AllocHGlobal(PointerSize*arrayData.arrayLength); Marshal.Copy(itemTypes.ToArray(), 0, arrayData.itemTypes, arrayData.arrayLength); Marshal.Copy(itemValues.ToArray(), 0, arrayData.itemValues, arrayData.arrayLength); IntPtr destinationPointer = Marshal.AllocHGlobal(V8ArrayDataSize); Marshal.StructureToPtr(arrayData, destinationPointer, false); return destinationPointer; } else if (clrObject.GetType().GetTypeInfo().IsGenericType && clrObject.GetType().GetGenericTypeDefinition() == typeof (Func<,>)) { Func<object, Task<object>> funcObject = clrObject as Func<object, Task<object>>; if (funcObject == null) { throw new Exception("Properties that return Func<> instances must return Func<object, Task<object>> instances"); } v8Type = V8Type.Function; return GCHandle.ToIntPtr(GCHandle.Alloc(funcObject)); } else { v8Type = clrObject is Exception ? V8Type.Exception : V8Type.Object; if (clrObject is Exception) { AggregateException aggregateException = clrObject as AggregateException; if (aggregateException?.InnerExceptions != null && aggregateException.InnerExceptions.Count > 0) { clrObject = aggregateException.InnerExceptions[0]; } else { TargetInvocationException targetInvocationException = clrObject as TargetInvocationException; if (targetInvocationException?.InnerException != null) { clrObject = targetInvocationException.InnerException; } } } List<Tuple<string, Func<object, object>>> propertyAccessors = GetPropertyAccessors(clrObject.GetType()); V8ObjectData objectData = new V8ObjectData(); int counter = 0; objectData.propertiesCount = propertyAccessors.Count; objectData.propertyNames = Marshal.AllocHGlobal(PointerSize*propertyAccessors.Count); objectData.propertyTypes = Marshal.AllocHGlobal(sizeof (int)*propertyAccessors.Count); objectData.propertyValues = Marshal.AllocHGlobal(PointerSize*propertyAccessors.Count); foreach (Tuple<string, Func<object, object>> propertyAccessor in propertyAccessors) { Marshal.WriteIntPtr(objectData.propertyNames, counter*PointerSize, Marshal.StringToHGlobalAnsi(propertyAccessor.Item1)); V8Type propertyType; Marshal.WriteIntPtr(objectData.propertyValues, counter*PointerSize, MarshalCLRToV8(propertyAccessor.Item2(clrObject), out propertyType)); Marshal.WriteInt32(objectData.propertyTypes, counter*sizeof (int), (int) propertyType); counter++; } IntPtr destinationPointer = Marshal.AllocHGlobal(V8ObjectDataSize); Marshal.StructureToPtr(objectData, destinationPointer, false); return destinationPointer; } }
public static void FreeMarshalData(IntPtr marshalData, int v8Type) { switch ((V8Type)v8Type) { case V8Type.String: case V8Type.Int32: case V8Type.Boolean: case V8Type.Number: case V8Type.Date: Marshal.FreeHGlobal(marshalData); break; case V8Type.Object: case V8Type.Exception: V8ObjectData objectData = Marshal.PtrToStructure <V8ObjectData>(marshalData); for (int i = 0; i < objectData.propertiesCount; i++) { int propertyType = Marshal.ReadInt32(objectData.propertyTypes, i * sizeof(int)); IntPtr propertyValue = Marshal.ReadIntPtr(objectData.propertyValues, i * PointerSize); IntPtr propertyName = Marshal.ReadIntPtr(objectData.propertyNames, i * PointerSize); FreeMarshalData(propertyValue, propertyType); Marshal.FreeHGlobal(propertyName); } Marshal.FreeHGlobal(objectData.propertyTypes); Marshal.FreeHGlobal(objectData.propertyValues); Marshal.FreeHGlobal(objectData.propertyNames); Marshal.FreeHGlobal(marshalData); break; case V8Type.Array: V8ArrayData arrayData = Marshal.PtrToStructure <V8ArrayData>(marshalData); for (int i = 0; i < arrayData.arrayLength; i++) { int itemType = Marshal.ReadInt32(arrayData.itemTypes, i * sizeof(int)); IntPtr itemValue = Marshal.ReadIntPtr(arrayData.itemValues, i * PointerSize); FreeMarshalData(itemValue, itemType); } Marshal.FreeHGlobal(arrayData.itemTypes); Marshal.FreeHGlobal(arrayData.itemValues); Marshal.FreeHGlobal(marshalData); break; case V8Type.Buffer: V8BufferData bufferData = Marshal.PtrToStructure <V8BufferData>(marshalData); Marshal.FreeHGlobal(bufferData.buffer); Marshal.FreeHGlobal(marshalData); break; case V8Type.Null: case V8Type.Function: break; default: throw new Exception("Unsupported marshalled data type: " + v8Type); } }
// ReSharper disable once InconsistentNaming public static IntPtr MarshalCLRToV8(object clrObject, out V8Type v8Type) { if (clrObject == null) { v8Type = V8Type.Null; return(IntPtr.Zero); } else if (clrObject is string) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi((string)clrObject)); } else if (clrObject is char) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi(clrObject.ToString())); } else if (clrObject is bool) { v8Type = V8Type.Boolean; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(int)); Marshal.WriteInt32(memoryLocation, ((bool)clrObject) ? 1 : 0); return(memoryLocation); } else if (clrObject is Guid) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi(clrObject.ToString())); } else if (clrObject is DateTime) { v8Type = V8Type.Date; DateTime dateTime = (DateTime)clrObject; if (dateTime.Kind == DateTimeKind.Local) { dateTime = dateTime.ToUniversalTime(); } else if (dateTime.Kind == DateTimeKind.Unspecified) { dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc); } long ticks = (dateTime.Ticks - MinDateTimeTicks) / 10000; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(double)); WriteDouble(memoryLocation, ticks); return(memoryLocation); } else if (clrObject is DateTimeOffset) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi(clrObject.ToString())); } else if (clrObject is Uri) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi(clrObject.ToString())); } else if (clrObject is short) { v8Type = V8Type.Int32; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(int)); Marshal.WriteInt32(memoryLocation, Convert.ToInt32(clrObject)); return(memoryLocation); } else if (clrObject is int) { v8Type = V8Type.Int32; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(int)); Marshal.WriteInt32(memoryLocation, (int)clrObject); return(memoryLocation); } else if (clrObject is long) { v8Type = V8Type.Number; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(double)); WriteDouble(memoryLocation, Convert.ToDouble((long)clrObject)); return(memoryLocation); } else if (clrObject is double) { v8Type = V8Type.Number; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(double)); WriteDouble(memoryLocation, (double)clrObject); return(memoryLocation); } else if (clrObject is float) { v8Type = V8Type.Number; IntPtr memoryLocation = Marshal.AllocHGlobal(sizeof(double)); WriteDouble(memoryLocation, Convert.ToDouble((Single)clrObject)); return(memoryLocation); } else if (clrObject is decimal) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi(clrObject.ToString())); } else if (clrObject is Enum) { v8Type = V8Type.String; return(Marshal.StringToHGlobalAnsi(clrObject.ToString())); } else if (clrObject is byte[] || clrObject is IEnumerable <byte> ) { v8Type = V8Type.Buffer; V8BufferData bufferData = new V8BufferData(); byte[] buffer; if (clrObject is byte[]) { buffer = (byte[])clrObject; } else { buffer = ((IEnumerable <byte>)clrObject).ToArray(); } bufferData.bufferLength = buffer.Length; bufferData.buffer = Marshal.AllocHGlobal(buffer.Length * sizeof(byte)); Marshal.Copy(buffer, 0, bufferData.buffer, bufferData.bufferLength); IntPtr destinationPointer = Marshal.AllocHGlobal(V8BufferDataSize); Marshal.StructureToPtr(bufferData, destinationPointer, false); return(destinationPointer); } else if (clrObject is IDictionary || clrObject is ExpandoObject) { v8Type = V8Type.Object; IEnumerable keys; int keyCount; Func <object, object> getValue; if (clrObject is ExpandoObject) { IDictionary <string, object> objectDictionary = (IDictionary <string, object>)clrObject; keys = objectDictionary.Keys; keyCount = objectDictionary.Keys.Count; getValue = index => objectDictionary[index.ToString()]; } else { IDictionary objectDictionary = (IDictionary)clrObject; keys = objectDictionary.Keys; keyCount = objectDictionary.Keys.Count; getValue = index => objectDictionary[index]; } V8ObjectData objectData = new V8ObjectData(); int counter = 0; objectData.propertiesCount = keyCount; objectData.propertyNames = Marshal.AllocHGlobal(PointerSize * keyCount); objectData.propertyTypes = Marshal.AllocHGlobal(sizeof(int) * keyCount); objectData.propertyValues = Marshal.AllocHGlobal(PointerSize * keyCount); foreach (object key in keys) { Marshal.WriteIntPtr(objectData.propertyNames, counter * PointerSize, Marshal.StringToHGlobalAnsi(key.ToString())); V8Type propertyType; Marshal.WriteIntPtr(objectData.propertyValues, counter * PointerSize, MarshalCLRToV8(getValue(key), out propertyType)); Marshal.WriteInt32(objectData.propertyTypes, counter * sizeof(int), (int)propertyType); counter++; } IntPtr destinationPointer = Marshal.AllocHGlobal(V8ObjectDataSize); Marshal.StructureToPtr(objectData, destinationPointer, false); return(destinationPointer); } else if (clrObject is IEnumerable) { v8Type = V8Type.Array; V8ArrayData arrayData = new V8ArrayData(); List <IntPtr> itemValues = new List <IntPtr>(); List <int> itemTypes = new List <int>(); foreach (object item in (IEnumerable)clrObject) { V8Type itemType; itemValues.Add(MarshalCLRToV8(item, out itemType)); itemTypes.Add((int)itemType); } arrayData.arrayLength = itemValues.Count; arrayData.itemTypes = Marshal.AllocHGlobal(sizeof(int) * arrayData.arrayLength); arrayData.itemValues = Marshal.AllocHGlobal(PointerSize * arrayData.arrayLength); Marshal.Copy(itemTypes.ToArray(), 0, arrayData.itemTypes, arrayData.arrayLength); Marshal.Copy(itemValues.ToArray(), 0, arrayData.itemValues, arrayData.arrayLength); IntPtr destinationPointer = Marshal.AllocHGlobal(V8ArrayDataSize); Marshal.StructureToPtr(arrayData, destinationPointer, false); return(destinationPointer); } else if (clrObject.GetType().GetTypeInfo().IsGenericType&& clrObject.GetType().GetGenericTypeDefinition() == typeof(Func <,>)) { Func <object, Task <object> > funcObject = clrObject as Func <object, Task <object> >; if (funcObject == null) { throw new Exception("Properties that return Func<> instances must return Func<object, Task<object>> instances"); } v8Type = V8Type.Function; return(GCHandle.ToIntPtr(GCHandle.Alloc(funcObject))); } else { v8Type = clrObject is Exception ? V8Type.Exception : V8Type.Object; if (clrObject is Exception) { AggregateException aggregateException = clrObject as AggregateException; if (aggregateException?.InnerExceptions != null && aggregateException.InnerExceptions.Count > 0) { clrObject = aggregateException.InnerExceptions[0]; } else { TargetInvocationException targetInvocationException = clrObject as TargetInvocationException; if (targetInvocationException?.InnerException != null) { clrObject = targetInvocationException.InnerException; } } } List <Tuple <string, Func <object, object> > > propertyAccessors = GetPropertyAccessors(clrObject.GetType()); V8ObjectData objectData = new V8ObjectData(); int counter = 0; objectData.propertiesCount = propertyAccessors.Count; objectData.propertyNames = Marshal.AllocHGlobal(PointerSize * propertyAccessors.Count); objectData.propertyTypes = Marshal.AllocHGlobal(sizeof(int) * propertyAccessors.Count); objectData.propertyValues = Marshal.AllocHGlobal(PointerSize * propertyAccessors.Count); foreach (Tuple <string, Func <object, object> > propertyAccessor in propertyAccessors) { Marshal.WriteIntPtr(objectData.propertyNames, counter * PointerSize, Marshal.StringToHGlobalAnsi(propertyAccessor.Item1)); V8Type propertyType; Marshal.WriteIntPtr(objectData.propertyValues, counter * PointerSize, MarshalCLRToV8(propertyAccessor.Item2(clrObject), out propertyType)); Marshal.WriteInt32(objectData.propertyTypes, counter * sizeof(int), (int)propertyType); counter++; } IntPtr destinationPointer = Marshal.AllocHGlobal(V8ObjectDataSize); Marshal.StructureToPtr(objectData, destinationPointer, false); return(destinationPointer); } }
public static object MarshalV8ToCLR(IntPtr v8Object, V8Type objectType) { switch (objectType) { case V8Type.String: return(Marshal.PtrToStringAnsi(v8Object)); case V8Type.Object: return(V8ObjectToExpando(Marshal.PtrToStructure <V8ObjectData>(v8Object))); case V8Type.Boolean: return(Marshal.ReadByte(v8Object) != 0); case V8Type.Number: return(ReadDouble(v8Object)); case V8Type.Date: double ticks = ReadDouble(v8Object); return(new DateTime(Convert.ToInt64(ticks) * 10000 + MinDateTimeTicks, DateTimeKind.Utc)); case V8Type.Null: return(null); case V8Type.Int32: return(Marshal.ReadInt32(v8Object)); case V8Type.UInt32: return((uint)Marshal.ReadInt32(v8Object)); case V8Type.Function: NodejsFunc nodejsFunc = new NodejsFunc(v8Object); return(nodejsFunc.GetFunc()); case V8Type.Array: V8ArrayData arrayData = Marshal.PtrToStructure <V8ArrayData>(v8Object); object[] array = new object[arrayData.arrayLength]; for (int i = 0; i < arrayData.arrayLength; i++) { int itemType = Marshal.ReadInt32(arrayData.itemTypes, i * sizeof(int)); IntPtr itemValuePointer = Marshal.ReadIntPtr(arrayData.itemValues, i * PointerSize); array[i] = MarshalV8ToCLR(itemValuePointer, (V8Type)itemType); } return(array); case V8Type.Buffer: V8BufferData bufferData = Marshal.PtrToStructure <V8BufferData>(v8Object); byte[] buffer = new byte[bufferData.bufferLength]; Marshal.Copy(bufferData.buffer, buffer, 0, bufferData.bufferLength); return(buffer); case V8Type.Exception: string message = Marshal.PtrToStringAnsi(v8Object); return(new Exception(message)); default: throw new Exception("Unsupported V8 object type: " + objectType + "."); } }