📄 usbhidiocdlg.cpp
字号:
OPEN_EXISTING,
0,
NULL);
DisplayLastError("CreateFile: ");
/*
API function: HidD_GetAttributes
Requests information from the device.
Requires: the handle returned by CreateFile.
Returns: a HIDD_ATTRIBUTES structure containing
the Vendor ID, Product ID, and Product Version Number.
Use this information to decide if the detected device is
the one we're looking for.
*/
//Set the Size to the number of bytes in the structure.
Attributes.Size = sizeof(Attributes);
Result = HidD_GetAttributes
(DeviceHandle,
&Attributes);
DisplayLastError("HidD_GetAttributes: ");
//Is it the desired device?
MyDeviceDetected = FALSE;
if (Attributes.VendorID == VendorID)
{
if (Attributes.ProductID == ProductID)
{
//Both the Product and Vendor IDs match.
MyDeviceDetected = TRUE;
DisplayData("Device detected");
//Get the device's capablities.
GetDeviceCapabilities();
PrepareForOverlappedTransfer();
} //if (Attributes.ProductID == ProductID)
else
//The Product ID doesn't match.
CloseHandle(DeviceHandle);
} //if (Attributes.VendorID == VendorID)
else
//The Vendor ID doesn't match.
CloseHandle(DeviceHandle);
//Free the memory used by the detailData structure (no longer needed).
free(detailData);
} //if (Result != 0)
else
//SetupDiEnumDeviceInterfaces returned 0, so there are no more devices to check.
LastDevice=TRUE;
//If we haven't found the device yet, and haven't tried every available device,
//try the next one.
MemberIndex = MemberIndex + 1;
} //do
while ((LastDevice == FALSE) && (MyDeviceDetected == FALSE));
if (MyDeviceDetected == FALSE)
DisplayData("Device not detected");
else
DisplayData("Device detected");
//Free the memory reserved for hDevInfo by SetupDiClassDevs.
SetupDiDestroyDeviceInfoList(hDevInfo);
DisplayLastError("SetupDiDestroyDeviceInfoList");
return MyDeviceDetected;
}
void CUsbhidiocDlg::GetDeviceCapabilities()
{
//Get the Capabilities structure for the device.
PHIDP_PREPARSED_DATA PreparsedData;
/*
API function: HidD_GetPreparsedData
Returns: a pointer to a buffer containing the information about the device's capabilities.
Requires: A handle returned by CreateFile.
There's no need to access the buffer directly,
but HidP_GetCaps and other API functions require a pointer to the buffer.
*/
HidD_GetPreparsedData
(DeviceHandle,
&PreparsedData);
DisplayLastError("HidD_GetPreparsedData: ");
/*
API function: HidP_GetCaps
Learn the device's capabilities.
For standard devices such as joysticks, you can find out the specific
capabilities of the device.
For a custom device, the software will probably know what the device is capable of,
and the call only verifies the information.
Requires: the pointer to the buffer returned by HidD_GetPreparsedData.
Returns: a Capabilities structure containing the information.
*/
HidP_GetCaps
(PreparsedData,
&Capabilities);
DisplayLastError("HidP_GetCaps: ");
//Display the capabilities
ValueToDisplay.Format("%s%X", "Usage Page: ", Capabilities.UsagePage);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Input Report Byte Length: ", Capabilities.InputReportByteLength);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Output Report Byte Length: ", Capabilities.OutputReportByteLength);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Feature Report Byte Length: ", Capabilities.FeatureReportByteLength);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Link Collection Nodes: ", Capabilities.NumberLinkCollectionNodes);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Input Button Caps: ", Capabilities.NumberInputButtonCaps);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of InputValue Caps: ", Capabilities.NumberInputValueCaps);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of InputData Indices: ", Capabilities.NumberInputDataIndices);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Output Button Caps: ", Capabilities.NumberOutputButtonCaps);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Output Value Caps: ", Capabilities.NumberOutputValueCaps);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Output Data Indices: ", Capabilities.NumberOutputDataIndices);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Feature Button Caps: ", Capabilities.NumberFeatureButtonCaps);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Feature Value Caps: ", Capabilities.NumberFeatureValueCaps);
DisplayData(ValueToDisplay);
ValueToDisplay.Format("%s%d", "Number of Feature Data Indices: ", Capabilities.NumberFeatureDataIndices);
DisplayData(ValueToDisplay);
//No need for PreparsedData any more, so free the memory it's using.
HidD_FreePreparsedData(PreparsedData);
DisplayLastError("HidD_FreePreparsedData: ") ;
}
void CUsbhidiocDlg::PrepareForOverlappedTransfer()
{
//Get another handle to the device for the overlapped ReadFiles.
ReadHandle=CreateFile
(detailData->DevicePath,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
DisplayLastError("CreateFile (ReadHandle): ");
//Get an event object for the overlapped structure.
/*API function: CreateEvent
Requires:
Security attributes or Null
Manual reset (true). Use ResetEvent to set the event object's state to non-signaled.
Initial state (true = signaled)
Event object name (optional)
Returns: a handle to the event object
*/
if (hEventObject == 0)
{
hEventObject = CreateEvent
(NULL,
TRUE,
TRUE,
"");
DisplayLastError("CreateEvent: ") ;
//Set the members of the overlapped structure.
HIDOverlapped.hEvent = hEventObject;
HIDOverlapped.Offset = 0;
HIDOverlapped.OffsetHigh = 0;
}
}
void CUsbhidiocDlg::ReadAndWriteToDevice()
{
//If we haven't done so already, find the device and learn its capabilities.
//Then send a report and request a report.
//The test device firmware (usbhidio) adds 1 to each byte received in an OUT report
//and sends the results back in the next IN report.
//Clear the List Box (optional).
//m_ResultsList.ResetContent();
{
DisplayData("***HID Test Report***");
DisplayCurrentTime();
//If the device hasn't been detected already, look for it.
if (DeviceDetected==FALSE)
DeviceDetected=FindTheHID();
if (DeviceDetected==TRUE)
{
//Write a report to the device.
WriteReport();
//Read a report from the device.
ReadReport();
}
}
}
void CUsbhidiocDlg::ReadReport()
{
CString ByteToDisplay = "";
CString MessageToDisplay = "";
DWORD Result;
//Read a report from the device.
/*API call:ReadFile
'Returns: the report in InputReport.
'Requires: a device handle returned by CreateFile
'(for overlapped I/O, CreateFile must be called with FILE_FLAG_OVERLAPPED),
'the Input report length in bytes returned by HidP_GetCaps,
'and an overlapped structure whose hEvent member is set to an event object.
*/
Result = ReadFile
(ReadHandle,
InputReport,
Capabilities.InputReportByteLength,
&NumberOfBytesRead,
(LPOVERLAPPED) &HIDOverlapped);
DisplayLastError("ReadFile: ") ;
/*API call:WaitForSingleObject
'Used with overlapped ReadFile.
'Returns when ReadFile has received the requested amount of data or on timeout.
'Requires an event object created with CreateEvent
'and a timeout value in milliseconds.
*/
Result = WaitForSingleObject
(hEventObject,
6000);
DisplayLastError("WaitForSingleObject: ") ;
switch (Result)
{
case WAIT_OBJECT_0:
{
ValueToDisplay.Format("%s", "ReadFile Completed");
DisplayData(ValueToDisplay);
break;
}
case WAIT_TIMEOUT:
{
ValueToDisplay.Format("%s", "ReadFile timeout");
DisplayData(ValueToDisplay);
//Cancel the Read operation.
/*API call: CancelIo
Cancels the ReadFile
Requires the device handle.
Returns non-zero on success.
*/
Result = CancelIo(ReadHandle);
//A timeout may mean that the device has been removed.
//Close the device handles and set DeviceDetected = False
//so the next access attempt will search for the device.
CloseHandle(ReadHandle);
CloseHandle(DeviceHandle);
DisplayData("Can't read from device");
DeviceDetected = FALSE;
break;
default:
ValueToDisplay.Format("%s", "Undefined error");
break;
}
}
/*
API call: ResetEvent
Sets the event object to non-signaled.
Requires a handle to the event object.
Returns non-zero on success.
*/
ResetEvent(hEventObject);
//Display the report data.
DisplayInputReport();
}
void CUsbhidiocDlg::WriteReport()
{
//Send a report to the device.
//The maximum size of an output report. (This can be increased).
const unsigned short int MAXREPORTSIZE = 256;
DWORD BytesWritten = 0;
INT Index =0;
CHAR OutputReport[MAXREPORTSIZE];
ULONG Result;
CString strBytesWritten = "";
//The first byte is the report number.
OutputReport[0]=0;
//Can set the other report values here, or get them from the combo boxes.
//OutputReport[1]=33;
//OutputReport[2]=6;
//OutputReport[3]=15;
//Get the bytes to send from the combo boxes.
//If Autoincrement is checked, increment the selection.
if (m_cbutAutoIncrement.GetCheck()>0)
{
Index=m_cboByteToSend0.GetCurSel();
Index=Index+1;
m_cboByteToSend0.SetCurSel(Index);
}
if (m_cbutAutoIncrement.GetCheck()>0)
{
Index=m_cboByteToSend1.GetCurSel();
Index=Index+1;
m_cboByteToSend1.SetCurSel(Index);
}
//Get the values from the combo boxes.
OutputReport[1]=m_cboByteToSend0.GetCurSel();
OutputReport[2]=m_cboByteToSend1.GetCurSel();
/*
API Function: WriteFile
Sends a report to the device.
Returns: success or failure.
Requires:
The device handle returned by CreateFile.
The Output Report length returned by HidP_GetCaps,
A report to send.
*/
Result = WriteFile
(DeviceHandle,
OutputReport,
Capabilities.OutputReportByteLength,
&BytesWritten,
NULL);
if (Result == 0)
{
//The WriteFile failed, so close the handle, display a message,
//and set DeviceDetected to FALSE so the next attempt will look for the device.
CloseHandle(DeviceHandle);
CloseHandle(ReadHandle);
DisplayData("Can't write to device");
DeviceDetected = FALSE;
}
//Display the result of the API call and the report bytes.
DisplayLastError("WriteFile: ");
strBytesWritten.Format("%s%d", "Bytes Written: ", BytesWritten);
DisplayData(strBytesWritten);
}
/*
Display-related routines
*/
void CUsbhidiocDlg::DisplayInputReport()
{
USHORT ByteNumber;
CHAR ReceivedByte;
//Display the received data in the log and the Bytes Received List boxes.
//Start at the top of the List Box.
m_BytesReceived.ResetContent();
//Step through the received bytes and display each.
for (ByteNumber=0; ByteNumber < Capabilities.InputReportByteLength; ByteNumber++)
{
//Get a byte.
ReceivedByte = InputReport[ByteNumber];
//Display it.
DisplayReceivedData(ReceivedByte);
}
}
void CUsbhidiocDlg::DisplayCurrentTime()
{
//Get the current time and date and display them in the log List Box.
CTime curTime = CTime::GetCurrentTime();
CString CurrentTime = curTime.Format( "%H:%M:%S, %B %d, %Y" );
DisplayData(CurrentTime);
}
void CUsbhidiocDlg::DisplayData(CString cstrDataToDisplay)
{
//Display data in the log List Box
USHORT Index;
Index=m_ResultsList.InsertString(-1, (LPCTSTR)cstrDataToDisplay);
ScrollToBottomOfListBox(Index);
}
void CUsbhidiocDlg::DisplayLastError(CString Operation)
{
//Display a message and the last error in the log List Box.
LPVOID lpMsgBuf;
USHORT Index = 0;
CString strLastError = "";
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
//Display the last error.
strLastError = Operation + (LPCTSTR)lpMsgBuf;
//Trim CR/LF from the error message.
strLastError.TrimRight();
Index = m_ResultsList.InsertString(-1, strLastError);
ScrollToBottomOfListBox(Index);
LocalFree(lpMsgBuf);
}
void CUsbhidiocDlg::DisplayReceivedData(char ReceivedByte)
{
//Display data received from the device.
CString strByteRead;
//Convert the value to a 2-character Cstring.
strByteRead.Format("%02X", ReceivedByte);
strByteRead = strByteRead.Right(2);
//Display the value in the Bytes Received List Box.
m_BytesReceived.InsertString(-1, strByteRead);
//Display the value in the log List Box (optional).
//MessageToDisplay.Format("%s%s", "Byte 0: ", strByteRead);
//DisplayData(MessageToDisplay);
}
void CUsbhidiocDlg::OnChangeResults()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
}
void CUsbhidiocDlg::ScrollToBottomOfListBox(USHORT Index)
{
/*
Scroll to the bottom of the list box.
To do so, add a line and set it as the current selection,
possibly scrolling the window.
Then deselect the line,
leaving the list box scrolled to the bottom with nothing selected.
*/
m_ResultsList.SetCurSel( Index );
m_ResultsList.SetCurSel( -1 );
}
/*
Misc. routines.
*/
void CUsbhidiocDlg::OnTimer(UINT nIDEvent)
{
//The timer event.
//Read and Write one pair of reports.
ReadAndWriteToDevice();
CDialog::OnTimer(nIDEvent);
}
void CUsbhidiocDlg::OnOK()
{
CDialog::OnOK();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -