using Google.Protobuf; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Runtime.ExceptionServices; namespace Tango.PMR { /// /// Represents a standard C++ protobuf method delegate. /// /// The request array. /// Size of the request array. /// The result array. /// The size of the result array. [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int NativeMethodDelegate(IntPtr requestArray, int requestArraySize, ref IntPtr resultArray); /// /// Represents a PMR wrapper for invoking native protobuf supported methods. /// /// The type of the Request. /// The type of the Response. public class NativePMR where Request : IMessage where Response : class, IMessage { private NativeMethodDelegate _nativeMethod; /// /// Initializes a new instance of the class. /// /// The native method. public NativePMR(NativeMethodDelegate nativeMethod) { _nativeMethod = nativeMethod; } /// /// Invokes the native method with the specified request. /// /// The request. /// The native method. /// [HandleProcessCorruptedStateExceptions] public Response Invoke(Request request) { try { //Serialize the request to byte array. byte[] messageData = request.ToByteArray(); //Allocate unmanaged array on memory. IntPtr unmanagedArr = Marshal.AllocHGlobal(messageData.Length); //Copy the request data to the unmanaged array. Marshal.Copy(messageData, 0, unmanagedArr, messageData.Length); //Initialize pointer for pointing to the result array. IntPtr output = IntPtr.Zero; //Invoke the native method. int size = _nativeMethod(unmanagedArr, messageData.Length, ref output); if (size == 0) return null; //Initialize a new byte array for holding the native result. byte[] responseData = new byte[size]; //Copy the unmanaged byte array result to the managed result array. Marshal.Copy(output, responseData, 0, size); //Generate response parser. MessageParser parser = new MessageParser(() => Activator.CreateInstance()); //Parse the response Response response = parser.ParseFrom(responseData); //Free unmanaged memory. Marshal.FreeHGlobal(unmanagedArr); return response; } catch (Exception) { throw; } } } }