使用David Brown's downloadable sample at ImplicitOperator我将一个经常工作的点文件图形渲染器组合到内存中的图像中。
不幸的是,我的版本失败了,在我安装的iis 7 asp.net web应用程序中,执行率为1/8。我知道点文件数据是一致的,因为我比较了失败实例和工作实例,它们是相同的。
由于david的网站似乎暗示博客的未来是不确定的,我将在这里重新发布interop文章。希望他不介意。失败在样本的末尾,在第三个语句集的renderimage中。我已经注意到与//todo:….的失败行。失败总是发生在那里(如果真的发生的话)。通过这一行,g和gvc指针是非零的,布局字符串被正确填充。
我真的不希望有人在运行时调试它。相反,我希望对互操作代码的一些静态分析可以揭示这个问题。我想不出这里有什么先进的封送处理技术——两个intptr和一个string不需要太多帮助,对吧?
谢谢!
旁注:我看过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);
    }
  }
}

最佳答案

visual studio 2010添加了一个“pinvokestack失衡”检测,我认为它帮助我解决了这个问题。虽然图像仍会生成,但我会多次收到此错误。
通过在所有libgvc pinvoke信号上指定CallingConvention = CallingConvention.Cdecl,错误和崩溃消失。

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

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

...

我做了这个改变之后就没有崩溃过,所以我现在就把这个标记为新的答案。

09-06 04:31