Use the .NET 3.5 Named Pipes IO for Inter-process communication by implementing a pipe listener on a separate thread. The first sample is a WPF project. It can also be done just as easily in Windows forms.
The sample demonstrates how to pass string data from clients to a pipe server application that contains a pipe listener that runs on a separate thread within the server application. The main requirement here is that the clients are collecting string data and the other application wants to use the string data too, but it needs to collect the information in a background thread.
The code snippet below shows the main window class that starts the Pipeserver thread in the Window_Loaded event handler. In Forms, it is the Form1_Load event.
I like to package the thread-owner attributes into a class of all static members. Then it is easy for this class to operate on owner objects.
namespace PipeServer
namespace
PipeServer
{
/// <summary>
/// PipeServer creates a listener thread and waits for messages from clients.
/// Received messages are displayed in Textbox
/// </summary>
public
partial
class
Window1 : Window
Window1()
InitializeComponent();
}
private
void
Window_Loaded(
object
sender, RoutedEventArgs e)
tbox.Text =
""
;
Pipeserver.pipeName =
"testpipe"
Pipeserver.owner =
this
Pipeserver.ownerInvoker =
new
Invoker(
);
ThreadStart pipeThread =
ThreadStart(Pipeserver.createPipeServer);
Thread listenerThread =
Thread(pipeThread);
listenerThread.SetApartmentState(ApartmentState.STA);
listenerThread.IsBackground =
true
listenerThread.Start();
Pipeserver.createPipeServer is the static thread method that is attached to the pipeThread delegate. Once the thread starts, createPipeServer runs in a continuous while loop which waits for a connection and processes data coming in on the pipe's stream.
The NamedPipeServerStream class has a complex set of constructors and properties. I'm using the 6th constructor and setting all the properties in this constructor. Here are the details on the class: http://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeserverstream.aspx
SetTextbox is the delegate that gets invoked on the main thread to update Textbox control.
I'm using a low-level read hear for flexibility. You could just as well be processing binary data (such as images) with it instead of text.
Note that it is important to Disconnect the PipeServerStream after processing each incomming message. Otherwise an error will be thrown when the process loops back to wait for the next connection.
After all of the bytes are collected as chars in the StringBuilder, the message is posted as a string using the Invoker class. Invoker has an Action<string> delegate (sDel) that runs a method delegate that takes a string parameter and is set to SetTexbox. In Windows Forms the doSetTextBox delegate object does the callback to run SetTexbox on the owner thread.
Pipeserver
static
Window1 owner;
Invoker ownerInvoker;
string
pipeName;
NamedPipeServerStream pipeServer;
readonly
int
BufferSize = 256;
SetTextbox(String text)
owner.tbox.Text = String.Concat(owner.tbox.Text, text);
if
(owner.tbox.ExtentHeight > owner.tbox.ViewportHeight)
owner.tbox.ScrollToEnd();
createPipeServer()
Decoder decoder = Encoding.Default.GetDecoder();
Byte[] bytes =
Byte[BufferSize];
char
[] chars =
[BufferSize];
numBytes = 0;
StringBuilder msg =
StringBuilder();
ownerInvoker.sDel = SetTextbox;
try
pipeServer =
NamedPipeServerStream(pipeName, PipeDirection.In, 1,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous);
while
(
)
pipeServer.WaitForConnection();
do
msg.Length = 0;
numBytes = pipeServer.Read(bytes, 0, BufferSize);
(numBytes > 0)
numChars = decoder.GetCharCount(bytes, 0, numBytes);
decoder.GetChars(bytes, 0, numBytes, chars, 0,
false
msg.Append(chars, 0, numChars);
(numBytes > 0 && !pipeServer.IsMessageComplete);
decoder.Reset();
ownerInvoker.Invoke(msg.ToString());
(numBytes != 0);
pipeServer.Disconnect();
catch
(Exception ex)
MessageBox.Show(ex.Message);
PipeClient
button1_Click(
using
(NamedPipeClientStream pipeClient =
NamedPipeClientStream(
"."
,
PipeDirection.Out,
PipeOptions.Asynchronous))
tbStatus.Text =
"Attempting to connect to pipe..."
pipeClient.Connect(2000);
MessageBox.Show(
"The Pipe server must be started in order to send data to it."
return
"Connected to pipe."
(StreamWriter sw =
StreamWriter(pipeClient))
sw.WriteLine(tbClientText.Text);
This article was featured on the home page of TechNet Wiki: social.technet.microsoft.com/.../default.aspx
And your article was featured on the Wiki Ninjas blog here: blogs.technet.com/.../june-c-guru-dan-randolph-brings-us-quot-named-pipes-io-for-inter-process-communication-quot.aspx
Thanks!
Your article was featured on MSDN blogs here: blogs.msdn.com/.../c-guru-named-pipes-io-for-inter-process-communication.aspx
You didn't have any competition, but that doesn't mean you didn't earn it! Great job!
It would be great to add a "[toc]" text to this at the top (which auto-creates a TOC).
Congratulations on winning the gold! blogs.technet.com/.../technet-guru-awards-june-2013.aspx