2012-05-03 12 views
0

名前付きパイプを使用してプロセスと通信しています。私はそれを次のコードで動作させることができました。 (オリジナルのコードはここで見つける:via archive.orgコンソールからコマンドを発行しないC#Named Pipes?

class ProgramPipeTest 
    { 

     public void ThreadSenderStartClient(object obj) 
     { 
      // Ensure that we only start the client after the server has created the pipe 
      ManualResetEvent SyncClientServer = (ManualResetEvent)obj; 

      using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".","ToSrvPipe",PipeDirection.Out,PipeOptions.None)) 
      { 
       // The connect function will indefinately wait for the pipe to become available 
       // If that is not acceptable specify a maximum waiting time (in ms) 
       pipeStream.Connect(); 

       Console.WriteLine("[Client] Pipe connection established"); 
       using (StreamWriter sw = new StreamWriter(pipeStream)) 
       { 
        sw.AutoFlush = true; 
        string temp; 
        Console.WriteLine("Please type a message and press [Enter], or type 'quit' to exit the program"); 
        while ((temp = Console.ReadLine()) != null) 
        { 
         if (temp == "quit") break; 
         sw.WriteLine(temp); 
        } 
       } 
      } 
     } 

     public void ThreadStartReceiverClient(object obj) 
     { 
      // Ensure that we only start the client after the server has created the pipe 
      ManualResetEvent SyncClientServer = (ManualResetEvent)obj; 

      using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "FromSrvPipe", PipeDirection.In, PipeOptions.None)) 
      { 
       // The connect function will indefinately wait for the pipe to become available 
       // If that is not acceptable specify a maximum waiting time (in ms) 
       pipeStream.Connect(); 

       Console.WriteLine("[ClientReceiver] Pipe connection established"); 

       using (StreamReader sr = new StreamReader(pipeStream)) 
       { 
        // Display the read text to the console 
        string temp; 
        while ((temp = sr.ReadLine()) != null) 
        { 
         Console.WriteLine("Received from server: {0}", temp); 
        } 
       } 
      } 
     } 

     static void Main(string[] args) 
     { 

      // To simplify debugging we are going to create just one process, and have two tasks 
      // talk to each other. (Which is a bit like me sending an e-mail to my co-workers) 

      ProgramPipeTest Client = new ProgramPipeTest(); 

      Thread ClientThread = new Thread(Client.ThreadSenderStartClient); 
      Thread ReceivedThread = new Thread(Client.ThreadStartReceiverClient); 

      ClientThread.Start(); 
      ReceivedThread.Start(); 


     } 
    } 

意図したとおりにすべてが動作します。ターゲットプロセス(大胆さ)にコマンドを発行することができます。

私の問題は、基本的にこのコードの周りにC#のGUIをラップしたいのですが、GUIを使ってコマンドを発行するため、コンソールを使わずに通信ができるように変更する方法がわかりません。コードから。

私はクラス変数に、プロパティを介して公開し、sw.WriteLine()をメソッドで呼び出すことを試みましたが、それは動作していないようです。

したがって、オブジェクト内でストリームをうまく前後にカプセル化する方法がわかりません。

私はこの記事が、Using Named Pipes to Connect a GUI to a Console App in Windowsにあったように見えましたが、残念ながら、コードが付いていないようで、参照することなく私の頭の上にあるようです。

コンソールを使用してコマンドを発行しなくても、名前付きパイプを使用するにはどうすればよいですか?

答えて

5

あなたがしたいことは、送信者、受信者のロジックの主要部分をそのコードから取り出し、目的別のラッパークラスのように使用できる再利用可能なクラスに書き換えることです。

おそらく、以下のコードをガイドラインとして役立ち得る(私はこれが動作するかどうかを確認するためにチェックしていない、それはマイナーな変更が必要になる場合があります)

public sealed class ResponseReceivedEventArgs : EventArgs 
{ 
    public ResponseReceivedEventArgs(string id, string response) 
    { 
     Id = id; 
     Response = response; 
    } 

    public string Id 
    { 
     private set; 
     get; 
    } 

    public string Response 
    { 
     private set; 
     get; 
    } 
} 

public delegate void ResponseReceived(object sender, ResponseReceivedEventArgs e); 

public sealed class NamedPipeCommands 
{ 
    private readonly Queue<Tuple<string, string>> _queuedCommands = new Queue<Tuple<string,string>>(); 
    private string _currentId; 

    private readonly Thread _sender; 
    private readonly Thread _receiver; 

    // Equivalent to receiving a "quit" on the console 
    private bool _cancelRequested; 

    // To wait till a response is received for a request and THEN proceed 
    private readonly AutoResetEvent _waitForResponse = new AutoResetEvent(false); 

    // Lock to modify the command queue safely 
    private readonly object _commandQueueLock = new object(); 

    // Raise an event when a response is received 
    private void RaiseResponseReceived(string id, string message) 
    { 
     if (ResponseReceived != null) 
      ResponseReceived(this, new ResponseReceivedEventArgs(id, message)); 
    } 

    // Add a command to queue of outgoing commands 
    // Returns the id of the enqueued command 
    // So the user can relate it with the corresponding response 
    public string EnqueueCommand(string command) 
    { 
     var resultId = Guid.NewGuid().ToString(); 
     lock (_commandQueueLock) 
     { 
      _queuedCommands.Enqueue(Tuple.Create(resultId, command)); 
     } 
     return resultId; 
    } 

    // Constructor. Please pass in whatever parameters the two pipes need 
    // The list below may be incomplete 
    public NamedPipeCommands(string servername, string pipeName) 
    { 
     _sender = new Thread(syncClientServer => 
     { 
      // Body of thread 
      var waitForResponse = (AutoResetEvent)syncClientServer; 

      using (var pipeStream = new NamedPipeClientStream(servername, pipeName, PipeDirection.Out, PipeOptions.None)) 
      { 
       pipeStream.Connect(); 

       using (var sw = new StreamWriter(pipeStream) { AutoFlush = true }) 
        // Do this till Cancel() is called 
        while (!_cancelRequested) 
        { 
         // No commands? Keep waiting 
         // This is a tight loop, perhaps a Thread.Yield or something? 
         if (_queuedCommands.Count == 0) 
          continue; 

         Tuple<string, string> _currentCommand = null; 

         // We're going to modify the command queue, lock it 
         lock (_commandQueueLock) 
          // Check to see if someone else stole our command 
          // before we got here 
          if (_queuedCommands.Count > 0) 
           _currentCommand = _queuedCommands.Dequeue(); 

         // Was a command dequeued above? 
         if (_currentCommand != null) 
         { 
          _currentId = _currentCommand.Item1; 
          sw.WriteLine(_currentCommand.Item2); 

          // Wait for the response to this command 
          waitForResponse.WaitOne(); 
         } 
        } 
      } 
     }); 

     _receiver = new Thread(syncClientServer => 
     { 
      var waitForResponse = (AutoResetEvent)syncClientServer; 

      using (var pipeStream = new NamedPipeClientStream(servername, pipeName, PipeDirection.In, PipeOptions.None)) 
      { 
       pipeStream.Connect(); 

       using (var sr = new StreamReader(pipeStream)) 
        // Do this till Cancel() is called 
        // Again, this is a tight loop, perhaps a Thread.Yield or something? 
        while (!_cancelRequested) 
         // If there's anything in the stream 
         if (!sr.EndOfStream) 
         { 
          // Read it 
          var response = sr.ReadLine(); 
          // Raise the event for processing 
          // Note that this event is being raised from the 
          // receiver thread and you can't access UI here 
          // You will need to Control.BeginInvoke or some such 
          RaiseResponseReceived(_currentId, response); 

          // Proceed with sending subsequent commands 
          waitForResponse.Set(); 
         } 
      } 
     }); 
    } 

    public void Start() 
    { 
     _sender.Start(_waitForResponse); 
     _receiver.Start(_waitForResponse); 
    } 

    public void Cancel() 
    { 
     _cancelRequested = true; 
    } 

    public event ResponseReceived ResponseReceived; 
} 

あなたは、私がConsole.ReadLineのための抽象化を作成していることがわかります(コマンドキュー)とConsole.WriteLine(イベント)を使用します。 "quit"は、 "Cancel()"メソッドで現在設定されているブール変数です。明らかに、これは最も最適で正しい方法ではありません - 私は、上記の命令コードを再利用可能なラッパークラスに関連付ける1つの方法を示しています。

+0

あなたを祝福してください。素晴らしい!これは完璧に動作します。 ToとFromのパイプの名前が同じではないため、別のpipeNameのコンストラクタに追加のパラメータを追加するだけでした。 – bulltorious

+0

LOL、私はそれがどれほど完全であるかはわかりませんでしたが、それは同じ静脈の将来の問題の指針になることを意図していました。それはうまくいってうれしい! – Ani

関連する問題