来自不受管理的c ++ dll的c#传递结构 [英] c# pass structure from unmanaged c++ dll

查看:89
本文介绍了来自不受管理的c ++ dll的c#传递结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关将结构从非托管c ++ dll传递到c#的帮助?

我正在努力将来自非托管第三方c ++ dll的结构传递回我的c#应用程序.该dll用于光谱仪.除此命令外,对光谱仪执行的所有其他命令均能正常运行.我在下面粘贴了更多文档,但这是c ++调用:

Help with passing structure from unmanaged c++ dll to c# ?

I am struggling with passing a structure from an unmanaged third party c++ dll back into my c# application. The dll is for a spectrometer. All of the other commands to the spectrometer work fine except this one. I am pasting more documentation below, but here is the c++ call:

SDK_API MTSSE_GetDeviceSpectrometerFrameData( int DeviceID, int SpectrometerID, int WaitUntilDone, tFrameRecord* &FrameData);



这是问题的最后一个论点.该文档说:


FrameRecordData-如果频谱准备就绪,则指向频谱数据结构的指针;如果频谱尚未准备就绪,则指向nil.它定义为:



and it is the last argument that is the problem. The documentation says this:


FrameRecordData - the pointer to the spectrum data structure if spectrum is ready or nil if spectrum is not ready. It is defined as:

typedef struct
{
  double* CCDData;
  double* CalibData;
  double* AbsIntenData
}tFrameRecord;


并且每个项目都应再次指向一个定义为double data [3648]的double数据数组.


首先,我尝试了此操作(在名称空间中):


And each item again should points to a double data array which defined as double data[3648].


First I tried this (in the namespace):

public struct MTFrameRecordData
{
    public double[] CCDData;
    public double[] CalibData;
    public double[] AbsIntenData;
}


在名为myUSBCam的类中,该类包含包装器:


With this in a class called myUSBCam, that holds the wrappers:

   //MTSSE_GetDeviceSpectrometerFrameData(int DeviceID, int SpectrometerID, int      WaitUntilDone, tFrameRecord* &FrameData );
   public int MTGetDeviceSpectrometerFrameData(int DeviceID, int SpectrometerID, int WaitUntilDone, MTFrameRecordData FrameData)
   {
       int numOut = MT_GetDeviceSpectrometerFrameData(DeviceID, SpectrometerID, WaitUntilDone, FrameData);

       if (numOut < 0)
       {
           MessageBox.Show("Error trying to SetDeviceExposureTime. No cameras found on USB 2.0 bus.", _camError, MessageBoxButtons.OK, MessageBoxIcon.Error);
       }

       return numOut;
   }

//...

   //MTSSE_GetDeviceSpectrometerFrameData(int DeviceID, int SpectrometerID, int WaitUntilDone, tFrameRecord* &FrameData );
   [DllImport("MT_Spectrometer_SDK.dll", EntryPoint = "MTSSE_GetDeviceSpectrometerFrameData", CallingConvention = CallingConvention.StdCall)]
   private static extern int MT_GetDeviceSpectrometerFrameData(int DeviceID, int SpectrometerID, int WaitUntilDone, MTFrameRecordData FrameData);


然后在我的主应用程序中将其调用(nInit等于1):


And then I call this in my main application (nInit is equal to 1):

int numOut5 = 0;
while (numOut5 <= 0)
{
    System.Threading.Thread.Sleep(20);
    numOut5 = myUSBCam.MTGetDeviceSpectrometerFrameData(nInit, 1, 1, frameRecordData);
 }



有了这个我得到错误信息:


USBCam.exe中发生了类型为"System.Runtime.InteropServices.MarshalDirectiveException"的未处理的异常


附加信息:无法编组参数#4":无效的托管/非托管类型组合.


我也尝试过这种方法来声明结构(同样在名称空间中):




With this I get the error message:


An unhandled exception of type ''System.Runtime.InteropServices.MarshalDirectiveException'' occurred in USBCam.exe


Additional information: Cannot marshal ''parameter #4'': Invalid managed/unmanaged type combination.


I also tried this for the declaration of the structure (again in the name space):


[StructLayout(LayoutKind.Explicit)]
public struct MTFrameRecordData
{
    [FieldOffset(0)]
    public double[] CCDData;
    [FieldOffset(29184)]
    public double[] CalibData;
    [FieldOffset(58368)]
    public double[] AbsIntenData;
}



这会产生错误消息

USBCam.exe中发生了类型为"System.Runtime.InteropServices.MarshalDirectiveException"的未处理的异常
附加信息:内部限制:方法签名太复杂或太大.

任何人都可以帮助我如何将结构从非托管C ++ dll传递到我的C#应用​​程序中吗?


从文档开始更详细的描述:

SDK_API MTSSE_GetDeviceSpectrometerFrameData(int DeviceID,int SpectrometerID,int WaitUntilDone,tFrameRecord *& FrameData);
发送上述MTSSE_StartGrabSpectrum()命令后,用户可以调用此函数以检查频谱是否已准备好并获取频谱.
参数:DeviceID-设备的索引,请参考MTSSE_InitDevice()函数的注释.
SpectrometerID –光谱仪的索引,应始终设置为1.
FrameRecordData-如果频谱准备就绪,则指向频谱数据结构的指针;如果频谱尚未准备就绪,则指向nil.它定义为:
typedef struct
{
double * CCDData;
double * CalibData;
double * AbsIntenData
} tFrameRecord;
并且每个项目都应再次指向一个定义为double data [3648]的double数据数组.
CCDData是原始像素数据,
CalibData是具有ETC校准的CCDDataa(如果打开了etc标志),如果ETC关闭,则它应等于CCDData.
如果AIC系数存在,则AbsIntenData返回绝对强度数据
WaitUntilDone –抓帧过程可能需要相当长的时间(取决于曝光时间设置和平均帧数设置).用户可以设置:
1:API将一直被阻塞,直到频谱被捕获为止,返回的频谱由FrameRecordData指向.如果返回的指针为nil,则会发生超时"错误.
0:不会阻塞API,如果频谱准备就绪,频谱将在FrameRecordData中返回),否则它将返回nil.
返回值:-1,如果抓取命令未完成(当WaitUntilDone为"0"时)或发生超时"错误(当WaitUntilDone为"1"时).
1,如果功能成功.



This produces the error messsage

An unhandled exception of type ''System.Runtime.InteropServices.MarshalDirectiveException'' occurred in USBCam.exe
Additional information: Internal limitation: method signature is too complex or too large.

Can anyone help me with how to pass the structure from the unmanaged c++ dll into my c# application?


Begin more detailed description from the documentation:

SDK_API MTSSE_GetDeviceSpectrometerFrameData( int DeviceID, int SpectrometerID, int WaitUntilDone, tFrameRecord* &FrameData);
After sending the above MTSSE_StartGrabSpectrum() command, user can invoke this function to check whether the spectrum is ready and to get the spectrum.
Arguments: DeviceID -- the index of the device, Please refer to the notes of MTSSE_InitDevice() function.
SpectrometerID – the index of the spectrometer, should always be set to 1.
FrameRecordData - the pointer to the spectrum data structure if spectrum is ready or nil if spectrum is not ready. It is defined as:
typedef struct
{
double* CCDData;
double* CalibData;
double* AbsIntenData
}tFrameRecord;
And each item again should points to a double data array which defined as double data[3648].
CCDData is the raw pixel data,
CalibData is the CCDDataa with ETC calibration (if etc flag was turned on), if ETC is off, it should equal the CCDData.
AbsIntenData returns the absolute intensity data if AIC coefficients exists
WaitUntilDone – the frame grabbing process may need considerable time (depends on the exposure time setting and average frame number setting). User might set:
1: The API will be blocked until the spectrum is grabbed, the returned spectrum is pointed by the FrameRecordData, If the returned pointer is nil, "Time out" error occurs.
0: The API will not be blocked, if the spectrum is ready, the spectrum will be returned in FrameRecordData), otherwise, it will return nil.
Return: -1, if the grabbing command is not finished (when WaitUntilDone is "0") or "Time out" error occurs (when WaitUntilDone is "1").
1, if function succeeds.

推荐答案

问题是,在C ++结构中有指针,您试图将它们转换为数组,这绝对是不行的. br/> 您将必须使用intptr或类似的东西.
我在这里找到了可以使您朝正确方向发展的东西:
http://blogs.msdn.com/b/jaredpar/archive/2008/11/05/dereference-a-double-intptr.aspx [
The problem is that in the C++ structure there are pointers, you are trying to convert those to arrays and that is definitely a no go.
You will have to use an intptr or something like that.
I found something that should get you in the right direction here :
http://blogs.msdn.com/b/jaredpar/archive/2008/11/05/dereference-a-double-intptr.aspx[^]


Philip Stuyck的引用非常有帮助,但我还要感谢制造光谱仪的公司(mightexsystems.com)的帮助.

我仍然不喜欢该解决方案,因为现在它在包装器(本质上是c ++)中使用了不安全的代码来取消对双指针的引用.有人可以为此建议纯安全的C#代码吗?

这是所有荣耀的解决方案.这与我上面的最初尝试的描述类似,但现在可以了:

在名称空间中:

The reference from Philip Stuyck was very helpful, but I want to also acknowledge receiving help from the company that makes the spectrometers (mightexsystems.com).

I still don''t like the solution, because now it uses unsafe code in the wrapper, essentially c++, to de-reference the double-pointer. Can anyone suggest pure safe c# code for this?

Here is the solution in all of it''s glory. This parallels the description of my initial attempt above, but now it works:

In the namespace:

public struct MTFrameRecordData
{
    public IntPtr CCDData;
    public IntPtr CalibData;
    public IntPtr AbsIntenData;
}



在光谱仪类中:



In the spectrometer class:

public double[] RawDataArray;
public double[] CaliDataArray;
public double[] AbsIntenArray;



同样在光谱仪类中,包装器:



Also in the spectrometer class, the wrapper:

// Note that the wrapper does not have the MTFrameRecordData
// structure as an argument. The return is passed directly into the
// public spectrometer class double[] arrays: RawDataArray,
// CaliDataArray, AbsIntenArray.
public int MTGetDeviceSpectrometerFrameData(int DeviceID,
     int SpectrometerID, int WaitUntilDone)
{
    IntPtr ptrFrameData = IntPtr.Zero;
    int numOut = MT_GetDeviceSpectrometerFrameData(DeviceID,
      SpectrometerID, WaitUntilDone, ref ptrFrameData);

    if (numOut < 0)
    {
       MessageBox.Show("Error in GetFrameData.", "Spectrometer error ",
        MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    else
    {
        unsafe
        {
            MTFrameRecordData* FrameRecordPtr;
            double* RawDataPtr;
            double* CaliDataPtr;
            double* AbsIntenPtr;
            int i;

            FrameRecordPtr = (MTFrameRecordData*)ptrFrameData;
            RawDataPtr = (double*)FrameRecordPtr->CCDData;
            CaliDataPtr = (double*)FrameRecordPtr->CalibData;
            AbsIntenPtr = (double*)FrameRecordPtr->AbsIntenData;
            for (i = 0;
              i < Properties.Settings.Default.pixelArrayLength; i++)
            {
                RawDataArray[i] = *RawDataPtr++;
                CaliDataArray[i] = *CaliDataPtr++;
                AbsIntenArray[i] = *AbsIntenPtr++;
            }
        }
    }

    return numOut;
}



我认为p调用仍然相同.对不起,包装不好.这里的格式很窄.



The p-invoke is still the same I think. Excuse the bad wrapping. The format here is narrow.

[DllImport("MT_Spectrometer_SDK.dll", EntryPoint = "MTSSE_GetDeviceSpectrometerFrameData", CallingConvention = CallingConvention.StdCall)]
private static extern int MT_GetDeviceSpectrometerFrameData(int DeviceID, int SpectrometerID, int WaitUntilDone, ref IntPtr ptrFrameData);



现在调用的主要形式为:



Now the call in the main form:

while (numOut5 <= 0)
{
    System.Threading.Thread.Sleep(100);
    numOut5 = mightexSpectrometer1.MTGetDeviceSpectrometerFrameData(nInit, 1, 1);
}


这篇关于来自不受管理的c ++ dll的c#传递结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆