Reputation: 16724
I have a C++ and C# applications where I send command to each one other by using named pipes. It was working well until I noticied I couldn't cancel the Read()
call, I was using a stop variable but didn't notice this wasn't all I need because it couldn't read the stop variable state until get off the Read()
call. I found I would use PIPE_NOWAIT attribute in the CreateNamedPipe()
call. When I added it the C# throw an System.NullReferenceException because the FileStream
was null, it's created from new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
where clientHandle
is created as following:
private void Listen()
{
while (!exitLoop)
{
clientHandle = CreateNamedPipe(this.pipeName,
DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_NOWAIT,
255,
BUFFER_SIZE,
BUFFER_SIZE,
0,
IntPtr.Zero);
if (clientHandle.IsInvalid)
{
return;
}
int ok = ConnectNamedPipe(clientHandle, IntPtr.Zero);
//could not connect client
if (ok == 0) // here's the error, getLastError() = ERROR_PIPE_LISTENING
{
return;
}
stream = new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
// ....
}
If matter, in C++ the pipe is created like this:
hPipe1 = CreateFile(lpszPipename1,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (!IsValidPipe(hPipe1))
{
openError();
return;
}
hPipe2 = CreateFile(lpszPipename2,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
So my question is: the error is ERROR_PIPE_LISTENING
after ConnectNamedPipe()
call, happend after I did add PIPE_NOWAIT
. Why is that error? how do I fix this? and this the right way to add support to cancel a named-pipe operation? I would kill the theread where Listen()
is running in but I read it isn't a good practive (it doesn't even work either).
NOTE: I'm working on existing code base and I would like to avoid rewrite everything using NamedPipeClientStream
for time reasons.
Upvotes: 2
Views: 1296
Reputation: 16724
I solved this with PeekNamedPipe
(), I get the number total of bytes available and call ReadFile
() only if it's > 0. This is a simple approach to emulate nonblocking mode and I can exit the loop running inside a thread just setting done
to true
.
Something like this:
while(!done) {
DWORD total_available_bytes = 0;
if(!PeekNamedPipe(hPipe2, NULL, 0, NULL, &total_available_bytes, NULL)) {
/* error handling goes here */
break;
}
// for avoid overuse of the CPU, sleep for a while until next check.
if(total_available_bytes == 0) {
Sleep(500);
continue;
}
if(ReadFile(hPipe2, ...)) {
// ...
}
}
Upvotes: 0
Reputation: 13073
In C++ you need to create the file with overlapped io, then WaitForMultipleObjects(..., INFINITE);
for a stop event and the IO.
If you get the stop event, then you CancelIO();
.
For C# msdn : Overlapped allows you to create an overlapped object (necessary for the read).
stackoverflow : pinvoke ReadFile. This shows how to natively call ReadFile with the overlapped option.
stackoverflow : waitformultipleobjects functionality Explains how to call WaitForMultipleObjects.
When solving this sort of problem I created a stand-alone function
ReadFileWithEvent( HANDLE file, VOID * pData, size_t data, HANDLE exitEvent, BOOL & signalled );
which packaged creating an overlapped object, waiting and explaining to the caller that the stop had occurred, and the Read had not completed. This simplified the code I needed.
Upvotes: 1