GraphViz的C#互操作导致AccessViolationException偶尔 [英] GraphViz C# interop resulting in AccessViolationException occasionally

查看:114
本文介绍了GraphViz的C#互操作导致AccessViolationException偶尔的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用大卫·布朗在ImplicitOperator下载的示例我已经把一个共同的往往的工作点文件的GraphViz的渲染器在内存中的图像。

不幸的是,我的版本在从与IIS 7 ASP.NET Web应用程序我已经得到了它1 8处决的guestimated率会失败。我知道DOT文件中的数据是一致的,因为我比较失败针对该工作实例实例和它们相同。

由于大卫的网站似乎表明,博客的未来是不确定的,我会在这里重新打印件互操作。希望他不介意。故障是朝向样品的端部,RenderImage内在第三语句集。我注意到// TODO的失败行:....失败总是发生在那里(如果发生的话)。通过这条线,g和GVC指针是非零和布局串被正确填充。

我真的不希望任何人在运行调试此。相反,我希望互操作code的一些静态分析可能会揭示问题。我想不出可以在这里找到任何先进的技术封送处理 - •两个IntPtrs和一个字符串不应该需要很多的帮助,右

谢谢!

附注:我已经看了MSAGL的试用,我不IM pressed - 为$ 99个来自微软,我期望节点的布局和/或文档更多的功能解释我缺少什么。也许我从QuickGraph快速端口AGL不公平的偏见,因为在一些方法根本区别(边缘为中心VS节点为中心,例如)我的经验。

 公共静态类的Graphviz
{
  公共常量字符串LIB_GVC =gvc.dll;
  公共常量字符串LIB_GRAPH =graph.dll;
  公共const int的成功= 0;  ///<总结>
  ///创建一个新的Graphviz上下文。
  ///< /总结>
  函数[DllImport(LIB_GVC)
  公共静态外部的IntPtr gvContext();  ///<总结>
  ///发布上下文的资源。
  ///< /总结>
  函数[DllImport(LIB_GVC)
  公共静态外部INT gvFreeContext(IntPtr的GVC);  ///<总结>
  ///读取从字符串的图表。
  ///< /总结>
  函数[DllImport(LIB_GRAPH)
  公共静态外部的IntPtr agmemread(字符串数据);  ///<总结>
  ///释放由图使用的资源。
  ///< /总结>
  函数[DllImport(LIB_GRAPH)
  公共静态外部无效agclose(IntPtr的G);  ///<总结>
  ///应用一个布局到使用给定的发动机的曲线图。
  ///< /总结>
  函数[DllImport(LIB_GVC)
  公共静态外部INT gvLayout(IntPtr的GVC,IntPtr的克,串引擎);  ///<总结>
  ///释放由布局使用的资源。
  ///< /总结>
  函数[DllImport(LIB_GVC)
  公共静态外部INT gvFreeLayout(IntPtr的GVC,IntPtr的G);  ///<总结>
  ///渲染图到文件中。
  ///< /总结>
  函数[DllImport(LIB_GVC)
  公共静态外部INT gvRenderFilename(IntPtr的GVC,IntPtr的克,
    字符串格式,字符串文件名);  ///<总结>
  ///呈现在存储器的图表。
  ///< /总结>
  函数[DllImport(LIB_GVC)
  公共静态外部INT gvRenderData(IntPtr的GVC,IntPtr的克,
    字符串格式,出的IntPtr结果,从INT长度);  公共静态图像RenderImage(字符串源字符串布局,字符串格式)
  {
    //创建的Graphviz背景
    IntPtr的GVC = gvContext();
    如果(GVC == IntPtr.Zero)
      抛出新的异常(无法创建Graphviz的背景。);    //将网点数据成图
    IntPtr的G = agmemread(源);
    如果(G == IntPtr.Zero)
      抛出新的异常(无法创建源图表检查语法错误。);    //应用布局
    如果(gvLayout(GVC,G,布局)=成功!)// TODO:在此处修复AccessViolationException
      抛出新的异常(布局失败。);    IntPtr的结果;
    INT长;    //渲染图
    如果(gvRenderData(GVC,G,格式,出结果,出长度)!= SUCCESS)
      抛出新的异常(渲染失败。);    //创建一个数组来保存渲染图
    字节[]字节=新的字节[长度]    //将图像从复制的IntPtr
    Marshal.Copy(结果,字节,0,长度);    //腾出资源
    gvFreeLayout(GVC,G);
    agclose(G);
    gvFreeContext(GVC);    使用(MemoryStream的流=新的MemoryStream(字节))
    {
      返回Image.FromStream(流);
    }
  }
}


解决方案

Visual Studio 2010中增加了一个PInvokeStackImbalance检测,我想帮助我解决这个问题。虽然仍然得到所生成的图像,我会得到这个错误好几次。

通过指定 CallingConvention = CallingConvention.Cdecl 上的所有LIBGVC的PInvoke sigantures,错误和崩溃消失。

 函数[DllImport(LIB_GVC,CallingConvention = CallingConvention.Cdecl)
公共静态外部的IntPtr gvContext();函数[DllImport(LIB_GVC,CallingConvention = CallingConvention.Cdecl)
公共静态外部INT gvFreeContext(IntPtr的GVC);...

我已经因为此更改没有崩溃,所以我会记住这为新的答案,现在是这样。

Using David Brown's downloadable sample at ImplicitOperator I've put together an often working GraphViz renderer of a DOT file to an in-memory image.

Unfortunately, my version fails at a guestimated rate of 1 in 8 executions from with the IIS 7 ASP.NET web application I've got it in. I know that the DOT file data is consistent because I've compared the failing instances against the working instances and they are identical.

As David's site seems to suggest that the blog's future is uncertain, I'll reprint the interop pieces here. Hope he doesn't mind. The failure is toward the end of the sample, within RenderImage at the third statement set. I've noted the failing line with // TODO: .... The failure always happens there (if it happens at all). By this line, g and gvc pointers are non-zero and the layout string is correctly populated.

I don't really expect anyone to debug this at runtime. Rather, I hope that some static analysis of the interop code might reveal the problem. I can't think of any advanced marshaling techniques available here - two IntPtrs and a string shouldn't need a lot of help, right?

Thanks!

Side note: I've looked at a trial of MSAGL and I'm not impressed - for $99 from Microsoft, I'd expect more features for node layout and/or documentation explaining what I'm missing. Maybe my rapid port from QuickGraph to AGL unfairly biases my experience because of some fundamental differences in the approaches (edge-centric vs node-centric, for example).

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);
    }
  }
}

解决方案

Visual Studio 2010 added a "PInvokeStackImbalance" detection that I think helped me fix the problem. While the image would still get generated, I would get this error several times.

By specifying CallingConvention = CallingConvention.Cdecl on all the LIBGVC PInvoke sigantures, the error and crashes disappear.

[DllImport(LIB_GVC, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr gvContext();

[DllImport(LIB_GVC, CallingConvention = CallingConvention.Cdecl)]
public static extern int gvFreeContext(IntPtr gvc);

...

I've had no crashes since making this change, so I'll mark this as the new answer, for now.

这篇关于GraphViz的C#互操作导致AccessViolationException偶尔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆