1

I am working with a C DLL and have trouble with marshalling strings using P/Invoke.

The DLL has a struct as follows:

typedef struct
{
    char sAddress[256];
    BYTE byUseRtsp;
    WORD wPort;
}INFO,*LPINFO;

My C# struct looks like this:

[StructLayout(LayoutKind.Sequential)]
public struct INFO
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string sAddress;

    public byte byUseRtsp;

    public short wPort;
}

The string marshalling for sAddress works with ASCII text, but the DLL uses UTF-8 encoding throughout. So as soon as multi-byte characters are used the marshalling garbles the text. Using CharSet.Unicode doesn't work here as that tells the marshaller to encode/decode strings as UTF-16 on Windows. I need a CharSet.Utf8 which unfortunately doesn't exist.

I do have a workaround, but it's ugly and want to avoid if possible. The workaround is to replace:

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string sAddress;

with:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public byte[] sAddress;

and then just re-write my code to use Encoding.UTF8.GetBytes/String() methods to get the string values. I will also need to handle null-terminators myself with this method.

Is there a better way of doing this?

Phil K
  • 4,939
  • 6
  • 31
  • 56

2 Answers2

2

Is there a better way of doing this?

Using the built-in options for marshalling what you have done is probably as good as it gets. You would want to write some helper methods to manage this for you, but I'm sure you are alive to that.

Beyond this you could use a custom marshaler. I'm not aware that there is a great body of work available on this topic. One of the more complete happens to be this question of mine: How do I write a custom marshaler which allows data to flow from native to managed?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Unfortunately custom marshallers don't work with `Marshal.SizeOf` which is required for my use case. Guess I'll have to go with the workaround I mentioned. – Phil K May 14 '20 at 21:02
0

[In case it helps others] .NET Framework 4.7 introduced UnmanagedType.LPUTF8Str which is likely just for this situation.

Dave Stucki
  • 121
  • 3