Search code examples
c#exceptionmarshalling

marshal.PtrToStructure access violation exception


I have a struct defined as

[StructLayout(LayoutKind.Sequential,Pack=1)]
    private struct networkMessage
        {
        public messageType type;
        public string message;
        }

and I have this function to convert the struct into byte[]

private byte[] ConvertToByteArray(networkMessage inStruct)
        {
        int structSize = Marshal.SizeOf(inStruct);
        byte[] byteArray = new byte[structSize];

        IntPtr memPtr = IntPtr.Zero;

        try
            {
            memPtr = Marshal.AllocHGlobal(structSize);
            Marshal.StructureToPtr(inStruct, memPtr, false);
            Marshal.Copy(memPtr, byteArray, 0, structSize);
            }
        finally
            {
            if (memPtr != IntPtr.Zero)
                {
                Marshal.FreeHGlobal(memPtr);
                }
            }
        foreach (byte b in byteArray)
            {
            Console.WriteLine(b + " ");
            }

        return byteArray;
        }

and this to convert back into a struct

private networkMessage ConvertFromByteArray(byte[] inByte)
        {
        foreach (byte b in inByte)
            {
            Console.WriteLine(b);
            }

        GCHandle handle = GCHandle.Alloc(inByte, GCHandleType.Pinned);

        networkMessage outStruct = (networkMessage) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(networkMessage));  //---Exception here

        return outStruct;
        }

This in use for a TCP application which both acts as a server and client, such that the same executable runs on both machines. Testing the conversion in the objects constructor shows it working fine, but a byte array coming from another computer causes an access violation exception. Printing out the bytes on both systems shows they are the same. What could be the problem? I assume this might have something to do with the struct?


Solution

  • This can't work.

    Try this: Set message to a string much longer than 16 characters and then look at the value of Marshal.SizeOf(inStruct). It will be 12 for a 64-bit version and 8 for a 32 bit version - regardless of the length of message.

    The correct solution to this is to use serialization to convert the data.

    You might want to check out NetTcpBinding, which can use DataContracts to serialize the data.

    Also, have a look at JSON serialization.