【问题标题】:Redirect STDERR output from COM object wrapper in .NET从 .NET 中的 COM 对象包装器重定向 STDERR 输出
【发布时间】:2011-06-22 22:47:52
【问题描述】:

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

我唯一的障碍是 COM 对象的“比较”方法将其结果返回给 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 来发送结果(它使用返回值作为成功指标)。所有其他方法(Identify、Convert、Mogrify 等)都可以正常工作。

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

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

并且 output.txt 已创建,但为空。没有任何内容被打印到 STDOUT 或 STDERR。

编辑:为了清楚地了解流写入器刷新/关闭以及如何使用 IronRuby 中的示例。

【问题讨论】:

    标签: c# .net com imagemagick


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • Compare 肯定会写入 STDERR。如果我取出 SetStdHandle 调用,它每次都会写入 STDERR。有了这些调用,它就永远不会这样做(也不会写入文件)。
    • 这并不意味着从命令行运行,因此该解决方案将无效。它需要作为库调用提供。
    • 我还应该补充最后一点,COM 互操作不一定使用与 Console.Error 相同的句柄,在我的情况下,它没有。 Console.Error 重定向适用于来自 .NET 的调用,但从非托管代码(例如我在此处交互的 COM 对象)重定向 STDERR 调用并不总是足够的。因此,调用 Console.Error 不是对我的情况的有效测试,尽管它看起来确实合乎逻辑,并且您的解决方案在这种情况下可以工作。
    • 您能否提供您正在使用的ImageMagickObject 版本的链接?源代码是否可用,我想看看Compare 方法是如何写入stderr 的。我希望它不会在方法内部某处缓存之前的stderr句柄或方法调用的函数。
    • 我使用的是 ImageMagick 6.6.7,他们的源包 FTP 服务器位于ftp.imagemagick.org/pub/ImageMagick。有问题的源位于 ImageMagick\contrib\win32\ATL7\ImageMagickObject 的目录中。我没有从源代码安装,但使用了位于imagemagick.org/script/binary-releases.php#windows 的 Windows 安装程序。
    【解决方案2】:

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

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

    ... }

    【讨论】:

    • 我尝试在调用 Compose 之前和之后显式刷新缓冲区,但没有成功。
    【解决方案3】:

    .Handle 似乎已被弃用,您是否尝试过 .SafeFileHandle.DangerousGetHandle()

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

    (另外:您能否确认在写入数据后关闭 StreamWriter?例如,如果您将其移至应用程序关闭之前,以查看数据是否流出?)

    【讨论】:

    • 对关闭streamwriter的积极态度。我也尝试了这两种处理方法,因为 VS 给了我弃用警告(它们似乎是等效的)。
    【解决方案4】:

    根据文档“FileShare.Read 是那些没有 F​​ileShare 参数的 FileStream 构造函数的默认值”...也许它可以帮助设置 FileAccess.Read、FileAccess.Write、FileShare.Read 和 FileShare.Write FileStream 客户端?

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 2015-07-24
    • 2011-07-22
    • 1970-01-01
    • 2010-09-27
    • 2010-09-15
    相关资源
    最近更新 更多