2011-02-07 13 views
5

.NETライブラリでImageMagick COMオブジェクト(ImageMagickObject)を使用しようとしています。このライブラリはIronRubyから呼び出されることを意図していますが、それだけではそれほど重要ではありません。私はこのアプローチを採用したいと思います。なぜなら、現時点でImageMagickバイナリを外部プロセスと呼んでいる私の既存の呼び出しに適合するからです。 COMオブジェクトはバイナリと同じ引数をとりますが、プロセスの作成を節約し、全体的に約5倍高速です。.NETのCOMオブジェクトラッパーからSTDERR出力をリダイレクト

私の唯一のハードルは、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に何も印刷されません。

EDITS:ストリームライターのフラッシュ/閉じると、サンプルがIronRubyからどのように使用されるかを明確にするためです。

答えて

0

試しましたか(フラッシング)ライターとストリームを廃棄しましたか?バッファーに詰まっていた可能性があります。ブロックを使用するとそこに助けになるかもしれません。

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

... }

+0

私は運のないComposeの呼び出しの前後に明示的にバッファをフラッシュしようとしました。 – cgyDeveloper

0

.Handleが廃止されましたように見え、あなたの代わりに.SafeFileHandle.DangerousGetHandle()を試してみましたか?

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

は(また:?あなたは、データが書き込まれた後のように、あなたはアプリがデータが出て、その方法を作るかどうかを確認するために、閉じる直前にそれを移動した場合のStreamWriterを閉じて確認することができます?)

+0

ストリームライターを閉じることについてポジティブです。 VSは私に非推奨警告を与えてくれたので、私は両方のハンドルメソッドも試しました(それらは同等です)。 – cgyDeveloper

1

debugオプションを追加した後、最終的にファイルにテキストがあります。

これはあなたが期待している結果ですか?その場合は、compareコマンドラインツールのdebugオプションを参照してください。

Console.ErrorまたはConsole.Outstreamwriterに設定すると、上記のプロパティを使用して直接的または間接的に何かを記録しようとすると例外が発生することに注意してください。

これらのプロパティを実際に設定する必要がある場合は、別のインスタンスをStreamWriterに設定します。必要がない場合は、Console.SetOutConsole.SetErrorの呼び出しを省略してください。

ImageMagickObject.MagickImageインスタンスが作成されると、標準エラーをリダイレクトすることはできません。標準エラーリダイレクションを元に戻す必要がある場合、または複数回実行する必要がある場合は、別のアプリケーションドメインでコードを実行してみてください。

+0

STDERRに間違いなく書き込みをしてください。私がSetStdHandle呼び出しを取り出すと、毎回STDERRに書き込まれます。これらの呼び出しが適切に行われると、決して実行されません(ファイルに書き込むこともありません)。 – cgyDeveloper

+0

これはコマンドラインから実行するためのものではありませんので、解決策は有効ではありません。ライブラリ呼び出しとして利用できる必要があります。 – cgyDeveloper

+0

また、COM相互運用機能がConsole.Errorと同じハンドルを必ずしも使用しているわけではなく、私の場合はそうではないという最後の注記を追加する必要があります。 Console.Errorリダイレクトは.NETからの呼び出しでも機能しますが、STDERR呼び出しをアンマネージコード(ここでやりとりしているCOMオブジェクトなど)からリダイレクトするだけでは必ずしも十分ではありません。 Console.Errorは論理的に見えますが、あなたのソリューションはそのように動作しますが、自分の状態に対して有効なテストではありません。 – cgyDeveloper

0

ドキュメントによると、FileShare.Readは、FileShareパラメータを持たないFileStreamコンストラクタのデフォルトです。おそらく、FileAccess.Read、FileAccess.Write、FileShare.Read、およびFileShare.Writeがオンになっている可能性があります。 FileStream c-tor?

私はImageMagick exeを使って遊ぶことはできません。あなたがリンクを投稿することができれば素晴らしいでしょう。

+0

この場合、ファイルのアクセス権は問題にはなりません。ImageMagickはhttp://imagemagick.org/script/binary-releases.php#windowsにあります。この例で使用しているように、インストール時にCOMオブジェクトをインストールして使用するようにしてください。 – cgyDeveloper

関連する問題