marshal c struct to c#

2019-06-12 10:54发布

问题:

Does any body can marshal this part of c/c++ code in c# please?

typedef struct
{
    BYTE    bCommandCode;
    BYTE    bParameterCode;

    struct
    {
        DWORD   dwSize;
        LPBYTE  lpbBody;
    }
    Data;
}
COMMAND, *LPCOMMAND;

thanks a lot

回答1:

First off, declare the above struct as a managed struct - something like:

    [StructLayout(LayoutKind.Sequential)]
    struct SomeStruct
    {
        byte bCommandCode;
        byte bParameterCode;

        SomeOtherStruct otherStruct;

        Data Data;
    }

    struct SomeOtherStruct
    {
        uint dwSize;
        byte lpBody;
    }

    struct Data
    {
    }

Though you may have to use the MarshalAs attribute here and there to ensure it's actually marshalling them as their proper types. If you want to then read this struct from memory for example, you could do something like:

        var bytes = ReadBytes(address, Marshal.SizeOf(typeof(SomeStruct)), isRelative);

        fixed (byte* b = bytes)
            return (T) Marshal.PtrToStructure(new IntPtr(b), typeof (SomeStruct));

I am assuming you want to read your struct from memory and marshal it into a managed struct, because otherwise you wouldn't even need the Marshal at all. Also, make sure to compile the above code with /unsafe enabled.



回答2:

//01. Declare 'Command' structure
public struct Command
{
    public byte CommandCode;
    public byte ParameterCode;
    public struct Data
    {
        public uint Size;
        public IntPtr Body;
    }
    public Data SendData;
}    

//02. Create & assign an instance of 'Command' structure 
//Create body array
byte[] body = { 0x33, 0x32, 0x34, 0x31, 0x30 };

//Get IntPtr from byte[] (Reference: http://stackoverflow.com/questions/537573/how-to-get-intptr-from-byte-in-c-sharp)
GCHandle pinnedArray = GCHandle.Alloc(body, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();

//Create command instance
var command = new CardReaderLib.Command
                  {
                      CommandCode = 0x30,
                      ParameterCode = 0x30,
                      SendData = {
                          Size = (uint) body.Length, 
                          Body = pointer
                      }
                  };

//do your stuff

if (pinnedArray.IsAllocated)
    pinnedArray.Free();