Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing Structure from C# to C++

Tags:

c++

c#

interop

I have the following structure in C++:

extern "C" __declspec(dllexport) struct SnapRoundingOption
{
    double PixelSize;
    bool IsISR;
    bool IsOutputInteger;
    int KdTrees;
};

And this is my function declaration in C++:

extern "C" __declspec(dllexport) void FaceGenerationDummy(SnapRoundingOption snapOption);

This is the corresponding C# code:

// I also tried not specifying Pack, but the same error occurred.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SnapRoundingOption
{
    public  double PixelSize;
    public bool IsISR;
    public bool IsOutputInteger;
    public int KdTrees;

    public SnapRoundingOption(double pixelSize, bool isISR, bool isOutputInt, int kdTrees)
    {
        PixelSize = pixelSize;
        IsISR = isISR;
        IsOutputInteger = isOutputInt;
        KdTrees = kdTrees;
    }
}

[DllImport("Face.dll")]
public static extern void FaceGenerationDummy(SnapRoundingOption snapRoundingOption);

However, when I call the FaceGenerationDummy with this test:

[Test]
public void DummyTest()
{
    SimpleInterop.FaceGenerationDummy(new SnapRoundingOption(10, true, false, 1));
}

I found that KdTrees is 0 in C++, instead of 1 as passed in.

What am I doing wrong?

Edit 1: I am using Visual Studio 2008 on Windows 7 32-bit.

Edit 2: Both sizeof(SnapRoundingOption) return the same number – 16.

like image 276
Graviton Avatar asked Mar 08 '11 08:03

Graviton


2 Answers

The problem here is how you are marshalling the bool fields. These are single bytes in C++ and so need to be marshalled so:

[StructLayout(LayoutKind.Sequential)]
public struct SnapRoundingOption
{
    public double PixelSize;
    [MarshalAs(UnmanagedType.U1)]
    public bool IsISR;
    [MarshalAs(UnmanagedType.U1)]
    public bool IsOutputInteger;
    public int KdTrees;
}

Match this up on the C++ side:

struct SnapRoundingOption
{
    double PixelSize;
    bool IsISR;
    bool IsOutputInteger;
    int KdTrees;
};

I removed the packing settings so that the structures will have alignment natural to the platform.

You should also make sure that your calling conventions agree. As it stands it looks like the C++ code uses cdecl, and the C# code uses stdcall. For example

[DllImport("Face.dll", CallingConvention=CallingConvention.Cdecl)]

would align the two sides of the interface.

like image 199
David Heffernan Avatar answered Sep 23 '22 18:09

David Heffernan


bool is NOT blittable! Its default marshaling is the Win32 BOOL (which is 4 bytes), not bool (which is 1 byte)!

like image 21
user541686 Avatar answered Sep 21 '22 18:09

user541686