Question

I have C code which will be build as a dynamic library (DLL) , which i would like to call C function from C# using dLL created from the C code

C code :

struct data
{
  char data_val1[100];
  float data_val2;
  float data_val3[50];
};
typedef struct data data;

#ifdef __cplusplus
extern "C" __declspec(dllexport) void cfun_call(data *pdata,long count);
#endif

#ifdef __cplusplus
extern "C"
{
#endif

__declspec(dllexport) void cfun_call(data *pdata,long count)
 {
   int x = 0;
   for(x=0;x<count;x++)
   {
     data[x].data_val2 = (pdata->data_val3[49] + pdata->data_val3[48]) / 2.0;
   }
 }
#ifdef __cplusplus
}
#endif  

Here i wanted to import the function "cfun_call" in C# code, and pass values to the fucntion call and manipulate the passed values in C function from the dll and wanted to display the updated values back to the C# code and display it, Since my expertise in C# is limited i need some help to solve this issue

C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

class Program
{
     public class data
     {
         public char[] data_val1 = new char[100];
         public float data_val2;
         public float[] data_val3 = new float[50];

     };
     [DllImport("mycdll.dll", EntryPoint = "cfun_call", CallingConvention =     CallingConvention.Cdecl, ExactSpelling = false)] 
     // void cfun_call(data *pdata,long count); //C function for reference
     public static extern void cfun_call([In, Out] data[] ouputdata, long count);
     static void Main(string[] args)
     {
            data[] objData = new data[10];
            for (int i = 0; i < 10; i++)
            {
                //Fill the data in objitemData
                objData[i] = new objData();
                for (int j = 0; j < 100; j++)
                {
                   objData[i].data_val1[j] =  '\0';
                }

                for (int k = 0; k < 50; k++)
                {
                  objData[i].data_val3[k] = 20.00;
                }
                objData[i].data_val2 = 0.00;
            }

            cfun_call(objData,10); //Making call to C dll function

            for (int i = 0; i < 10; i++)
                Console.WriteLine("{0} ", objData[i].data_val2);

             Console.WriteLine("");//new line
             Console.ReadLine();

     }
 }

Here the values (objData) passed from C# function is not updated by using the C dll fucntion , I am not sure why. Can anyone point me to right direction ?

Edit 1:

I have updated code as suggested ,

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct data
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
    public char[] data_val1;
    public float data_val2;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
    public float[] data_val3;
};

Initialized struct elements like below ,

    data[] objData = new data[10];

    for (int i = 0; i < 10; i++)
    {
        //Fill the data in objitemData
        objData[i] = new objData();
        for (int j = 0; j < 100; j++)
        {
           objData[i].data_val1[j] =  '\0'; //I am getting exception here 
        }

        for (int k = 0; k < 50; k++)
        {
          objData[i].data_val3[k] = 20.00;
        }
        objData[i].data_val2 = 0.00;
    }

Runtime i am getting null ptr exception , like

An unhandled exception of type 'System.NullReferenceException' occurred in mybinary.exe

Additional information: Object reference not set to an instance of an object.

How to initialize the struct array elements properly in manged code ?

Edit 2:

Hi one more question , when i add , objData[i].data_val3[k] = randomData; //randomvalues, It is not updated when making cfun_call while using contnt value it is updated why ?

Was it helpful?

Solution

Your translation of the struct is incorrect. You need it to be like so:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct data
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
    public char[] data_val1;
    public float data_val2;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
    public float[] data_val3;
};

You have to make this a struct since you need to pass an array of values. Your declaration using class leads to you passing an array of references.

You will need to initialize the arrays explicitly now. That might look like so:

data[] objData = new data[10];
for (int i = 0; i < 10; i++)
{
    objData[i].data_val1 = new char[100];
    objData[i].data_val2 = 0.00;
    objData[i].data_val3 = new float[50];
    for (int k = 0; k < 50; k++)
    {
        objData[i].data_val3[k] = 20.0f;
    }
 }

Further, C++ long is 32 bits wide, but C# long is 64 bits wide. You therefore have a mismatch. Your p/invoke should be:

[DllImport("mycdll.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern void cfun_call(
    [In, Out] data[] ouputItem_data, 
    int count
);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top