// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Standard Library using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace AWS.GameKit.Runtime.Utils { /// /// Class to help with marshalling for calling exported C methods (of the GameKit C++ SDK) /// public static class Marshaller { /// /// Call an Action with data referenced by an IntPtr. /// /// The data to work on. /// The action the data is called with. public static void Dispatch(object obj, Action work) { GCHandle gch = GCHandle.Alloc(obj); try { work(GCHandle.ToIntPtr(gch)); } finally { gch.Free(); } } /// /// Call an Action with data referenced by an IntPtr. /// /// The data to work on. /// The action the data is called with. public static T Dispatch(object obj, Func work) { GCHandle gch = GCHandle.Alloc(obj); try { return work(GCHandle.ToIntPtr(gch)); } finally { gch.Free(); } } /// /// Get a GCHandle to data in unmanaged memory. /// /// Type of the object. /// IntPtr pointing to object in unmanaged memory. /// Marshalled object. public static T GetDispatchObject(IntPtr intptr) { GCHandle gch = GCHandle.FromIntPtr(intptr); return (T)gch.Target; } /// /// Marshalls array in unmanaged memory to managed memory. /// /// Array element type. /// Pointer to array in unmanaged memory. /// Size of the array (in size of type) /// Marshalled array. public static T[] IntPtrToArray(IntPtr pointerToArray, uint sizeOfArray) where T : new() { T[] array = new T[sizeOfArray]; int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); for (int i = 0; i < sizeOfArray; ++i) { try { array[i] = Marshal.PtrToStructure(pointerToArray + (size * i)); } catch (Exception e) { array[i] = new T(); Logging.LogException("Unable to construct an array from the provided pointer", e); } } return array; } /// /// Marshalls array from managed to unmanaged memory. /// /// Type of array element. /// Array in managed memory. /// IntPtr to array in unmanaged memory. public static IntPtr ArrayToIntPtr(T[] array) { IntPtr head = IntPtr.Zero; if (array.Length > 0) { head = Marshal.AllocHGlobal(Marshal.SizeOf(array[0]) * array.Length); long nextAddr = head.ToInt64(); for (uint i = 0; i < array.Length; ++i) { IntPtr next = new IntPtr(nextAddr); Marshal.StructureToPtr(array[i], next, false); nextAddr += Marshal.SizeOf(typeof(T)); } } return head; } /// /// Marshalls array of strings to array in unmanaged memory. /// /// Array of strings in managed memory. /// Array of IntPtr. public static IntPtr[] ArrayOfStringsToArrayOfIntPtr(string[] array) { IntPtr[] arrayOfPointers = new IntPtr[array.Length]; for (uint i = 0; i < array.Length; ++i) { arrayOfPointers[i] = Marshal.StringToHGlobalAnsi(array[i]); } return arrayOfPointers; } /// /// Frees an array of IntPtr. /// /// The IntPtr array. public static void FreeArrayOfIntPtr(IntPtr[] array) { for (uint i = 0; i < array.Length; ++i) { Marshal.FreeHGlobal(array[i]); array[i] = IntPtr.Zero; } } /// /// Append value to an array of type T /// /// Type of array element. /// Data array. /// Value to be appended. public static void AppendToArray(ref T[] arrayOfValues, T value) { List buffer = new List(arrayOfValues); buffer.Add(value); arrayOfValues = buffer.ToArray(); } } }