Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
128 views
in Technique[技术] by (71.8m points)

Is there a way to pass a C++ struct containing another C++ struct back to C#?

Suppose I have the following 2 C++ structs:

struct UsbErrorCodes
{
    const signed int UsbInterfaceErrorCode = 0;
    const DWORD WinDriverErrorCode = 0;

    UsbErrorCodes(const signed int usbInterfaceErrorCode, const DWORD winDriverErrorCode)
        : UsbInterfaceErrorCode(usbInterfaceErrorCode),
        WinDriverErrorCode(winDriverErrorCode)
    {
    }
};

struct NativeReadBytesResponse
{
    const unsigned long NumberOfBytesRead = 0;
    const UsbErrorCodes UsbErrorCodes;

    NativeReadBytesResponse(const unsigned long numberOfBytesRead, const ::UsbErrorCodes usbErrorCodes)
        : NumberOfBytesRead(numberOfBytesRead),
        UsbErrorCodes(usbErrorCodes)
    {
    }
};

And I have a C++ function returning a NativeReadBytesResponse:

NativeReadBytesResponse ReadBytes
(
    unsigned long numberOfBytesToRead,
    unsigned char* bytesBuffer,
    unsigned long transferTimeout = 3000
);

How do I setup a C# method to call that function and get me back that NativeReadBytesResponse?

I have tried this but get a Managed Debugging Assistant 'PInvokeStackImbalance' exception when it's called.

    [DllImport("MyNativeLibrary.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern NativeReadBytesResponse ReadBytes
    (
        uint numberOfBytesToRead,
        [Out]
        out byte[] bytesBuffer,
        uint transferTimeout = 3000
    );

I should also note that I have been able to return UsbErrorCodes from C++ to its C# equivalent struct by mimicing the struct in C# and adding [StructLayout(LayoutKind.Sequential, Size = 64)] on top of the struct. Here are the 2 C# structs which the 2 C++ structs should map to:

[StructLayout(LayoutKind.Sequential, Size = 64)]
public partial struct UsbErrorCodes : IEquatable<UsbErrorCodes>
{
    public static bool operator ==(UsbErrorCodes left, UsbErrorCodes right)
        => left.Equals(right);

    public static bool operator !=(UsbErrorCodes left, UsbErrorCodes right)
        => !left.Equals(right);

    [DisplayName("USB Interface Error Code")]
    public uint UsbInterfaceErrorCode { get; }

    [DisplayName("Windows Driver Error Code")]
    public WinDriverError WinDriverErrorCode { get; }
    
    [Newtonsoft.Json.JsonConstructor]
    public UsbErrorCodes
    (
        uint usbInterfaceErrorCode,
        WinDriverError winDriverErrorCode
    )
    {
        UsbInterfaceErrorCode = usbInterfaceErrorCode;
        WinDriverErrorCode = winDriverErrorCode;
    }

    public bool Equals(UsbErrorCodes other)
        => UsbInterfaceErrorCode.Equals(other.UsbInterfaceErrorCode)
        && WinDriverErrorCode.Equals(other.WinDriverErrorCode);

    public override bool Equals(object obj)
        => obj is UsbErrorCodes usbErrorCodes
        ? Equals(usbErrorCodes)
        : base.Equals(obj);

    public override int GetHashCode()
        => UsbInterfaceErrorCode.GetHashCode()
        ^ WinDriverErrorCode.GetHashCode();
}

[StructLayout(LayoutKind.Sequential, Size = 96)]
public struct NativeReadBytesResponse : IEquatable<NativeReadBytesResponse>
{
    public static bool operator ==(NativeReadBytesResponse left, NativeReadBytesResponse right)
        => left.Equals(right);

    public static bool operator !=(NativeReadBytesResponse left, NativeReadBytesResponse right)
        => !left.Equals(right);

    public uint NumberOfBytesRead { get; }

    [DisplayName("USB Error Codes")]
    public UsbErrorCodes UsbErrorCodes { get; }
    
    [Newtonsoft.Json.JsonConstructor]
    public NativeReadBytesResponse
    (
        uint numberOfBytesRead,
        UsbErrorCodes usbErrorCodes
    )
    {
        NumberOfBytesRead = numberOfBytesRead;
        UsbErrorCodes = usbErrorCodes;
    }

    public bool Equals(NativeReadBytesResponse other)
        => NumberOfBytesRead.Equals(other.NumberOfBytesRead)
        && UsbErrorCodes.Equals(other.UsbErrorCodes);

    public override bool Equals(object obj)
        => obj is NativeReadBytesResponse nativeReadBytesResponse
        ? Equals(nativeReadBytesResponse)
        : base.Equals(obj);

    public override int GetHashCode()
        => NumberOfBytesRead.GetHashCode()
        ^ UsbErrorCodes.GetHashCode();
}

Does C#-to-C++-to-C# interop not support objects nested within objects or is something else at fault here?

question from:https://stackoverflow.com/questions/65598933/is-there-a-way-to-pass-a-c-struct-containing-another-c-struct-back-to-c

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...