Sử dụng David Brown's downloadable sample at ImplicitOperator Tôi đã đặt cùng nhau một thường là làm việc GraphViz kết xuất đồ họa của tệp DOT thành hình ảnh trong bộ nhớ.GraphViz C# interop dẫn đến AccessViolationException thỉnh thoảng
Thật không may, phiên bản của tôi không thành công với tỷ lệ 1 trong 8 hành vi được áp dụng từ ứng dụng web IIS 7 ASP.NET mà tôi đã có. Tôi biết rằng dữ liệu tệp DOT phù hợp vì tôi đã so sánh các trường hợp không thành công đối với các cá thể làm việc và chúng giống hệt nhau.
Vì trang web của David dường như gợi ý rằng tương lai của blog không chắc chắn, tôi sẽ in lại các phần tương tác tại đây. Hy vọng anh ta không phiền. Sự thất bại là vào cuối của mẫu, trong RenderImage tại tập lệnh thứ ba. Tôi đã lưu ý dòng thất bại với // TODO: .... Sự thất bại luôn luôn xảy ra ở đó (nếu nó xảy ra ở tất cả). Bởi dòng này, g và con trỏ gvc không khác và chuỗi bố cục được điền chính xác.
Tôi thực sự không mong đợi bất kỳ ai gỡ lỗi cài đặt này khi chạy. Thay vào đó, tôi hy vọng rằng một số phân tích tĩnh của mã interop có thể tiết lộ vấn đề. Tôi không thể nghĩ ra bất kỳ kỹ thuật đầm lầy tiên tiến nào có sẵn ở đây - hai IntPtr và một chuỗi không cần nhiều sự trợ giúp, đúng không?
Cảm ơn!
Lưu ý phụ: Tôi đã xem xét bản dùng thử MSAGL và tôi không ấn tượng - với giá 99 đô la từ Microsoft, tôi mong đợi nhiều tính năng hơn cho bố cục nút và/hoặc tài liệu giải thích những gì tôi thiếu. Có lẽ cổng nhanh của tôi từ QuickGraph đến AGL không công bằng với kinh nghiệm của tôi vì một số khác biệt cơ bản trong các cách tiếp cận (ví dụ như trung tâm so với nút trung tâm).
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);
}
}
}
Tôi biết điều này nghe có vẻ ngu ngốc. Nhưng có cần phải chạy dll trực tiếp trong mã của bạn? Có thể tạo ngôn ngữ dấu chấm trong một tệp văn bản và sau đó chạy thực thi dấu chấm độc lập với một lệnh như: "dot -Tpng -o MyFile.png MyFile.dot" bằng cách sử dụng lớp C# Process? Một khi bạn có hình ảnh bạn chỉ có thể tải nó trực tiếp vào bộ nhớ chương trình của bạn. – jluzwick
Tôi đoán đó là một tùy chọn, nhưng việc xử lý các tệp trên đĩa cho thao tác này sẽ chậm và sẽ giới thiệu thêm các điểm thất bại trong chính các cơ chế I/O. Kể từ khi dll được sử dụng một trong hai cách, tôi muốn hiểu làm thế nào để làm cho nó hoạt động đúng trong bộ nhớ. –
Bạn có thể cho biết cách sử dụng lớp học của mình không? –