简体   繁体   English

从C#调用非托管C ++库(dll):如何在托管代码和非托管代码之间正确传递数据

[英]Calling unmanaged C++ library (dll) from C# : How to properly pass data between managed and unmanaged code

I have been working with an interface which read measurement data from a sensor and use a library written in C++ to analyse that data. 我一直在使用从传感器读取测量数据并使用C ++编写的库来分析该数据的接口。

The function is just about the following: 该功能大致如下:

  1. Set measurement parameters on the C++ library 在C ++库上设置测量参数
  2. Get data from the sensor (1200 measurements alltogether) 从传感器获取数据(总共进行了1200次测量)
  3. Write data to C++ library 将数据写入C ++库
  4. Process all 1200 measurements in C++ library 在C ++库中处理所有1200次测量
  5. Read results from C++ library 从C ++库读取结果

Calling this C++ library from C#-code is previously dealt with this question: Calling unmanaged C++ library (dll) from C# creates an access violation error (0xc0000005). 从C#代码调用此C ++库以前已解决以下问题:从C# 调用非托管C ++库(dll)会产生访问冲突错误(0xc0000005)。

Now it seems, that the C++ library either 现在看来,C ++库要么

  • doesn't get data correctly 无法正确获取数据
  • is not able to hold data 无法保存数据
  • is not able to properly return results to my C#-code. 无法将结果正确返回到我的C#代码。

Bad thing is, that I'm not able to debug this C++ library. 不好的是,我无法调试此C ++库。

What is wrong with my code? 我的代码有什么问题?

1) Setting the measurement parameters 1)设置测量参数

namespace PdWaveApi
{
[StructLayout(LayoutKind.Sequential)]
public struct PDDataInfo

{                   
   public int   nPings;              
   public int   nDataRate;          
   public int   nSamples;            
   public float fFrequency;          
   public float fBeamAngle;          
   public int   nInstrument;         
   public int   nCoordSystem;        
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
   public short[] hBeamToXYZ;       
   public short hWaveT1;

    // Constructor
   public static PDDataInfo Create()
   {
       PDDataInfo DataStruct = new PDDataInfo();
       DataStruct.hBeamToXYZ = new short[9];
       return DataStruct;
   }
   }
}

public class PdWaveBaseLWrapper
{
   [DllImport("PdWaveBase.dll", EntryPoint = "PDSetInstrumentConfig")]
   public static extern int PDSetInstrumentConfig(ref PDDataInfo pDataInfo);
}

public void SetInstrumentConfiguration()
{
    PdWaveApi.PDDataInfo InstrumentConfiguration = new PdWaveApi.PDDataInfo();
    .................
    Initializing the InstrumentConfiguration structure
    ...............
    PdWaveBaseLWrapper.PDSetInstrumentConfig(ref InstrumentConfiguration);
}

3) Reading data from sensor and writing data to C++ library 3)从传感器读取数据并将数据写入C ++库

namespace PdWaveApi
{
    [StructLayout(LayoutKind.Sequential)]
    public struct PDWaveSample
    {   
        [MarshalAs(UnmanagedType.I1)]
        public bool Valid;
        public float fPressure;
        public float fDistance;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PD_MAX_WAVEBEAMS)]
        public float[] fVel;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PD_MAX_WAVEBEAMS)]
        public ushort[] nAmp;

        // Constructor

        public static PDWaveSample Create()
        {
            PDWaveSample DataStruct = new PDWaveSample();
            DataStruct.fVel = new float[Constants.PD_MAX_WAVEBEAMS];
            DataStruct.nAmp = new ushort[Constants.PD_MAX_WAVEBEAMS];
            return DataStruct;
        }
    }
}

public class PdWaveBaseLWrapper
{
    [DllImport("PdWaveBase.dll", EntryPoint = "PDSetWaveSample")]
    public static extern int PDSetWaveSample(ref PDWaveSample pWaveSample);
}

namespace SensorInterface
{
    public partial class frmSensorInterface : Form
    {
        public PdWaveApi.PDWaveSample WaveSampleData = PdWaveApi.PDWaveSample.Create();

        private void OnNewData(object sender, OnNewDataEvent e)
        {
            ReadWaveSample(ref WaveSampleData);
            SetWaveSample(ref WaveSampleData);
        }

        public void ReadWaveSample(ref PdWaveApi.PDWaveSample WaveSampleData)
        {
            DateTime MeasurementTimeStamp;
            float[] dVel = new float[4];
            float dTemperature = new float();
            float dPitch = new float();
            float dRoll = new float();
            float dHeading = new float();
            float dPressure = new float();
            short[] sAmp = new short[4];

            //  Read some of the latest data from the control
            GetVelocity(ref dVel[0], ref dVel[1], ref dVel[2], ref dVel[3]);
            GetAmplitude(ref sAmp[0], ref sAmp[1], ref sAmp[2], ref sAmp[2]);

            ..............
            // Set other data to the structure

        }

        public void SetWaveSample(ref PdWaveApi.PDWaveSample WaveSampleData)
        {
            PdWaveBaseLWrapper.PDSetWaveSample(ref WaveSampleData);
        }
    }
}

4) Process all 1200 measurements in C++ library 4)在C ++库中处理所有1200次测量

[StructLayout(LayoutKind.Sequential)]
public struct PDWaveBurst
{
    [MarshalAs(UnmanagedType.ByValArray , SizeConst = Constants.PD_MAX_WAVEMEAS_AST)]    
    public float[] fST; 
    public float fWinFloor;
    public float fWinCeil;
    [MarshalAs(UnmanagedType.I1)]
    public bool bUseWindow;
    [MarshalAs(UnmanagedType.I1)]
    public bool bSTOk;
    [MarshalAs(UnmanagedType.I1)]
    public bool bGetRawAST;
    [MarshalAs(UnmanagedType.I1)]
    public bool bValidBurst;

    public static PDWaveBurst Create()
    {
        PDWaveBurst DataStruct = new PDWaveBurst();
        DataStruct.fST = new float[Constants.PD_MAX_WAVEMEAS_AST];
        return DataStruct;
    }
}

[DllImport("PdWaveBase.dll", EntryPoint = "PDPreProcess")]
public static extern int PDPreProcess(int nSample, ref PDWaveBurst pWaveBurst);

[DllImport("PdWaveBase.dll", EntryPoint = "PDProcessReturnInt")]
public static extern int PDProcessReturnInt();

public void PreprocessBurstData(int nSamples)
{
    PdWaveApi.PDWaveBurst WaveBurstData = PdWaveApi.PDWaveBurst.Create();

    WaveBurstData.fST = new float[4096];
    WaveBurstData.fWinFloor = (float)1.25;
    WaveBurstData.fWinCeil = 2;
    WaveBurstData.bUseWindow = false;
    WaveBurstData.bSTOk = false;
    WaveBurstData.bGetRawAST = false;
    WaveBurstData.bValidBurst = false;

    PdWaveBaseLWrapper.PDPreProcess(nSamples, ref WaveBurstData);
}

public void ProcessData()
{
    int ProcessError = PdWaveBaseLWrapper.PDProcessReturnInt();
}

5) Read results from C++ library 5)从C ++库读取结果

[StructLayout(LayoutKind.Sequential)]
public struct PDWavePar {
   public float fTm02;  
   public float fTp;     
   public float fDirTp;  
   public float fSprTp;  
   public float fMainDir;
   public float fUI;     
   public float fHm0;   
   public float fH3;
   public float fT3;    
   public float fH10; 
   public float fT10;
   public float fHmax;
   public float fTmax;
   public float fTz;
   public float fMeanPres;
   public int   nNumNoDet;
   public int   nNumBadDet;
   public int   nErrCode;  
   public int   nSpectrum; 
   public float fMeanAST;
}


[DllImport("PdWaveBase.dll", EntryPoint = "PDGetWavePar")]
public static extern int PDGetWavePar(ref PDWavePar pwWavePar);

public void GetOutput()
{
    PdWaveApi.PDWavePar WaveParameters = new PdWaveApi.PDWavePar();
    PdWaveBaseLWrapper.PDGetWavePar(ref WaveParameters);
}

So, as conclusion: 因此,作为结论:

What should I change in my code - to pass data correctly to unmanaged dll - to have dll hold and process the data in its' internal structures - to read results correctly from unmanaged code to my C# program? 我应该在代码中进行哪些更改-正确地将数据传递给非托管dll-使dll保留并处理其内部结构中的数据-从非托管代码正确读取结果到C#程序?

(Sorry about the length of my question.) (很抱歉,我的提问时间太长了。)

The final solution to my problem was to change the alignment to 1 byte, like this: 我的问题的最终解决方案是将对齐方式更改为1个字节,如下所示:

C# struct definitions: From: C#结构定义:来自:

    [StructLayout(LayoutKind.Sequential)]

to

    [StructLayout(LayoutKind.Sequential, Pack=1)]

This has been discussed at least here: Calling C++ metro dll from c# metro app and returning filled structures 至少在这里已对此进行了讨论: 从c#Metro应用程序调用C ++ Metro dll并返回填充的结构

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从C#windows服务调用C ++ DLL(非托管代码)(用托管代码编写) - Calling a C++ dll (unmanaged code) from a C# windows service (written in managed code) 如何将结构从C#托管结构传递到C ++非托管DLL并得到结果结构? - How can I pass struct from C# managed to C++ unmanaged DLL and get struct in result? 在从托管C#应用程序进行的非托管C ++ Dll调用中,如何处理数据类型之间的冲突 - In Unmanaged C++ Dll call From Managed C# Application, How to handle conflicts between Datatypes 如何在托管 (C#) 和非托管 (C++) 代码之间来回传递数组内容 - How to pass array contents back and forth between managed (C#) and unmanaged (C++) code 从非托管C ++代码调用托管C#组件,我该如何定义配置 - calling managed c# component from unmanaged c++ code, how do i define config 从非托管C ++调用托管C#函数 - calling managed c# functions from unmanaged c++ 如何从非托管应用程序将数据传递给C#COM DLL - How to pass data to C# COM DLL from unmanaged application 如何从 C# 的 char * 传递和接收数据到非托管 C++ DLL - How to pass and receive data from a char * from C# to an unmanaged C++ DLL 从托管 C# 回调到非托管 C++ 代码 - Callbacks from Managed C# to Unmanaged C++ Code 从C#调用非托管C ++类DLL - Calling unmanaged C++ Class DLL from C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM