Перенаправить вывод STDERR из оболочки COM-объектов в .NET - PullRequest
5 голосов
/ 07 февраля 2011

Я пытаюсь использовать COM-объект ImageMagick (ImageMagickObject) в библиотеке .NET. Эта библиотека предназначена для вызова из 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 для отправки результата (в качестве индикатора успеха используется возвращаемое значение). Все остальные методы (определение, преобразование, Mogrify и т. Д.) Работают так, как вы ожидаете.

Для справки, его называют примерно так (из IronRuby):

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

И output.txt создан, но пуст. Ничего не печатается в STDOUT или STDERR.

РЕДАКТИРОВАТЬ: для ясности относительно смыва / закрытия потокового устройства и того, как образец используется из IronRuby.

Ответы [ 4 ]

1 голос
/ 13 февраля 2011

После добавления опции debug я наконец получил некоторый текст в файле.

Это ожидаемый результат?Если это так, см. Параметр debug инструмента командной строки compare.

Обратите внимание, что установка Console.Error или Console.Out на streamwriter вызовет исключение, если вы попытаетесь что-либо зарегистрироватьпрямо или косвенно используя вышеупомянутые свойства.

Если вам действительно нужно установить эти свойства, установите для них другой экземпляр StreamWriter.Если они вам не нужны, пропустите вызовы Console.SetOut и Console.SetError.

Я также заметил, что после создания экземпляра ImageMagickObject.MagickImage невозможно перенаправить стандартную ошибку.Если стандартное перенаправление ошибок необходимо отменить или выполнить несколько раз, попробуйте выполнить код в другом домене приложения.

0 голосов
/ 17 февраля 2011

В соответствии с документацией «FileShare.Read является значением по умолчанию для тех конструкторов FileStream без параметра FileShare» ... Возможно, может быть полезно включить FileAccess.Read, FileAccess.Write, FileShare.Read и FileShare.Write вFileStream c-tor?

У меня нет программы ImageMagick exe для игры ... если вы можете опубликовать ссылку, это было бы здорово.

0 голосов
/ 10 февраля 2011

Похоже, .Handle устарела, вы пробовали .SafeFileHandle.DangerousGetHandle() вместо?

Ссылка: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.dangerousgethandle.aspx

(Дополнительно: можете ли вы подтвердить, что закрыли StreamWriter после того, как данные были записаны? Например, если вы переместили его непосредственно перед закрытием приложения, чтобы проверить, удаляются ли данные?)

0 голосов
/ 07 февраля 2011

Вы пытались удалить (или очистить) писатель и поток? Он мог умереть застрявшим в буфере. Там может помочь использование блока.

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

... }

...