我是P /调用Graphviz as shown here。当我写这篇博客文章时,代码运行得很好。现在,我正在整理使用该代码呈现Graphviz图形的HttpModule
,但我在AccessViolationException
处获得了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都是一样的。
编辑:我尝试将string
更改为StringBuilder
,但这会产生相同的结果。然后,我添加了MarshalAs
属性:
static extern IntPtr agmemread([MarshalAs(UnmanagedType.LPWStr)] string data);
这样,我不再获得AccessViolationException
,但Graphviz无法正确读取字符串并返回空指针。
答案 0 :(得分:6)
非托管代码很少需要C#的大量帮助才能开始生成访问冲突。您的P / Invoke签名没有任何问题,这可能不是原因。
非托管代码中最常见的AV源是堆损坏。 C / C ++代码没有垃圾收集器,必须明确管理内存。它不仅必须处理释放内存(或它将泄漏),它还负责分配正确的大小并确保写入分配的内存的代码不会写入已分配的内存块的末尾或写入已经释放的内存中。最后一个要求是C / C ++代码经常失败的地方。
堆损坏的问题在于诊断起来非常困难。它可能会被忽视很长一段时间。典型的损坏是内部堆结构受到损害,或者另一个堆分配中的数据被覆盖。直到稍后,当释放堆块或使用覆盖的数据时,这不会导致问题。生成异常的代码实际上不对之前完成的损坏负责。这会让你走上错误的轨道,试图找到问题的根源。
找到真正的麻烦制造者是非常困难的,你只需要一些面包屑来弄清楚可能出现的问题。拥有C / C ++源代码非常困难,但在调试版本中使用调试分配器运行它有帮助。没有源代码时,这是不可能的。
除非您能够确定使用早期调用API的问题,否则您需要供应商或支持小组的帮助才能真正解决此问题。祝你好运。
答案 1 :(得分:0)
我遇到了同样的问题 - P/Invoke
签名需要添加CallingConvention=CallingConvention.Cdecl.
Graphviz库是C调用约定,而不是StdCall
。
请参阅this thread。