从.NET中的COM对象包装器重定向STDERR输出

时间:2011-02-07 18:52:30

标签: c# .net com imagemagick

我正在尝试在.NET库中使用ImageMagick COM对象(ImageMagickObject)。这个库旨在从IronRuby中调用,但这并不是那么重要。我想采用这种方法,因为它适合我现有的调用,当前调用ImageMagick二进制文件作为外部进程。 COM对象将采用与二进制文件相同的参数,但将保存进程创建速度,整体速度提高约5倍。

我唯一的障碍是COM对象的“Compare”方法将其结果返回给STDERR。这也是二进制文件的一个问题,但很容易将其传回STDOUT,我期待它。使用COM对象,我从函数返回值中获取结果。

如何将结果从“比较”重定向到字符串缓冲区甚至文件而不是STDERR?

我已经尝试过以下操作,它会阻止输出到达STDERR,但它不会按预期写入文件:

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

只有“比较”动作似乎使用STDERR发送结果(它使用返回值作为成功指示符)。所有其他方法(识别,转换,Mogrify等)都可以正常工作。

作为参考,它被称为这样的东西(来自IronRuby):

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

并且创建了output.txt,但是为空。没有任何东西被打印到STDOUT或STDERR。

编辑:为了清楚说明关于河流写入器的冲洗/关闭以及如何从IronRuby使用样本。

4 个答案:

答案 0 :(得分:1)

添加debug选项后,我终于在文件中找到了一些文本。

这是你期待的结果吗?如果是,请参阅debug命令行工具的compare选项。

请注意,如果您尝试使用上述属性直接或间接记录任何内容,则将Console.ErrorConsole.Out设置为streamwriter会导致异常。

如果您确实需要设置这些属性,请将它们设置为StreamWriter的另一个实例。如果您不需要,请忽略对Console.SetOutConsole.SetError的调用。

我还注意到,一旦创建ImageMagickObject.MagickImage实例,就无法重定向标准错误。如果标准错误重定向需要撤消或执行多次,请尝试在另一个应用程序域中执行代码。

答案 1 :(得分:0)

您是否尝试过处理(或刷新)编写器和流?它可能已经死在缓冲区中。使用块可能有帮助。

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

...         }

答案 2 :(得分:0)

看来.Handle已被弃用,您是否尝试了.SafeFileHandle.DangerousGetHandle()

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

(另外:您可以确认在写完数据后关闭了StreamWriter吗?比如,如果你把它移到应用程序关闭之前,看看数据是否已经出来了?)

答案 3 :(得分:0)

根据文档“FileShare.Read是那些没有FileShare参数的FileStream构造函数的默认值”......也许它可以帮助设置FileAccess.Read,FileAccess.Write,FileShare.Read和FileShare.Write FileStream c-tor?

我没有使用ImageMagick exe ...如果你可以发布链接,那就太好了。