c# - 导致 AccessViolationException 的非托管 DLL

标签 c# c++ dll interop

这个真的开始让我头疼了:(

我有一个非托管 DLL,我正尝试与之互操作,但运行不顺利。该应用程序有时会正常工作......但大多数时候,随机通过 AccessViolationException 并可怕地崩溃。

我想我已经将问题缩小到我对单个 DllImport 的处理不当:

C++函数:

HTMLRENDERERDLL_REDIST_API void SetDataBuffer( int windowHandle, unsigned char* dataSource, int format, int stride, int totalBufferSize );

C# Dll导入:

[DllImport("MyDll.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
    static private extern unsafe void SetDataBuffer(Int32 windowHandle, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] dataSource, Int32 format, Int32 stride, Int32 totalBufferSize);

调用所述函数:

var buffer = new byte[windowWidth * windowHeight * bytesPerPixel];
SetDataBuffer(windowHandle, buffer, (Int32)0, (Int32)(windowWidth * bytesPerPixel), (Int32)(windowWidth * windowHeight * bytesPerPixel));

这有什么明显的错误吗?我怀疑 dataSource 是罪魁祸首,但...不确定如何证明!

谢谢

最佳答案

您的问题可以从函数名称推断出来。当您“设置缓冲区”时, native 代码稍后可能会使用该缓冲区。这与垃圾收集器不兼容,它会在压缩堆时移动数组。当 native 代码随后写入缓冲区时,这是一个很大的 Kaboom,它将写入不再存在的内存。当垃圾收集器检测到堆完整性受到损害时,最典型的结果是 FatalExecutionEngineException。

数组需要固定,这是 pinvoke 编码器在调用函数时执行的操作,但它会在调用后取消固定数组。

您可以使用 GCHandle.Alloc() 固定托管数组,但如果长时间固定它,这对垃圾收集器非常不利。到目前为止,最好的解决方案是使用 Marshal.AllocHGlobal 分配一 block 非托管内存,它永远不会移动。

如果您仍然遇到问题,请担心缓冲区的大小。在 native 代码中只是简单的痛苦,它很少需要太多帮助来解决 AccessViolation。这是 native 代码的标准故障模式。很难诊断,如果你没有它的源代码就不可能。联系代码所有者寻求支持,提供一个小的重现片段来帮助他找到问题。

关于c# - 导致 AccessViolationException 的非托管 DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11671385/

相关文章:

c# - .net 中有哪些不同的堆?

c# - C#中AppDomain的使用

c# - 强制循环迭代

android - C++ JNI 互操作性

python - 无法在 python 中导入/安装任何库

c# - 从驻留在转发器控件内的用户控件调用父页面中的方法

c++ - 将 Char* 与 String 和运算符进行比较

javascript 和 c++ 双数 0.0

c# - 当前位置没有可用的资源

java - jstring转c++字符串结果java代码执行报错