C#调用C/C++ dll中结构体内float*等指针的方法

      搞C#开发的应该经常遇到需要调用C/C++的DLL,对于托管的库还好说,可以直接引用。非托管的就相对麻烦一些,需要DllImport导入,这时候就要参考头文件重写一遍所有的函数,以及函数中的枚举、结构体等。于是,问题就来了,C++中经常用到的指针该怎么传递给C#呢?下面告诉大家C#如何调用C/C++ dll中结构体内float*等指针。

        C++ dll的头文件代码如下所示:

 /// <summary>
 /// 雷达帧数据
 /// </summary>
 struct FrameData
 {
     float* points;   //点坐标x,y,z循环(x为行走方向,为当前距离值)
     int pointsLen;      //points指针数组长度
     float distance;  //当前距离(单位:m)
     float circleX;   //拟合圆心坐标X(单位:mm)
     float circleY;   //拟合圆心坐标Y(单位:mm)
 };


/// <summary>
/// 绑定显示控件句柄
/// </summary>
/// <param name="hwd">控件句柄</param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
extern "C" _declspec(dllexport) void* _stdcall BindingHandle(HWND hwd, int width, int height);

/// <summary>
/// 传入数据
/// </summary>
/// <param name="frameDatas">帧数据</param>
/// <param name="pointNum">帧总数</param>
/// <returns></returns>
extern "C" _declspec(dllexport) int _stdcall EntryData(FrameData* frameDatas, int pointNum);
 
/// <summary>
/// 设置管道参数
/// </summary>
/// <param name="pipeDiameter">管道直径</param>
/// <returns></returns>
extern "C" _declspec(dllexport) int _stdcall SetPipePara(int pipeDiameter);

        C#需要调用其中的方法时,对于float指针points这个参数,C#是不能够直接用float[]进行传递的,可以使用不安全代码unsafe构造同样的float*指针进行传递。也可以使用IntPtr。

   public class PointCloudLib
    {
        /// <summary>
        /// 雷达帧数据
        /// </summary>
        public unsafe struct FrameData
        {
            public float* points;     //点坐标x,y,z循环(x为行走方向,为当前距离值)
           // public IntPtr points; 
            public int pointsLen;      //points数组长度
            public float circleX;    //拟合圆心坐标X(单位:mm)
            public float circleY;    //拟合圆心坐标Y(单位:mm)
            public float radius;     //拟合圆半径(单位:mm)
        };

        public const string dllPath = "ZYPointCloudLib.dll";

        [DllImport(dllPath, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr BindingHandle( IntPtr hwd, int width, int height);


        [DllImport(dllPath, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int EntryData(FrameData[] frameDatas, int pointNum);

        [DllImport(dllPath, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int SetPipePara(int pipeDiameter);

    }

使用指针时,采用如下方法赋值,stackalloc 分配的内存有限:

PointCloudLib.FrameData[] frameDatas = new PointCloudLib.FrameData[lidData.frameDatas.Length];
unsafe
{
    for (int i = 0; i < lidData.frameDatas.Length; i++)
    {
        float* p = stackalloc float[lidData.frameDatas[i].ValidDataCount * 3]; //stackalloc仅在局部变量的初始值设定项中有效,自动释放
        frameDatas[i].points = p;
        frameDatas[i].pointsLen = lidData.frameDatas[i].ValidDataCount * 3;
        List<PointF> CoordinatePoints = DataProcess.DataProcessing(lidData.frameDatas[i].FrameData, 0, lidData.frameDatas[i].ValidDataCount, 0, 360, true);
        int index = 0;
        for (int j = 0; j < CoordinatePoints.Count; j++)
        {
            frameDatas[i].points[index] = lidData.frameDatas[i].Distance * 1000;
            frameDatas[i].points[index + 1] = CoordinatePoints[j].X;
            frameDatas[i].points[index + 2] = CoordinatePoints[j].Y;
            index += 3;
        }

        frameDatas[i].circleX = lidData.frameDatas[i].CircleX;
        frameDatas[i].circleY = lidData.frameDatas[i].CircleY;
        frameDatas[i].radius = lidData.frameDatas[i].FittingCircleDia / 2;
    }
    bool ret = PointCloudLib.SetPipePara(lidData.headInfo.PipeSize[0]);
    ret = PointCloudLib.EntryData(frameDatas, frameDatas.Length);
}
                  

使用IntPtr时,使用如下方法赋值:

for (int i = 0; i < lidData.frameDatas.Length; i++)
{
    List<PointF> CoordinatePoints = DataProcess.DataProcessing(lidData.frameDatas[i].FrameData, 0, lidData.frameDatas[i].ValidDataCount, 0, 360, true);
    float[] points = new float[CoordinatePoints.Count * 3];
    frameDatas[i].pointsLen = CoordinatePoints.Count * 3;
    int index = 0;
    for (int j = 0; j < CoordinatePoints.Count; j++)
    {
        points[index] = lidData.frameDatas[i].Distance * 1000;
        points[index + 1] = CoordinatePoints[j].X;
        points[index + 2] = CoordinatePoints[j].Y;
        index += 3;
    }
    frameDatas[i].points = Marshal.AllocHGlobal(CoordinatePoints.Count * 3 * sizeof(float));
    Marshal.Copy(points, 0, frameDatas[i].points, points.Length);
    frameDatas[i].circleX = lidData.frameDatas[i].CircleX;
    frameDatas[i].circleY = lidData.frameDatas[i].CircleY;
    frameDatas[i].radius = lidData.frameDatas[i].FittingCircleDia / 2;
}
bool ret = PointCloudLib.SetPipePara(lidData.headInfo.PipeSize[0]);
ret = PointCloudLib.EntryData(frameDatas, frameDatas.Length);

posted on 2022-03-21 21:51  FreshBreezes  阅读(820)  评论(0编辑  收藏  举报

导航