Jas*_*ban 8 c# graphviz access-violation
在ImplicitOperator中使用David Brown的可下载示例我将一个经常工作的DOT文件的GraphViz渲染器组合到一个内存中的图像中.
不幸的是,我的版本因为我已经使用IIS 7 ASP.NET Web应用程序的8次执行中的1次失败率而失败.我知道DOT文件数据是一致的,因为我将失败的实例与工作实例,它们是相同的.
由于大卫的网站似乎暗示博客的未来不确定,我将在这里重新打印互联网文章.希望他不介意.失败是在示例的末尾,在第三个语句集的RenderImage中.我已经注意到// TODO的失败行:......失败总是发生在那里(如果它发生的话).通过这一行,g和gvc指针不为零,并且正确填充了布局字符串.
我真的不希望任何人在运行时调试它.相反,我希望对互操作代码的一些静态分析可能会揭示问题.我想不出任何先进的编组技术 - 两个IntPtrs和一个字符串不需要很多帮助,对吧?
谢谢!
旁注:我看了一下MSAGL的试用版,我没有留下深刻的印象 - 微软99美元,我希望节点布局和/或文档的更多功能可以解释我所缺少的内容.也许我从QuickGraph到AGL的快速端口不公平地偏向于我的经验,因为这些方法存在一些根本的差异(例如,以边缘为中心与以节点为中心).
public static class Graphviz
{
public const string LIB_GVC = "gvc.dll";
public const string LIB_GRAPH = "graph.dll";
public const int SUCCESS = 0;
/// <summary>
/// Creates a new Graphviz context.
/// </summary>
[DllImport(LIB_GVC)]
public static extern IntPtr gvContext();
/// <summary>
/// Releases a context's resources.
/// </summary>
[DllImport(LIB_GVC)]
public static extern int gvFreeContext(IntPtr gvc);
/// <summary>
/// Reads a graph from a string.
/// </summary>
[DllImport(LIB_GRAPH)]
public static extern IntPtr agmemread(string data);
/// <summary>
/// Releases the resources used by a graph.
/// </summary>
[DllImport(LIB_GRAPH)]
public static extern void agclose(IntPtr g);
/// <summary>
/// Applies a layout to a graph using the given engine.
/// </summary>
[DllImport(LIB_GVC)]
public static extern int gvLayout(IntPtr gvc, IntPtr g, string engine);
/// <summary>
/// Releases the resources used by a layout.
/// </summary>
[DllImport(LIB_GVC)]
public static extern int gvFreeLayout(IntPtr gvc, IntPtr g);
/// <summary>
/// Renders a graph to a file.
/// </summary>
[DllImport(LIB_GVC)]
public static extern int gvRenderFilename(IntPtr gvc, IntPtr g,
string format, string fileName);
/// <summary>
/// Renders a graph in memory.
/// </summary>
[DllImport(LIB_GVC)]
public static extern int gvRenderData(IntPtr gvc, IntPtr g,
string format, out IntPtr result, out int length);
public static Image RenderImage(string source, string layout, string format)
{
// Create a Graphviz context
IntPtr gvc = gvContext();
if (gvc == IntPtr.Zero)
throw new Exception("Failed to create Graphviz context.");
// Load the DOT data into a graph
IntPtr g = agmemread(source);
if (g == IntPtr.Zero)
throw new Exception("Failed to create graph from source. Check for syntax errors.");
// Apply a layout
if (gvLayout(gvc, g, layout) != SUCCESS) // TODO: Fix AccessViolationException here
throw new Exception("Layout failed.");
IntPtr result;
int length;
// Render the graph
if (gvRenderData(gvc, g, format, out result, out length) != SUCCESS)
throw new Exception("Render failed.");
// Create an array to hold the rendered graph
byte[] bytes = new byte[length];
// Copy the image from the IntPtr
Marshal.Copy(result, bytes, 0, length);
// Free up the resources
gvFreeLayout(gvc, g);
agclose(g);
gvFreeContext(gvc);
using (MemoryStream stream = new MemoryStream(bytes))
{
return Image.FromStream(stream);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Visual Studio 2010添加了一个"PInvokeStackImbalance"检测,我认为这有助于我解决问题.虽然图像仍然会生成,但我会多次出现此错误.
通过指定CallingConvention = CallingConvention.Cdecl所有LIBGVC PInvoke sigantures,错误和崩溃消失.
[DllImport(LIB_GVC, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr gvContext();
[DllImport(LIB_GVC, CallingConvention = CallingConvention.Cdecl)]
public static extern int gvFreeContext(IntPtr gvc);
...
Run Code Online (Sandbox Code Playgroud)
自从做出这个改变后我没有崩溃,所以我现在将此标记为新的答案.