2

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 ?

cslrnr
  • 694
  • 1
  • 8
  • 24
  • 1
    Pretty unclear how item_data and data are related in the C# snippet, post real code. It must be struct, not a class and the arrays require the [MarshalAs(UnmanagedType.ByValArray, SizeConst = xx)] attribute. Second argument is int, not long. – Hans Passant Apr 10 '14 at 09:39
  • edited the code.. this code is similar to real code...If i use MarshalAs(...), how do initialize the elements of sturct, will that be auto initialized ? – cslrnr Apr 10 '14 at 09:48
  • 1
    No, you need to initialize them. You don't have any choice in the matter. You have to declare it as a struct. – David Heffernan Apr 10 '14 at 10:08
  • I have updated code but i am getting null ptr exception, i think i havn't initalized them properly.. – cslrnr Apr 10 '14 at 12:37
  • 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 ? – cslrnr Apr 10 '14 at 14:45

1 Answers1

3

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
);
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Hi,Thanks for the reply. I have put a print statement in cfun_call in code and compiled and used that dll in C# , The count value is printed correctly but when i put print for pdata->data_val3[49] it is printing zero, I think the memory is not correctly copied to pdata to c call , what do you think? – cslrnr Apr 10 '14 at 09:37
  • What I think is what is written above in the answer. – David Heffernan Apr 10 '14 at 09:38
  • Hi i have updated the code as suggested but I am not sure if i have initialized it correctly, can you give me suggestion on the code plz? – cslrnr Apr 10 '14 at 12:52
  • 1
    You need to initialise the arrays. You are not doing that. Let me add some code to my answer. – David Heffernan Apr 10 '14 at 12:55
  • 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 ? – cslrnr Apr 10 '14 at 14:38