C# Marshalling

Man of Honour
Joined
13 Nov 2009
Posts
11,662
Location
Northampton
This one is definitely not my strong suit.

I'm using a Third Party DLL for a USB interface that I'm trying to work with in .NET

There's a ReadData and WriteData function provided by the DLL which both take a structure pointer as a parameter

In C the structure looks like this

Code:
typedef struct _msg
{
    unsigned int ProtocolID;
    unsigned int RxStatus;
    unsigned int TxFlags;
    unsigned int Timestamp;
    unsigned int DataSize;
    unsigned int ExtraDataIndex;
    unsigned char Data[PM_DATA_LEN]
} msg;

and in C#
Code:
[StructLayout(LayoutKind.Sequential, Size = 4152)]
        public class Msg
        {
            [MarshalAs(UnmanagedType.U4)] public PassThruProtocol ProtocolID;
            [MarshalAs(UnmanagedType.U4)] public PassThruRxStatus RxStatus;
            [MarshalAs(UnmanagedType.U4)] public J2534_TxFlags TxFlags;
            [MarshalAs(UnmanagedType.U4)] public UInt32 Timestamp;
            [MarshalAs(UnmanagedType.U4)] public UInt32 DataSize;
            [MarshalAs(UnmanagedType.U4)] public UInt32 ExtraDataIndex;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4128)] public byte[] Data = new byte[4128];
}

And I'm importing to two DLL functions as follows

Code:
        [DllImport(MyDLL)]
        public static extern UInt32 WriteMsg(Msg pMsg);

        [DllImport(MyDLL)]
        public static extern UInt32 ReadMsg(Msg pMsg);

Now here's where I'm stuck. Calling the write function works perfectly fine, the USB interface takes my call does exactly as it should. The read function on the other hand never seems to write it's data into the Msg stuct.
It's not the DLL, I can call the read function in c++ or Delphi and it does exactly as it should. If I give the Read function a byte array by changing it's declaration like below it also does exactly as it should. There's clearly something I'm missing as far as how I should be passing/Marshalling my struct between managed/unmanaged code
Code:
[DllImport(MyDLL)]
public static extern UInt32 ReadMsg(byte[] pMsg);

Using the out keyword Gives me a Attempted to read or write protected memory error.
 
Last edited:
it’s lately pretty simple. Ignoring the code that comes before to connect to the interface and send a message

Code:
UInt32 result;
Msg RxMsg = new Msg();

result = ReadMsg(RxMsg);
 
Last edited:
Just a guess but your result is declared as a UInt32, so are you sure you are trying to put UInt32 data into it when reading RxMsg? i.e. do you have the correct type of data.
 
Just a guess but your result is declared as a UInt32, so are you sure you are trying to put UInt32 data into it when reading RxMsg? i.e. do you have the correct type of data.

The data types are definitely correct. The library function has an unsigned int return type which is an enum signifying a success or cause of failure.

If it’s a success it then copies the payload from the USB device into the RxMsg structure
 
I don't really touch C# but you probably need to pass a pointer to ReadMsg for RxMsg or something like that. In C probably just &RxMsg (actually a reference in this case).
 
Last edited:
I don't really touch C# but you probably need to pass a pointer to ReadMsg for RxMsg or something like that. In C probably just &RxMsg (actually a reference in this case).

Yeah. It’s a ref/pointer in C/cpp and Delphi

The bit really stumping me is both the ReadMsg and WriteMsg functions both take a pointer to a Msg struct and the write works as it should while the read doesn’t. But passing a byte array works.

Which in some fairness might actually just be the solution. Give readmsg a byte array then use that to build a Msg object/struct
 
Last edited:
I'm not sure, but I don't think you want to be assigning a new byte[] to Data.
I mean, when all is said and done a byte[] of the correct size and a struct are the same thing in memory. I’m not doing that in the non working examples though. The working cases do with with me changing the data types for the parameters and passing a byte[] though

This is why I like embedded and C. Managed languages have their place but that lack of being in control of what memory is being allocated is a nuisance
 
Last edited:
Yeah. It’s a ref/pointer in C/cpp and Delphi

The bit really stumping me is both the ReadMsg and WriteMsg functions both take a pointer to a Msg struct and the write works as it should while the read doesn’t. But passing a byte array works.

Which in some fairness might actually just be the solution. Give readmsg a byte array then use that to build a Msg object/struct

Think I misread some of it on my phone earlier - this is why I generally like to stick to plain old C.
 
Back
Top Bottom