Search code examples
c#dllpinvokearmadillo

Calling functions in a c++ dll from c# that are defined in another dll


I have already been able to read functions in a c++ dll that contains methods like this:

 extern "C" { __declspec(dllexport) Vector4  resta(Vector4 vector1,Vector4 vector2); }

I have been given a dll that implements the following function:

 extern "C"{ __declspec(dllexport) void pinverse(Vector4 skel[20], Vector4 result[20]); }

this function takes an array of 20 vector4 variables and computes the pseudoinverse of the matrix using armadillo routines, but I wasn't told which routines exactly, and when executing the function from c# i get a matrix of all zeros. I have also executed the function from c++ while keeping the armadillo dlls in the projecto folder an adding them to the linker input and I have gotten a result which is non-zero. So the question would be, how do I include the armadillo routines that are supposed to be executed on the c# code? Why am I not seeing any error message if the routine in the dll doesn't find the other routines from the library?

The syntax in c# I am using is this:

 [DllImport("C:\\Users\\PALMA\\Documents\\Visual Studio 2013\\Projects\\PruebaTest\\PruebaTest\\PruebaDll.dll", CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void pinverse(Vector4[] skel, Vector4[] result);

and Vector4 is a struct defined like this:

 public struct Vector4{

   public static bool operator !=(Vector4 vector1, Vector4 vector2);
   public static bool operator ==(Vector4 vector1, Vector4 vector2);

   public float W { get; set; }
   public float X { get; set; }
   public float Y { get; set; }
   public float Z { get; set; }

   public override bool Equals(object obj);
   public bool Equals(Vector4 vector);
   public override int GetHashCode();

}

In c# I then proceed to create a class that calls the imported function like this:

 public static  Vector4[]  ProbarArmadillo(Vector4[] resultado)
      {
    Vector4[] skel1=new Vector4[20];
    Vector4[] skel2=new Vector4[20];

    skel1[0].X = (float)-0.505401; skel1[0].Y = (float)-0.0968128; skel1[0].Z = (float)2.54701; skel1[0].W = 1;
    skel1[1].X = (float)-0.547074; skel1[1].Y = (float)-0.0348387; skel1[1].Z = (float)2.5876; skel1[1].W = 1;
    skel1[2].X = (float)-0.532013; skel1[2].Y = (float)0.323909; skel1[2].Z = (float)2.60893; skel1[2].W = 1;
    skel1[3].X = (float)-0.468823; skel1[3].Y = (float)0.514958; skel1[3].Z = (float)2.63824; skel1[3].W = 1;
    skel1[4].X = (float)-0.642778; skel1[4].Y = (float)0.221897; skel1[4].Z = (float)2.49321; skel1[4].W = 1;
    skel1[5].X = (float)-0.765644; skel1[5].Y = (float)0.172945; skel1[5].Z = (float)2.27342; skel1[5].W = 1;
    skel1[6].X = (float)-0.793357; skel1[6].Y = (float)0.258069; skel1[6].Z = (float)2.04539; skel1[6].W = 1;
    skel1[7].X = (float)-0.802389; skel1[7].Y = (float)0.291529; skel1[7].Z = (float)2.01768; skel1[7].W = 1;
    skel1[8].X = (float)-0.405216; skel1[8].Y = (float)0.194607; skel1[8].Z = (float)2.75541; skel1[8].W = 1;
    skel1[9].X = (float)-0.297749; skel1[9].Y = (float)0.153036; skel1[9].Z = (float)2.85184; skel1[9].W = 1;
    skel1[10].X = (float)-0.164521; skel1[10].Y = (float)0.228597; skel1[10].Z = (float)2.93223; skel1[10].W = 1;
    skel1[11].X = (float)-0.105644; skel1[11].Y = (float)0.269457; skel1[11].Z = (float)2.98627; skel1[11].W = 1;
    skel1[12].X = (float)-0.551655; skel1[12].Y = (float)-0.15617; skel1[12].Z = (float)2.48071; skel1[12].W = 1;
    skel1[13].X = (float)-0.605082; skel1[13].Y = (float)-0.55405; skel1[13].Z = (float)2.37626; skel1[13].W = 1;
    skel1[14].X = (float)-0.659974; skel1[14].Y = (float)-0.880765; skel1[14].Z = (float)2.35654; skel1[14].W = 1;
    skel1[15].X = (float)-0.597098; skel1[15].Y = (float)-0.914582; skel1[15].Z = (float)2.29637; skel1[15].W = 1;
    skel1[16].X = (float)-0.448527; skel1[16].Y = (float)-0.184062; skel1[16].Z = (float)2.58483; skel1[16].W = 1;
    skel1[17].X = (float)-0.49097; skel1[17].Y = (float)-0.628932; skel1[17].Z = (float)2.57352; skel1[17].W = 1;
    skel1[18].X = (float)-0.515788; skel1[18].Y = (float)-0.962651; skel1[18].Z = (float)2.54876; skel1[18].W = 1;
    skel1[19].X = (float)-0.476598; skel1[19].Y = (float)-1.02878; skel1[19].Z = (float)2.53682; skel1[19].W = 1;

    skel2[0].X = (float)-0.505401; skel2[0].Y = (float)-0.0968128; skel2[0].Z = (float)2.54701; skel2[0].W = 1;
    skel2[1].X = (float)-0.547074; skel2[1].Y = (float)-0.0348387; skel2[1].Z = (float)2.5876; skel2[1].W = 1;
    skel2[2].X = (float)-0.532013; skel2[2].Y = (float)0.323909; skel2[2].Z = (float)2.60893; skel2[2].W = 1;
    skel2[3].X = (float)-0.468823; skel2[3].Y = (float)0.514958; skel2[3].Z = (float)2.63824; skel2[3].W = 1;
    skel2[4].X = (float)-0.642778; skel2[4].Y = (float)0.221897; skel2[4].Z = (float)2.49321; skel2[4].W = 1;
    skel2[5].X = (float)-0.765644; skel2[5].Y = (float)0.172945; skel2[5].Z = (float)2.27342; skel2[5].W = 1;
    skel2[6].X = (float)-0.793357; skel2[6].Y = (float)0.258069; skel2[6].Z = (float)2.04539; skel2[6].W = 1;
    skel2[7].X = (float)-0.802389; skel2[7].Y = (float)0.291529; skel2[7].Z = (float)2.01768; skel2[7].W = 1;
    skel2[8].X = (float)-0.405216; skel2[8].Y = (float)0.194607; skel2[8].Z = (float)2.75541; skel2[8].W = 1;
    skel2[9].X = (float)-0.297749; skel2[9].Y = (float)0.153036; skel2[9].Z = (float)2.85184; skel2[9].W = 1;
    skel2[10].X = (float)-0.164521; skel2[10].Y = (float)0.228597; skel2[10].Z = (float)2.93223; skel2[10].W = 1;
    skel2[11].X = (float)-0.105644; skel2[11].Y = (float)0.269457; skel2[11].Z = (float)2.98627; skel2[11].W = 1;
    skel2[12].X = (float)-0.551655; skel2[12].Y = (float)-0.15617; skel2[12].Z = (float)2.48071; skel2[12].W = 1;
    skel2[13].X = (float)-0.605082; skel2[13].Y = (float)-0.55405; skel2[13].Z = (float)2.37626; skel2[13].W = 1;
    skel2[14].X = (float)-0.659974; skel2[14].Y = (float)-0.880765; skel2[14].Z = (float)2.35654; skel2[14].W = 1;
    skel2[15].X = (float)-0.597098; skel2[15].Y = (float)-0.914582; skel2[15].Z = (float)2.29637; skel2[15].W = 1;
    skel2[16].X = (float)-0.448527; skel2[16].Y = (float)-0.184062; skel2[16].Z = (float)2.58483; skel2[16].W = 1;
    skel2[17].X = (float)-0.49097; skel2[17].Y = (float)-0.628932; skel2[17].Z = (float)2.57352; skel2[17].W = 1;
    skel2[18].X = (float)-0.515788; skel2[18].Y = (float)-0.962651; skel2[18].Z = (float)2.54876; skel2[18].W = 1;
    skel2[19].X = (float)-0.476598; skel2[19].Y = (float)-1.02878; skel2[19].Z = (float)2.53682; skel2[19].W = 1;

  //  pinverse(skel1, Resultado);
    pinverse(skel1, resultado);
    return resultado;
}

and finally I use the function in the main like this:

        Vector4[] resultado = new Vector4[20];

        resultado= Procesar.ProbarArmadillo(resultado);
        Recorder.SaveArmadillo(resultado);

Recorder is a class that puts the output on a txt file, but the file shows a matrix full of zeros.


Solution

  • Your struct declaration is a little off I think. I'm not sure how the marshaller treats auto-implemented properties. I would avoid them. I'd have the struct like this:

    [StructLayout(LayoutKind.Sequential)]
    public struct Vector4
    {
        public float W;
        public float X;
        public float Y;
        public float Z;
    }
    

    And the p/invoke should provide directional attributes. There's also no need for unsafe which I assumed you added whilst trying things at random.

    [DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
    public static extern void pinverse(
        [In, MarshalAs(UnmanagedType.LPArray, SizeConst = 20)]
        Vector4[] skel, 
        [Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 20)]
        Vector4[] result
    );