The call to ReadFile passes the handle returned by CreateFile, an array to store the returned report, the report’s length, a pointer to a variable to hold the num-ber of bytes read, and
Trang 1eventObject = CreateEvent
(IntPtr.Zero,
false,
false,
String.Empty);
HidOverlapped.OffsetLow = 0;
HidOverlapped.OffsetHigh = 0;
HidOverlapped.EventHandle = eventObject;
unManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
unManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(HidOverlapped)); Marshal.StructureToPtr(HidOverlapped, unManagedOverlapped, false);
readHandle = CreateFile
(devicePathName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
success = ReadFile
(readHandle,
unManagedBuffer,
inputReportBuffer.Length,
ref numberOfBytesRead,
unManagedOverlapped);
Trang 2// If ReadFile returned true, a report is available Otherwise, check for completion.
if (!success)
{
result = WaitForSingleObject
(eventObject,
3000);
switch ( result )
{
case WAIT_OBJECT_0:
success = True;
GetOverlappedResult (readHandle, unManagedOverlapped, ref numberOfBytesRead, false);
break;
case WAIT_TIMEOUT:
CancelIo(readHandle);
break;
default:
CancelIo(readHandle);
break;
}
}
if (success)
{
// A report was received.
// Copy the received data to inputReportBuffer for the application to use.
Marshal.Copy(unManagedBuffer, inputReportBuffer, 0, numberOfBytesRead); }
Marshal.FreeHGlobal(unManagedOverlapped);
Marshal.FreeHGlobal(unManagedBuffer);
Trang 3The buffer passed to ReadFile should be at least the size reported in the InputReportByteLength property of the HIDP_CAPS structure returned by HidP_GetCaps
The CreateEvent function returns a pointer to an event object that will be set to the signaled state when the read operation succeeds or the function times out or returns another error The call to ReadFile passes the returned pointer in the HidOverlapped structure Marshaling allocates memory for the overlapped structure and the report buffer to ensure that their contents remain accessible for the life of the overlapped operation
C r e a t e Fi l e o b t a i n s a h a n d l e f o r ov e r l a p p e d I / O b y s e t t i n g t h e dwFlagsAndAttributes parameter to FILE_FLAG_OVERLAPPED
The call to ReadFile passes the handle returned by CreateFile, an array to store the returned report, the report’s length, a pointer to a variable to hold the num-ber of bytes read, and a pointer to a NativeOverlapped structure The struc-ture’s EventHandle member is the handle returned by CreateEvent
ReadFile returns immediately A return value of true indicates that the function has retrieved one or more reports False means that a report wasn’t available To detect when a report arrives, the application calls WaitForSingleObject, passing
a pointer to the event object and a timeout value in milliseconds
If WaitForSingleObject returns success (WAIT_OBJECT_0), GetOverlappe-dResult returns the number of bytes read The Marshal.Copy method copies the report data to the managed inputReportBuffer array The application can then use the report data as desired and free the memory previously allocated and no longer needed
The first byte in inputReportBuffer is the Report ID, and the following bytes are the report data If the interface supports only the default Report ID of zero, the Report ID doesn’t transmit on the bus but is still present in the buffer returned by ReadFile
A call to ReadFile doesn’t initiate traffic on the bus The host begins requesting reports when the HID driver loads during enumeration, and the driver stores received reports in a ring buffer When the buffer is full and a new report arrives, the buffer drops the oldest report A call to ReadFile reads the oldest report in the buffer If the driver’s buffer is empty, ReadFile waits for a report to arrive
Trang 4Under Windows 98 SE and later, HidD_SetNumInputBuffers can set the buffer size Different Windows editions have different default buffer sizes, rang-ing from 2 under Windows 98 Gold to 32 under Windows XP
Each handle with read access to the HID has its own Input buffer, so multiple applications can read the same reports
If the application doesn’t request reports as frequently as the endpoint sends them, some reports will be lost One way to keep from losing reports is to increase the size of the report buffer passed to ReadFile If multiple reports are available, ReadFile returns as many as will fit in the buffer If you need to be absolutely sure not to lose a report, use Feature reports instead Also see the tips
in Chapter 3 about performing time-critical transfers
The Idle rate introduced in Chapter 11 determines whether or not a device sends a report if the data hasn’t changed since the last transfer
If ReadFile isn’t returning, these are possible reasons:
• The HID’s interrupt IN endpoint is NAKing the IN token packets because the endpoint hasn’t been armed to send report data An endpoint’s inter-rupt typically triggers only after endpoint sends data, so the device must arm the endpoint to send the first report before the first interrupt
• The number of bytes the endpoint is sending doesn’t equal the number of bytes in a report (for HIDs that use the default Report ID) or the number
of bytes in a report + 1 (for HIDs that use other Report IDs)
• For HIDs with multiple Report IDs, the first byte doesn’t match a valid Report ID
9TKVKPIC(GCVWTG4GRQTVVQVJG&GXKEG
To send a Feature report to a device, use HidD_SetFeature, which sends a Set Report request and a report in a control transfer
Trang 58$ Definitions
<DllImport("hid.dll", SetLastError:=True)> _
Shared Function HidD_SetFeature _
(ByVal HidDeviceObject As SafeFileHandle, _
ByVal lpReportBuffer() As Byte, _
ByVal ReportBufferLength As Int32) _
As Boolean
End Function
Use
Dim outFeatureReportBuffer() As Byte = Nothing
Dim success As Boolean
Array.Resize(outFeatureReportBuffer, Capabilities.FeatureReportByteLength)
' Store the Report ID in the first byte of the buffer:
outFeatureReportBuffer(0) = 0
' Store the report data following the Report ID Example:
outFeatureReportBuffer(1) = 79
outFeatureReportBuffer(2) = 75
success = HidD_SetFeature _
(deviceHandle, _
outFeatureReportBuffer, _
outFeatureReportBuffer.Length)
8% Definitions
[ DllImport( "hid.dll", SetLastError=true ) ]
internal static extern Boolean HidD_SetFeature
( SafeFileHandle HidDeviceObject,
Byte lpReportBuffer[],
Int32 ReportBufferLength );
Use
Byte[] outFeatureReportBuffer = null;
Boolean success = false;
Array.Resize(ref outFeatureReportBuffer, Capabilities.FeatureReportByteLength);
Trang 6// Store the Report ID in the first byte of the buffer:
outFeaturetReportBuffer[ 0 ] = 0;
// Store the report data following the Report ID Example:
outFeatureReportBuffer[ 1 ] = 79;
outFeatureReportBuffer[ 2 ] = 75;
success = HidD_SetFeature
(deviceHandle,
outFeatureReportBuffer,
outFeatureReportBuffer.Length);
&GVCKNU
HidD_SetFeature requires a handle to the HID, an array to write, and the array’s length The first byte in the outFeatureReportBuffer array is the Report
ID The array’s length is in the HIDP_CAPS structure retrieved by HidP_GetCaps
The function returns true on success If the device continues to NAK the report data, the function times out and returns
A call to HidD_SetOutputReport works in much the same way to send an Output report using a control transfer The function passes a handle to the HID, a pointer to a byte array containing an Output report, and the number of bytes in the report plus one byte for the Report ID
4GCFKPIC(GCVWTG4GRQTVHTQOC&GXKEG
To read a Feature report from a device, use HidD_GetFeature, which sends a Get_Feature request in a control transfer The endpoint returns the report in the Data stage
8$ Definitions
<DllImport("hid.dll", SetLastError:=True)> _
Shared Function HidD_GetFeature _
(ByVal HidDeviceObject As SafeFileHandle, _
ByVal lpReportBuffer() As Byte, _
ByVal ReportBufferLength As Int32) _
As Boolean
Trang 7Dim inFeatureReportBuffer() As Byte = Nothing
Dim success As Boolean
Array.Resize(inFeatureReportBuffer, Capabilities.FeatureReportByteLength)
'The first byte in the report buffer is the Report ID:
InFeatureReportBuffer(0) = 0
success = HidD_GetFeature _
(deviceHandle, _
inFeatureReportBuffer, _
inFeatureReportBuffer.Length)
8% Definitions
[ DllImport( "hid.dll", SetLastError=true ) ]
internal static extern Boolean HidD_GetFeature
( SafeFileHandle HidDeviceObject,
Byte[] lpReportBuffer,
Int32 ReportBufferLength );
Use
Byte[] inFeatureReportBuffer = null;
Boolean success = false;
Array.Resize(ref inFeatureReportBuffer, Capabilities.FeatureReportByteLength);
// The first byte in the report buffer is the Report ID:
inFeatureReportBuffer[0] = 0;
success = HidD_GetFeature
(deviceHandle,
inFeatureReportBuffer,
inFeatureReportBuffer.Length);
&GVCKNU
HidD_GetFeature requires a handle to the HID, an array to hold the retrieved report(s), and the array’s length The inFeatureReportBuffer array holds the
Trang 8The function returns true on success If the device continues to return NAK in the Data stage of the transfer, the function times out and returns
A call to HidD_GetInputReport works in much the same way to request an Input report using a control transfer The function passes a handle to the HID,
an array to hold the Input report, and the number of bytes in the report plus one byte for the Report ID
%NQUKPI%QOOWPKECVKQPU
When finished communicating, the application should call the Close method
to close any SafeFileHandles opened by CreateFile as described in Chapter 10 When finished using the PreparsedData buffer that HidD_GetPreparsedData returned, the application should call HidD_FreePreparsedData
8$ Definitions
<DllImport("hid.dll", SetLastError:=True)> _
Shared Function HidD_FreePreparsedData _
(ByVal PreparsedData As IntPtr) _
As Boolean
End Function
Use
Dim success As Boolean
success = HidD_FreePreparsedData(preparsedData)
8% Definitions
[ DllImport( "hid.dll", SetLastError=true ) ]
internal static extern Boolean HidD_FreePreparsedData
( IntPtr PreparsedData );
Use
Boolean success = false;
success = HidD_FreePreparsedData( preparsedData );
Trang 107UKPI9KP75$HQT
8GPFQT&GHKPGF(WPEVKQPU
An option for devices that perform vendor-specific functions is Microsoft’s WinUSB driver This chapter shows how to develop a device that uses the WinUSB driver and how to use the WinUSB API to access the device from applications
%CRCDKNKVKGUCPF.KOKVU
A device is a candidate for using the WinUSB driver if the device and its host computer(s) meet the requirements below
&GXKEG4GSWKTGOGPVU
The device:
• Exchanges application data using any combination of control, interrupt, and bulk endpoints (The driver doesn’t support isochronous transfers.)
• Has descriptors that specify a vendor-specific class