📄 usbhidiocdlg.cpp
字号:
// usbhidiocDlg.cpp : implementation file
/*
Project: usbhidioc.cpp
Version: 3.0
Date: 7/18/05
by Jan Axelson (jan@Lvr.com)
Purpose: demonstrates USB communications with a HID-class device.
Description:
Finds an attached HID-class device that matches a specified Vendor ID and Product ID.
Retrieves the HID's capabilities.
Sends a report to the HID and receives a report from the HID.
Supports Input, Output, and Feature reports.
A list box displays a log of activity.
A list box displays the most recent received report bytes.
Combo boxes enable the user to select bytes to send.
Edit boxes enable the user to specify a Vendor ID and Product ID.
A check box causes the application to increment the bytes sent
with each report.
Clicking the Once button causes the application to exchange one set of reports.
Clicking the Continuous button causes the application to exchange reports periodically
(every 5 seconds).
A button enables setting the number of Input reports the HID buffer can store.
This application was created with Visual C++ 6's AppWizard as a dialog-based application.
Companion firmware and other sample code is available from www.Lvr.com.
Send comments, questions, bug reports, etc. to jan@Lvr.com.
About overlapped I/O
The API function ReadFile retrieves Input reports from the HID driver's buffer.
Non-overlapped ReadFile is a blocking call.
If a report isn't available, the function waits.
With overlapped I/O, the call to ReadFile returns immediately. The application then calls
WaitForSingleObject, which returns when either the data has arrived or the specified timeout has elapsed.
This application has been tested on Windows 98 SE, Windows 2000, and Windows XP.
*/
#include "stdafx.h"
#include "usbhidioc.h"
#include "usbhidiocDlg.h"
#include <wtypes.h>
#include <initguid.h>
#define MAX_LOADSTRING 256
extern "C" {
// This file is in the Windows DDK available from Microsoft.
#include "hidsdi.h"
#include <setupapi.h>
#include <dbt.h>
}
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//function prototypes
BOOL DeviceNameMatch(LPARAM lParam);
bool FindTheHID();
LRESULT Main_OnDeviceChange(WPARAM wParam, LPARAM lParam);
void CloseHandles();
void DisplayCurrentTime();
void DisplayData(CString cstrDataToDisplay);
void DisplayFeatureReport();
void DisplayInputReport();
void DisplayLastError(CString Operation);
void DisplayReceivedData(char ReceivedByte);
void GetDeviceCapabilities();
void PrepareForOverlappedTransfer();
void ScrollToBottomOfListBox(USHORT idx);
void ReadAndWriteToDevice();
void ReadFeatureReport();
void ReadInputReport();
void RegisterForDeviceNotifications();
void WriteFeatureReport();
void WriteOutputReport();
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CUsbhidiocDlg dialog
CUsbhidiocDlg::CUsbhidiocDlg(CWnd* pParent /*=NULL*/)
: CDialog(CUsbhidiocDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CUsbhidiocDlg)
m_AutoIncrement = FALSE;
m_ResultsString = _T("");
m_strBytesReceived = _T("");
m_strByteToSend0 = _T("");
m_strByteToSend1 = _T("");
m_ReportType = 0;
m_UseControlTransfersOnly = FALSE;
m_ProductIDString = _T("1299");
m_VendorIDString = _T("0925");
m_InputReportBufferSize = _T("32");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
//Application global variables
DWORD ActualBytesRead;
DWORD BytesRead;
HIDP_CAPS Capabilities;
DWORD cbBytesRead;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData;
HANDLE DeviceHandle;
DWORD dwError;
char FeatureReport[256];
HANDLE hEventObject;
HANDLE hDevInfo;
GUID HidGuid;
OVERLAPPED HIDOverlapped;
char InputReport[256];
ULONG Length;
LPOVERLAPPED lpOverLap;
bool MyDeviceDetected = FALSE;
CString MyDevicePathName;
DWORD NumberOfBytesRead;
char OutputReport[256];
HANDLE ReadHandle;
DWORD ReportType;
ULONG Required;
CString ValueToDisplay;
HANDLE WriteHandle;
//These are the vendor and product IDs to look for.
//Uses Lakeview Research's Vendor ID.
int VendorID = 0x0925;
int ProductID = 0x1299;
void CUsbhidiocDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CUsbhidiocDlg)
DDX_Control(pDX, IDC_txtVendorID, m_VendorID);
DDX_Control(pDX, IDC_txtProductID, m_ProductID);
DDX_Control(pDX, IDC_Continuous, m_Continuous);
DDX_Control(pDX, IDC_AutoIncrement, m_cbutAutoIncrement);
DDX_Control(pDX, IDC_cboByteToSend1, m_cboByteToSend1);
DDX_Control(pDX, IDC_cboByteToSend0, m_cboByteToSend0);
DDX_Control(pDX, IDC_lstBytesReceived, m_BytesReceived);
DDX_Control(pDX, IDC_LIST2, m_ResultsList);
DDX_Control(pDX, IDC_Once, m_Once);
DDX_Check(pDX, IDC_AutoIncrement, m_AutoIncrement);
DDX_LBString(pDX, IDC_LIST2, m_ResultsString);
DDX_LBString(pDX, IDC_lstBytesReceived, m_strBytesReceived);
DDX_CBString(pDX, IDC_cboByteToSend0, m_strByteToSend0);
DDX_CBString(pDX, IDC_cboByteToSend1, m_strByteToSend1);
DDX_Radio(pDX, IDC_optExchangeInputAndOutputReports, m_ReportType);
DDX_Check(pDX, IDC_chkUseControlTransfersOnly, m_UseControlTransfersOnly);
DDX_Text(pDX, IDC_txtProductID, m_ProductIDString);
DDX_Text(pDX, IDC_txtVendorID, m_VendorIDString);
DDX_Text(pDX, IDC_txtInputReportBufferSize, m_InputReportBufferSize);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CUsbhidiocDlg, CDialog)
//{{AFX_MSG_MAP(CUsbhidiocDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_Once, OnOnce)
ON_EN_CHANGE(IDC_Results, OnChangeResults)
ON_BN_CLICKED(IDC_Continuous, OnContinuous)
ON_WM_TIMER()
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_cmdFindMyDevice, On_cmdFindMyDevice)
ON_EN_CHANGE(IDC_txtVendorID, OnChange_txtVendorID)
ON_EN_CHANGE(IDC_txtProductID, OnChange_txtProductID)
ON_BN_CLICKED(IDC_optExchangeInputAndOutputReports, On_optExchangeInputAndOutputReports)
ON_BN_CLICKED(IDC_optExchangeFeatureReports, On_optExchangeFeatureReports)
ON_BN_CLICKED(IDC_chkUseControlTransfersOnly, On_chkUseControlTransfersOnly)
ON_EN_CHANGE(IDC_txtInputReportBufferSize, OnChange_txtInputReportBufferSize)
ON_BN_CLICKED(IDC_cmdInputReportBufferSize, On_cmdInputReportBufferSize)
//}}AFX_MSG_MAP
//ON_WM_DEVICECHANGE()
ON_MESSAGE(WM_DEVICECHANGE, Main_OnDeviceChange)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CUsbhidiocDlg message handlers
BOOL CUsbhidiocDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//My declares begin here
int ByteToSend = 0;
CString strByteToSend = "";
CString strComboBoxText="";
//End my declares
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
/*
My code begins here.
Anything that needs to happen when the application starts goes in this routine.
*/
//Populate the combo boxes with values from 00 to FF.
MyDeviceDetected=FALSE;
for (ByteToSend=0; ByteToSend < 256; ByteToSend++)
{
//Display the value as a 2-digit Hex value.
strByteToSend.Format("%.2X",ByteToSend);
//Add the value to the combo boxes.
m_cboByteToSend0.AddString(strByteToSend);
m_cboByteToSend1.AddString(strByteToSend);
}
//Select default values for the combo boxes.
m_cboByteToSend0.SetCurSel(0);
m_cboByteToSend1.SetCurSel(128);
//Check the autoincrement check box.
m_cbutAutoIncrement.SetCheck(1);
//Set the caption for the Continous button.
m_Continuous.SetWindowText("Continuous");
//end my code
return TRUE; // return TRUE unless you set the focus to a control
}
void CUsbhidiocDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CUsbhidiocDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CUsbhidiocDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
/*
My routines (routines specific to this application) start here.
*/
void CUsbhidiocDlg::CloseHandles()
{
//Close open handles.
if (DeviceHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(DeviceHandle);
}
if (ReadHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(ReadHandle);
}
if (WriteHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(WriteHandle);
}
}
BOOL CUsbhidiocDlg::DeviceNameMatch(LPARAM lParam)
{
// Compare the device path name of a device recently attached or removed
// with the device path name of the device we want to communicate with.
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
DisplayData("MyDevicePathName = " + MyDevicePathName);
if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
PDEV_BROADCAST_DEVICEINTERFACE lpdbi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
CString DeviceNameString;
//The dbch_devicetype parameter indicates that the event applies to a device interface.
//So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure,
//which begins with a DEV_BROADCAST_HDR.
//The dbcc_name parameter of DevBroadcastDeviceInterface contains the device name.
//Compare the name of the newly attached device with the name of the device
//the application is accessing (myDevicePathName).
DeviceNameString = lpdbi->dbcc_name;
DisplayData("DeviceNameString = " + DeviceNameString);
if ((DeviceNameString.CompareNoCase(MyDevicePathName)) == 0)
{
//The name matches.
return true;
}
else
{
//It's a different device.
return false;
}
}
else
{
return false;
}
}
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::DisplayFeatureReport()
{
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.FeatureReportByteLength; ByteNumber++)
{
//Get a byte.
ReceivedByte = FeatureReport[ByteNumber];
//Display it.
DisplayReceivedData(ReceivedByte);
}
}
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::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);
//UpdateData(false);
}
bool CUsbhidiocDlg::FindTheHID()
{
//Use a series of API calls to find a HID with a specified Vendor IF and Product ID.
HIDD_ATTRIBUTES Attributes;
DWORD DeviceUsage;
SP_DEVICE_INTERFACE_DATA devInfoData;
bool LastDevice = FALSE;
int MemberIndex = 0;
LONG Result;
CString UsageDescription;
Length = 0;
detailData = NULL;
DeviceHandle=NULL;
/*
API function: HidD_GetHidGuid
Get the GUID for all system HIDs.
Returns: the GUID in HidGuid.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -