I have a c# .net 2.0 CF application that interfaces with a native DLL implementing a function like this:
struct NATIVE_METHOD_REPLY { int other_irrelevant_data; int data_size; void* data; } // reply_buffer will contain an array of NATIVE_METHOD_REPLY structures // and their data. // // returns an error code int Foo(NATIVE_METHOD_REPLY* reply_buffer, int reply_size); I've implemented it in C# like this:
[StructLayout(LayoutKind.Sequential)] internal struct NATIVE_METHOD_REPLY { public Int32 OtherIrrelevantData; public Int16 DataSize; public IntPtr DataPtr; } [DllImport("my_lib.dll", SetLastError = true)] internal static extern Int32 Foo(byte[] replyBuffer, Int32 replySize); public byte[] void Bar() { // data returned to the user. May be an arbitrary size. byte[] result_buffer = new byte[256]; // data sent to Foo() byte[] reply_buffer = new byte[Marshal.SizeOf(typeof(NativeMethods.NATIVE_METHOD_REPLY)) + result_buffer.Length]; NativeMethods.Foo(reply_buffer, reply_buffer.Length); // is there a better way of doing this? NativeMethods.NATIVE_METHOD_REPLY reply; GCHandle pinned_reply = GCHandle.Alloc(reply_buffer, GCHandleType.Pinned); try { reply = (NativeMethods.NATIVE_METHOD_REPLY)Marshal.PtrToStructure( pinned_reply.AddrOfPinnedObject(), typeof(NativeMethods.NATIVE_METHOD_REPLY)); Marshal.Copy(reply.DataPtr, result_buffer, 0, reply.DataSize); } finally { pinned_reply.Free(); } // bonus point*: is this okay to do after the Free() call? int test = reply.OtherIrrelevantData; return result_buffer; } While this works correctly, I would like to know if this is the most efficient / most correct way of implementing this function.
Is there some method converting a managed byte array to a managed structure that doesn't involve an intermediate native handle and a copy? For instance, in C++, I would just do this:
NATIVE_METHOD_REPLY* reply = reinterpret_cast< NATIVE_METHOD_REPLY* >( reply.DataPtr ); *For a bonus point, is it okay to use data in the structure after the native handle has been freed?
Thanks, PaulH
Edit: Updated solution
[DllImport("my_lib.dll", SetLastError = true)] internal static extern Int32 Foo(IntPtr replyBuffer, Int32 replySize); public byte[] void Bar() { byte[] result_buffer = new byte[256]; int reply_buffer_len = Marshal.SizeOf(typeof(NativeMethods.NATIVE_METHOD_REPLY)) + result_buffer.Length; IntPtr reply_buffer = Marshal.AllocCoTaskMem(reply_buffer_len); NativeMethods.NATIVE_METHOD_REPLY reply; try { NativeMethods.Foo(reply_buffer, reply_buffer_len); reply = (NativeMethods.NATIVE_METHOD_REPLY)Marshal.PtrToStructure( reply_buffer, typeof(NativeMethods.NATIVE_METHOD_REPLY)); Marshal.Copy(reply.DataPtr, result_buffer, 0, reply.DataSize); } finally { Marshal.FreeCoTaskMem(reply_buffer); } return result_buffer; }