Взаимодействие GraphViz с C # время от времени приводит к исключению AccessViolationException

Использование загружаемого образца Дэвида Брауна в ImplicitOperator I ' Мы собрали часто работающий модуль рендеринга GraphViz из файла DOT в изображение в памяти.

К сожалению, моя версия терпит неудачу с расчетной скоростью 1 из 8 выполнений с IIS 7 ASP.NET я знаю, что данные файла DOT согласованы, потому что я сравнил отказавшие экземпляры с рабочими экземплярами, и они идентичны.

Поскольку сайт Дэвида, похоже, предполагает, что будущее блога неопределенное , Я перепечатаю здесь фрагменты взаимодействия. Надеюсь, он не против. Ошибка находится ближе к концу образца, в RenderImage в третьем наборе операторов. Я отметил строку с ошибкой с помощью // TODO: .... Сбой всегда происходит там (если это вообще происходит). В этой строке указатели g и gvc не равны нулю, а строка макета заполнена правильно.

Я не делаю ' На самом деле я не ожидаю, что кто-нибудь отладит это во время выполнения. Скорее, я надеюсь, что некоторый статический анализ кода взаимодействия может выявить проблему. Я не могу вспомнить какие-либо продвинутые методы маршалинга, доступные здесь - два IntPtr и строка не должны нуждаться в большой помощи, верно?

Спасибо!

Примечание: я посмотрел пробную версию MSAGL и Я не впечатлен - за 99 долларов от Microsoft я бы ожидал большего количества функций для компоновки узлов и / или документации, объясняющей, чего мне не хватает. Возможно, мой быстрый перенос с 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;

  ///  
  /// Creates a new Graphviz context. 
  ///  
  [DllImport(LIB_GVC)]
  public static extern IntPtr gvContext();

  ///  
  /// Releases a context's resources. 
  ///  
  [DllImport(LIB_GVC)]
  public static extern int gvFreeContext(IntPtr gvc);

  ///  
  /// Reads a graph from a string. 
  ///  
  [DllImport(LIB_GRAPH)]
  public static extern IntPtr agmemread(string data);

  ///  
  /// Releases the resources used by a graph. 
  ///  
  [DllImport(LIB_GRAPH)]
  public static extern void agclose(IntPtr g);

  ///  
  /// Applies a layout to a graph using the given engine. 
  ///  
  [DllImport(LIB_GVC)]
  public static extern int gvLayout(IntPtr gvc, IntPtr g, string engine);

  ///  
  /// Releases the resources used by a layout. 
  ///  
  [DllImport(LIB_GVC)]
  public static extern int gvFreeLayout(IntPtr gvc, IntPtr g);

  ///  
  /// Renders a graph to a file. 
  ///  
  [DllImport(LIB_GVC)]
  public static extern int gvRenderFilename(IntPtr gvc, IntPtr g,
    string format, string fileName);

  ///  
  /// Renders a graph in memory. 
  ///  
  [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);
    }
  }
}

8
задан Jason Kleban 3 February 2011 в 01:45
поделиться