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

标签 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 问题的解决方案,但没有任何效果,而且我总是会看到相同的“应用程序已停止工作”弹出窗口。我真的只需要以某种方式将这些数据以整数形式保存到文本文件中。

最佳答案

如果不能访问图书馆本身,就很难提供直接帮助。然而,互操作问题通常可以通过创建一个 shim 来解决,然后在 shim 工作后将 shim 的代码收缩为不存在。这种方法的另一个好处是它将问题拆分为更易于管理的 block ,并且在遇到困难时更容易寻求有针对性的帮助。

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

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

      The above code works, but when I change the parameter from classA to classB, line 5 causes a crash with the error message "error: foo". I thought this change was OK because of ZZZ. How can I add a classB parameter without this crash?

  4. 将第 1 步中的应用程序重新编译为库。修改第 3 步中的代码以调用此库。
  5. (可选)内联第 1 步和第 3 步中的代码(即去掉 shim)。如果此步骤失败,您可能会停留在特定参数上,这可能再次适合重新处理成 stackoverflow 问题。
  6. (可选)重新组合在第 3 步中拆分的所有参数。

关于c# - 尝试将 uint8_t* 从 C# 传递到 C++ 的奇怪问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49661658/

相关文章:

c# - 应该使用 ToEntity<T> 而不是类型转换吗?

c# - 删除 ExpanderView 中的左边距/填充

c# - foreach 循环的当前索引

c++ - 是 Visual C++ 优化器错误还是我的代码中有错误?

c++ - 执行 pthread_join 时间歇性应用程序崩溃

c# - 有人可以解释一下如何正确处理应用程序范围的异常吗

c# - SSIS:无法将类型为 'System.Decimal' 的对象转换为类型 'System.Char[]'

c++ - if(isspace()) 语句不工作 C++

c# - C# 中的 Java 的 search()、get() 和 size()

c# - 使用C#从flv文件中提取信息