0

I want to marshall the following c structs with c#.

struct ConnectionMessage
{
    static const size_t MESSAGE_MAX_PATH = 260;

    uint32_t version;
    uint64_t pid;
    char machineName[32];
    char executablePath[MESSAGE_MAX_PATH];
};

struct TextMessage
{
    static const size_t TEXT_SIZE = 256;

    uint64_t timestamp;
    uint32_t severity;
    char module[32];
    char channel[32];
    char message[TEXT_SIZE];
};


struct RawLogMessage
{
    uint32_t type;
    union
    {
        ConnectionMessage connection;
        TextMessage text;
    };
};

The structs I've been using in the past were working fine until I changed the C# assembly to x64.

These are the structs:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct TextMessage
{
    [FieldOffset(0), MarshalAs(UnmanagedType.U8)]
    public UInt64 Timestamp;
    [FieldOffset(8), MarshalAs(UnmanagedType.U4)]
    public LogSeverity Severity;
    [FieldOffset(12), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string Module;
    [FieldOffset(44), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string Channel;
    [FieldOffset(76), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string Message;

    public override string ToString()
    {
        return String.Format("{0} {1} {2} {3} {4}", this.Timestamp, this.Severity, this.Module, this.Channel, this.Message);
    }
}

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct ConnectionMessage
{
    [FieldOffset(0)]
    public UInt32 Version;
    [FieldOffset(8)]
    public UInt32 Pid;

    public override string ToString()
    {
        return String.Format("{0} {1}", this.Version, this.Pid);
    }
}


[StructLayout(LayoutKind.Explicit, Pack = 0)]
public struct RawLogMessage
{
    [FieldOffset(0), MarshalAs(UnmanagedType.U4)]
    public MessageType Type;
    [FieldOffset(8)]
    public TextMessage TextMessage;
    [FieldOffset(8)]
    public ConnectionMessage ConnectionMessage;
}

What would be the proper way to handle that? What is the reason that it doesn't work anymore after changing the C# assembly to x64? I appreciate any hint/help.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
duketwo
  • 4,865
  • 1
  • 11
  • 9
  • Possible duplicate of [C# StructLayout.Explicit Question](https://stackoverflow.com/questions/1182782/c-sharp-structlayout-explicit-question) – Etienne de Martel Jul 12 '19 at 16:58

1 Answers1

1

To clarify, you recently started compiling your C library as 64bit as well? That could have changed the default packing on the structs, but it might not. Have you manually specified the alignment boundaries in your C code? You need to clarify that fact first. Is the C struct packing now 8 bytes or is it still 4? Or was it set to pack tight, to byte-align?

Having a field offset of 8 on ConnectionMessage::Pid seems to imply that you think the C fields are now 8-byte aligned, since the field above it is clearly only 4 bytes wide. And if you are 8-byte aligned, you can't have an offset at 12 or 44, etc. If you are byte-aligned or 4-byte-aligned, offsetting the Pid to 8 bytes is clearly wrong. Same story on Text/ConnectionMessage.

Brannon
  • 5,324
  • 4
  • 35
  • 83
  • Thanks! The above code is what works with 32bit C# code. It doesn't matter if I change the C++ part to 32/x64. Both works. Just if I try to change the C# client to x64 I get errors. Is there an easy way to figure out how the structures are packed/aligned? Also do I need to use LayoutKind.Explicit? Or would Sequential also work except for the union? – duketwo Jul 12 '19 at 17:19
  • Running a 32bit C# app with a 64bit C DLL won't work; it won't even load the DLL. And vice-versa for running a 64bit C# app with 32bit C DLL. If you're seeing different behavior then you have a mistake in your DLL choice. As far as determining the C code alignment, you would need to look through the code for `pragma pack` and `((packed))` and check the compiler parameters for `pack-struct` parameters. – Brannon Jul 12 '19 at 22:24
  • It's a client/server architecture. The server is closed source. The c structs I've been using are from another client which I'm trying to port to C# x64. – duketwo Jul 12 '19 at 22:47