There\'s a problem with the NamedPipeClientStream
class in .NET, in that you cannot create an instance of this class with PipeDirection.In
, and the
Looking at the Microsoft reference source, I could see that setting the ReadMode
property simply calls the win32 SetNamedPipeHandleState
function to perform the operation, with errors from this call raised as exceptions. As per the documentation SetNamedPipeHandleState function it states about the pipe handle that in order to call this function
the handle must have GENERIC_WRITE access to the named pipe for a write-only or read/write pipe, or it must have GENERIC_READ and FILE_WRITE_ATTRIBUTES access for a read-only pipe.
Herein lies the problem.
If we look at the constructors for NamedPipeClientStream that take in a PipeDirection
setting, we see that they only request GENERIC_READ
access for PipeDirection.In
, and GENERIC_WRITE
access for PipeDirection.Out
(or both for InOut
). This means that any pipe opened in Out
or InOut
mode will work, as GENERIC_WRITE
access is sufficient for those cases, but we need both GENERIC_READ
and FILE_WRITE_ATTRIBUTES
for a read-only pipe, which the NamedPipeClientStream
class never requests. This is a defect in the class, and should be corrected by Microsoft.
I've submitted a bug report on Microsoft Connect here:
https://connect.microsoft.com/VisualStudio/feedback/details/1825187
Please up-vote it if you come across this problem yourself, it might help speed up a fix.
Until a fix (none as of 3/2017), one can work around this problem entirely by using a different constructor for NamedPipeClientStream
.
There's one overload of the constructor that takes in, instead of a PipeDirection
enumeration, a PipeAccessRights
enumeration instead, where you can specify the particular combination of access rights you want to obtain for the handle. The constructor then derives the direction of the pipe from the combination of specified access rights (In
if ReadData
is specified, Out
" if WriteData
is specified, InOut
if they are both specified).
This means, you can solve this problem without having to make your pipes full duplex, by simply changing a constructor line like this:
var pipeIn = new NamedPipeClientStream("<ServerName>", "<PipeName>", PipeDirection.In);
to this:
var pipeIn =
new NamedPipeClientStream("<ServerName>",
"<PipeName>",
PipeAccessRights.ReadData | PipeAccessRights.WriteAttributes,
PipeOptions.None,
System.Security.Principal.TokenImpersonationLevel.None,
System.IO.HandleInheritability.None);
If you use this alternate constructor as a suggested workaround, the result will be identical and indistinguishable from the result you would get from the first form of the constructor, with the exception that this additional access right will be obtained, so that message mode can be enabled.