Search code examples
c#c++pointersinteroppinvoke

pointers between c# and c++ - p/invoke


hi im trying to call some c++ code from c#. So i followed several tutorials, amde my own dll, and now i call it from my c# wrapper. the thing is, i have a function that receives a pointer and i can't seem to make it work, visual studio just shows me red errors that i don't understand very well. can someone tell me what im doing wrong? and i have another question, if the functions in c++ call other functions, all the data will remain intact right? because this array that i pass will be manipulated inside the dll and, afterwards, im gonna call other function from the dll to get the results - my fear is that the data is lost between function calls!

thanks!

dll .h #include

   #include <stdio.h> 

   #include <stdlib.h> 

   #include <math.h> 

   #include <string> 

   #include <vector> 

   #include <fstream> 

   #include <sstream> 

   #include <cstring> 

   #include <fstream>

   #include <iomanip> 

   #include <cstdlib> 

   #include <string> 

   #include <cstring> 

   #include "opencv\ml.h"

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

#define db at<double>


   extern "C" __declspec(dllexport) points * mapear_kinect_porto(points pontos[]);


   CvERTrees *  Rtree ;


   extern "C" __declspec(dllexport)     void calibrate_to_file(points pontos[]);

   extern "C" __declspec(dllexport)     int calibration_neutral();

   extern "C" __declspec(dllexport)       int EmotionsRecognition();

c# wrapper

             [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct points
{

    /// double
    public double x;

    /// double
    public double y;

    /// double
    public double z;
}


class CPlusPlusWrapper
{

/// Return Type: void
    ///pontos: points*
    [System.Runtime.InteropServices.DllImportAttribute("DLLTUT.dll", EntryPoint =  "calibrate_to_file")]
    public static extern void calibrate_to_file(ref points pontos);
    public unsafe void calibrate_file()
    {

        points[] shit = new points[8];
        points*[] pBLA; //error here!!!!
        pBLA = &shit;
   //            calibrate_to_file(pbla);
    }

}

btw i used p/invoke assistant and i got this

public partial class NativeConstants {

/// db -> at<double>
/// Error generating expression: Expression is not parsable.  Treating value as a raw string
public const string db = "at<double>";
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct points {

/// double
public double x;

/// double
public double y;

/// double
public double z;
}

public partial class NativeMethods {

/// Return Type: points*
///pontos: points*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="mapear_kinect_porto")]
public static extern  System.IntPtr mapear_kinect_porto(ref points pontos) ;


/// Return Type: void
///pontos: points*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="calibrate_to_file")]
public static extern  void calibrate_to_file(ref points pontos) ;


/// Return Type: int
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="calibration_neutral")]
public static extern  int calibration_neutral() ;


/// Return Type: int
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="EmotionsRecognition")]
public static extern  int EmotionsRecognition() ;

}

Solution

  • You appear to be trying to call the function named calibrate_to_file. That receives an array of points. The p/invoke for that is:

    [DllImportAttribute("DLLTUT.dll", CallingConvention=CallingConvention.Cdecl)]
    public static extern void calibrate_to_file(points[] pontos);
    

    There's absolutely no need for unsafe code. Just make an array of type points[] in your calling code and then call calibrate_to_file.

    You need to make sure the calling conventions match. Since you did not specify a calling convention in the C++ code I assume the default of cdecl is used.

    The struct can be declared simply as

    [StructLayout(LayoutKind.Sequential)]
    public struct points
    {
        public double x;
        public double y;
        public double z;
    }
    

    The mapear_kinect_porto function is going to be more tricky because you are returning a pointer as the function return value. It would be easier for you to return that information using a parameter instead of the function return value.

    My best advice for you is to break this problem down into small pieces. Get the simplest function working. Then move on to the next function. And so on. Don't try to solve the entire problem in one go. Then you'll not know where to look for the error when it inevitably fails.