今回は複数のクライアントからの接続に対応したいと思います。クライアントはボタンを通じて、任意のタイミングでメッセージを送信できるようにします。クライアントの例を示します。データの取得は別スレッドで行っているという点です。このデータの取得を別スレッドで行うのです。理由は、ReadFileによってコードの進行がブロックされるため、メインスレッドで呼び出してはUIの操作ができなくなるからです。上記のコードのままでは、ReadFileは期待した動作を行わないはずです。別スレッドのReadFileで取得してしまうような事態に陥るからです。自分で書き込んだデータを自分で取得するようなことが発生するのです。これを防ぐために、サーバーはPIPE_ACCESS_DUPLEXのパイプを作成するべきではありません。それを適切に使い分けるようにします。サーバーを実装するうえで考慮すべきもう1つの点は、スレッドに関する問題です。このReadFileでスレッドが待機してしまっては、2つ目のクライアントのためにConnectNamedPipeを呼び出せません。接続用のスレッドと読み書き用のスレッドを作成するようにします。自身は再びConnectNamedPipeで待機します。データを取得した後はクライアントにデータを送信し、再びデータが送られるまで待機します。読み書き用のスレッドは、接続してくるクライアントの数だけ作成されます。それでは、サーバーのコードを実際に見ていきます。FALSE;}WM_CREATEでリストボックスを作成しているのは、クライアントが接続してきたことや、送信されたデータを表示するためです。WM_CREATEではスレッドも作成していますが、このスレッドが接続用のスレッドになります。実行される関数はThreadProcConnectであり、まず次の部分に注目します。(LPARAM)TEXT("名前付きパイプの作成に失敗"));break;}}既に述べたようにサーバーはパイプが2つ必要になるため、CreateNamedPipeを2回呼び出しています。ブロッキングが発生しないようにFILE_FLAG_OVERLAPPEDを指定します。パイプに接続できる最大数に到達していることを意味します。これ以上パイプを作成するわけにはいきません。このようなときは、クライアントが接続を切断するまで待機し、それを検出した後にCreateNamedPipeを呼び出せばよいでしょう。これをWaitEventに指定すれば、関数の成功時には接続に空きが生じしていると判断できます。g_hEventDisconnectを再び使用する可能性があるので、ResetEventで非シグナル状態にしておきます。NULL);パイプを作成したら、ConnectNamedPipeでクライアントが接続してくるまで待機します。WaitEventで待機することになります。2つ目のConnectNamedPipeも成功して、直ちに制御を返すことになるでしょう。この際にはクライアントのプロセスIDも表示したら便利であるため、GetNamedPipeClientProcessIdを呼び出しています。Vistaから使用可能であるため注意してください。CreateThreadに指定しているThreadProcReadWriteが、読み書き用のスレッドの開始アドレスです。このスレッドにはパイプなどを渡したいため、DATA構造体のメモリを確保し、それをCreateThreadの第4引数に指定しています。0;}データを最初に送信するのはクライアントであるため、サーバーはReadFileから呼び出します。第5引数にOVERLAPPED構造体を指定して、WaitEventで待機するようにします。WaitEventから制御が返ると、オーバーラップ(非同期)操作が成功したかどうかを確認するために、GetOverlappedResultを呼び出します。パイプを閉じたことによって操作が完了したと判断できます。接続に空きができたことをSetEventで通知します。dwTransferredが0でない場合はReadFileを呼び出してデータを取得し、それをリストボックスに表示します。その後、WriteFileでデータを返信し、再びデータが送られるのをWaitEventで待機します。続いて、クライアントのコードを示します。実行時には、事前にサーバーを起動しておいてください。TEXT("メッセージを入力してください。TEXT("パイプへこれ以上接続できません。TEXT("パイプへの接続に失敗しました。TEXT("データの送信に失敗しました。TEXT("サーバーとの接続が切断されました。TEXT("%dバイト受信しました。FALSE;}サーバーはパイプを2つ作成していたため、クライアントはCreateFileを2回呼び出してそれぞれのパイプに接続します。hPipeReadはReadFileに指定することになるため、その際にオーバーラップが可能になるようにFILE_FLAG_OVERLAPPEDを指定します。GetLastErrorがERROR_PIPE_BUSYを返した場合は、CreateNamedPipeの第4引数に指定した数だけのクライアントが既に接続していることを意味します。この場合は、別のクライアントを終了させてからもう一度起動することになるでしょう。WM_COMMANDでは、エディットコントロールに入力された文字列をWriteFileで書き込みます。このときに使用するパイプは、書き込み用のhPipeWriteでなければなりません。ThreadProcでは、サーバーからのデータを取得するためにReadFileを呼び出します。WaitEventやGetOverlappedResultを呼び出すのは、サーバーと同じ要領です。接続の空きがないことが原因で失敗した場合は、接続に空きができるまで待つようにしてもよいでしょう。WaitNamedPipeを呼び出すようにすればこのような事は可能です。TEXT("メッセージを入力してください。TEXT("パイプへの接続に失敗しました。TEXT("データの送信に失敗しました。0;}CreateFileでERROR_PIPE_BUSYを返った場合に、接続の空きを確認するためのスレッドを作成します。第1引数の名前のパイプに空きができるまで待機します。WM_CONNECTという独自のメッセージを送ります。WM_CONNECTではCreateFileを呼び出してパイプに接続します。