Skip to content

Commit

Permalink
Fixes for ReadReport timeouts and lost reports after wait timeouts (#80)
Browse files Browse the repository at this point in the history
1. Fixed the issue with Read timing out even when Read time out is set to 0.   This boils down to using an incorrect value for WAIT_INFINITE
2. Fixed the issue with ReadReport failing after being blocked initially on a read.  The Wait after readreport is also now conditional, based on whether or not the ReadReport succeeded.  There is also an additional call to get overlapped result to retrieve data after a Wait
  • Loading branch information
ananth-racherla authored and mikeobrien committed Feb 22, 2017
1 parent 0b1fa07 commit 574bc60
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 22 deletions.
53 changes: 33 additions & 20 deletions src/HidLibrary/HidDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -587,12 +587,14 @@ protected HidDeviceData ReadData(int timeout)
{
var buffer = new byte[] { };
var status = HidDeviceData.ReadStatus.NoDataRead;
IntPtr nonManagedBuffer;

if (_deviceCapabilities.InputReportByteLength > 0)
{
uint bytesRead = 0;

buffer = CreateInputBuffer();
nonManagedBuffer = Marshal.AllocHGlobal(buffer.Length);

if (_deviceReadMode == DeviceMode.Overlapped)
{
Expand All @@ -610,40 +612,51 @@ protected HidDeviceData ReadData(int timeout)

try
{
NativeMethods.ReadFile(Handle, buffer, (uint)buffer.Length, out bytesRead, ref overlapped);

var result = NativeMethods.WaitForSingleObject(overlapped.EventHandle, overlapTimeout);

switch (result)
{
case NativeMethods.WAIT_OBJECT_0: status = HidDeviceData.ReadStatus.Success; break;
case NativeMethods.WAIT_TIMEOUT:
status = HidDeviceData.ReadStatus.WaitTimedOut;
buffer = new byte[] { };
break;
var success = NativeMethods.ReadFile(Handle, nonManagedBuffer, (uint)buffer.Length, out bytesRead, ref overlapped);

if (!success) {
var result = NativeMethods.WaitForSingleObject(overlapped.EventHandle, overlapTimeout);

switch (result)
{
case NativeMethods.WAIT_OBJECT_0:
status = HidDeviceData.ReadStatus.Success;
NativeMethods.GetOverlappedResult(Handle, ref overlapped, out bytesRead, false);
break;
case NativeMethods.WAIT_TIMEOUT:
status = HidDeviceData.ReadStatus.WaitTimedOut;
buffer = new byte[] { };
break;
case NativeMethods.WAIT_FAILED:
status = HidDeviceData.ReadStatus.WaitFail;
buffer = new byte[] { };
break;
default:
status = HidDeviceData.ReadStatus.NoDataRead;
buffer = new byte[] { };
break;
status = HidDeviceData.ReadStatus.WaitFail;
buffer = new byte[] { };
break;
default:
status = HidDeviceData.ReadStatus.NoDataRead;
buffer = new byte[] { };
break;
}
}
Marshal.Copy(nonManagedBuffer, buffer, 0, (int)bytesRead);
}
catch { status = HidDeviceData.ReadStatus.ReadError; }
finally { CloseDeviceIO(overlapped.EventHandle); }
finally {
CloseDeviceIO(overlapped.EventHandle);
Marshal.FreeHGlobal(nonManagedBuffer);
}
}
else
{
try
{
var overlapped = new NativeOverlapped();

NativeMethods.ReadFile(Handle, buffer, (uint)buffer.Length, out bytesRead, ref overlapped);
NativeMethods.ReadFile(Handle, nonManagedBuffer, (uint)buffer.Length, out bytesRead, ref overlapped);
status = HidDeviceData.ReadStatus.Success;
Marshal.Copy(nonManagedBuffer, buffer, 0, (int)bytesRead);
}
catch { status = HidDeviceData.ReadStatus.ReadError; }
finally { Marshal.FreeHGlobal(nonManagedBuffer); }
}
}
return new HidDeviceData(buffer, status);
Expand Down
7 changes: 5 additions & 2 deletions src/HidLibrary/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static class NativeMethods
internal const uint WAIT_OBJECT_0 = 0;
internal const uint WAIT_FAILED = 0xffffffff;

internal const int WAIT_INFINITE = 0xffff;
internal const int WAIT_INFINITE = -1;
[StructLayout(LayoutKind.Sequential)]
internal struct OVERLAPPED
{
Expand Down Expand Up @@ -55,10 +55,13 @@ internal struct SECURITY_ATTRIBUTES
static internal extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);

[DllImport("kernel32.dll", SetLastError = true)]
static internal extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped);
static internal extern bool ReadFile(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped);

[DllImport("kernel32.dll")]
static internal extern uint WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

[DllImport("kernel32.dll", SetLastError = true)]
static internal extern bool GetOverlappedResult(IntPtr hFile, [In] ref System.Threading.NativeOverlapped lpOverlapped, out uint lpNumberOfBytesTransferred, bool bWait);

[DllImport("kernel32.dll")]
static internal extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, [In] ref System.Threading.NativeOverlapped lpOverlapped);
Expand Down

1 comment on commit 574bc60

@mikeobrien
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TeamCity Hid Library :: Deploy Build 3.2.41.0 outcome was SUCCESS
Summary: Running Build time: 00:00:32

Please sign in to comment.