2011-02-07 34 views
5

Tôi đang cố gắng sử dụng đối tượng COM ImageMagick (ImageMagickObject) trong một thư viện .NET. Thư viện này có ý định được gọi từ IronRuby, nhưng đó không phải là tất cả những điều quan trọng. Tôi muốn thực hiện phương pháp này vì nó sẽ phù hợp với các cuộc gọi hiện tại của tôi, hiện đang gọi các tệp nhị phân ImageMagick dưới dạng các quy trình bên ngoài. Đối tượng COM sẽ lấy các đối số giống như các tệp nhị phân, nhưng sẽ lưu quá trình tạo và nhanh hơn khoảng 5 lần tổng thể.Chuyển hướng đầu ra STDERR từ trình bao bọc đối tượng COM trong .NET

Trở ngại duy nhất của tôi là phương pháp "So sánh" đối tượng COM trả về kết quả của nó cho STDERR. Đây cũng là một vấn đề với nhị phân, nhưng thật dễ dàng để quay trở lại STDOUT, nơi tôi đang mong đợi nó. Với đối tượng COM, tôi nhận được kết quả từ các giá trị trả về hàm.

Làm cách nào để chuyển hướng kết quả từ "So sánh" sang bộ đệm chuỗi hoặc thậm chí một tệp thay vì STDERR?

Tôi đã thử những điều sau đây, mà không ngăn chặn đầu ra từ đạt stderr, nhưng nó không ghi được vào file như mong đợi:

using ImageMagickObject; 
... 

public class ImageMagickCOM 
{ 
    [DllImport("Kernel32.dll", SetLastError = true)] 
    public static extern int SetStdHandle(int device, IntPtr handle); 

    private const int STDOUT_HANDLE = -11; 
    private const int STDERR_HANDLE = -12; 

    private ImageMagickObject.MagickImage magickImage = null; 

    private FileStream filestream = null; 
    private StreamWriter streamwriter = null; 

    public ImageMagickCOM() 
    { 
     IntPtr handle; 
     int status; 

     filestream = new FileStream("output.txt", FileMode.Create); 
     streamwriter = new StreamWriter(filestream); 
     streamwriter.AutoFlush = true; 

     //handle = filestream.Handle; // deprecated 
     handle = filestream.SafeFileHandle.DangerousGetHandle(); // replaces filestream.handle 
     status = SetStdHandle(STDOUT_HANDLE, handle); 
     status = SetStdHandle(STDERR_HANDLE, handle); 

     Console.SetOut(streamwriter); 
     Console.SetError(streamwriter); 

     magickImage = new ImageMagickObject.MagickImage(); 
    } 

    public string Compare() 
    { 
     object[] args = new object[] { "-metric", "AE", "-fuzz", "10%", "imageA.jpg", "imageB.jpg", "diff.png" }; 
     return (string)this.magickImage.Compare(ref args); 
    } 

    public void Close() 
    { 
     if (this.magickImage != null) 
     { 
      Marshal.ReleaseComObject(magickImage); 
      this.magickImage = null; 
     } 
     if (this.streamwriter != null) 
     { 
      this.streamwriter.Flush(); 
      this.streamwriter.Close(); 
      this.streamwriter = null; 
      this.filestream = null; 
     } 
    } 
} 

Chỉ "So sánh" hành động dường như sử dụng thiết bị lỗi chuẩn để gửi một kết quả (nó sử dụng giá trị trả về như một chỉ báo thành công). Tất cả các phương pháp khác (Xác định, Chuyển đổi, Mogrify, vv) hoạt động như bạn mong đợi.

Để tham khảo, nó được gọi là một cái gì đó như thế này (từ IronRuby):

require 'ImagingLib.dll' 
im = ImagingLib::ImageMagickCOM.new 
im.compare # returns nil 
im.close 

Và output.txt được tạo ra, nhưng trống rỗng. Không có gì được in tới STDOUT hoặc STDERR.

CHỈNH SỬA: Để rõ ràng về tuôn ra luồng/đóng luồng và cách mẫu được sử dụng từ IronRuby.

Trả lời

0

Bạn đã thử Gỡ bỏ luồng và luồng ghi (hoặc xả)? Nó có thể đã chết bị mắc kẹt trong bộ đệm. Một khối sử dụng có thể giúp bạn.

using(filestream = new FileStream("output.txt", FileMode.Create)) 
    using(streamwriter = new StreamWriter(filestream)) 
    { 

... }

+0

Tôi đã cố gắng xóa bộ đệm trước và sau khi gọi xong để không có may mắn. – cgyDeveloper

0

Dường như .Handle bị phản đối, bạn đã thử .SafeFileHandle.DangerousGetHandle() để thay thế?

Ref: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.dangerousgethandle.aspx

(Ngoài ra: bạn có thể xác nhận rằng bạn đóng StreamWriter sau khi dữ liệu đã được viết Giống như, nếu bạn di chuyển nó đến ngay trước khi ứng dụng đóng lại, để xem nếu dữ liệu làm theo cách của mình ra? ?)

+0

Tích cực về việc đóng trình viết luồng. Tôi cũng đã thử cả hai phương pháp xử lý kể từ khi VS cho tôi cảnh báo không dùng nữa (chúng có vẻ tương đương). – cgyDeveloper

1

Sau khi thêm tùy chọn debug tôi cuối cùng cũng có một số văn bản trong tệp.

Đó có phải là kết quả bạn đang mong đợi không? Nếu vậy, hãy xem debug tùy chọn của công cụ dòng lệnh compare.

Xin lưu ý rằng việc đặt Console.Error hoặc Console.Out thành streamwriter sẽ gây ra ngoại lệ nếu bạn cố đăng nhập trực tiếp hoặc gián tiếp bằng cách sử dụng các thuộc tính nói trên.

Nếu bạn thực sự cần đặt các thuộc tính đó, hãy đặt chúng thành một phiên bản khác là StreamWriter. Nếu bạn không cần chúng, hãy bỏ qua các cuộc gọi đến Console.SetOutConsole.SetError.

Tôi cũng nhận thấy rằng khi cá thể ImageMagickObject.MagickImage được tạo, không thể chuyển hướng lỗi chuẩn. Nếu chuyển hướng lỗi tiêu chuẩn cần được hoàn tác hoặc thực hiện nhiều lần, hãy thử thực thi mã trong miền ứng dụng khác.

+0

So sánh chắc chắn ghi vào STDERR. Nếu tôi đưa ra các cuộc gọi SetStdHandle, nó sẽ ghi vào STDERR mỗi lần. Với những cuộc gọi tại chỗ, nó không bao giờ làm (cũng không ghi vào tập tin). – cgyDeveloper

+0

Điều này không có nghĩa là được chạy từ dòng lệnh, vì vậy giải pháp đó sẽ không hợp lệ. Nó cần phải có sẵn như là một cuộc gọi thư viện. – cgyDeveloper

+0

Tôi cũng nên thêm một lưu ý cuối cùng rằng COM interop không nhất thiết phải sử dụng cùng một xử lý như Console.Error và, trong trường hợp của tôi, nó không. Chuyển hướng Console.Error sẽ làm việc cho các cuộc gọi từ .NET, nhưng không phải lúc nào cũng đủ để chuyển hướng các cuộc gọi STDERR từ mã không được quản lý (chẳng hạn như đối tượng COM mà tôi đang tương tác với ở đây). Vì vậy, gọi Console.Error không phải là một thử nghiệm hợp lệ cho tình trạng của tôi, mặc dù nó xuất hiện hợp lý và giải pháp của bạn sẽ làm việc trong trường hợp đó. – cgyDeveloper

0

Theo tài liệu "FileShare.Read là mặc định cho các nhà xây dựng FileStream mà không có tham số FileShare" ... Có lẽ nó có thể giúp có FileAccess.Read, FileAccess.Write, FileShare.Read và FileShare.Write được đặt trong FileStream c-tor?

Tôi không có ImageMagick exe để chơi cùng ... nếu bạn có thể đăng liên kết, nó sẽ tuyệt vời.

+0

Quyền đối với tệp không phải là vấn đề trong trường hợp này, ImageMagick có tại đây: http://imagemagick.org/script/binary-releases.php#windows. Đảm bảo cài đặt đối tượng COM trong khi cài đặt để sử dụng nó như tôi đang trong ví dụ. – cgyDeveloper

Các vấn đề liên quan