2011-02-07 18 views
5

Próbuję użyć obiektu COM ImageMagick (ImageMagickObject) w bibliotece .NET. Ta biblioteka ma być wywoływana z IronRuby, ale nie jest to aż tak ważne. Chcę przyjąć to podejście, ponieważ będzie pasować do moich istniejących połączeń, które obecnie nazywają binaria ImageMagick jako procesy zewnętrzne. Obiekt COM będzie przyjmował te same argumenty co pliki binarne, ale zapisze proces tworzenia i będzie około 5 razy szybszy.Przekierowanie danych wyjściowych STDERR z opakowania obiektu COM w .NET

Moja jedyna przeszkoda polega na tym, że metoda "Porównaj" dla obiektu COM zwraca wynik do STDERR. Jest to również problem związany z binariami, ale łatwo można go przekierować z powrotem do STDOUT, gdzie oczekiwałem. Za pomocą obiektu COM otrzymuję wyniki z wartości zwracanych przez funkcję.

Jak mogę przekierować wynik z "Porównaj" do bufora ciągów lub nawet do pliku zamiast STDERR?

Próbowałem następujące dane, które kończy wyjście z dotarciem STDERR, ale nie zapisuje do pliku zgodnie z oczekiwaniami:

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

Tylko „Porównaj” akcja wydaje się używać STDERR wysłać wynik (używa wartości zwracanej jako wskaźnika sukcesu). Wszystkie inne metody (Identify, Convert, Mogrify, itp.) Działają tak, jak byś tego oczekiwał.

Dla porównania, to jest wywoływana coś takiego (z IronRuby):

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

I output.txt jest tworzony, ale pusty. Nic nie zostanie wydrukowane na STDOUT lub STDERR.

EDYCJE: Dla przejrzystości w odniesieniu do flush/close streamwriter i sposobu użycia próbki z IronRuby.

Odpowiedz

0

Czy próbowałeś Pozbyć się pisaka i strumienia? Mogłoby zginąć w buforze. Pomocny może tu być blok przy użyciu.

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

... }

+0

Próbowałem jawnie opróżniać bufor przed i po wywołaniu funkcji Kompiluj bez powodzenia. – cgyDeveloper

0

Wygląda .Handle jest przestarzała, czy próbowałeś .SafeFileHandle.DangerousGetHandle() zamiast?

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

(Dodatkowo: można potwierdzić zamknięciu StreamWriter po dane zostały napisane Podobnie jak w przypadku przeniesienia go tuż przed aplikacja zamyka się, aby sprawdzić, czy dane sprawia, że ​​jego wyjście? ?)

+0

Pozytywna informacja o zamknięciu streamwritera. Próbowałem również obie metody obsługi, ponieważ VS dał mi ostrzeżenie o przestarzałości (wydają się być równoważne). – cgyDeveloper

1

Po dodaniu opcji debug w końcu dostałem trochę tekstu w pliku.

Czy to wynik, którego się spodziewasz? Jeśli tak, zobacz opcję debug narzędzia wiersza polecenia .

Należy pamiętać, że ustawienie Console.Error lub Console.Out na streamwriter spowoduje wyjątek, jeśli spróbujesz zalogować się do niczego bezpośrednio lub pośrednio, korzystając z wyżej wymienionych właściwości.

Jeśli naprawdę potrzebujesz ustawić te właściwości, ustaw je na inne wystąpienie StreamWriter. Jeśli ich nie potrzebujesz, pomiń połączenia z Console.SetOut i Console.SetError.

Zauważyłem również, że po utworzeniu instancji ImageMagickObject.MagickImage przekierowanie standardowego błędu nie jest możliwe. Jeśli standardowe przekierowanie błędu musi zostać cofnięte lub wykonane wiele razy, spróbuj wykonać kod w innej domenie aplikacji.

+0

Porównaj zdecydowanie pisze do STDERR. Jeśli wyjmę połączenia SetStdHandle, za każdym razem zapisze STDERR. Przy tych połączeniach nie ma (ani nie zapisuje się do pliku). – cgyDeveloper

+0

Nie należy go uruchamiać z wiersza poleceń, aby rozwiązanie nie było poprawne. Musi być dostępny jako wywołanie biblioteki. – cgyDeveloper

+0

Powinienem również dodać ostatnią nutę, że interop COM nie musi używać tego samego uchwytu co Console.Error, aw moim przypadku tak nie jest. Console.Error przekierowanie będzie działać dla wywołań z .NET, ale nie zawsze wystarcza przekierowanie wywołań STDERR z niezarządzanego kodu (takiego jak obiekt COM, z którym się tutaj komunikuję). Tak więc wywoływanie Console.Error nie jest ważnym testem dla mojego stanu, chociaż wydaje się logiczne i twoje rozwiązanie zadziała w takim przypadku. – cgyDeveloper

0

Zgodnie z dokumentacją "FileShare.Read jest domyślnym dla konstruktorów FileStream bez parametru FileShare" ... Być może może pomóc FileAccess.Read, FileAccess.Write, FileShare.Read i FileShare.Write włączone w pliku FileStream?

Nie mam programu ImageMagick do grania z ... jeśli umieścisz łącze, byłoby wspaniale.

+0

Uprawnienia do plików nie są w tym przypadku problemem, ImageMagick jest tutaj: http://imagemagick.org/script/binary-releases.php#windows. Pamiętaj, aby zainstalować obiekt COM podczas instalacji, aby go użyć, tak jak ja w tym przykładzie. – cgyDeveloper

Powiązane problemy