📄 pnp.cpp
字号:
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
pnp.c
Abstract:
This module contains the code
for finding, adding, removing, and identifying hid devices.
Environment:
User mode
--*/
#include "stdafx.h"
#include <dbt.h>
#include "hid.h"
#include <basetyps.h>
#include <stdlib.h>
#include <wtypes.h>
#include <setupapi.h>
#define TENX_VID 0x1130
#define TENX_PID 0x0202
/*++
Routine Description:
Do the required PnP things in order to find the 1603 HID device in
the system at this time.
--*/
BOOLEAN FindGenericHIDDevice(PHID_DEVICE HidDevice, PHID_DEVICE HidCBWDevice, HWND hWnd)
{
HDEVINFO hardwareDeviceInfo;
SP_INTERFACE_DEVICE_DATA deviceInfoData;
ULONG i;
GUID hidGuid;
PSP_INTERFACE_DEVICE_DETAIL_DATA functionClassDeviceData = NULL;
ULONG predictedLength = 0;
ULONG requiredLength = 0;
BOOL bFindDevice, bFindCBWDevice, bFind;
bFindDevice = bFindCBWDevice = FALSE;
HidD_GetHidGuid (&hidGuid);
//
// Open a handle to the plug and play dev node.
//
hardwareDeviceInfo = SetupDiGetClassDevs ( &hidGuid,
NULL, // Define no enumerator (global)
NULL, // Define no
(DIGCF_PRESENT | // Only Devices present
DIGCF_DEVICEINTERFACE)); // Function class devices.
deviceInfoData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
for (i=0; SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, 0, &hidGuid, i, &deviceInfoData); i++) {
bFind = FALSE;
//
// allocate a function class device data structure to receive the
// goods about this particular device.
//
SetupDiGetDeviceInterfaceDetail (
hardwareDeviceInfo,
&deviceInfoData,
NULL, // probing so no output buffer yet
0, // probing so output buffer length of zero
&requiredLength,
NULL); // not interested in the specific dev-node
predictedLength = requiredLength;
functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc (predictedLength);
if (functionClassDeviceData)
{
functionClassDeviceData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
}
else
{
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
return FALSE;
}
//
// Retrieve the information from Plug and Play.
//
if (! SetupDiGetDeviceInterfaceDetail (
hardwareDeviceInfo,
&deviceInfoData,
functionClassDeviceData,
predictedLength,
&requiredLength,
NULL))
{
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
return FALSE;
}
//
// Open device with just generic query abilities to begin with
//
if(!bFindDevice) {
bFind = bFindDevice = OpenHidDevice (functionClassDeviceData -> DevicePath,
TRUE, // ReadAccess - none
TRUE, // WriteAccess - none
FALSE, // Overlapped - no
FALSE, // Exclusive - no
TRUE, // GetDeviceInfo - yes
HidDevice,
hWnd,
1, 0);
}
if(!bFindCBWDevice && !bFind) {
bFindCBWDevice = OpenHidDevice (functionClassDeviceData -> DevicePath,
TRUE, // ReadAccess - none
TRUE, // WriteAccess - none
FALSE, // Overlapped - no
FALSE, // Exclusive - no
TRUE, // GetDeviceInfo - yes
HidCBWDevice,
hWnd,
1, 3);
}
if(bFindDevice && bFindCBWDevice) break;
}
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
return (bFindDevice && bFindCBWDevice);
}
/*++
RoutineDescription:
Given the HardwareDeviceInfo, representing a handle to the plug and
play information, and deviceInfoData, representing a specific hid device,
open that device and fill in all the relivant information in the given
HID_DEVICE structure.
return if the open and initialization was successfull or not.
--*/
BOOLEAN
OpenHidDevice (
IN PCHAR DevicePath,
IN BOOL HasReadAccess,
IN BOOL HasWriteAccess,
IN BOOL IsOverlapped,
IN BOOL IsExclusive,
IN BOOL GetDeviceInfo,
IN OUT PHID_DEVICE HidDevice,
IN HWND hWnd,
IN USHORT usUsagePage,
IN USHORT usUsageID
)
{
DWORD accessFlags = 0;
DWORD sharingFlags = 0;
DWORD dwLen = strlen(DevicePath);
HidDevice -> DevicePath = (PCHAR)malloc(dwLen + 1);
if (NULL == HidDevice -> DevicePath)
{
return (FALSE);
}
strcpy(HidDevice -> DevicePath, DevicePath);
HidDevice -> DevicePath[dwLen] = '\0';
if (HasReadAccess)
{
accessFlags |= GENERIC_READ;
}
if (HasWriteAccess)
{
accessFlags |= GENERIC_WRITE;
}
if (!IsExclusive)
{
sharingFlags = FILE_SHARE_READ | FILE_SHARE_WRITE;
}
HidDevice->HidDevice = CreateFile (DevicePath,
accessFlags,
sharingFlags,
NULL, // no SECURITY_ATTRIBUTES structure
OPEN_EXISTING, // No special create flags
IsOverlapped ? FILE_FLAG_OVERLAPPED : 0,
NULL); // No template file
if (INVALID_HANDLE_VALUE == HidDevice->HidDevice)
{
free(HidDevice -> DevicePath);
return FALSE;
}
HidDevice -> OpenedForRead = HasReadAccess;
HidDevice -> OpenedForWrite = HasWriteAccess;
HidDevice -> OpenedOverlapped = IsOverlapped;
HidDevice -> OpenedExclusive = IsExclusive;
//
// If the device was not opened as overlapped, then fill in the rest of the
// HidDevice structure. However, if opened as overlapped, this handle cannot
// be used in the calls to the HidD_ exported functions since each of these
// functions does synchronous I/O.
//
if (!HidD_GetAttributes (HidDevice->HidDevice, &HidDevice->Attributes))
{
free(HidDevice -> DevicePath);
CloseHandle(HidDevice -> HidDevice);
return FALSE;
} else { // Check the VID/PID
if( (HidDevice->Attributes.VendorID != TENX_VID) || (HidDevice->Attributes.ProductID != TENX_PID) ) {
free(HidDevice -> DevicePath);
CloseHandle(HidDevice -> HidDevice);
return FALSE;
}
}
if (GetDeviceInfo)
{
if (!HidD_GetPreparsedData (HidDevice->HidDevice, &HidDevice->Ppd))
{
free(HidDevice -> DevicePath);
CloseHandle(HidDevice -> HidDevice);
return FALSE;
}
if (!HidP_GetCaps (HidDevice->Ppd, &HidDevice->Caps))
{
free(HidDevice -> DevicePath);
CloseHandle(HidDevice -> HidDevice);
HidD_FreePreparsedData (HidDevice->Ppd);
return FALSE;
} else { // Check the usage page and usage ID.
if((HidDevice->Caps.UsagePage != (USAGE)usUsagePage) || (HidDevice->Caps.Usage != (USAGE)usUsageID)) {
free(HidDevice -> DevicePath);
CloseHandle(HidDevice -> HidDevice);
HidD_FreePreparsedData (HidDevice->Ppd);
return FALSE;
}
}
//
// At this point the client has a choice. It may chose to look at the
// Usage and Page of the top level collection found in the HIDP_CAPS
// structure. In this way it could just use the usages it knows about.
// If either HidP_GetUsages or HidP_GetUsageValue return an error then
// that particular usage does not exist in the report.
// This is most likely the preferred method as the application can only
// use usages of which it already knows.
// In this case the app need not even call GetButtonCaps or GetValueCaps.
//
// In this example, however, we will call FillDeviceInfo to look for all
// of the usages in the device.
//
FillDeviceInfo(HidDevice);
DEV_BROADCAST_HANDLE broadcastHandle;
broadcastHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
broadcastHandle.dbch_devicetype = DBT_DEVTYP_HANDLE;
broadcastHandle.dbch_handle = HidDevice->HidDevice;
HidDevice->hDeviceNotificationHandle = RegisterDeviceNotification(
hWnd,
&broadcastHandle,
DEVICE_NOTIFY_WINDOW_HANDLE);
HidDevice->bFound = TRUE;
}
return (TRUE);
}
VOID
FillDeviceInfo(
IN PHID_DEVICE HidDevice
)
{
USHORT numValues;
USHORT numCaps;
PHIDP_BUTTON_CAPS buttonCaps;
PHIDP_VALUE_CAPS valueCaps;
PHID_DATA data;
ULONG i;
USAGE usage;
//
// setup Input Data buffers.
//
//
// Allocate memory to hold on input report
//
HidDevice->InputReportBuffer = (PCHAR)
calloc (HidDevice->Caps.InputReportByteLength, sizeof (CHAR));
//
// Allocate memory to hold the button and value capabilities.
// NumberXXCaps is in terms of array elements.
//
HidDevice->InputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
calloc (HidDevice->Caps.NumberInputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
calloc (HidDevice->Caps.NumberInputValueCaps, sizeof (HIDP_VALUE_CAPS));
//
// Have the HidP_X functions fill in the capability structure arrays.
//
numCaps = HidDevice->Caps.NumberInputButtonCaps;
HidP_GetButtonCaps (HidP_Input,
buttonCaps,
&numCaps,
HidDevice->Ppd);
numCaps = HidDevice->Caps.NumberInputValueCaps;
HidP_GetValueCaps (HidP_Input,
valueCaps,
&numCaps,
HidDevice->Ppd);
//
// Depending on the device, some value caps structures may represent more
// than one value. (A range). In the interest of being verbose, over
// efficient, we will expand these so that we have one and only one
// struct _HID_DATA for each value.
//
// To do this we need to count up the total number of values are listed
// in the value caps structure. For each element in the array we test
// for range if it is a range then UsageMax and UsageMin describe the
// usages for this range INCLUSIVE.
//
numValues = 0;
for (i = 0; i < HidDevice->Caps.NumberInputValueCaps; i++, valueCaps++)
{
if (valueCaps->IsRange)
{
numValues += valueCaps->Range.UsageMax - valueCaps->Range.UsageMin + 1;
}
else
{
numValues++;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -