Search code examples
c#c++interoppinvoke

Passing vector struct between C++ and C#


I have c++ unmanaged code that i want to access from c#. So i followed some tutorials and i build a dll for my project (only one class btw). Now i want to use it from c#, and i'm using p/invoke as follows.

my question is: is it possible to marshall my windows point so i can pass it as a vector into my c++ code? i can change all the code (except the qwindows point, but i can make my own point). IS there a solution where i dont have to create a c wrapper? i was following this question: How to call an unmanaged C++ function with a std::vector<>::iterator as parameter from C#?

many thanks1 ps, i found a "solution" but i cant view it http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21461195.html

c#

using Point = System.Windows.Point;

class CPlusPlusWrapper
{

    [DllImport("EmotionsDLL.dll", EntryPoint = "calibrate_to_file")]
    static extern int calibrate_to_file(vector<points> pontos);//marshall here

    [DllImport("EmotionsDLL.dll", EntryPoint = "calibration_neutral")]
    static extern int calibration_neutral();
    /// <summary>
    /// wraps c++ project into c#
    /// </summary>

    public void calibrate_to_file() { 

}

dll header

namespace EMOTIONSDLL
{
    struct points{
        double x;
        double y;
        double z;
    };

    #define db at<double>

    class DLLDIR EMOTIONS
    {
    public:

        EMOTIONS();

        CvERTrees *  Rtree ;


        vector<points> mapear_kinect_porto(vector<points> pontos);

        void calibrate_to_file(vector<points> pontos);

        int calibration_neutral();

        int EmotionsRecognition();
    };
}

Solution

  • You could marshal a C# array as a C++ std::vector, but it would be very complicated and is simply not a good idea because the layout and implementation of std::vector is not guaranteed to be the same between compiler versions.

    Instead you should change the parameter into a pointer to an array, and add a parameter specifying the length of the array:

    int calibrate_to_file(points* pontos, int length);
    

    And in C# declare the method as taking an array and apply the MarshalAs(UnmanagedType.LPArray) attribute:

    static extern int calibrate_to_file([MarshalAs(UnmanagedType.LPArray)]] Point[] pontos, int length);
    

    Note also that your C++ point structure is not compatible with System.Windows.Point. The latter doesn't have a z member.

    But a bigger issue with your code is that you can't really expect to DLL-import an instance method and be able to call it just like that. An instance method needs an instance of its class, and there's no easy way to create an instance of a non-COM C++ class from C# (and is also not a good idea). Therefore, you should turn this into a COM class, or create a C++/CLI wrapper for it.