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

  • 相关阅读:
    JSTL标签用法
    (转)javascript正则实战
    Spring中几种数据源的配置
    (转)常用正则表达式
    EL表达式详解
    JAVA环境变量配置(转)
    S2SH整合步骤
    正则表达式30分钟教程(转)
    在Flash Player 10.2中使用原生鼠标指针
    time
  • 原文地址:https://www.cnblogs.com/thebreeze/p/16036843.html
Copyright © 2020-2023  润新知