// 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();
}
}
}