2411 lines
78 KiB
C
2411 lines
78 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft 1998, All Rights Reserved
|
|
|
|
Module Name:
|
|
|
|
hclient.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code for handling HClient's main dialog box and
|
|
for performing/calling the appropriate other routines.
|
|
|
|
Environment:
|
|
|
|
User mode
|
|
|
|
Revision History:
|
|
|
|
Nov-97 : Created
|
|
|
|
--*/
|
|
|
|
#define __HCLIENT_C__
|
|
#define LOG_FILE_NAME NULL
|
|
|
|
/*****************************************************************************
|
|
/* HClient include files
|
|
/*****************************************************************************/
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <wtypes.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <dbt.h>
|
|
#include "hidsdi.h"
|
|
#include "hid.h"
|
|
#include "resource.h"
|
|
#include "hclient.h"
|
|
#include "extcalls.h"
|
|
#include "buffers.h"
|
|
#include "ecdisp.h"
|
|
#include "debug.h"
|
|
#include "logpnp.h"
|
|
|
|
#define USE_MACROS
|
|
#include "list.h"
|
|
|
|
/*****************************************************************************
|
|
/* Local display macro definitions
|
|
/*****************************************************************************/
|
|
|
|
#define INPUT_BUTTON 1
|
|
#define INPUT_VALUE 2
|
|
#define OUTPUT_BUTTON 3
|
|
#define OUTPUT_VALUE 4
|
|
#define FEATURE_BUTTON 5
|
|
#define FEATURE_VALUE 6
|
|
#define HID_CAPS 7
|
|
#define DEVICE_ATTRIBUTES 8
|
|
|
|
#define MAX_LB_ITEMS 200
|
|
|
|
#define MAX_WRITE_ELEMENTS 100
|
|
#define MAX_OUTPUT_ELEMENTS 50
|
|
|
|
#define CONTROL_COUNT 9
|
|
#define MAX_LABEL 128
|
|
#define MAX_VALUE 128
|
|
|
|
#define WM_UNREGISTER_HANDLE WM_USER+1
|
|
|
|
/*****************************************************************************
|
|
/* Macro definition to get device block from the main dialog box procedure
|
|
/*****************************************************************************/
|
|
|
|
#define GET_CURRENT_DEVICE(hDlg, pDevice) \
|
|
{ \
|
|
pDevice = NULL; \
|
|
iIndex = (INT) SendDlgItemMessage(hDlg, \
|
|
IDC_DEVICES, \
|
|
CB_GETCURSEL, \
|
|
0, \
|
|
0); \
|
|
if (CB_ERR != iIndex) { \
|
|
pDevice = (PHID_DEVICE) SendDlgItemMessage(hDlg, \
|
|
IDC_DEVICES, \
|
|
CB_GETITEMDATA, \
|
|
iIndex, \
|
|
0); \
|
|
} \
|
|
}
|
|
|
|
/*****************************************************************************
|
|
/* Data types local to the HClient display routines
|
|
/*****************************************************************************/
|
|
|
|
typedef struct rWriteDataStruct_type
|
|
{
|
|
|
|
char szLabel[MAX_LABEL];
|
|
char szValue[MAX_VALUE];
|
|
|
|
} rWriteDataStruct, *prWriteDataStruct;
|
|
|
|
typedef struct rGetWriteDataParams_type
|
|
{
|
|
prWriteDataStruct prItems;
|
|
int iCount;
|
|
|
|
} rGetWriteDataParams, *prGetWriteDataParams;
|
|
|
|
typedef struct {
|
|
|
|
LIST_NODE_HDR Hdr;
|
|
HDEVNOTIFY NotificationHandle;
|
|
HID_DEVICE HidDeviceInfo;
|
|
|
|
} DEVICE_LIST_NODE, *PDEVICE_LIST_NODE;
|
|
|
|
/*****************************************************************************
|
|
/* Global module variables
|
|
/*****************************************************************************/
|
|
|
|
static HINSTANCE hGInstance; //global application instance handle
|
|
static BOOL IsHIDTestLoaded;
|
|
static HANDLE DLLModuleHandle;
|
|
|
|
/*
|
|
// Variables for handling the two different types of devices that can be loaded
|
|
// into the system. PhysicalDeviceList contains all the actual HID devices
|
|
// attached via the USB bus. LogicalDeviceList contains those preparsed
|
|
// data structures which were obtained through report descriptors and saved
|
|
// via the latest version of HidView.
|
|
*/
|
|
|
|
static LIST PhysicalDeviceList;
|
|
static LIST LogicalDeviceList;
|
|
|
|
/*****************************************************************************
|
|
/* Local data routine declarations
|
|
/*****************************************************************************/
|
|
|
|
VOID
|
|
vReadDataFromControls(
|
|
HWND hDlg,
|
|
prWriteDataStruct prData,
|
|
int iOffset,
|
|
int iCount
|
|
);
|
|
|
|
BOOL CALLBACK
|
|
bGetDataDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL CALLBACK
|
|
bMainDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL CALLBACK
|
|
bFeatureDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
BOOL CALLBACK
|
|
bReadDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
);
|
|
|
|
VOID
|
|
vLoadItemTypes(
|
|
HWND hItemTypes
|
|
);
|
|
|
|
BOOL
|
|
bGetData(
|
|
prWriteDataStruct,
|
|
int iCount,
|
|
HWND hParent,
|
|
char *pszDialogName
|
|
);
|
|
|
|
VOID
|
|
vLoadDevices(
|
|
HWND hDeviceCombo
|
|
);
|
|
|
|
VOID
|
|
vFreeDeviceList(
|
|
PHID_DEVICE DeviceList,
|
|
ULONG nDevices
|
|
);
|
|
|
|
VOID
|
|
vDisplayInputButtons(
|
|
PHID_DEVICE pDevice,
|
|
HWND hControl
|
|
);
|
|
|
|
VOID
|
|
vDisplayInputValues(
|
|
PHID_DEVICE pDevice,
|
|
HWND hControl
|
|
);
|
|
|
|
VOID
|
|
vDisplayOutputButtons(
|
|
PHID_DEVICE pDevice,
|
|
HWND hControl
|
|
);
|
|
|
|
VOID
|
|
vDisplayOutputValues(
|
|
PHID_DEVICE pDevice,
|
|
HWND hControl
|
|
);
|
|
|
|
VOID
|
|
vDisplayFeatureButtons(
|
|
PHID_DEVICE pDevice,
|
|
HWND hControl
|
|
);
|
|
|
|
VOID
|
|
vDisplayFeatureValues(
|
|
PHID_DEVICE pDevice,
|
|
HWND hControl
|
|
);
|
|
|
|
VOID
|
|
vWriteDataToControls(
|
|
HWND hDlg,
|
|
prWriteDataStruct prData,
|
|
int iOffset,
|
|
int iCount
|
|
);
|
|
|
|
int
|
|
iPrepareDataFields(
|
|
PHID_DATA pData,
|
|
ULONG ulDataLength,
|
|
rWriteDataStruct rWriteData[],
|
|
int iMaxElements
|
|
);
|
|
|
|
BOOL
|
|
bParseData(
|
|
PHID_DATA pData,
|
|
rWriteDataStruct rWriteData[],
|
|
INT iCount,
|
|
INT *piErrorLine
|
|
);
|
|
|
|
BOOL
|
|
bSetButtonUsages(
|
|
PHID_DATA pCap,
|
|
PCHAR pszInputString
|
|
);
|
|
|
|
VOID
|
|
BuildReportIDList(
|
|
IN PHIDP_BUTTON_CAPS phidButtonCaps,
|
|
IN USHORT nButtonCaps,
|
|
IN PHIDP_VALUE_CAPS phidValueCaps,
|
|
IN USHORT nValueCaps,
|
|
OUT UCHAR **ppReportIDList,
|
|
OUT INT *nReportIDs
|
|
);
|
|
|
|
VOID
|
|
ReportToString(
|
|
PHID_DATA pData,
|
|
PCHAR szBuff
|
|
);
|
|
|
|
BOOL
|
|
RegisterHidDevice(
|
|
IN HWND WindowHandle,
|
|
IN PDEVICE_LIST_NODE DeviceNode
|
|
);
|
|
|
|
VOID
|
|
DestroyDeviceListCallback(
|
|
IN PLIST_NODE_HDR ListNode
|
|
);
|
|
|
|
|
|
/*****************************************************************************
|
|
/* Function Definitions
|
|
/*****************************************************************************/
|
|
|
|
/*******************************
|
|
*WinMain: Windows Entry point *
|
|
********************************/
|
|
int PASCAL
|
|
WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
/*
|
|
// Save instance of the application for further reference
|
|
*/
|
|
|
|
hGInstance = hInstance;
|
|
|
|
/*
|
|
// Set the debug trapping mechanism on if DEBUG is defined. We will
|
|
// break into the debugger now on assertion failures and so forth
|
|
*/
|
|
|
|
TRAP_ON();
|
|
|
|
/*
|
|
// Attempt to load HIDTest.DLL. If the DLL exists and can be loaded, then
|
|
// we can show the START_TEST button in the main dialog box. Otherwise,
|
|
// the button is hidden.
|
|
*/
|
|
|
|
DLLModuleHandle = LoadLibrary("HIDTEST.DLL");
|
|
|
|
IsHIDTestLoaded = (NULL != DLLModuleHandle);
|
|
|
|
/*
|
|
// Try to create the main dialog box. Cannot do much else if it fails
|
|
// so we'll throw up a message box and then exit the app
|
|
*/
|
|
|
|
if (-1 == DialogBox(hInstance, "MAIN_DIALOG", NULL, (DLGPROC)bMainDlgProc)) {
|
|
|
|
MessageBox(NULL,
|
|
"Unable to create root dialog!",
|
|
"DialogBox failure",
|
|
MB_ICONSTOP);
|
|
}
|
|
|
|
/*
|
|
// Unloaded HIDTest.DLL if it is loaded
|
|
*/
|
|
|
|
if (IsHIDTestLoaded) {
|
|
FreeLibrary(DLLModuleHandle);
|
|
}
|
|
|
|
/*
|
|
// Call the DEBUG functions to check for memory leaks in the DEBUG version of
|
|
// HClient
|
|
*/
|
|
|
|
CHECKFORLEAKS();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************
|
|
* Main Dialog proc *
|
|
**************************************************/
|
|
|
|
/*
|
|
// This the dialog box procedure for the main dialog display.
|
|
*/
|
|
|
|
BOOL CALLBACK
|
|
bMainDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
static HWND hComboCtrl;
|
|
static rWriteDataStruct rWriteData[MAX_OUTPUT_ELEMENTS];
|
|
static HDEVNOTIFY diNotifyHandle;
|
|
INT iIndex;
|
|
INT iCount;
|
|
CHAR szTempBuff[128];
|
|
PHID_DEVICE pDevice;
|
|
PHIDP_BUTTON_CAPS pButtonCaps;
|
|
PHIDP_VALUE_CAPS pValueCaps;
|
|
INT iErrorLine;
|
|
INT iItemType;
|
|
PHID_DEVICE tempDeviceList;
|
|
ULONG numberDevices;
|
|
PDEVICE_LIST_NODE listNode;
|
|
DEV_BROADCAST_DEVICEINTERFACE broadcastInterface;
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
/*
|
|
// Initialize the two device lists
|
|
*/
|
|
|
|
InitializeList(&PhysicalDeviceList);
|
|
InitializeList(&LogicalDeviceList);
|
|
|
|
/*
|
|
// Begin by finding all the HID devices currently attached to the
|
|
// system. If that fails, we exit the dialog box
|
|
*/
|
|
|
|
if (!FindKnownHidDevices(&tempDeviceList,
|
|
&numberDevices
|
|
)) {
|
|
EndDialog(hDlg, 0);
|
|
}
|
|
|
|
pDevice = tempDeviceList;
|
|
for (iIndex = 0; (ULONG) iIndex < numberDevices; iIndex++, pDevice++) {
|
|
|
|
listNode = malloc(sizeof(DEVICE_LIST_NODE));
|
|
|
|
if (NULL == listNode) {
|
|
|
|
/*
|
|
// When freeing up the device list, we need to kill those
|
|
// already in the Physical Device List and close
|
|
// that have not been added yet in the enumerated list
|
|
*/
|
|
|
|
DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
|
|
CloseHidDevices(pDevice, numberDevices - iIndex);
|
|
free(tempDeviceList);
|
|
|
|
EndDialog(hDlg, 0);
|
|
}
|
|
|
|
listNode -> HidDeviceInfo = *pDevice;
|
|
|
|
if (!RegisterHidDevice(hDlg, listNode)) {
|
|
|
|
DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
|
|
|
|
CloseHidDevices(pDevice, numberDevices - iIndex);
|
|
|
|
free(tempDeviceList);
|
|
free(listNode);
|
|
|
|
EndDialog(hDlg, 0);
|
|
|
|
}
|
|
|
|
InsertTail(&PhysicalDeviceList, listNode);
|
|
}
|
|
|
|
/*
|
|
// Free the temporary device list...It is no longer needed
|
|
*/
|
|
|
|
free(tempDeviceList);
|
|
|
|
/*
|
|
// Register for notification from the HidDevice class
|
|
*/
|
|
|
|
broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
|
|
broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
|
|
|
HidD_GetHidGuid(&broadcastInterface.dbcc_classguid);
|
|
|
|
diNotifyHandle = RegisterDeviceNotification(hDlg,
|
|
&broadcastInterface,
|
|
DEVICE_NOTIFY_WINDOW_HANDLE
|
|
);
|
|
if (NULL == diNotifyHandle) {
|
|
|
|
DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
|
|
|
|
EndDialog(hDlg, 0);
|
|
}
|
|
|
|
/*
|
|
// Update the device list box...
|
|
//
|
|
*/
|
|
|
|
vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
|
|
|
|
/*
|
|
// Load the types box
|
|
*/
|
|
vLoadItemTypes(GetDlgItem(hDlg,IDC_TYPE));
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_START_TESTS), IsHIDTestLoaded);
|
|
|
|
/*
|
|
// Post a message that the device changed so the appropriate
|
|
// data for the first device in the system can be displayed
|
|
*/
|
|
|
|
PostMessage(hDlg,
|
|
WM_COMMAND,
|
|
IDC_DEVICES + (CBN_SELCHANGE<<16),
|
|
(LONG) GetDlgItem(hDlg, IDC_DEVICES)
|
|
);
|
|
|
|
break; /*end WM_INITDIALOG case*/
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch(LOWORD(wParam)) {
|
|
|
|
/*
|
|
// For a read, simply get the current device instance
|
|
// from the DEVICES combo box and call the read procedure
|
|
// with the HID_DEVICE block
|
|
*/
|
|
|
|
case IDC_READ:
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
if (NULL != pDevice) {
|
|
iIndex = DialogBoxParam(hGInstance,
|
|
"READDATA",
|
|
hDlg,
|
|
bReadDlgProc,
|
|
(LPARAM) pDevice
|
|
);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
// For a write, the following steps are performed:
|
|
// 1) Get the current device data from the combo box
|
|
// 2) Prepare the data fields for display based on the data
|
|
// output data stored in the device data
|
|
// 3) Retrieve the data the from the user that is to be sent
|
|
// to the device
|
|
// 4) If all goes well and the data parses correctly, send the
|
|
// the new data values to the device
|
|
*/
|
|
|
|
case IDC_WRITE:
|
|
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
if (NULL != pDevice) {
|
|
iCount = iPrepareDataFields(pDevice -> OutputData,
|
|
pDevice -> OutputDataLength,
|
|
rWriteData,
|
|
MAX_OUTPUT_ELEMENTS
|
|
);
|
|
|
|
if (bGetData(rWriteData, iCount, hDlg, "WRITEDATA")) {
|
|
|
|
if (bParseData(pDevice -> OutputData, rWriteData, iCount, &iErrorLine)) {
|
|
Write(pDevice);
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,
|
|
"Unable to parse line %x of output data",
|
|
iErrorLine);
|
|
|
|
MessageBox(hDlg,
|
|
szTempBuff,
|
|
"Data Error",
|
|
MB_ICONEXCLAMATION
|
|
);
|
|
}
|
|
}
|
|
}
|
|
break; /*end case IDC_WRITE*/
|
|
|
|
/*
|
|
// For processing features, get the current device data and call
|
|
// the Features dialog box, This dialog box will deal with
|
|
// sending and retrieving the features.
|
|
*/
|
|
|
|
case IDC_FEATURES:
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
if (NULL != pDevice) {
|
|
iIndex = DialogBoxParam(hGInstance,
|
|
"FEATURES",
|
|
hDlg,
|
|
bFeatureDlgProc,
|
|
(LPARAM) pDevice
|
|
);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
// Likewise with extended calls dialog box. This procedure
|
|
// passes the address to the device data structure and lets
|
|
// the dialog box procedure manipulate the data however it
|
|
// wants to.
|
|
*/
|
|
|
|
case IDC_EXTCALLS:
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
if (NULL != pDevice) {
|
|
iIndex = DialogBoxParam(hGInstance,
|
|
"EXTCALLS",
|
|
hDlg,
|
|
bExtCallDlgProc,
|
|
(LPARAM) pDevice
|
|
);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
// START_TESTS occurs only when HIDTEST.DLL is loaded. This
|
|
// DLL is for internal test purposes and is not provided
|
|
// in the DDK sample.
|
|
*/
|
|
|
|
case IDC_START_TESTS:
|
|
break;
|
|
|
|
/*
|
|
// If there was a device change, we simply issue an IDC_TYPE
|
|
// change to insure that the currently displayed types are
|
|
// updated to reflect the values of the device that has
|
|
// been selected
|
|
*/
|
|
|
|
case IDC_DEVICES:
|
|
switch (HIWORD(wParam)) {
|
|
|
|
case CBN_SELCHANGE:
|
|
PostMessage(hDlg,
|
|
WM_COMMAND,
|
|
IDC_TYPE + (CBN_SELCHANGE<<16),
|
|
(LPARAM) GetDlgItem(hDlg,IDC_TYPE)
|
|
);
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
/*
|
|
// On a type change, we retrieve the currently active device
|
|
// from the IDC_DEVICES box and display the data that
|
|
// corresponds to the item just selected
|
|
*/
|
|
|
|
case IDC_TYPE:
|
|
switch (HIWORD(wParam)) {
|
|
case CBN_SELCHANGE:
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_ITEMS,
|
|
LB_RESETCONTENT,
|
|
0,
|
|
0);
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_ATTRIBUTES,
|
|
LB_RESETCONTENT,
|
|
0,
|
|
0);
|
|
|
|
if (NULL != pDevice) {
|
|
iIndex = SendDlgItemMessage(hDlg,
|
|
IDC_TYPE,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
|
|
iItemType = SendDlgItemMessage(hDlg,
|
|
IDC_TYPE,
|
|
CB_GETITEMDATA,
|
|
iIndex,
|
|
0);
|
|
|
|
switch(iItemType) {
|
|
case INPUT_BUTTON:
|
|
vDisplayInputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
|
|
break;
|
|
|
|
case INPUT_VALUE:
|
|
vDisplayInputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
|
|
break;
|
|
|
|
case OUTPUT_BUTTON:
|
|
vDisplayOutputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
|
|
break;
|
|
|
|
case OUTPUT_VALUE:
|
|
vDisplayOutputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
|
|
break;
|
|
|
|
case FEATURE_BUTTON:
|
|
vDisplayFeatureButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
|
|
break;
|
|
|
|
case FEATURE_VALUE:
|
|
vDisplayFeatureValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
|
|
break;
|
|
}
|
|
|
|
PostMessage(hDlg,
|
|
WM_COMMAND,
|
|
IDC_ITEMS + (LBN_SELCHANGE << 16),
|
|
(LPARAM) GetDlgItem(hDlg,IDC_ITEMS)
|
|
);
|
|
}
|
|
break; // case CBN_SELCHANGE
|
|
|
|
} //end switch HIWORD wParam
|
|
break; //case IDC_TYPE control
|
|
|
|
case IDC_ITEMS:
|
|
switch(HIWORD(wParam)) {
|
|
case LBN_SELCHANGE:
|
|
iItemType = 0;
|
|
iIndex = SendDlgItemMessage(hDlg,
|
|
IDC_TYPE,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0);
|
|
|
|
if (-1 != iIndex) {
|
|
iItemType = (INT) SendDlgItemMessage(hDlg,
|
|
IDC_TYPE,
|
|
CB_GETITEMDATA,
|
|
iIndex,
|
|
0
|
|
);
|
|
}
|
|
|
|
iIndex = SendDlgItemMessage(hDlg,
|
|
IDC_ITEMS,
|
|
LB_GETCURSEL,
|
|
0,
|
|
0
|
|
);
|
|
|
|
switch (iItemType) {
|
|
case INPUT_BUTTON:
|
|
case OUTPUT_BUTTON:
|
|
case FEATURE_BUTTON:
|
|
pButtonCaps = NULL;
|
|
if (-1 != iIndex){
|
|
pButtonCaps = (PHIDP_BUTTON_CAPS) SendDlgItemMessage(hDlg,
|
|
IDC_ITEMS,
|
|
LB_GETITEMDATA,
|
|
iIndex,
|
|
0);
|
|
}
|
|
|
|
SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
|
|
if (NULL != pButtonCaps) {
|
|
vDisplayButtonAttributes(pButtonCaps, GetDlgItem(hDlg,IDC_ATTRIBUTES));
|
|
}
|
|
break;
|
|
|
|
|
|
case INPUT_VALUE:
|
|
case OUTPUT_VALUE:
|
|
case FEATURE_VALUE:
|
|
pValueCaps = NULL;
|
|
if (-1 != iIndex) {
|
|
pValueCaps = (PHIDP_VALUE_CAPS) SendDlgItemMessage(hDlg,
|
|
IDC_ITEMS,
|
|
LB_GETITEMDATA,
|
|
iIndex,
|
|
0);
|
|
}
|
|
|
|
SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
|
|
if (NULL != pValueCaps) {
|
|
vDisplayValueAttributes(pValueCaps,GetDlgItem(hDlg,IDC_ATTRIBUTES));
|
|
}
|
|
break;
|
|
|
|
case HID_CAPS:
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
if (NULL != pDevice) {
|
|
vDisplayDeviceCaps(&(pDevice -> Caps),GetDlgItem(hDlg,IDC_ATTRIBUTES));
|
|
}
|
|
break;
|
|
|
|
case DEVICE_ATTRIBUTES:
|
|
GET_CURRENT_DEVICE(hDlg, pDevice);
|
|
|
|
if (NULL != pDevice) {
|
|
SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
|
|
vDisplayDeviceAttributes(&(pDevice -> Attributes) ,GetDlgItem(hDlg,IDC_ATTRIBUTES));
|
|
}
|
|
break;
|
|
|
|
} /*end switch iItemType*/
|
|
break; /*end case LBN_SELCHANGE in IDC_ITEMS*/
|
|
|
|
} /*end switch HIWORD wParam*/
|
|
break; /*case IDC_ITEMS*/
|
|
|
|
/*
|
|
// To load a logical device, we first have insure that
|
|
// we have space left in the list of logical devices
|
|
// If there isn't space, we have to realloc more space
|
|
// or print an error message saying the limit has
|
|
// been reached. Once we've allocated space for the
|
|
// logical device, the next step is to pass the HID_DEVICE
|
|
// structure to our load logical device routine to get
|
|
// the data for that device.
|
|
*/
|
|
|
|
case IDC_LOAD_LOGICAL_DEVICE:
|
|
listNode = malloc(sizeof(DEVICE_LIST_NODE));
|
|
|
|
if (NULL == listNode) {
|
|
|
|
MessageBox(hDlg,
|
|
"Error -- Couldn't allocate memory for device list node",
|
|
"HClient Error",
|
|
MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL
|
|
);
|
|
return (FALSE);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
// Now call the LogPnp_LoadLogicalDevice to load all the data for
|
|
// the logical device
|
|
*/
|
|
|
|
if (LogPnP_LoadLogicalDevice(LOG_FILE_NAME, &(listNode -> HidDeviceInfo))) {
|
|
|
|
listNode -> NotificationHandle = NULL;
|
|
|
|
InsertTail(&LogicalDeviceList, listNode);
|
|
|
|
vLoadDevices(GetDlgItem(hDlg, IDC_DEVICES));
|
|
}
|
|
break;
|
|
|
|
case IDC_ABOUT:
|
|
MessageBox(hDlg,
|
|
"Sample HID client Application. Microsoft Corp \nCopyright (C) 1997",
|
|
"About HClient",
|
|
MB_ICONINFORMATION
|
|
);
|
|
break;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
|
|
DestroyListWithCallback(&LogicalDeviceList, DestroyDeviceListCallback);
|
|
EndDialog(hDlg,0);
|
|
break;
|
|
|
|
} /*end switch wParam*/
|
|
break;
|
|
|
|
/*
|
|
// For a device change message, we are only concerned about the
|
|
// DBT_DEVICEREMOVECOMPLETE and DBT_DEVICEARRIVAL events. I have
|
|
// yet to determine how to process the device change message
|
|
// only for HID devices. Therefore, there are two problems
|
|
// with the below implementation. First of all, we must reload
|
|
// the device list any time a device is added to the system.
|
|
// Secondly, at least two DEVICEARRIVAL messages are received
|
|
// per HID. One corresponds to the physical device. The second
|
|
// change and any more correspond to each collection on the
|
|
// physical device so a system that has one HID device with
|
|
// two top level collections (a keyboard and a mouse) will receive
|
|
// three DEVICEARRIVAL/REMOVALs causing the program to reload it's
|
|
// device list more than once.
|
|
*/
|
|
|
|
/*
|
|
// To handle dynamic changing of devices, we have already registered
|
|
// notification for both HID class changes and for notification
|
|
// for our open file objects. Since we are only concerned about
|
|
// arrival/removal of devices, we only need to process those wParam.
|
|
// lParam points to some sort of DEV_BROADCAST_HDR struct. For device
|
|
// arrival, we only deal with the message if that struct is a
|
|
// DEV_BROADCAST_DEVICEINTERFACE structure. For device removal, we're
|
|
// only concerned if the struct is a DEV_BROADCAST_HANDLE structure.
|
|
*/
|
|
|
|
case WM_DEVICECHANGE:
|
|
switch (wParam) {
|
|
PDEV_BROADCAST_HDR broadcastHdr;
|
|
|
|
|
|
case DBT_DEVICEARRIVAL:
|
|
broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
|
|
|
|
if (DBT_DEVTYP_DEVICEINTERFACE == broadcastHdr -> dbch_devicetype) {
|
|
|
|
PDEV_BROADCAST_DEVICEINTERFACE broadcastInterface;
|
|
|
|
broadcastInterface = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
|
|
|
|
/*
|
|
// In this structure, we are given the name of the device
|
|
// to open. So all that needs to be done is open
|
|
// a new hid device with the string
|
|
*/
|
|
|
|
listNode = (PDEVICE_LIST_NODE) malloc(sizeof(DEVICE_LIST_NODE));
|
|
|
|
if (NULL == listNode) {
|
|
|
|
MessageBox(hDlg,
|
|
"Error -- Couldn't allocate memory for new device list node",
|
|
"HClient Error",
|
|
MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL
|
|
);
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
// Open the hid device
|
|
*/
|
|
|
|
OpenHidDevice (broadcastInterface -> dbcc_name,
|
|
&(listNode -> HidDeviceInfo)
|
|
);
|
|
|
|
if (!RegisterHidDevice(hDlg, listNode)) {
|
|
|
|
MessageBox(hDlg,
|
|
"Error -- Couldn't register handle notification",
|
|
"HClient Error",
|
|
MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL
|
|
);
|
|
|
|
CloseHidDevice(&(listNode -> HidDeviceInfo));
|
|
free(listNode);
|
|
break;
|
|
|
|
}
|
|
|
|
InsertTail(&PhysicalDeviceList, listNode);
|
|
|
|
vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
|
|
PostMessage(hDlg,
|
|
WM_COMMAND,
|
|
IDC_DEVICES + (CBN_SELCHANGE << 16),
|
|
(LPARAM) GetDlgItem(hDlg,IDC_DEVICES));
|
|
|
|
}
|
|
break;
|
|
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
|
|
|
|
if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype) {
|
|
|
|
PDEV_BROADCAST_HANDLE broadcastHandle;
|
|
PDEVICE_LIST_NODE currNode;
|
|
HANDLE deviceHandle;
|
|
|
|
broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam;
|
|
|
|
/*
|
|
// Get the file handle of the device that was removed
|
|
// from the system
|
|
*/
|
|
|
|
deviceHandle = (HANDLE) broadcastHandle -> dbch_handle;
|
|
|
|
|
|
/*
|
|
// Search the physical device list for the handle that
|
|
// was removed...
|
|
*/
|
|
|
|
currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
|
|
|
|
/*
|
|
// This loop should always terminate since the device
|
|
// handle should be somewhere in the physical device list
|
|
*/
|
|
|
|
while (currNode -> HidDeviceInfo.HidDevice != deviceHandle) {
|
|
currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
|
|
}
|
|
|
|
/*
|
|
// Node in PhysicalDeviceList has been found, do:
|
|
// 1) Unregister notification
|
|
// 2) Close the hid device
|
|
// 3) Remove the entry from the list
|
|
// 4) Free the memory for the entry
|
|
//
|
|
*/
|
|
|
|
PostMessage(hDlg,
|
|
WM_UNREGISTER_HANDLE,
|
|
0,
|
|
(LPARAM) currNode -> NotificationHandle
|
|
);
|
|
|
|
CloseHidDevice(&(currNode -> HidDeviceInfo));
|
|
|
|
RemoveNode(currNode);
|
|
|
|
free(currNode);
|
|
|
|
/*
|
|
// Reload the device list
|
|
*/
|
|
|
|
vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
|
|
PostMessage(hDlg,
|
|
WM_COMMAND,
|
|
IDC_DEVICES + (CBN_SELCHANGE << 16),
|
|
(LPARAM) GetDlgItem(hDlg,IDC_DEVICES));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
// Application specific message used to defer the unregistering of a
|
|
// file object for device change notification. This separte message
|
|
// is sent when a WM_DEVICECHANGE (DBT_DEVICEREMOVECOMPLETE) has been
|
|
// received. The Unregistering of the notification must be deferred
|
|
// until after the WM_DEVICECHANGE message has been processed or the
|
|
// system will deadlock. The handle that is to be freed will be passed
|
|
// in as lParam for this message
|
|
*/
|
|
|
|
case WM_UNREGISTER_HANDLE:
|
|
UnregisterDeviceNotification ( (HDEVNOTIFY) lParam );
|
|
break;
|
|
|
|
} /*end switch message*/
|
|
return FALSE;
|
|
} /*end MainDlgProc*/
|
|
|
|
|
|
BOOL
|
|
bParseData(
|
|
PHID_DATA pData,
|
|
rWriteDataStruct rWriteData[],
|
|
int iCount,
|
|
int *piErrorLine
|
|
)
|
|
{
|
|
INT iCap;
|
|
PHID_DATA pWalk;
|
|
BOOL bNoError = TRUE;
|
|
|
|
pWalk = pData;
|
|
for (iCap = 0; (iCap < iCount) && bNoError; iCap++) {
|
|
|
|
/*
|
|
// Check to see if our data is a value cap or not
|
|
*/
|
|
|
|
if (!pWalk->IsButtonData) {
|
|
|
|
pWalk -> ValueData.Value = atol(rWriteData[iCap].szValue);
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!bSetButtonUsages(pWalk, rWriteData[iCap].szValue) ) {
|
|
|
|
*piErrorLine = iCap;
|
|
bNoError = FALSE;
|
|
}
|
|
}
|
|
pWalk++;
|
|
}
|
|
return bNoError;
|
|
}
|
|
|
|
BOOL
|
|
bSetButtonUsages(
|
|
PHID_DATA pCap,
|
|
PCHAR pszInputString
|
|
)
|
|
{
|
|
CHAR szTempString[128];
|
|
PCHAR pszDelimiter=" ";
|
|
PCHAR pszToken;
|
|
INT iLoop;
|
|
PUSAGE pUsageWalk;
|
|
BOOL bNoError=TRUE;
|
|
|
|
|
|
strcpy(szTempString, pszInputString);
|
|
pszToken = strtok(szTempString, pszDelimiter);
|
|
|
|
pUsageWalk = pCap -> ButtonData.Usages;
|
|
memset(pUsageWalk, 0, pCap->ButtonData.MaxUsageLength * sizeof(USAGE));
|
|
|
|
for (iLoop = 0; ((ULONG) iLoop < pCap->ButtonData.MaxUsageLength) && (pszToken != NULL) && bNoError; iLoop++)
|
|
{
|
|
*pUsageWalk = atoi(pszToken);
|
|
|
|
pszToken = strtok(NULL, pszDelimiter);
|
|
pUsageWalk++;
|
|
}
|
|
|
|
return bNoError;
|
|
} /*end function bSetButtonUsages*/
|
|
|
|
|
|
INT
|
|
iPrepareDataFields(
|
|
PHID_DATA pData,
|
|
ULONG ulDataLength,
|
|
rWriteDataStruct rWriteData[],
|
|
int iMaxElements
|
|
)
|
|
{
|
|
INT i;
|
|
PHID_DATA pWalk;
|
|
|
|
pWalk = pData;
|
|
|
|
for (i = 0; (i < iMaxElements) && ((unsigned) i < ulDataLength); i++)
|
|
{
|
|
if (!pWalk->IsButtonData) {
|
|
|
|
wsprintf(rWriteData[i].szLabel,
|
|
"ValueCap; ReportID: 0x%x, UsagePage=0x%x, Usage=0x%x",
|
|
pWalk->ReportID,
|
|
pWalk->UsagePage,
|
|
pWalk->ValueData.Usage);
|
|
}
|
|
else {
|
|
wsprintf(rWriteData[i].szLabel,
|
|
"Button; ReportID: 0x%x, UsagePage=0x%x, UsageMin: 0x%x, UsageMax: 0x%x",
|
|
pWalk->ReportID,
|
|
pWalk->UsagePage,
|
|
pWalk->ButtonData.UsageMin,
|
|
pWalk->ButtonData.UsageMax
|
|
);
|
|
}
|
|
pWalk++;
|
|
}
|
|
return i;
|
|
} /*end function iPrepareDataFields*/
|
|
|
|
|
|
BOOL CALLBACK
|
|
bReadDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
static PHID_DEVICE pDevice;
|
|
static INT iLbCounter;
|
|
static CHAR szTempBuff[1024];
|
|
INT iIndex;
|
|
PHID_DATA pData;
|
|
UINT uLoop;
|
|
|
|
switch(message) {
|
|
case WM_INITDIALOG:
|
|
iLbCounter = 0;
|
|
pDevice = (PHID_DEVICE) lParam;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam)) {
|
|
case IDC_READ:
|
|
Read(pDevice);
|
|
pData = pDevice -> InputData;
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)"-------------------------------------------");
|
|
|
|
iLbCounter++;
|
|
if (iLbCounter > MAX_LB_ITEMS) {
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_DELETESTRING,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
for (uLoop = 0; uLoop < pDevice->InputDataLength; uLoop++) {
|
|
|
|
ReportToString(pData, szTempBuff);
|
|
iIndex = SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM) szTempBuff
|
|
);
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_SETCURSEL,
|
|
iIndex,
|
|
0
|
|
);
|
|
|
|
iLbCounter++;
|
|
if (iLbCounter > MAX_LB_ITEMS) {
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_DELETESTRING,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
pData++;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,0);
|
|
break;
|
|
}
|
|
break;
|
|
} /*end switch message*/
|
|
return FALSE;
|
|
} /*end bReadDlgProc*/
|
|
|
|
VOID
|
|
ReportToString(
|
|
PHID_DATA pData,
|
|
PCHAR szBuff
|
|
)
|
|
{
|
|
PCHAR pszWalk;
|
|
PUSAGE pUsage;
|
|
ULONG i;
|
|
|
|
/*
|
|
// For button data, all the usages in the usage list are to be displayed
|
|
*/
|
|
|
|
if (pData -> IsButtonData) {
|
|
wsprintf (szBuff,
|
|
"Usage Page: 0x%x, Usages: ",
|
|
pData -> UsagePage
|
|
);
|
|
|
|
pszWalk = szBuff + strlen(szBuff);
|
|
*pszWalk = '\0';
|
|
|
|
for (i = 0, pUsage = pData -> ButtonData.Usages;
|
|
i < pData -> ButtonData.MaxUsageLength;
|
|
i++, pUsage++) {
|
|
|
|
if (0 == *pUsage) {
|
|
break; // A usage of zero is a non button.
|
|
}
|
|
pszWalk += wsprintf (pszWalk, " 0x%x", *pUsage);
|
|
}
|
|
}
|
|
else {
|
|
|
|
wsprintf (szBuff,
|
|
"Usage Page: 0x%x, Usage: 0x%x, Scaled: %d Value: %d",
|
|
pData->UsagePage,
|
|
pData->ValueData.Usage,
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
bFeatureDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
static PHID_DEVICE pDevice;
|
|
static INT iLbCounter;
|
|
static rWriteDataStruct rWriteData[50];
|
|
static CHAR szTempBuff[1024];
|
|
INT iIndex;
|
|
INT iCount;
|
|
INT iErrorLine;
|
|
PHID_DATA pData;
|
|
UINT uLoop;
|
|
|
|
switch(message) {
|
|
case WM_INITDIALOG:
|
|
iLbCounter = 0;
|
|
pDevice = (PHID_DEVICE) lParam;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam)) {
|
|
case IDC_READ:
|
|
GetFeature(pDevice);
|
|
pData = pDevice -> FeatureData;
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LONG)"------------ Read Features ---------------");
|
|
iLbCounter++;
|
|
|
|
if (iLbCounter > MAX_LB_ITEMS) {
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_DELETESTRING,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
for (uLoop = 0; uLoop < pDevice -> FeatureDataLength; uLoop++) {
|
|
|
|
ReportToString(pData, szTempBuff);
|
|
iIndex = SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM) szTempBuff
|
|
);
|
|
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_SETCURSEL,
|
|
iIndex,
|
|
(LPARAM) 0
|
|
);
|
|
|
|
iLbCounter++;
|
|
if (iLbCounter > MAX_LB_ITEMS) {
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_DELETESTRING,
|
|
0,
|
|
0);
|
|
}
|
|
pData++;
|
|
}
|
|
break;
|
|
|
|
case IDC_WRITE:
|
|
iCount = iPrepareDataFields(pDevice -> FeatureData,
|
|
pDevice -> FeatureDataLength,
|
|
rWriteData,
|
|
MAX_OUTPUT_ELEMENTS
|
|
);
|
|
|
|
if (bGetData(rWriteData, iCount, hDlg, "WRITEFEATURE")) {
|
|
|
|
if (!bParseData(pDevice -> FeatureData, rWriteData,iCount, &iErrorLine)) {
|
|
wsprintf(szTempBuff,
|
|
"Unable to parse line %x of output data",
|
|
iErrorLine
|
|
);
|
|
|
|
MessageBox(hDlg,
|
|
szTempBuff,
|
|
"Data Error",
|
|
MB_ICONEXCLAMATION
|
|
);
|
|
}
|
|
else {
|
|
if ( SetFeature(pDevice) ) {
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)"------------ Write Feature ---------------");
|
|
}
|
|
else {
|
|
SendDlgItemMessage(hDlg,
|
|
IDC_OUTPUT,
|
|
LB_ADDSTRING,
|
|
0,
|
|
(LPARAM)"------------ Write Feature Error ---------------");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,0);
|
|
break;
|
|
}
|
|
break;
|
|
} /*end switch message*/
|
|
return FALSE;
|
|
} /*end bReadDlgProc*/
|
|
|
|
VOID
|
|
vDisplayDeviceCaps(
|
|
IN PHIDP_CAPS pCaps,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
static CHAR szTempBuff[128];
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, 0);
|
|
|
|
wsprintf(szTempBuff, "Usage Page: 0x%x", pCaps -> UsagePage);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,"Usage: 0x%x",pCaps -> Usage);
|
|
SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,"Input report byte length: %d",pCaps -> InputReportByteLength);
|
|
SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,"Output report byte length: %d",pCaps -> OutputReportByteLength);
|
|
SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,"Feature report byte length: %d",pCaps -> FeatureReportByteLength);
|
|
SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,"Number of collection nodes %d: ", pCaps -> NumberLinkCollectionNodes);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayDeviceAttributes(
|
|
PHIDD_ATTRIBUTES pAttrib,
|
|
HWND hControl
|
|
)
|
|
{
|
|
static CHAR szTempBuff[128];
|
|
|
|
wsprintf(szTempBuff, "Vendor ID: 0x%x", pAttrib -> VendorID);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Product ID: 0x%x", pAttrib -> ProductID);
|
|
SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Version Number 0x%x", pAttrib -> VersionNumber);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayDataAttributes(
|
|
PHIDP_DATA pData,
|
|
BOOL IsButton,
|
|
HWND hControl
|
|
)
|
|
{
|
|
static CHAR szTempBuff[128];
|
|
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "================");
|
|
|
|
wsprintf(szTempBuff, "Index: 0x%x", pData -> DataIndex);
|
|
SendMessage(hControl,LB_ADDSTRING, 0, (LONG)szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "IsButton: %s", IsButton ? "TRUE" : "FALSE");
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LONG)szTempBuff);
|
|
|
|
if (IsButton) {
|
|
wsprintf(szTempBuff, "Button pressed: %s", pData -> On ? "TRUE" : "FALSE");
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff, "Data value: 0x%x", pData -> RawValue);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
vDisplayButtonAttributes(
|
|
IN PHIDP_BUTTON_CAPS pButton,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
static CHAR szTempBuff[128];
|
|
|
|
wsprintf(szTempBuff, "Report ID: 0x%x", pButton->ReportID);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Usage Page: 0x%x", pButton->UsagePage);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,
|
|
"Alias: %s",
|
|
pButton -> IsAlias ? "TRUE" : "FALSE"
|
|
);
|
|
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,
|
|
"Link Collection: %hu",
|
|
pButton -> LinkCollection
|
|
);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,
|
|
"Link Usage Page: 0x%x",
|
|
pButton -> LinkUsagePage
|
|
);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,
|
|
"Link Usage: 0x%x",
|
|
pButton -> LinkUsage
|
|
);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pButton->IsRange) {
|
|
wsprintf(szTempBuff,
|
|
"Usage Min: 0x%x, Usage Max: 0x%x",
|
|
pButton->Range.UsageMin,
|
|
pButton->Range.UsageMax
|
|
);
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,"Usage: 0x%x",pButton->NotRange.Usage);
|
|
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pButton->IsRange) {
|
|
wsprintf(szTempBuff,
|
|
"Data Index Min: 0x%x, Data Index Max: 0x%x",
|
|
pButton->Range.DataIndexMin,
|
|
pButton->Range.DataIndexMax);
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,"DataIndex: 0x%x",pButton->NotRange.DataIndex);
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pButton->IsStringRange) {
|
|
|
|
wsprintf(szTempBuff,
|
|
"String Min: 0x%x, String Max: 0x%x",
|
|
pButton->Range.StringMin,
|
|
pButton->Range.StringMax);
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,"String Index: 0x%x",pButton->NotRange.StringIndex);
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pButton->IsDesignatorRange) {
|
|
wsprintf(szTempBuff,
|
|
"Designator Min: 0x%x, Designator Max: 0x%x",
|
|
pButton->Range.DesignatorMin,
|
|
pButton->Range.DesignatorMax);
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,
|
|
"Designator Index: 0x%x",
|
|
pButton->NotRange.DesignatorIndex);
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
|
|
|
|
if (pButton->IsAbsolute) {
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: Yes");
|
|
}
|
|
else {
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: No");
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayValueAttributes(
|
|
IN PHIDP_VALUE_CAPS pValue,
|
|
HWND hControl
|
|
)
|
|
{
|
|
static CHAR szTempBuff[128];
|
|
|
|
wsprintf(szTempBuff, "Report ID 0x%x", pValue->ReportID);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Usage Page: 0x%x", pValue->UsagePage);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Bit size: 0x%x", pValue->BitSize);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Report Count: 0x%x", pValue->ReportCount);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Unit Exponent: 0x%x", pValue->UnitsExp);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
|
|
if (pValue->IsAlias) {
|
|
wsprintf(szTempBuff, "Alias");
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff, "=====");
|
|
}
|
|
SendMessage(hControl,LB_ADDSTRING,0,(LONG)szTempBuff);
|
|
|
|
if (pValue->IsRange) {
|
|
|
|
wsprintf(szTempBuff,
|
|
"Usage Min: 0x%x, Usage Max 0x%x",
|
|
pValue->Range.UsageMin,
|
|
pValue->Range.UsageMax);
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff, "Usage: 0x%x", pValue -> NotRange.Usage);
|
|
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pValue->IsRange) {
|
|
wsprintf(szTempBuff,
|
|
"Data Index Min: 0x%x, Data Index Max: 0x%x",
|
|
pValue->Range.DataIndexMin,
|
|
pValue->Range.DataIndexMax);
|
|
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff, "DataIndex: 0x%x", pValue->NotRange.DataIndex);
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,
|
|
"Physical Minimum: %d, Physical Maximum: %d",
|
|
pValue->PhysicalMin,
|
|
pValue->PhysicalMax);
|
|
|
|
SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff,
|
|
"Logical Minimum: 0x%x, Logical Maximum: 0x%x",
|
|
pValue->LogicalMin,
|
|
pValue->LogicalMax);
|
|
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pValue->IsStringRange) {
|
|
|
|
wsprintf(szTempBuff,
|
|
"String Min: 0x%x String Max 0x%x",
|
|
pValue->Range.StringMin,
|
|
pValue->Range.StringMax);
|
|
|
|
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,"String Index: 0x%x",pValue->NotRange.StringIndex);
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pValue->IsDesignatorRange) {
|
|
|
|
wsprintf(szTempBuff,
|
|
"Designator Minimum: 0x%x, Max: 0x%x",
|
|
pValue->Range.DesignatorMin,
|
|
pValue->Range.DesignatorMax);
|
|
}
|
|
else {
|
|
wsprintf(szTempBuff,"Designator Index: 0x%x",pValue->NotRange.DesignatorIndex);
|
|
}
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (pValue->IsAbsolute) {
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: Yes");
|
|
}
|
|
else {
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: No");
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayInputButtons(
|
|
IN PHID_DEVICE pDevice,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
INT iLoop;
|
|
PHIDP_BUTTON_CAPS pButtonCaps;
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0);
|
|
|
|
pButtonCaps = pDevice->InputButtonCaps;
|
|
for (iLoop = 0; iLoop < pDevice->Caps.NumberInputButtonCaps; iLoop++) {
|
|
|
|
wsprintf(szTempBuff, "Input button cap # %d", iLoop);
|
|
|
|
iIndex = SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (iIndex!=-1) {
|
|
SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pButtonCaps);
|
|
}
|
|
|
|
pButtonCaps++;
|
|
}
|
|
SendMessage(hControl, LB_SETCURSEL, 0, 0 );
|
|
}
|
|
|
|
VOID
|
|
vDisplayOutputButtons(
|
|
IN PHID_DEVICE pDevice,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
INT iLoop;
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
PHIDP_BUTTON_CAPS pButtonCaps;
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0);
|
|
pButtonCaps = pDevice -> OutputButtonCaps;
|
|
|
|
for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputButtonCaps; iLoop++) {
|
|
|
|
wsprintf(szTempBuff, "Output button cap # %d", iLoop);
|
|
iIndex = SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (-1 != iIndex) {
|
|
SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps);
|
|
}
|
|
pButtonCaps++;
|
|
}
|
|
|
|
SendMessage(hControl, LB_SETCURSEL, 0, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayInputValues(
|
|
IN PHID_DEVICE pDevice,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
INT iLoop;
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
PHIDP_VALUE_CAPS pValueCaps;
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, 0);
|
|
|
|
pValueCaps = pDevice -> InputValueCaps;
|
|
for (iLoop=0; iLoop < pDevice->Caps.NumberInputValueCaps; iLoop++) {
|
|
|
|
wsprintf(szTempBuff,"Input value cap # %d",iLoop);
|
|
iIndex = SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (-1 != iIndex) {
|
|
SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pValueCaps);
|
|
}
|
|
pValueCaps++;
|
|
|
|
}
|
|
|
|
SendMessage(hControl, LB_SETCURSEL, 0, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayOutputValues(
|
|
IN PHID_DEVICE pDevice,
|
|
IN HWND hControl)
|
|
{
|
|
INT iLoop;
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
PHIDP_VALUE_CAPS pValueCaps;
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, 0);
|
|
pValueCaps = pDevice -> OutputValueCaps;
|
|
|
|
for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputValueCaps; iLoop++) {
|
|
|
|
wsprintf(szTempBuff, "Output value cap # %d", iLoop);
|
|
iIndex=SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (-1 != iIndex) {
|
|
SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps);
|
|
}
|
|
pValueCaps++;
|
|
}
|
|
SendMessage(hControl,LB_SETCURSEL,0,0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayFeatureButtons(
|
|
IN PHID_DEVICE pDevice,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
INT iLoop;
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
PHIDP_BUTTON_CAPS pButtonCaps;
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, 0);
|
|
pButtonCaps = pDevice -> FeatureButtonCaps;
|
|
|
|
for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureButtonCaps; iLoop++) {
|
|
|
|
wsprintf(szTempBuff, "Feature button cap # %d", iLoop);
|
|
iIndex = SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (-1 != iIndex) {
|
|
SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps);
|
|
}
|
|
pButtonCaps++;
|
|
}
|
|
SendMessage(hControl, LB_SETCURSEL, 0, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayFeatureValues(
|
|
IN PHID_DEVICE pDevice,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
INT iLoop;
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
PHIDP_VALUE_CAPS pValueCaps;
|
|
|
|
SendMessage(hControl, LB_RESETCONTENT, 0, 0);
|
|
pValueCaps = pDevice ->FeatureValueCaps;
|
|
|
|
for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureValueCaps; iLoop++) {
|
|
|
|
wsprintf(szTempBuff, "Feature value cap # %d", iLoop);
|
|
iIndex = SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (-1 != iIndex) {
|
|
SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps);
|
|
}
|
|
|
|
pValueCaps++;
|
|
}
|
|
SendMessage(hControl, LB_SETCURSEL, 0, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vLoadItemTypes(
|
|
IN HWND hItemTypes
|
|
)
|
|
{
|
|
INT iIndex;
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "INPUT BUTTON");
|
|
if (-1 != iIndex) {
|
|
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_BUTTON);
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0 ,(LPARAM) "INPUT VALUE");
|
|
if (-1 != iIndex) {
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_VALUE);
|
|
}
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT BUTTON");
|
|
if (-1 != iIndex) {
|
|
SendMessage(hItemTypes,CB_SETITEMDATA,iIndex,OUTPUT_BUTTON);
|
|
}
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT VALUE");
|
|
if (-1 != iIndex) {
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, OUTPUT_VALUE);
|
|
}
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE BUTTON");
|
|
if (-1 != iIndex) {
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_BUTTON);
|
|
}
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE VALUE");
|
|
if (-1 != iIndex) {
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_VALUE);
|
|
}
|
|
|
|
iIndex=SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "HID CAPS");
|
|
if (-1 != iIndex ) {
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, HID_CAPS);
|
|
}
|
|
|
|
iIndex = SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "DEVICE ATTRIBUTES");
|
|
if (-1 != iIndex) {
|
|
SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, DEVICE_ATTRIBUTES);
|
|
}
|
|
|
|
SendMessage(hItemTypes, CB_SETCURSEL, 0, 0);
|
|
}
|
|
}
|
|
|
|
VOID vLoadDevices(
|
|
HWND hDeviceCombo
|
|
)
|
|
{
|
|
PDEVICE_LIST_NODE currNode;
|
|
|
|
static CHAR szTempBuff[128];
|
|
INT iIndex;
|
|
|
|
/*
|
|
// Reset the content of the device list box.
|
|
*/
|
|
|
|
SendMessage(hDeviceCombo, CB_RESETCONTENT, 0, 0);
|
|
|
|
|
|
if (!IsListEmpty(&PhysicalDeviceList)) {
|
|
|
|
currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
|
|
|
|
do {
|
|
|
|
wsprintf(szTempBuff,
|
|
"Device %d, UsagePage 0%x, Usage 0%x",
|
|
currNode -> HidDeviceInfo.HidDevice,
|
|
currNode -> HidDeviceInfo.Caps.UsagePage,
|
|
currNode -> HidDeviceInfo.Caps.Usage);
|
|
|
|
iIndex = SendMessage(hDeviceCombo, CB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (CB_ERR != iIndex) {
|
|
SendMessage(hDeviceCombo, CB_SETITEMDATA, iIndex, (LPARAM) &(currNode -> HidDeviceInfo));
|
|
}
|
|
|
|
currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
|
|
|
|
} while ((PLIST) currNode != &PhysicalDeviceList);
|
|
|
|
}
|
|
|
|
/*
|
|
// Now we need to load any logical devices that might currently be in our
|
|
// logical device list
|
|
*/
|
|
|
|
if (!IsListEmpty(&LogicalDeviceList)) {
|
|
|
|
currNode = (PDEVICE_LIST_NODE) GetListHead(&LogicalDeviceList) ;
|
|
|
|
do {
|
|
|
|
wsprintf(szTempBuff,
|
|
"Device: Logical, UsagePage 0%x, Usage 0%x",
|
|
currNode -> HidDeviceInfo.Caps.UsagePage,
|
|
currNode -> HidDeviceInfo.Caps.Usage);
|
|
|
|
iIndex = SendMessage(hDeviceCombo, CB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
if (CB_ERR != iIndex) {
|
|
SendMessage(hDeviceCombo, CB_SETITEMDATA, iIndex, (LPARAM) &(currNode -> HidDeviceInfo));
|
|
}
|
|
|
|
currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
|
|
|
|
} while ((PLIST) currNode != &LogicalDeviceList);
|
|
|
|
}
|
|
|
|
SendMessage(hDeviceCombo, CB_SETCURSEL, 0, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
bGetData(
|
|
prWriteDataStruct pItems,
|
|
INT iCount,
|
|
HWND hParent,
|
|
PCHAR pszDialogName
|
|
)
|
|
{
|
|
rGetWriteDataParams rParams;
|
|
rWriteDataStruct arTempItems[MAX_WRITE_ELEMENTS];
|
|
INT iResult;
|
|
|
|
|
|
if (iCount > MAX_WRITE_ELEMENTS) {
|
|
iCount = MAX_WRITE_ELEMENTS;
|
|
}
|
|
|
|
memcpy( &(arTempItems[0]), pItems, sizeof(rWriteDataStruct)*iCount);
|
|
|
|
rParams.iCount = iCount;
|
|
rParams.prItems = &(arTempItems[0]);
|
|
iResult = DialogBoxParam(hGInstance,
|
|
pszDialogName,
|
|
hParent,
|
|
bGetDataDlgProc,
|
|
(LPARAM) &rParams);
|
|
if (iResult) {
|
|
memcpy(pItems, arTempItems, sizeof(rWriteDataStruct)*iCount);
|
|
}
|
|
return iResult;
|
|
}
|
|
|
|
BOOL CALLBACK
|
|
bGetDataDlgProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
static prWriteDataStruct prData;
|
|
static prGetWriteDataParams pParams;
|
|
static INT iDisplayCount;
|
|
static INT iScrollRange;
|
|
static INT iCurrentScrollPos=0;
|
|
static HWND hScrollBar;
|
|
INT iTemp;
|
|
SCROLLINFO rScrollInfo;
|
|
INT iReturn;
|
|
|
|
switch(message) {
|
|
case WM_INITDIALOG:
|
|
pParams = (prGetWriteDataParams) lParam;
|
|
prData = pParams -> prItems;
|
|
hScrollBar = GetDlgItem(hDlg, IDC_SCROLLBAR);
|
|
|
|
if (pParams -> iCount > CONTROL_COUNT) {
|
|
iDisplayCount = CONTROL_COUNT;
|
|
iScrollRange = pParams -> iCount - CONTROL_COUNT;
|
|
rScrollInfo.fMask = SIF_RANGE | SIF_POS;
|
|
rScrollInfo.nPos = 0;
|
|
rScrollInfo.nMin = 0;
|
|
rScrollInfo.nMax = iScrollRange;
|
|
rScrollInfo.cbSize = sizeof(rScrollInfo);
|
|
rScrollInfo.nPage = CONTROL_COUNT;
|
|
iReturn = SetScrollInfo(hScrollBar,SB_CTL,&rScrollInfo,TRUE);
|
|
}
|
|
else {
|
|
iDisplayCount=pParams->iCount;
|
|
EnableWindow(hScrollBar,FALSE);
|
|
}
|
|
vWriteDataToControls(hDlg, prData, 0, pParams->iCount);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam)) {
|
|
case IDOK:
|
|
case ID_SEND:
|
|
vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
|
|
EndDialog(hDlg,1);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hDlg,0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_VSCROLL:
|
|
vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
|
|
|
|
switch(LOWORD(wParam)) {
|
|
case SB_LINEDOWN:
|
|
++iCurrentScrollPos;
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
--iCurrentScrollPos;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
iCurrentScrollPos = HIWORD(wParam);
|
|
|
|
case SB_PAGEUP:
|
|
iCurrentScrollPos -= CONTROL_COUNT;
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
iCurrentScrollPos += CONTROL_COUNT;
|
|
break;
|
|
}
|
|
|
|
if (iCurrentScrollPos < 0) {
|
|
iCurrentScrollPos = 0;
|
|
}
|
|
|
|
if (iCurrentScrollPos > iScrollRange) {
|
|
iCurrentScrollPos = iScrollRange;
|
|
}
|
|
|
|
SendMessage(hScrollBar, SBM_SETPOS, iCurrentScrollPos, TRUE);
|
|
iTemp = LOWORD(wParam);
|
|
|
|
if ( (iTemp == SB_LINEDOWN) || (iTemp == SB_LINEUP) || (iTemp == SB_THUMBPOSITION)|| (iTemp == SB_PAGEUP) || (iTemp==SB_PAGEDOWN) ) {
|
|
vWriteDataToControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
} /*end function bGetDataDlgProc*/
|
|
|
|
VOID
|
|
vReadDataFromControls(
|
|
HWND hDlg,
|
|
prWriteDataStruct prData,
|
|
INT iOffset,
|
|
INT iCount
|
|
)
|
|
{
|
|
INT iLoop;
|
|
INT iValueControlID = IDC_OUT_EDIT1;
|
|
prWriteDataStruct pDataWalk;
|
|
HWND hValueWnd;
|
|
|
|
pDataWalk = prData + iOffset;
|
|
for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++) {
|
|
|
|
hValueWnd = GetDlgItem(hDlg, iValueControlID);
|
|
GetWindowText(hValueWnd, pDataWalk -> szValue, MAX_VALUE);
|
|
iValueControlID++;
|
|
pDataWalk++;
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vWriteDataToControls(
|
|
HWND hDlg,
|
|
prWriteDataStruct prData,
|
|
INT iOffset,
|
|
INT iCount
|
|
)
|
|
{
|
|
INT iLoop;
|
|
INT iLabelControlID = IDC_OUT_LABEL1;
|
|
INT iValueControlID = IDC_OUT_EDIT1;
|
|
HWND hLabelWnd, hValueWnd;
|
|
prWriteDataStruct pDataWalk;
|
|
|
|
pDataWalk = prData + iOffset;
|
|
|
|
for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++) {
|
|
|
|
hLabelWnd = GetDlgItem(hDlg, iLabelControlID);
|
|
hValueWnd = GetDlgItem(hDlg, iValueControlID);
|
|
|
|
ShowWindow(hLabelWnd, SW_SHOW);
|
|
ShowWindow(hValueWnd, SW_SHOW);
|
|
|
|
SetWindowText(hLabelWnd, pDataWalk -> szLabel);
|
|
SetWindowText(hValueWnd, pDataWalk -> szValue);
|
|
|
|
iLabelControlID++;
|
|
iValueControlID++;
|
|
pDataWalk++;
|
|
|
|
}
|
|
|
|
/*
|
|
// Hide the controls
|
|
*/
|
|
|
|
for (; iLoop < CONTROL_COUNT; iLoop++) {
|
|
|
|
hLabelWnd = GetDlgItem(hDlg,iLabelControlID);
|
|
hValueWnd = GetDlgItem(hDlg,iValueControlID);
|
|
|
|
ShowWindow(hLabelWnd,SW_HIDE);
|
|
ShowWindow(hValueWnd,SW_HIDE);
|
|
|
|
iLabelControlID++;
|
|
iValueControlID++;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
vCreateUsageString(
|
|
IN PUSAGE pUsageList,
|
|
OUT CHAR szString[]
|
|
)
|
|
{
|
|
wsprintf(szString,
|
|
"Usage: %#04x",
|
|
*pUsageList
|
|
);
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
vCreateUsageAndPageString(
|
|
IN PUSAGE_AND_PAGE pUsageList,
|
|
OUT CHAR szString[]
|
|
)
|
|
{
|
|
wsprintf(szString,
|
|
"Usage Page: %#04x Usage: %#04x",
|
|
pUsageList -> UsagePage,
|
|
pUsageList -> Usage
|
|
);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vDisplayLinkCollectionNode(
|
|
IN PHIDP_LINK_COLLECTION_NODE pLCNode,
|
|
IN ULONG ulLinkIndex,
|
|
IN HWND hControl
|
|
)
|
|
{
|
|
static CHAR szTempBuff[128];
|
|
|
|
wsprintf(szTempBuff, "Index: 0x%x", ulLinkIndex);
|
|
SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Usage Page: 0x%x", pLCNode -> LinkUsagePage);
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM)szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Usage: 0x%x", pLCNode -> LinkUsage);
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Parent Index: 0x%x", pLCNode -> Parent);
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Number of Children: 0x%x", pLCNode -> NumberOfChildren);
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "Next Sibling: 0x%x", pLCNode -> NextSibling);
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
|
|
|
|
wsprintf(szTempBuff, "First Child: 0x%x", pLCNode -> FirstChild);
|
|
SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
vCreateUsageValueStringFromArray(
|
|
PCHAR pBuffer,
|
|
USHORT BitSize,
|
|
USHORT UsageIndex,
|
|
CHAR szString[]
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Given a report buffer, pBuffer, this routine extracts the given usage
|
|
at UsageIndex from the array and outputs to szString the string
|
|
representation of that value. The input parameter BitSize specifies
|
|
the number of bits representing that value in the array. This is
|
|
useful for extracting individual members of a UsageValueArray.
|
|
--*/
|
|
{
|
|
INT iByteIndex;
|
|
INT iByteOffset;
|
|
UCHAR ucLeftoverBits;
|
|
ULONG ulMask;
|
|
ULONG ulValue;
|
|
|
|
/*
|
|
// Calculate the byte and byte offset into the buffer for the given
|
|
// index value
|
|
*/
|
|
|
|
iByteIndex = (UsageIndex * BitSize) >> 3;
|
|
iByteOffset = (UsageIndex * BitSize) & 7;
|
|
|
|
/*
|
|
// Extract the 32-bit value beginning at ByteIndex. This value
|
|
// will contain some or all of the value we are attempting to retrieve
|
|
*/
|
|
|
|
ulValue = *(PULONG) (pBuffer + iByteIndex);
|
|
|
|
/*
|
|
// Shift that value to the right by our byte offset..
|
|
*/
|
|
|
|
ulValue = ulValue >> iByteOffset;
|
|
|
|
/*
|
|
// At this point, ulValue contains the first 32-iByteOffset bits beginning
|
|
// the appropriate offset in the buffer. There are now two cases to
|
|
// look at:
|
|
//
|
|
// 1) BitSize > 32-iByteOffset -- In which case, we need to extract
|
|
// iByteOffset bits from the next
|
|
// byte in the array and OR them as
|
|
// the MSBs of ulValue
|
|
//
|
|
// 2) BitSize < 32-iByteOffset -- Need to get only the BitSize LSBs
|
|
//
|
|
*/
|
|
|
|
/*
|
|
// Case #1
|
|
*/
|
|
|
|
if (BitSize > sizeof(ULONG)*8 - iByteOffset) {
|
|
|
|
/*
|
|
// Get the next byte of the report following the four bytes we
|
|
// retrieved earlier for ulValue
|
|
*/
|
|
|
|
ucLeftoverBits = *(pBuffer+iByteIndex+4);
|
|
|
|
/*
|
|
// Shift those bits to the left for anding to our previous value
|
|
*/
|
|
|
|
ulMask = ucLeftoverBits << (24 + (8 - iByteOffset));
|
|
ulValue |= ulMask;
|
|
|
|
}
|
|
else if (BitSize < sizeof(ULONG)*8 - iByteOffset) {
|
|
|
|
/*
|
|
// Need to mask the most significant bits that are part of another
|
|
// value(s), not the one we are currently working with.
|
|
*/
|
|
|
|
ulMask = (1 << BitSize) - 1;
|
|
ulValue &= ulMask;
|
|
}
|
|
|
|
/*
|
|
// We've now got the correct value, now output to the string
|
|
*/
|
|
|
|
wsprintf(szString, "Usage value: %lu", ulValue);
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
RegisterHidDevice(
|
|
IN HWND WindowHandle,
|
|
IN PDEVICE_LIST_NODE DeviceNode
|
|
)
|
|
{
|
|
DEV_BROADCAST_HANDLE broadcastHandle;
|
|
|
|
broadcastHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
|
|
broadcastHandle.dbch_devicetype = DBT_DEVTYP_HANDLE;
|
|
broadcastHandle.dbch_handle = DeviceNode -> HidDeviceInfo.HidDevice;
|
|
|
|
DeviceNode -> NotificationHandle = RegisterDeviceNotification(
|
|
WindowHandle,
|
|
&broadcastHandle,
|
|
DEVICE_NOTIFY_WINDOW_HANDLE
|
|
);
|
|
|
|
return (DeviceNode != NULL);
|
|
}
|
|
|
|
VOID
|
|
DestroyDeviceListCallback(
|
|
PLIST_NODE_HDR ListNode
|
|
)
|
|
{
|
|
PDEVICE_LIST_NODE deviceNode;
|
|
|
|
|
|
deviceNode = (PDEVICE_LIST_NODE) ListNode;
|
|
|
|
/*
|
|
// The callback function needs to do the following steps...
|
|
// 1) Close the HidDevice
|
|
// 2) Unregister device notification (if registered)
|
|
// 3) Free the allocated memory block
|
|
*/
|
|
|
|
CloseHidDevice(&(deviceNode -> HidDeviceInfo));
|
|
|
|
if (NULL != deviceNode -> NotificationHandle)
|
|
UnregisterDeviceNotification(deviceNode -> NotificationHandle);
|
|
|
|
free (deviceNode);
|
|
|
|
return;
|
|
}
|
|
|