📄 myusbhidtestappdlg.cpp
字号:
/******************************************************************
本程序只供学习使用,未经作者许可,不得用于其它任何用途
欢迎访问我的USB专区:http://group.ednchina.com/93/
欢迎访问我的blog: http://www.ednchina.com/blog/computer00
http://computer00.21ic.org
作者:电脑圈圈
建立日期: 2008.07.22
修改日期: 2008.07.23
版本:V1.1
版权所有,盗版必究。
Copyright(C) 电脑圈圈 2008-2018
All rights reserved
*******************************************************************/
// MyUsbHidTestAppDlg.cpp : implementation file
//
#include "stdafx.h"
#include "MyUsbHidTestApp.h"
#include "MyUsbHidTestAppDlg.h"
#include "dbt.h"
extern "C" {
#include "hidsdi.h"
#include "setupapi.h"
}
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
UCHAR LedStatus=0; //LED状态
UCHAR KeyStatus=0; //按键状态
//用来保存找到的设备路径
CString MyDevPathName="";
//用来保存设备是否已经找到
BOOL MyDevFound=FALSE;
//定义变量用来保存VID、PID、版本号
DWORD MyVid,MyPid,MyPvn;
//用来保存读数据的设备句柄
HANDLE hReadHandle=INVALID_HANDLE_VALUE;
//用来保存写数据的设备句柄
HANDLE hWriteHandle=INVALID_HANDLE_VALUE;
//正在发送数据的标志
BOOL DataInSending=FALSE;
//发送报告的缓冲区,1字节报告ID+8字节报告数据。
UCHAR WriteReportBuffer[8];
//接收报告的缓冲区,1字节报告ID+8字节报告数据。
UCHAR ReadReportBuffer[9];
//发送报告用的OVERLAPPED。
OVERLAPPED WriteOverlapped;
//接收报告用的OVERLAPPED。
OVERLAPPED ReadOverlapped;
//指向读报告线程的指针
CWinThread * pReadReportThread;
//指向写报告线程的指针
CWinThread * pWriteReportThread;
//用来注册设备通知事件用的广播接口。
//要使用该结构体,需要在StdAfx.h中将增加语句#define WINVER 0x0500
DEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface;
/////////////////////////////////////////////////////////////////////////////
// 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()
};
//////////////////////////////End of function//////////////////////
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
//////////////////////////////End of function//////////////////////
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
//////////////////////////////End of function//////////////////////
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyUsbHidTestAppDlg dialog
CMyUsbHidTestAppDlg::CMyUsbHidTestAppDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyUsbHidTestAppDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMyUsbHidTestAppDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
//////////////////////////////End of function//////////////////////
void CMyUsbHidTestAppDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyUsbHidTestAppDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
//////////////////////////////End of function//////////////////////
BEGIN_MESSAGE_MAP(CMyUsbHidTestAppDlg, CDialog)
//{{AFX_MSG_MAP(CMyUsbHidTestAppDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_ABOUT, OnAbout)
ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_CLEAR_INF, OnClearInf)
ON_BN_CLICKED(IDC_LED1, OnLed1)
ON_BN_CLICKED(IDC_LED2, OnLed2)
ON_BN_CLICKED(IDC_LED3, OnLed3)
ON_BN_CLICKED(IDC_LED4, OnLed4)
ON_BN_CLICKED(IDC_LED5, OnLed5)
ON_BN_CLICKED(IDC_LED6, OnLed6)
ON_BN_CLICKED(IDC_LED7, OnLed7)
ON_BN_CLICKED(IDC_LED8, OnLed8)
ON_BN_CLICKED(IDC_OPEN_DEVICE, OnOpenDevice)
ON_BN_CLICKED(IDC_CLOSE_DEVICE, OnCloseDevice)
ON_BN_CLICKED(IDC_QUIT, OnQuit)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_CLEAR_COUNTER, OnClearCounter)
ON_WM_TIMER()
ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyUsbHidTestAppDlg message handlers
BOOL CMyUsbHidTestAppDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 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
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
//////////////////////////////End of function//////////////////////
void CMyUsbHidTestAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
//////////////////////////////End of function//////////////////////
// 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 CMyUsbHidTestAppDlg::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();
}
}
//////////////////////////////End of function//////////////////////
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMyUsbHidTestAppDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
//////////////////////////////End of function//////////////////////
void CMyUsbHidTestAppDlg::OnAbout()
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
//////////////////////////////End of function//////////////////////
//读报告的线程。由于使用的是异步调用,因而在调用ReadFile
//函数时提供一个Overlapped的结构,该结构中含有一个事件的
//句柄。平时该事件是处于无信号状态的,因而等待事件的函数
//就会被挂起,从而该线程被阻塞。当数据正确返回后,事件被
//触发,线程恢复运行。并检查返回的数据量以及报告ID是否正
//确,从而设置界面上各开关的状态。由于该函数并不是
//CMyUsbHidTestAppDlg类(就是该工程中主窗口类)中的成员函数,
//所以无法直接调用CMyUsbHidTestAppDlg类中的成员函数。
//在创建该线程时,通过pParam参数传递了一个this指针,将参数pParam
//强制转化为CMyUsbHidTestAppDlg类的指针即可访问CMyUsbHidTestAppDlg类
//中的成员函数。
UINT ReadReportThread(LPVOID pParam)
{
CMyUsbHidTestAppDlg *pAppDlg;
DWORD Length, Counter;
UINT i;
CString Str;
//将参数pParam取出,并转换为CMyUsbHidTestAppDlg型指针,
//以供下面调用其成员函数。
pAppDlg=(CMyUsbHidTestAppDlg*)pParam;
//该线程是个死循环,直到程序退出时,它才退出
while(1)
{
//设置事件为无效状态
ResetEvent(ReadOverlapped.hEvent);
//如果设备已经找到
if(MyDevFound==TRUE)
{
if(hReadHandle==INVALID_HANDLE_VALUE) //如果读句柄无效
{
pAppDlg->AddToInfOut("无效的读报告句柄,可能是打开设备时失败");
}
else //否则,句柄有效
{
//则调用ReadFile函数请求9字节的报告数据
ReadFile(hReadHandle,
ReadReportBuffer,
9,
NULL,
&ReadOverlapped);
}
//等待事件触发
WaitForSingleObject(ReadOverlapped.hEvent,INFINITE);
//如果等待过程中设备被拔出,也会导致事件触发,但此时MyDevFound
//被设置为假,因此在这里判断MyDevFound为假的话就进入下一轮循环。
if(MyDevFound==FALSE) continue;
//如果设备没有被拔下,则是ReadFile函数正常操作完成。
//通过GetOverlappedResult函数来获取实际读取到的字节数。
GetOverlappedResult(hReadHandle,&ReadOverlapped,&Length,TRUE);
//如果字节数不为0,则将读到的数据显示到信息框中
if(Length!=0)
{
pAppDlg->AddToInfOut("读取报告"+pAppDlg->itos(Length)+"字节");
Str="";
for(i=0;i<Length;i++)
{
Str+=pAppDlg->itos(ReadReportBuffer[i],16).Right(2)+" ";
}
pAppDlg->AddToInfOut(Str, FALSE);
}
//如果字节数为9,则说明获取到了正确的9字节报告
if(Length==9)
{
//第一字节为报告ID,应该为0
if(ReadReportBuffer[0]==0)
{
//第二字节为按键状态,将其保存到KeyStatus中。
KeyStatus=ReadReportBuffer[1];
//刷新按键的情况。
pAppDlg->SetKeyStatus();
//第3、4、5、6字节为设备返回的发送次数值。计算出值后并显示。
Counter=ReadReportBuffer[5];
Counter=(Counter<<8)+ReadReportBuffer[4];
Counter=(Counter<<8)+ReadReportBuffer[3];
Counter=(Counter<<8)+ReadReportBuffer[2];
pAppDlg->SetCounterNumber(Counter);
}
}
}
else
{
//阻塞线程,直到下次事件被触发
WaitForSingleObject(ReadOverlapped.hEvent,INFINITE);
}
}
return 0;
}
//////////////////////////////End of function//////////////////////
//写报告的线程,该线程比较简单,只是简单地等待事件被触发,
//然后清除数据正在发送的标志。
UINT WriteReportThread(LPVOID pParam)
{
while(1)
{
//设置事件为无效状态
ResetEvent(WriteOverlapped.hEvent);
//等待事件触发
WaitForSingleObject(WriteOverlapped.hEvent,INFINITE);
//清除数据正在发送标志
DataInSending=FALSE;
//WriteReportBuffer[2]为非0值时将让设备清除它的计数值,
//当点击清除计数器按键时,将会设置该值为非0,等数据发送
//完毕后,将它改回0。这样在发送LED状态时,就可以不用去设置
//WriteReportBuffer[2]的值了。
WriteReportBuffer[2]=0;
}
return 0;
}
//////////////////////////////End of function//////////////////////
//窗口将要显示时的函数
void CMyUsbHidTestAppDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
HICON hIcon;
GUID HidGuid;
CDialog::OnShowWindow(bShow, nStatus);
// TODO: Add your message handler code here
//初始化
//LED加载熄灭态图标
hIcon=AfxGetApp()->LoadIcon(IDI_LED_OFF);
GetDlgItem(IDC_LED1)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED2)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED3)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED4)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED5)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED6)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED7)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
GetDlgItem(IDC_LED8)->SendMessage(BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);
//禁止LED按钮,打开设备后才能使用
GetDlgItem(IDC_LED1)->EnableWindow(FALSE);
GetDlgItem(IDC_LED2)->EnableWindow(FALSE);
GetDlgItem(IDC_LED3)->EnableWindow(FALSE);
GetDlgItem(IDC_LED4)->EnableWindow(FALSE);
GetDlgItem(IDC_LED5)->EnableWindow(FALSE);
GetDlgItem(IDC_LED6)->EnableWindow(FALSE);
GetDlgItem(IDC_LED7)->EnableWindow(FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -