Using Pipes in C# with Overlapped I/O

D

dvestal

I'm trying to use Overlapped I/O from C#, and utterly failing. I've
tried to boil down my code to as simple an example as possible, in
hopes that you people can point to where I'm going wrong. I've
included my test program. The behavior I'm seeing is that the callback
routine is never called, despite the fact that the thread is (AFAIK) in
an alertable state. The program just hangs waiting for the
m_doneEvent.

In other scenarios, I'm able to transfer data, but it is sometimes
received as zeros instead of the real data. Any help, or pointers to a
good discussion of managed overlapped I/O using pipes, would be
appreciated. I'd love a website, but I can buy a book if need be.

static unsafe class Program
{
static private AutoResetEvent m_doneEvent = new AutoResetEvent(false);
static private string m_action = string.Empty;

[DllImport("kernel32.dll", EntryPoint = "ReadFileEx", SetLastError =
true,
CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern int ReadFileEx(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int nNumberOfBytesToRead,
NativeOverlapped* lpOverlapped,
[MarshalAs(UnmanagedType.FunctionPtr)] IOCompletionCallback callback
);

[DllImport("kernel32.dll", EntryPoint = "WriteFileEx", SetLastError =
true,
CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern int WriteFileEx(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int nNumberOfBytesToWrite,
NativeOverlapped* lpOverlapped,
[MarshalAs(UnmanagedType.FunctionPtr)] IOCompletionCallback callback
);

[STAThread]
static void Main()
{
ManualResetEvent actionCompletedEvent = new ManualResetEvent(false);
Overlapped overlapped = new Overlapped(0, 0,
actionCompletedEvent.SafeWaitHandle.DangerousGetHandle(),
null);
IOCompletionCallback callback = Finished;
byte[] bytes = new byte[1000];
NativeOverlapped* nativeOverlapped = overlapped.Pack(callback,
bytes);

IntPtr m_pipeHandle = CreateNamedPipe(
@"\\.\pipe\DSV",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
PIPE_UNLIMITED_INSTANCES,
2048,
2048,
1000,
null
);

for(int i = 0; i < 100; i++)
{
System.Diagnostics.Trace.WriteLine("Beginning transfer");

new Random().NextBytes(bytes);
m_action = "Writing";
WriteFileEx(m_pipeHandle,
bytes,
bytes.Length,
nativeOverlapped,
callback);
m_doneEvent.WaitOne();

m_action = "Reading";
ReadFileEx(m_pipeHandle,
bytes,
1000,
nativeOverlapped,
callback);
m_doneEvent.WaitOne();
}
System.Diagnostics.Trace.WriteLine("all done");
}

[ComVisibleAttribute(true)]
static public void Finished(
uint errorCode,
uint bytesTransferred,
NativeOverlapped* overlapped)
{
System.Diagnostics.Trace.WriteLine(
m_action
+ ": errorCode=" + errorCode
+ " bytesTransferred=" + bytesTransferred);
m_doneEvent.Set();
}
}
 
B

Ben Voigt

I'm trying to use Overlapped I/O from C#, and utterly failing. I've
tried to boil down my code to as simple an example as possible, in
hopes that you people can point to where I'm going wrong. I've
included my test program. The behavior I'm seeing is that the callback
routine is never called, despite the fact that the thread is (AFAIK) in
an alertable state. The program just hangs waiting for the
m_doneEvent.

I'm not aware of any pure .NET means for putting a thread into an alertable
wait. You end up having to p/invoke the Windows API wait functions, at
which point going to C++/CLI for "It Just Works" becomes pretty attractive.
That's what I've done.

see
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/wait_functions.asp

I posted a bug here:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=137088
which Microsoft closed without comment, so I guess that means they aren't
going to fix it. You could validate it and post a comment to show Microsoft
that this is important to more than just one person.
In other scenarios, I'm able to transfer data, but it is sometimes
received as zeros instead of the real data. Any help, or pointers to a
good discussion of managed overlapped I/O using pipes, would be
appreciated. I'd love a website, but I can buy a book if need be.

static unsafe class Program
{
static private AutoResetEvent m_doneEvent = new AutoResetEvent(false);
static private string m_action = string.Empty;

[DllImport("kernel32.dll", EntryPoint = "ReadFileEx", SetLastError =
true,
CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern int ReadFileEx(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int nNumberOfBytesToRead,
NativeOverlapped* lpOverlapped,
[MarshalAs(UnmanagedType.FunctionPtr)] IOCompletionCallback callback
);

[DllImport("kernel32.dll", EntryPoint = "WriteFileEx", SetLastError =
true,
CharSet = CharSet.Ansi, ExactSpelling = true)]
private static extern int WriteFileEx(
IntPtr hFile,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
int nNumberOfBytesToWrite,
NativeOverlapped* lpOverlapped,
[MarshalAs(UnmanagedType.FunctionPtr)] IOCompletionCallback callback
);

[STAThread]
static void Main()
{
ManualResetEvent actionCompletedEvent = new ManualResetEvent(false);
Overlapped overlapped = new Overlapped(0, 0,
actionCompletedEvent.SafeWaitHandle.DangerousGetHandle(),
null);
IOCompletionCallback callback = Finished;
byte[] bytes = new byte[1000];
NativeOverlapped* nativeOverlapped = overlapped.Pack(callback,
bytes);

IntPtr m_pipeHandle = CreateNamedPipe(
@"\\.\pipe\DSV",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
PIPE_UNLIMITED_INSTANCES,
2048,
2048,
1000,
null
);

for(int i = 0; i < 100; i++)
{
System.Diagnostics.Trace.WriteLine("Beginning transfer");

new Random().NextBytes(bytes);
m_action = "Writing";
WriteFileEx(m_pipeHandle,
bytes,
bytes.Length,
nativeOverlapped,
callback);
m_doneEvent.WaitOne();

m_action = "Reading";
ReadFileEx(m_pipeHandle,
bytes,
1000,
nativeOverlapped,
callback);
m_doneEvent.WaitOne();
}
System.Diagnostics.Trace.WriteLine("all done");
}

[ComVisibleAttribute(true)]
static public void Finished(
uint errorCode,
uint bytesTransferred,
NativeOverlapped* overlapped)
{
System.Diagnostics.Trace.WriteLine(
m_action
+ ": errorCode=" + errorCode
+ " bytesTransferred=" + bytesTransferred);
m_doneEvent.Set();
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top