子プロセスの標準ストリームとして取得できるオブジェクトはStreamWriter/StreamReaderであるため、バイナリ形式での読み書きには向いていません。 また、非同期読み込みでのイベント引数DataReceivedEventArgsも文字列型(≒テキスト形式)として受信されるようになっています。

子プロセスの標準ストリームに対してバイナリ形式の読み書きを行う場合は、まず標準ストリームのStreamWriter/StreamReaderからBaseStreamプロパティを参照することにより、標準ストリームのStreamを取得します。

次に、BaseStreamプロパティから取得したStreamに対して直接読み書きを行うか、StreamからBinaryWriter/BinaryReaderなどを作成して読み書きすることにより、標準ストリームでバイナリ形式のデータを扱うことができるようになります。

parent.exe:子プロセスの標準ストリームからBinaryWriter/BinaryReaderを作成して読み書きする
Imports System
Imports System.Diagnostics
Imports System.IO
Imports System.Text

Class Sample
  Shared Sub Main()
    ' 子プロセスchild.exeの起動オプション
    Dim psi As New ProcessStartInfo("child.exe")
    ' シェルを使用せず子プロセスを起動する
    ' (リダイレクトするために必要)
    ' ⚠.NET Core/.NET 5以降ではデフォルトでFalseとなっている
    psi.UseShellExecute = False
    ' 起動した子プロセスの標準入出力をリダイレクトする
    psi.RedirectStandardInput = True
    psi.RedirectStandardOutput = True

    ' 子プロセスを起動する
    Using child As Process = Process.Start(psi)
      ' リダイレクトされた子プロセスの標準入出力を取得する
      Dim stdin As StreamWriter = child.StandardInput
      Dim stdout As StreamReader = child.StandardOutput

      ' BaseStreamを参照して標準入出力のStreamを取得し、
      ' BinaryWriter/BinaryReaderを作成する
      Using stdinWriter As New BinaryWriter(stdin.BaseStream)
        ' 6バイトのバイナリデータを標準入力へ書き込む
        stdinWriter.Write(New Byte() {&H48, &H65, &H6C, &H6C, &H6F, &H21})
      End Using ' 子プロセスの標準入力を閉じて書き込みを終了する

      Dim output As Byte()

      Using stdoutReader As New BinaryReader(stdout.BaseStream)
        ' 標準出力から最大16バイトのバイナリデータを読み込む
        output = stdoutReader.ReadBytes(16)
      End Using

      ' 子プロセスの終了を待機する
      child.WaitForExit()

      ' 読み込んだバイナリデータ文字列に変換して表示する
      Console.WriteLine(Encoding.ASCII.GetString(output))
    End Using
  End Sub
End Class
child.exe:標準入力の内容をBASE64エンコードして標準出力に書き込む
Imports System
Imports System.IO
Imports System.Security.Cryptography

Class Sample
  Shared Sub Main()
    ' 標準入力のStreamを取得
    Dim input As Stream = Console.OpenStandardInput()

    ' 標準出力のStreamをベースに、書き込まれる内容を
    ' BASE64エンコードするCryptoStreamを作成する
    Using output As New CryptoStream(
      Console.OpenStandardOutput(),
      New ToBase64Transform(),
      CryptoStreamMode.Write,
      leaveOpen := True
    )
      ' 入力ストリームの内容を出力ストリームに書き込む
      ' (BASE64エンコードされた上で書き込まれる)
      input.CopyTo(output)
    End Using
  End Sub
End Class
実行結果
>parent.exe
SGVsbG8h

StandardInput/StandardOutput/StandardErrorで取得できるStreamWriter/StreamReaderは内部でバッファリングが行われます。 このため、StandardInput/StandardOutput/StandardErrorを使った読み書きと、BaseStreamから取得したStreamへの読み書きを混在させると入出力内容に不整合が起こる(入出力されるデータの一部の順序が前後する)可能性があり、両者の使用は排他的とする必要があります。

つまり、BaseStreamから取得したStreamで読み書きを行う場合は、それのみを使って読み書きを行う、あるいはどちらか一方をFlushするまではもう一方を使って読み書きしないようにします。

Windows上では、BaseStreamプロパティから取得したStreamを閉じたあとにStandardOutput/StandardErrorを閉じると、StreamWriterがFlushしようとして例外ObjectDisposedExceptionがスローされます。 そのため、StreamWriterとBaseStreamプロパティから取得したStreamの両方をCloseしないように(二重にCloseする動作とならないように)注意する必要があります。

自プロセスの標準ストリームのStreamを取得する方法については自プロセスの標準入出力 §.標準ストリームの取得を参照してください。

Streamクラスを使った読み書きの方法についてはストリームの基本とStreamクラス、BinaryWriterクラス/BinaryReaderクラスを使った読み書きの方法についてはBinaryReaderクラス・BinaryWriterクラスを参照してください。

MENTAにてテキストチャットによるサポートを行っています。 問題の解決法をお探しの方や.NET/C#を学習中の方はどうぞご利用ください。