⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myusbhidtestappdlg.cpp

📁 对HID类设备进行读写
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/******************************************************************
   本程序只供学习使用,未经作者许可,不得用于其它任何用途
			
        欢迎访问我的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 + -