1

I have a native struct:

typedef struct
{
    char Message[STR_MAX];
    char Params[10][STR_MAX];
    int GetParamStr[10];
    int ParamCount;
} FormattedMessage_t;

and callback type:

typedef void(*FormatMsgCB_t)(FormattedMessage_t *FormatMsgs, int FormatMsgCount);

static array:

static FormattedMessage_t gFormattedMessages[10];

callback set function:

extern "C" __declspec(dllexport) void DllGuiSetFormatMsgCB(FormatMsgCB_t pCB)
{
    gFormatMsgCB = pCB;
}   

call from native to managed:

void DllGuiSetFormatMessage()
{
    gFormatMsgCB(gFormattedMessages, gFormattedMsgIndex);
}

In Managed:

    [StructLayout(LayoutKind.Sequential)]
    public struct FormattedMessage_t
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxStrLength)]
        public string Message;

        public string[] ParamStrings;
        public int[] GetParamStrs;
        public int ParamCount;

        public const int MaxStrLength = StrMax;
    }

    public static T[] GetArray<T>(IntPtr aTblPtr, int nRows)
    {
        var entrySize = Marshal.SizeOf(typeof(T));
        IntPtr oneRowPtr = new IntPtr(aTblPtr.ToInt64());
        T[] array = new T[nRows];

        for (int i = 0; i < nRows; i++)
        {
            array[i] = (T)Marshal.PtrToStructure(oneRowPtr, typeof(T));
            oneRowPtr = new IntPtr(oneRowPtr.ToInt64() + entrySize);
        }

        return array;
    }

    private void OnSetFormatMsg(IntPtr formatMsg, int nFormatMsg)
    {
        var array = GetArray<FormattedMessage_t>(formatMsg, nFormatMsg);
        foreach (var msg in array)
        {
            var str = msg.Message;
            // and so on
        }
    }

This GetArray works for simple types as struct members. This is way beyond my P/Invoke and Native Interop skills.

This is probably wrong in many ways. Any hints how this should be done (changing both structs is no problem) would be highly appreciated.

1
  • 1
    I don't remember the details from the top of my mind, but iirc you can create either a custom marshaller or add the MarshalAs flags to ParamStrings etc. (These seem to be missing.) Commented Mar 2, 2016 at 12:22

1 Answer 1

3

You'll need to declare the C# struct like so:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FormattedMessage_t
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxStrLength)]
    public string Message;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10*MaxStrLength)]
    public byte[] ParamStrings;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public int[] GetParamStrs;

    public int ParamCount;

    public const int MaxStrLength = StrMax;
}

Then you'll need to pick out each item from ParamStrings by performing the indexing manually. The ith value runs from indices i*MaxStrLength to (i+1)*MaxStrLength-1. You'll need to pick that out, find the null terminator, and use Encoding.Default.GetString.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! I realized myself after asking that MarshalAs-decorations were missing, but wasn't sure how to write them. Unfortunately I didn't understand the explanation about the ParamStrings.
The thing is, that char Params[10][STR_MAX] is a two dimensional array, and the C# marshaller cannot handle that automatically. It's laid out in memory in the same way as a one dimensional array of length 10*STR_MAX. So that's what my MarshalAs does. But now you need to find the 10 strings contained within that flattened one dimensional array, and convert them to C# strings.
Thanks. I understood what you mean. But does this indicate that I can't call Marshal.PtrToStructure at all? That I got to marshal all members separaterly? Marshal.PtrToStructure results in System.AccessViolationException so I guess that I have to marshal all separately somehow.
There should be no problem with PtrToStructure. You'll just end up with a byte[] array for ParamStrings that will take a little extra work to decode.
Thanks a lot! Now it works. I sort this byte[] to string[] out and I'm done.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.