试图将uint8_t *从C#传递到C ++的奇怪问题

时间:2018-04-04 22:55:45

标签: c# c++ .net dll

我在使用C#的第三方API时遇到了重大问题。我没有此API的完整源代码,也不知道DLL是如何编译的。我已经尝试了很多很长时间才弄清楚这一点无济于事。

据我所知,有问题的函数在C ++中定义如下:

    extern "C" uint32_t __stdcall GetQHYCCDSingleFrame(qhyccd_handle *handle,
 uint32_t *w, uint32_t *h, uint32_t *bpp, uint32_t *channels, uint8_t *imgdata);

有问题的问题是uint8_t *imgdata。它旨在成为一个8位整数数组,通过引用该函数传递。在C ++中,我声明了对象:

ImgData = (unsigned char *)malloc(length);
memset(ImgData,0,length);

在将其传递给上述函数之前。

在C#中,我尝试了一些正确传递imgdata对象的方法,但都导致了类似的问题。例如,我在C#中声明了一个字节数组: byte[] ImgData = new byte[length]。使用以下声明将GetQHYCCDSingleFrame函数导入C#:

[DllImport("qhyccd.dll", EntryPoint = "GetQHYCCDSingleFrame")]
        public static extern UInt32 GetQHYCCDSingleFrame(IntPtr handle, ref UInt32 w, ref UInt32 h, ref UInt32 bpp, ref UInt32 channels, byte[] rawArray);

我可以正确调用该函数而不会出错,但在尝试在C#中使用ImgData数组时遇到了问题。特别是,假设我想使用以下代码片段将数组中的每个元素打印到控制台:

for (int i = 0; i < length; i++)
{
    Console.WriteLine(Convert.ToString(ImgData[i]));  
}

这似乎一直持续到第84,000个元素,此时会出现一个弹出窗口,告诉我“应用程序已停止工作”,没有其他错误信息。我可以很好地访问该元素,但如果我想将每个元素写入.CSV文件,循环将始终使我的程序崩溃而没有错误信息。为了使事情更奇怪,以下代码片段将起作用:

byte safeByte;
for (int i = 0; i < length; i++)
{
   safeByte = rawArray[i];

}

这表明它不一定是内存访问问题。而且,最后,为了让事情更加令人困惑,这段代码片段会因“应用程序已停止工作”弹出窗口而崩溃:

byte safeByte;
byte[] newArray = new byte[length];
for (int i = 0; i < length; i++)
{
     safeByte = rawArray[i];
}

除了在声明newArray对象之前它会崩溃,甚至在进入循环之前。

我尝试过类似于我的stackoverflow问题的许多解决方案,但没有任何工作,我将始终得到相同的“应用程序已停止工作”弹出窗口。我真的只需要以某种方式将这些数据以整数形式保存到文本文件中。

1 个答案:

答案 0 :(得分:0)

如果无法访问图书馆本身,很难提供直接帮助。但是,通常可以通过创建填充程序来解决互操作问题,然后在填充程序工作时将填充程序的代码收缩为不存在。这种方法的另一个好处是,它可以将问题分解为更易于管理的块,并且如果卡住,可以更容易地请求集中帮助。

如何通过填充来解决C#/ C ++互操作问题:

  1. 编写一个可以调用库的C ++应用程序。 理想情况下,这只是编译代码示例的问题 供应商。
  2. 编写一个可以从C#调用的简单C ++库。 这应该只是从MSDN或其他地方编译代码示例。
  3. 从步骤2迭代地修改C ++和C#代码的签名,直到它与步骤1中使用的签名相同。如果您遇到任何复杂参数,请将它们拆分为基元并单独传递它们。
    • 如果将参数拆分为足够基本的组件,您可能会找到工作代码示例。
    • 如果您遇到某个特定参数,请同时写下一个损坏的版本(使用您坚持使用的参数)和一个工作版本(使用您在步骤2中工作的参数)。然后,您可以在SO上发布问题,
        

      上面的代码有效,但是当我将参数从classA更改为classB时,第5行会导致崩溃并显示错误消息“error:foo”。由于ZZZ,我认为这种改变是可以的。如何在没有崩溃的情况下添加classB参数?

  4. 在步骤1中将您的应用程序重新编译为库。修改步骤3中的代码以调用此库。
  5. (可选)内联步骤1和3中的代码(即,去除垫片)。如果此步骤失败,您可能会陷入某个特定参数,这也可能适合重新处理stackoverflow问题。
  6. (可选)重新组合在步骤3中拆分的所有参数。