使用dllimport从C#代码更新C dll结构数组及其元素值

时间:2014-04-10 09:22:16

标签: c# c pinvoke dllimport dllexport

我有C代码,它将构建为动态库(DLL),我想要 使用从C代码创建的dLL从C#调用C函数

C代码:

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  

这里我想导入函数&#34; cfun_call&#34;在C#代码中,并将值传递给fucntion调用 并从dll处理C函数中传递的值,并希望显示更新的值 回到C#代码并显示它,因为我对C#的专业知识有限,我需要一些帮助来解决这个问题

C#代码:

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();

     }
 }

这里从C#函数传递的值(objData)没有使用C dll函数更新,我不知道为什么。 有人能指出我正确的方向吗?

编辑1:

我按照建议更新了代码,

[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;
};

初始化的struct元素,如下所示,

    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;
    }

运行时我得到null ptr异常,比如

未处理的类型&#39; System.NullReferenceException&#39;发生在mybinary.exe

附加信息:未将对象引用设置为对象的实例。

如何在manged代码中正确初始化struct数组元素?

编辑2:

还有一个问题,当我添加时,objData [i] .data_val3 [k] = randomData; // randomvalues,在使用contnt值进行cfun_call时没有更新它更新为什么?

1 个答案:

答案 0 :(得分:3)

您对结构的翻译不正确。你需要它是这样的:

[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;
};

您必须将此结构化为结构,因为您需要传递值数组。使用类的声明会导致您传递一系列引用。

您现在需要显式初始化数组。这可能是这样的:

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;
    }
 }

此外,C ++ long是32位宽,但C#long是64位宽。因此你有一个不匹配。你的p / invoke应该是:

[DllImport("mycdll.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern void cfun_call(
    [In, Out] data[] ouputItem_data, 
    int count
);