|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionI know this is the nth article about using Windows Pipes in .NET. The only reason I am writing this is because I wanted a very simple implementation of a managed wrapper for Windows Pipes. Ivan's article on The Code Project is like an example of military-grade implementation! I wanted something simpler and easier to use. How much easier? Sending a message should be as easy as My implementation uses only one class, _pipe = new ManagedPipe("Test1", ManagedPipeType.Server,...
or a client pipe connection: _pipe = new ManagedPipe("Test1", ManagedPipeType.Client,...
The BackgroundPeople looking for something more flexible and robust should read the articles by Ivan and John Korres. You will also be interested in reading about Windows Pipes in the MSDN library. Server ConnectionSince this is supposed to be a very easy-to-use wrapper, let's see how quickly we can create a connection and start sending messages. A server connection is created like this: _pipe = new ManagedPipe("Test1", ManagedPipeType.Server,
BlockingMode.Wait, 1024, 1024);
_pipe.Open();
The first parameter is the name of the pipe. The second parameter specifies if this is a server application or a client application. The third parameter is to specify whether the I have not added any _pipe.WaitForClientToConnect();
The above function is a blocking call and will not return until a client connects to the server. Once this function returns, you can call the _pipe.Send("Hello");
......
string message = _pipe.Receive();
......
If a blocking private void ReceiveThreadFunction()
{
_pipe.WaitForClientToConnect();
btnSend.Invoke((MethodInvoker)delegate()
{
btnSend.Enabled = true;
});
while (true)
{
string message = _pipe.Receive();
if (message == null)
return;
txtReceiveMessage.Invoke((MethodInvoker)delegate()
{
txtReceiveMessage.Text += message + "\r\n";
});
}
}
Client ConnectionThe client connection code is as follows: _pipe = new ManagedPipe("Test1", ManagedPipeType.Client,
BlockingMode.Wait, 1024, 1024);
_pipe.Open();
This is exactly similar to the server connection call except for the second parameter. All the other parameters should be identical to the ones specified on the server connection. To find out why, please read about Windows Pipes on MSDN. Sending and receiving messages is similar to what we did in the server connection. The difference is that from the client you do not call private void ReceiveThreadFunction()
{
while (true)
{
string message = _pipe.Receive();
if (message == null)
return;
txtReceiveMessage.Invoke((MethodInvoker)delegate()
{
txtReceiveMessage.Text += message + "\r\n";
});
}
}
Dispose!Once you are finished using the _pipe.Dispose();
I know .NET has garbage collection and all that. The GC might eventually call The ManagedPipe WrapperYou would have noticed that I have not mentioned anything about the wrapper code. This was deliberate. To use the wrapper, one does not need to know its internals. Remember, it's supposed to be very easy to use! Now that we have covered the "how to use", lets' take a look at the wrapper itself. The wrapper internally creates two pipe connections. The first connection is a dedicated pipe to Design
CodeThe server pipe connection is created like this: protected void CreateServer()
{
UInt32 pipeMode;
if (_blockingMode == BlockingMode.Wait)
pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
else
pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT;
_hSendPipe = CreateNamedPipe(@"\\.\pipe\Send_" + _name,
PIPE_ACCESS_OUTBOUND,
pipeMode,
1,
_outputBufferSize,
_inputBufferSize,
0,
IntPtr.Zero);
if (_hSendPipe.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
_hReceivePipe = CreateNamedPipe(@"\\.\pipe\Receive_" + _name,
PIPE_ACCESS_INBOUND,
pipeMode,
1,
_outputBufferSize,
_inputBufferSize,
0,
IntPtr.Zero);
if (_hReceivePipe.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
As mentioned earlier, you will notice that I create two pipe connections to facilitate parallel The client pipe connection is created like this: protected void CreateClient()
{
_hSendPipe = CreateFile(@"\\.\pipe\Receive_" + _name,
GENERIC_WRITE,
0,
IntPtr.Zero,
OPEN_EXISTING,
0,
IntPtr.Zero);
if (_hSendPipe.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
_hReceivePipe = CreateFile(@"\\.\pipe\Send_" + _name,
GENERIC_READ,
0,
IntPtr.Zero,
OPEN_EXISTING,
0,
IntPtr.Zero);
if (_hReceivePipe.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Here we swap the server's The rest of the wrapper code is pretty straight forward. public void Open()
{
if (_type == ManagedPipeType.Server)
CreateServer();
else
CreateClient();
_textReader = new StreamReader(new FileStream(_hReceivePipe,
FileAccess.Read));
_textWriter = new StreamWriter(new FileStream(_hSendPipe,
FileAccess.Write));
}
public void Send(string message)
{
if (_hSendPipe == null)
throw new InvalidOperationException("Pipe is not open.");
_textWriter.WriteLine(message);
_textWriter.Flush();
}
public string Receive()
{
if (_hReceivePipe == null)
throw new InvalidOperationException("Pipe is not open.");
return _textReader.ReadLine();
}
When Points of Interest
History
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||