3

我正在 P/Invoking 到 Graphviz ,如下所示。当我写那个博客条目时,代码运行得很好。现在,我正在整理一个HttpModule使用该代码呈现 Graphviz 图形的组件,但我得到了一个AccessViolationExceptionat agmemread

// Native signature
Agraph_t agmemread(char *);

// P/Invoke Signature
[DllImport(LIB_GRAPH)]
private static extern IntPtr agmemread(string data);

// Usage
IntPtr g = agmemread(data);

就像我说的,这在以前很有效。但是现在,我无法让我的代码在任何事情上工作。甚至我基于相同代码的旧 Graphviz 应用程序也不再工作了。

我可能会改变什么会导致这种情况?我什至没有下载新版本的 Graphviz 或任何东西,所以 DLL 都是一样的。

编辑:我尝试更改stringStringBuilder,但产生了相同的结果。然后,我添加了一个MarshalAs属性:

static extern IntPtr agmemread([MarshalAs(UnmanagedType.LPWStr)] string data);

这样,我不再得到一个AccessViolationException,但 Graphviz 无法正确读取字符串并返回一个空指针。

4

1 回答 1

6

非托管代码很少需要 C# 的大量帮助来开始生成访问冲突。您的 P/Invoke 签名没有问题,这不是原因。

非托管代码中最常见的 AV 来源是堆损坏。C/C++ 代码没有垃圾收集器,必须显式管理内存。它不仅必须负责释放内存(否则会泄漏),它还负责分配正确的大小并确保写入分配内存的代码不会超过分配内存块的末尾或写入已经释放的内存。最后一个要求是 C/C++ 代码经常失败的地方。

堆损坏的问题在于极难诊断。它可能会在很长一段时间内被忽视。造成的典型损害是内部堆结构被破坏,或者另一个堆分配中的数据被覆盖。直到稍后释放堆块或使用覆盖的数据时,这才会导致问题。生成异常的代码实际上不对先前造成的损害负责。这会让你走上错误的轨道,试图找到问题的根源。

找到真正的麻烦制造者非常困难,你只有几个面包屑来找出可能出了什么问题。当您拥有 C/C++ 源代码时非常困难,但使用调试分配器在调试版本中运行它会有所帮助。没有源代码是不可能的。

除非您可以从之前的调用中找出使用 API 的问题,否则您将需要供应商或支持小组的帮助才能真正解决此问题。祝你好运。

于 2010-01-30T09:11:36.810 回答