Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3099 lines
100 KiB

  1. /*++
  2. Copyright (c) Microsoft 1998, All Rights Reserved
  3. Module Name:
  4. hclient.c
  5. Abstract:
  6. This module contains the code for handling HClient's main dialog box and
  7. for performing/calling the appropriate other routines.
  8. Environment:
  9. User mode
  10. Revision History:
  11. Nov-97 : Created
  12. --*/
  13. #define __HCLIENT_C__
  14. #define LOG_FILE_NAME NULL
  15. //****************************************************************************
  16. // HClient include files
  17. //****************************************************************************
  18. #include <windows.h>
  19. #include <stdlib.h>
  20. #include <wtypes.h>
  21. #include <math.h>
  22. #include <assert.h>
  23. #include <dbt.h>
  24. #include "hidsdi.h"
  25. #include "hid.h"
  26. #include "resource.h"
  27. #include "hclient.h"
  28. #include "buffers.h"
  29. #include "ecdisp.h"
  30. #include "logpnp.h"
  31. #include "list.h"
  32. //****************************************************************************
  33. // Local display macro definitions
  34. //****************************************************************************
  35. #define INPUT_BUTTON 1
  36. #define INPUT_VALUE 2
  37. #define OUTPUT_BUTTON 3
  38. #define OUTPUT_VALUE 4
  39. #define FEATURE_BUTTON 5
  40. #define FEATURE_VALUE 6
  41. #define HID_CAPS 7
  42. #define DEVICE_ATTRIBUTES 8
  43. #define MAX_LB_ITEMS 200
  44. #define MAX_WRITE_ELEMENTS 100
  45. #define MAX_OUTPUT_ELEMENTS 50
  46. #define CONTROL_COUNT 9
  47. #define MAX_LABEL 128
  48. #define MAX_VALUE 128
  49. //****************************************************************************
  50. // Macro definition to get device block from the main dialog box procedure
  51. //****************************************************************************
  52. #define GET_CURRENT_DEVICE(hDlg, pDevice) \
  53. { \
  54. pDevice = NULL; \
  55. iIndex = (INT) SendDlgItemMessage(hDlg, \
  56. IDC_DEVICES, \
  57. CB_GETCURSEL, \
  58. 0, \
  59. 0); \
  60. if (CB_ERR != iIndex) { \
  61. pDevice = (PHID_DEVICE) SendDlgItemMessage(hDlg, \
  62. IDC_DEVICES, \
  63. CB_GETITEMDATA, \
  64. iIndex, \
  65. 0); \
  66. } \
  67. }
  68. //****************************************************************************
  69. // Data types local to the HClient display routines
  70. //****************************************************************************
  71. typedef struct rWriteDataStruct_type
  72. {
  73. char szLabel[MAX_LABEL];
  74. char szValue[MAX_VALUE];
  75. } rWriteDataStruct, *prWriteDataStruct;
  76. typedef struct rGetWriteDataParams_type
  77. {
  78. prWriteDataStruct prItems;
  79. int iCount;
  80. } rGetWriteDataParams, *prGetWriteDataParams;
  81. typedef struct _DEVICE_LIST_NODE
  82. {
  83. LIST_NODE_HDR Hdr;
  84. HDEVNOTIFY NotificationHandle;
  85. HID_DEVICE HidDeviceInfo;
  86. BOOL DeviceOpened;
  87. } DEVICE_LIST_NODE, *PDEVICE_LIST_NODE;
  88. //****************************************************************************
  89. // Global program variables
  90. //****************************************************************************
  91. //
  92. // Pointers to the HID.DLL functions that were added into the Win98 OSR and
  93. // Windows 2000 but we're not included in the original implementation of
  94. // HID.DLL in Windows 98. By getting pointers to these functions instead of
  95. // statically linking with them, we can avoid the link error that would
  96. // occur when this runs on Windows 98. The typedefs to make this easier to
  97. // declare are also included below.
  98. //
  99. PGETEXTATTRIB pfnHidP_GetExtendedAttributes = NULL;
  100. PINITREPORT pfnHidP_InitializeReportForID = NULL;
  101. //****************************************************************************
  102. // Global module variables
  103. //****************************************************************************
  104. static HINSTANCE hGInstance; //global application instance handle
  105. static BOOL IsHIDTestLoaded;
  106. static HANDLE TestDLLModuleHandle;
  107. static VOID (*HIDTest_StartTestFunc) (VOID);
  108. static HANDLE HIDDLLModuleHandle;
  109. //
  110. // Variables for handling the two different types of devices that can be loaded
  111. // into the system. PhysicalDeviceList contains all the actual HID devices
  112. // attached via the USB bus. LogicalDeviceList contains those preparsed
  113. // data structures which were obtained through report descriptors and saved
  114. // via the latest version of HidView.
  115. //
  116. static LIST PhysicalDeviceList;
  117. static LIST LogicalDeviceList;
  118. //****************************************************************************
  119. // Local data routine declarations
  120. //****************************************************************************
  121. VOID
  122. vReadDataFromControls(
  123. HWND hDlg,
  124. prWriteDataStruct prData,
  125. int iOffset,
  126. int iCount
  127. );
  128. INT_PTR CALLBACK
  129. bGetDataDlgProc(
  130. HWND hDlg,
  131. UINT message,
  132. WPARAM wParam,
  133. LPARAM lParam
  134. );
  135. INT_PTR CALLBACK
  136. bMainDlgProc(
  137. HWND hDlg,
  138. UINT message,
  139. WPARAM wParam,
  140. LPARAM lParam
  141. );
  142. INT_PTR CALLBACK
  143. bFeatureDlgProc(
  144. HWND hDlg,
  145. UINT message,
  146. WPARAM wParam,
  147. LPARAM lParam
  148. );
  149. INT_PTR CALLBACK
  150. bReadDlgProc(
  151. HWND hDlg,
  152. UINT message,
  153. WPARAM wParam,
  154. LPARAM lParam
  155. );
  156. VOID
  157. vLoadItemTypes(
  158. HWND hItemTypes
  159. );
  160. BOOL
  161. bGetData(
  162. prWriteDataStruct,
  163. int iCount,
  164. HWND hParent,
  165. char *pszDialogName
  166. );
  167. VOID
  168. vLoadDevices(
  169. HWND hDeviceCombo
  170. );
  171. VOID
  172. vFreeDeviceList(
  173. PHID_DEVICE DeviceList,
  174. ULONG nDevices
  175. );
  176. VOID
  177. vDisplayInputButtons(
  178. PHID_DEVICE pDevice,
  179. HWND hControl
  180. );
  181. VOID
  182. vDisplayInputValues(
  183. PHID_DEVICE pDevice,
  184. HWND hControl
  185. );
  186. VOID
  187. vDisplayOutputButtons(
  188. PHID_DEVICE pDevice,
  189. HWND hControl
  190. );
  191. VOID
  192. vDisplayOutputValues(
  193. PHID_DEVICE pDevice,
  194. HWND hControl
  195. );
  196. VOID
  197. vDisplayFeatureButtons(
  198. PHID_DEVICE pDevice,
  199. HWND hControl
  200. );
  201. VOID
  202. vDisplayFeatureValues(
  203. PHID_DEVICE pDevice,
  204. HWND hControl
  205. );
  206. VOID
  207. vWriteDataToControls(
  208. HWND hDlg,
  209. prWriteDataStruct prData,
  210. int iOffset,
  211. int iCount
  212. );
  213. int
  214. iPrepareDataFields(
  215. PHID_DATA pData,
  216. ULONG ulDataLength,
  217. rWriteDataStruct rWriteData[],
  218. int iMaxElements
  219. );
  220. BOOL
  221. bParseData(
  222. PHID_DATA pData,
  223. rWriteDataStruct rWriteData[],
  224. INT iCount,
  225. INT *piErrorLine
  226. );
  227. BOOL
  228. bSetButtonUsages(
  229. PHID_DATA pCap,
  230. PCHAR pszInputString
  231. );
  232. VOID
  233. BuildReportIDList(
  234. IN PHIDP_BUTTON_CAPS phidButtonCaps,
  235. IN USHORT nButtonCaps,
  236. IN PHIDP_VALUE_CAPS phidValueCaps,
  237. IN USHORT nValueCaps,
  238. OUT UCHAR **ppReportIDList,
  239. OUT INT *nReportIDs
  240. );
  241. VOID
  242. ReportToString(
  243. PHID_DATA pData,
  244. PCHAR szBuff
  245. );
  246. BOOL
  247. RegisterHidDevice(
  248. IN HWND WindowHandle,
  249. IN PDEVICE_LIST_NODE DeviceNode
  250. );
  251. VOID
  252. DestroyDeviceListCallback(
  253. IN PLIST_NODE_HDR ListNode
  254. );
  255. //****************************************************************************
  256. // Function Definitions
  257. //****************************************************************************
  258. /*******************************
  259. *WinMain: Windows Entry point *
  260. *******************************/
  261. int PASCAL
  262. WinMain(
  263. HINSTANCE hInstance,
  264. HINSTANCE hPrevInstance,
  265. LPSTR lpCmdLine,
  266. int nCmdShow
  267. )
  268. {
  269. //
  270. // Save instance of the application for further reference
  271. //
  272. hGInstance = hInstance;
  273. //
  274. // Attempt to load HID.DLL...This should already be loaded due to the
  275. // static linking of HID.DLL to this app on compilation. However,
  276. // to insure that this application runs on Windows 98 gold, we cannot
  277. // directly reference the new functions HidP_GetExtendedAttributes and
  278. // HidP_InitializeReportForID so to use them, we'll get pointers to their
  279. // functions instead.
  280. //
  281. HIDDLLModuleHandle = LoadLibrary("HID.DLL");
  282. if (NULL == HIDDLLModuleHandle)
  283. {
  284. //
  285. // Something really bad happened here...Throw up and error dialog
  286. // and bolt.
  287. //
  288. MessageBox(NULL,
  289. "Unable to open HID.DLL\n"
  290. "This should never occur",
  291. HCLIENT_ERROR,
  292. MB_ICONSTOP);
  293. return (0);
  294. }
  295. //
  296. // Get the function pointers,
  297. //
  298. pfnHidP_GetExtendedAttributes = (PGETEXTATTRIB) GetProcAddress(HIDDLLModuleHandle,
  299. "HidP_GetExtendedAttributes");
  300. pfnHidP_InitializeReportForID = (PINITREPORT) GetProcAddress(HIDDLLModuleHandle,
  301. "HidP_InitializeReportForID");
  302. //
  303. // Attempt to load HIDTest.DLL. If the DLL exists and can be loaded, then
  304. // we can show the START_TEST button in the main dialog box. Otherwise,
  305. // the button is hidden.
  306. //
  307. // Note: HIDTEST.DLL is used for internal testing purposes and is not included
  308. // with the DDK sources
  309. //
  310. //
  311. TestDLLModuleHandle = LoadLibrary("HIDTEST.DLL");
  312. IsHIDTestLoaded = (NULL != TestDLLModuleHandle);
  313. if (IsHIDTestLoaded)
  314. {
  315. HIDTest_StartTestFunc = (VOID (*)(VOID)) GetProcAddress(TestDLLModuleHandle,
  316. "HIDTest_DoFullTest");
  317. if (NULL == HIDTest_StartTestFunc)
  318. {
  319. IsHIDTestLoaded = FALSE;
  320. FreeLibrary(TestDLLModuleHandle);
  321. }
  322. }
  323. //
  324. // Try to create the main dialog box. Cannot do much else if it fails
  325. // so we'll throw up a message box and then exit the app
  326. //
  327. if (-1 == DialogBox(hInstance, "MAIN_DIALOG", NULL, (DLGPROC)bMainDlgProc))
  328. {
  329. MessageBox(NULL,
  330. "Unable to create root dialog!",
  331. "DialogBox failure",
  332. MB_ICONSTOP);
  333. }
  334. //
  335. // Unloaded HIDTest.DLL if it is loaded
  336. //
  337. if (IsHIDTestLoaded)
  338. {
  339. FreeLibrary(TestDLLModuleHandle);
  340. }
  341. FreeLibrary (HIDDLLModuleHandle);
  342. return (0);
  343. }
  344. /*************************************************
  345. * Main Dialog proc *
  346. *************************************************/
  347. //
  348. // This the dialog box procedure for the main dialog display.
  349. //
  350. INT_PTR CALLBACK
  351. bMainDlgProc(
  352. HWND hDlg,
  353. UINT message,
  354. WPARAM wParam,
  355. LPARAM lParam
  356. )
  357. {
  358. static HWND hComboCtrl;
  359. static rWriteDataStruct rWriteData[MAX_OUTPUT_ELEMENTS];
  360. static HDEVNOTIFY diNotifyHandle;
  361. INT iIndex;
  362. INT iCount;
  363. CHAR szTempBuff[128];
  364. PHID_DEVICE pDevice;
  365. PHIDP_BUTTON_CAPS pButtonCaps;
  366. PHIDP_VALUE_CAPS pValueCaps;
  367. INT iErrorLine;
  368. INT iItemType;
  369. PHID_DEVICE tempDeviceList;
  370. ULONG numberDevices;
  371. PDEVICE_LIST_NODE listNode;
  372. DEV_BROADCAST_DEVICEINTERFACE broadcastInterface;
  373. HID_DEVICE writeDevice;
  374. BOOL status;
  375. switch (message)
  376. {
  377. case WM_INITDIALOG:
  378. //
  379. // Initialize the two device lists.
  380. // -- PhysicalDeviceList is for devices that are actually attached
  381. // to the HID bus
  382. //
  383. // -- LogicalDeviceList is for devices that are loaded from a
  384. // a preparsed data file. The preparsed data for a device
  385. // can be saved by a program such as HIDView.
  386. //
  387. //
  388. InitializeList(&PhysicalDeviceList);
  389. InitializeList(&LogicalDeviceList);
  390. //
  391. // Begin by finding all the Physical HID devices currently attached to
  392. // the system. If that fails, exit the dialog box. Logical devices
  393. // are loaded via the button in the main dialog box.
  394. //
  395. if (!FindKnownHidDevices(&tempDeviceList, &numberDevices))
  396. {
  397. EndDialog(hDlg, 0);
  398. return FALSE;
  399. }
  400. //
  401. // For each device in the newly acquired list, create a device list
  402. // node and add it the the list of physical device on the system
  403. //
  404. pDevice = tempDeviceList;
  405. for (iIndex = 0; (ULONG) iIndex < numberDevices; iIndex++, pDevice++)
  406. {
  407. listNode = malloc(sizeof(DEVICE_LIST_NODE));
  408. if (NULL == listNode) {
  409. //
  410. // When freeing up the device list, we need to kill those
  411. // already in the Physical Device List and close
  412. // that have not been added yet in the enumerated list
  413. //
  414. DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
  415. CloseHidDevices(pDevice, numberDevices - iIndex);
  416. free(tempDeviceList);
  417. EndDialog(hDlg, 0);
  418. return FALSE;
  419. }
  420. listNode -> HidDeviceInfo = *pDevice;
  421. listNode -> DeviceOpened = TRUE;
  422. //
  423. // Register this device node with the PnP system so the dialog
  424. // window can recieve notification if this device is unplugged.
  425. //
  426. if (!RegisterHidDevice(hDlg, listNode))
  427. {
  428. DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
  429. CloseHidDevices(pDevice, numberDevices - iIndex);
  430. free(tempDeviceList);
  431. free(listNode);
  432. EndDialog(hDlg, 0);
  433. return FALSE;
  434. }
  435. InsertTail(&PhysicalDeviceList, listNode);
  436. }
  437. //
  438. // Free the temporary device list...It is no longer needed
  439. //
  440. free(tempDeviceList);
  441. //
  442. // Register for notification from the HidDevice class. Doing so
  443. // allows the dialog box to receive device change notifications
  444. // whenever a new HID device is added to the system
  445. //
  446. broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  447. broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  448. HidD_GetHidGuid(&broadcastInterface.dbcc_classguid);
  449. diNotifyHandle = RegisterDeviceNotification(hDlg,
  450. &broadcastInterface,
  451. DEVICE_NOTIFY_WINDOW_HANDLE
  452. );
  453. if (NULL == diNotifyHandle)
  454. {
  455. DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
  456. EndDialog(hDlg, 0);
  457. return FALSE;
  458. }
  459. //
  460. // Update the device list box...
  461. //
  462. //
  463. vLoadDevices(GetDlgItem(hDlg, IDC_DEVICES));
  464. //
  465. // Load the types box
  466. //
  467. vLoadItemTypes(GetDlgItem(hDlg, IDC_TYPE));
  468. //
  469. // Show the Start Tests button on if hidtest.dll was found and
  470. // loaded.
  471. //
  472. ShowWindow(GetDlgItem(hDlg, IDC_START_TESTS), IsHIDTestLoaded);
  473. //
  474. // Post a message that the device changed so the appropriate
  475. // data for the first device in the system can be displayed
  476. //
  477. PostMessage(hDlg,
  478. WM_COMMAND,
  479. IDC_DEVICES + (CBN_SELCHANGE<<16),
  480. (LPARAM) GetDlgItem(hDlg, IDC_DEVICES));
  481. break; // end WM_INITDIALOG case
  482. case WM_COMMAND:
  483. switch(LOWORD(wParam))
  484. {
  485. //
  486. // For a read, simply get the current device instance
  487. // from the DEVICES combo box and call the read procedure
  488. // with the HID_DEVICE block
  489. //
  490. case IDC_READ:
  491. GET_CURRENT_DEVICE(hDlg, pDevice);
  492. if (NULL != pDevice)
  493. {
  494. iIndex = (INT) DialogBoxParam(hGInstance,
  495. "READDATA",
  496. hDlg,
  497. bReadDlgProc,
  498. (LPARAM) pDevice);
  499. }
  500. break;
  501. //
  502. // For a write, the following steps are performed:
  503. // 1) Get the current device data from the combo box
  504. // 2) Prepare the data fields for display based on the data
  505. // output data stored in the device data
  506. // 3) Retrieve the data the from the user that is to be sent
  507. // to the device
  508. // 4) If all goes well and the data parses correctly, send the
  509. // the new data values to the device
  510. //
  511. case IDC_WRITE:
  512. GET_CURRENT_DEVICE(hDlg, pDevice);
  513. if (NULL != pDevice)
  514. {
  515. //
  516. // In order to write to the device, need to get a
  517. // writable handle to the device. In this case, the
  518. // write will be a synchronous write. Begin by
  519. // trying to open a second instance of this device with
  520. // write access
  521. //
  522. memcpy(&writeDevice, pDevice, sizeof(HID_DEVICE));
  523. status = OpenHidDevice(pDevice -> DevicePath,
  524. FALSE,
  525. TRUE,
  526. FALSE,
  527. FALSE,
  528. FALSE,
  529. &writeDevice);
  530. if (!status)
  531. {
  532. MessageBox(hDlg,
  533. "Couldn't open device for write access",
  534. HCLIENT_ERROR,
  535. MB_ICONEXCLAMATION);
  536. }
  537. else
  538. {
  539. iCount = iPrepareDataFields(writeDevice.OutputData,
  540. writeDevice.OutputDataLength,
  541. rWriteData,
  542. MAX_OUTPUT_ELEMENTS);
  543. if (bGetData(rWriteData, iCount, hDlg, "WRITEDATA"))
  544. {
  545. if (bParseData(writeDevice.OutputData, rWriteData, iCount, &iErrorLine))
  546. {
  547. Write(&writeDevice);
  548. }
  549. else
  550. {
  551. wsprintf(szTempBuff,
  552. "Unable to parse line %x of output data",
  553. iErrorLine);
  554. MessageBox(hDlg,
  555. szTempBuff,
  556. HCLIENT_ERROR,
  557. MB_ICONEXCLAMATION);
  558. }
  559. }
  560. CloseHidDevice(&writeDevice, FALSE);
  561. }
  562. }
  563. break; //end case IDC_WRITE//
  564. //
  565. // For processing features, get the current device data and call
  566. // the Features dialog box, This dialog box will deal with
  567. // sending and retrieving the features.
  568. //
  569. case IDC_FEATURES:
  570. GET_CURRENT_DEVICE(hDlg, pDevice);
  571. if (NULL != pDevice)
  572. {
  573. iIndex = (INT) DialogBoxParam(hGInstance,
  574. "FEATURES",
  575. hDlg,
  576. bFeatureDlgProc,
  577. (LPARAM) pDevice);
  578. }
  579. break;
  580. //
  581. // Likewise with extended calls dialog box. This procedure
  582. // passes the address to the device data structure and lets
  583. // the dialog box procedure manipulate the data however it
  584. // wants to.
  585. //
  586. case IDC_EXTCALLS:
  587. GET_CURRENT_DEVICE(hDlg, pDevice);
  588. if (NULL != pDevice)
  589. {
  590. iIndex = (INT) DialogBoxParam(hGInstance,
  591. "EXTCALLS",
  592. hDlg,
  593. bExtCallDlgProc,
  594. (LPARAM) pDevice);
  595. }
  596. break;
  597. //
  598. // START_TESTS occurs only when HIDTEST.DLL is loaded. This
  599. // DLL is for internal test purposes and is not provided
  600. // in the DDK sample.
  601. //
  602. case IDC_START_TESTS:
  603. HIDTest_StartTestFunc();
  604. break;
  605. //
  606. // If there was a device change, issue an IDC_TYPE
  607. // change to insure that the currently displayed types are
  608. // updated to reflect the values of the device that has
  609. // been selected
  610. //
  611. case IDC_DEVICES:
  612. switch (HIWORD(wParam))
  613. {
  614. case CBN_SELCHANGE:
  615. GET_CURRENT_DEVICE(hDlg, pDevice);
  616. EnableWindow(GetDlgItem(hDlg, IDC_READ),
  617. (pDevice != NULL) &&
  618. (pDevice -> Caps.InputReportByteLength));
  619. EnableWindow(GetDlgItem(hDlg, IDC_WRITE),
  620. (pDevice != NULL) &&
  621. (pDevice -> Caps.OutputReportByteLength));
  622. EnableWindow(GetDlgItem(hDlg, IDC_FEATURES),
  623. (pDevice != NULL) &&
  624. (pDevice -> Caps.FeatureReportByteLength));
  625. PostMessage(hDlg,
  626. WM_COMMAND,
  627. IDC_TYPE + (CBN_SELCHANGE<<16),
  628. (LPARAM) GetDlgItem(hDlg,IDC_TYPE));
  629. break;
  630. }
  631. break;
  632. //
  633. // On a type change, retrieve the currently active device
  634. // from the IDC_DEVICES box and display the data that
  635. // corresponds to the item just selected
  636. //
  637. case IDC_TYPE:
  638. switch (HIWORD(wParam))
  639. {
  640. case CBN_SELCHANGE:
  641. GET_CURRENT_DEVICE(hDlg, pDevice);
  642. SendDlgItemMessage(hDlg,
  643. IDC_ITEMS,
  644. LB_RESETCONTENT,
  645. 0,
  646. 0);
  647. SendDlgItemMessage(hDlg,
  648. IDC_ATTRIBUTES,
  649. LB_RESETCONTENT,
  650. 0,
  651. 0);
  652. if (NULL != pDevice)
  653. {
  654. iIndex = (INT) SendDlgItemMessage(hDlg,
  655. IDC_TYPE,
  656. CB_GETCURSEL,
  657. 0,
  658. 0);
  659. iItemType = (INT) SendDlgItemMessage(hDlg,
  660. IDC_TYPE,
  661. CB_GETITEMDATA,
  662. iIndex,
  663. 0);
  664. switch(iItemType)
  665. {
  666. case INPUT_BUTTON:
  667. vDisplayInputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
  668. break;
  669. case INPUT_VALUE:
  670. vDisplayInputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
  671. break;
  672. case OUTPUT_BUTTON:
  673. vDisplayOutputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
  674. break;
  675. case OUTPUT_VALUE:
  676. vDisplayOutputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
  677. break;
  678. case FEATURE_BUTTON:
  679. vDisplayFeatureButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
  680. break;
  681. case FEATURE_VALUE:
  682. vDisplayFeatureValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
  683. break;
  684. }
  685. PostMessage(hDlg,
  686. WM_COMMAND,
  687. IDC_ITEMS + (LBN_SELCHANGE << 16),
  688. (LPARAM) GetDlgItem(hDlg,IDC_ITEMS));
  689. }
  690. break; // case CBN_SELCHANGE
  691. } //end switch HIWORD wParam
  692. break; //case IDC_TYPE control
  693. case IDC_ITEMS:
  694. switch(HIWORD(wParam))
  695. {
  696. case LBN_SELCHANGE:
  697. iItemType = 0;
  698. iIndex = (INT) SendDlgItemMessage(hDlg,
  699. IDC_TYPE,
  700. CB_GETCURSEL,
  701. 0,
  702. 0);
  703. if (-1 != iIndex)
  704. {
  705. iItemType = (INT) SendDlgItemMessage(hDlg,
  706. IDC_TYPE,
  707. CB_GETITEMDATA,
  708. iIndex,
  709. 0);
  710. }
  711. iIndex = (INT) SendDlgItemMessage(hDlg,
  712. IDC_ITEMS,
  713. LB_GETCURSEL,
  714. 0,
  715. 0);
  716. switch (iItemType)
  717. {
  718. case INPUT_BUTTON:
  719. case OUTPUT_BUTTON:
  720. case FEATURE_BUTTON:
  721. pButtonCaps = NULL;
  722. if (-1 != iIndex)
  723. {
  724. pButtonCaps = (PHIDP_BUTTON_CAPS) SendDlgItemMessage(hDlg,
  725. IDC_ITEMS,
  726. LB_GETITEMDATA,
  727. iIndex,
  728. 0);
  729. }
  730. SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
  731. if (NULL != pButtonCaps)
  732. {
  733. vDisplayButtonAttributes(pButtonCaps, GetDlgItem(hDlg,IDC_ATTRIBUTES));
  734. }
  735. break;
  736. case INPUT_VALUE:
  737. case OUTPUT_VALUE:
  738. case FEATURE_VALUE:
  739. pValueCaps = NULL;
  740. if (-1 != iIndex)
  741. {
  742. pValueCaps = (PHIDP_VALUE_CAPS) SendDlgItemMessage(hDlg,
  743. IDC_ITEMS,
  744. LB_GETITEMDATA,
  745. iIndex,
  746. 0);
  747. }
  748. SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
  749. if (NULL != pValueCaps)
  750. {
  751. vDisplayValueAttributes(pValueCaps,GetDlgItem(hDlg,IDC_ATTRIBUTES));
  752. }
  753. break;
  754. case HID_CAPS:
  755. GET_CURRENT_DEVICE(hDlg, pDevice);
  756. if (NULL != pDevice)
  757. {
  758. vDisplayDeviceCaps(&(pDevice -> Caps),GetDlgItem(hDlg,IDC_ATTRIBUTES));
  759. }
  760. break;
  761. case DEVICE_ATTRIBUTES:
  762. GET_CURRENT_DEVICE(hDlg, pDevice);
  763. if (NULL != pDevice)
  764. {
  765. SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
  766. vDisplayDeviceAttributes(&(pDevice -> Attributes) ,GetDlgItem(hDlg,IDC_ATTRIBUTES));
  767. }
  768. break;
  769. } //end switch iItemType//
  770. break; //end case LBN_SELCHANGE in IDC_ITEMS//
  771. } //end switch HIWORD wParam//
  772. break; //case IDC_ITEMS//
  773. //
  774. // To load a logical device, we first have insure that
  775. // we have space left in the list of logical devices
  776. // If there isn't space, we have to realloc more space
  777. // or print an error message saying the limit has
  778. // been reached. Once we've allocated space for the
  779. // logical device, the next step is to pass the HID_DEVICE
  780. // structure to our load logical device routine to get
  781. // the data for that device.
  782. //
  783. case IDC_LOAD_LOGICAL_DEVICE:
  784. listNode = malloc(sizeof(DEVICE_LIST_NODE));
  785. if (NULL == listNode)
  786. {
  787. MessageBox(hDlg,
  788. "Error -- Couldn't allocate memory for device list node",
  789. HCLIENT_ERROR,
  790. MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
  791. return (FALSE);
  792. }
  793. //
  794. // Now call the LogPnp_LoadLogicalDevice to load all the data for
  795. // the logical device
  796. //
  797. if (LogPnP_LoadLogicalDevice(LOG_FILE_NAME, &(listNode -> HidDeviceInfo)))
  798. {
  799. listNode -> NotificationHandle = NULL;
  800. InsertTail(&LogicalDeviceList, listNode);
  801. vLoadDevices(GetDlgItem(hDlg, IDC_DEVICES));
  802. }
  803. else
  804. {
  805. free(listNode);
  806. return (FALSE);
  807. }
  808. break;
  809. case IDC_ABOUT:
  810. MessageBox(hDlg,
  811. "Sample HID client Application. Microsoft Corp \nCopyright (C) 1997",
  812. "About HClient",
  813. MB_ICONINFORMATION);
  814. break;
  815. case IDOK:
  816. case IDCANCEL:
  817. //
  818. // Destroy the physical and logical device lists for exit
  819. //
  820. DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
  821. DestroyListWithCallback(&LogicalDeviceList, DestroyDeviceListCallback);
  822. EndDialog(hDlg,0);
  823. break;
  824. } //end switch wParam//
  825. break;
  826. //
  827. // For a device change message, we are only concerned about the
  828. // DBT_DEVICEREMOVECOMPLETE and DBT_DEVICEARRIVAL events. I have
  829. // yet to determine how to process the device change message
  830. // only for HID devices. Therefore, there are two problems
  831. // with the below implementation. First of all, we must reload
  832. // the device list any time a device is added to the system.
  833. // Secondly, at least two DEVICEARRIVAL messages are received
  834. // per HID. One corresponds to the physical device. The second
  835. // change and any more correspond to each collection on the
  836. // physical device so a system that has one HID device with
  837. // two top level collections (a keyboard and a mouse) will receive
  838. // three DEVICEARRIVAL/REMOVALs causing the program to reload it's
  839. // device list more than once.
  840. //
  841. //
  842. // To handle dynamic changing of devices, we have already registered
  843. // notification for both HID class changes and for notification
  844. // for our open file objects. Since we are only concerned about
  845. // arrival/removal of devices, we only need to process those wParam.
  846. // lParam points to some sort of DEV_BROADCAST_HDR struct. For device
  847. // arrival, we only deal with the message if that struct is a
  848. // DEV_BROADCAST_DEVICEINTERFACE structure. For device removal, we're
  849. // only concerned if the struct is a DEV_BROADCAST_HANDLE structure.
  850. //
  851. case WM_DEVICECHANGE:
  852. switch (wParam)
  853. {
  854. PDEV_BROADCAST_HDR broadcastHdr;
  855. case DBT_DEVICEARRIVAL:
  856. broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
  857. if (DBT_DEVTYP_DEVICEINTERFACE == broadcastHdr -> dbch_devicetype)
  858. {
  859. PDEV_BROADCAST_DEVICEINTERFACE broadcastInterface;
  860. PDEVICE_LIST_NODE currNode, lastNode;
  861. broadcastInterface = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
  862. //
  863. // Search for a previous instance of this device
  864. // in the device list...In some cases, multiple
  865. // messages are received for the same device. We
  866. // obviously only want one instance of the device
  867. // showing up in the dialog box.
  868. //
  869. if (!IsListEmpty(&PhysicalDeviceList))
  870. {
  871. currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
  872. lastNode = (PDEVICE_LIST_NODE) GetListTail(&PhysicalDeviceList);
  873. //
  874. // This loop should always terminate since the device
  875. // handle should be somewhere in the physical device list
  876. //
  877. while (1)
  878. {
  879. if (0 == strcmp(currNode -> HidDeviceInfo.DevicePath,
  880. broadcastInterface -> dbcc_name))
  881. {
  882. return (TRUE);
  883. }
  884. if (currNode == lastNode)
  885. {
  886. break;
  887. }
  888. currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
  889. }
  890. }
  891. //
  892. // In this structure, we are given the name of the device
  893. // to open. So all that needs to be done is open
  894. // a new hid device with the string
  895. //
  896. listNode = (PDEVICE_LIST_NODE) malloc(sizeof(DEVICE_LIST_NODE));
  897. if (NULL == listNode)
  898. {
  899. MessageBox(hDlg,
  900. "Error -- Couldn't allocate memory for new device list node",
  901. HCLIENT_ERROR,
  902. MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
  903. break;
  904. }
  905. //
  906. // Open the hid device for query access
  907. //
  908. if (!OpenHidDevice (broadcastInterface -> dbcc_name,
  909. FALSE,
  910. FALSE,
  911. FALSE,
  912. FALSE,
  913. TRUE,
  914. &(listNode -> HidDeviceInfo))) {
  915. MessageBox(hDlg,
  916. "Error -- Couldn't open HID device",
  917. HCLIENT_ERROR,
  918. MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
  919. free(listNode);
  920. break;
  921. }
  922. if (!RegisterHidDevice(hDlg, listNode))
  923. {
  924. MessageBox(hDlg,
  925. "Error -- Couldn't register handle notification",
  926. HCLIENT_ERROR,
  927. MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
  928. CloseHidDevice(&(listNode -> HidDeviceInfo), TRUE);
  929. free(listNode);
  930. break;
  931. }
  932. listNode -> DeviceOpened = TRUE;
  933. InsertTail(&PhysicalDeviceList, listNode);
  934. vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
  935. PostMessage(hDlg,
  936. WM_COMMAND,
  937. IDC_DEVICES + (CBN_SELCHANGE << 16),
  938. (LPARAM) GetDlgItem(hDlg,IDC_DEVICES));
  939. }
  940. break;
  941. case DBT_DEVICEQUERYREMOVE:
  942. //
  943. // If this message is received, the device is either
  944. // being disabled or removed through device manager.
  945. // To properly handle this request, we need to close
  946. // the handle to the device.
  947. //
  948. broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
  949. if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype)
  950. {
  951. PDEV_BROADCAST_HANDLE broadcastHandle;
  952. PDEVICE_LIST_NODE currNode;
  953. HANDLE deviceHandle;
  954. broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam;
  955. //
  956. // Get the file handle of the device that was removed
  957. // from the system
  958. //
  959. deviceHandle = (HANDLE) broadcastHandle -> dbch_handle;
  960. //
  961. // Search the physical device list for the handle that
  962. // was removed...
  963. //
  964. currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
  965. //
  966. // This loop should always terminate since the device
  967. // handle should be somewhere in the physical device list
  968. //
  969. while (currNode -> HidDeviceInfo.HidDevice != deviceHandle)
  970. {
  971. currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
  972. }
  973. CloseHidDevice(&(currNode -> HidDeviceInfo), TRUE);
  974. currNode -> DeviceOpened = FALSE;
  975. }
  976. return (TRUE);
  977. case DBT_DEVICEREMOVEPENDING:
  978. case DBT_DEVICEREMOVECOMPLETE:
  979. //
  980. // Do the same steps for DBT_DEVICEREMOVEPENDING and
  981. // DBT_DEVICEREMOVECOMPLETE. We do not receive the
  982. // remove complete request for a device if it is
  983. // disabled or removed via Device Manager. However,
  984. // in that case will receive the remove pending.
  985. // We remove the device from our currently displayed
  986. // list of devices and unregister notification.
  987. //
  988. broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
  989. if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype)
  990. {
  991. PDEV_BROADCAST_HANDLE broadcastHandle;
  992. PDEVICE_LIST_NODE currNode;
  993. HANDLE deviceHandle;
  994. broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam;
  995. //
  996. // Get the file handle of the device that was removed
  997. // from the system
  998. //
  999. deviceHandle = (HANDLE) broadcastHandle -> dbch_handle;
  1000. //
  1001. // Search the physical device list for the handle that
  1002. // was removed...
  1003. //
  1004. currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
  1005. //
  1006. // This loop should always terminate since the device
  1007. // handle should be somewhere in the physical device list
  1008. //
  1009. while (currNode -> HidDeviceInfo.HidDevice != deviceHandle)
  1010. {
  1011. currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
  1012. }
  1013. //
  1014. // Node in PhysicalDeviceList has been found, do:
  1015. // 1) Unregister notification
  1016. // 2) Close the hid device
  1017. // 3) Remove the entry from the list
  1018. // 4) Free the memory for the entry
  1019. //
  1020. //
  1021. PostMessage(hDlg,
  1022. WM_UNREGISTER_HANDLE,
  1023. 0,
  1024. (LPARAM) currNode -> NotificationHandle);
  1025. //
  1026. // Close the device if still opened...This would
  1027. // occur on surprise removal.
  1028. //
  1029. if (currNode -> DeviceOpened)
  1030. {
  1031. CloseHidDevice(&(currNode -> HidDeviceInfo), TRUE);
  1032. }
  1033. RemoveNode(currNode);
  1034. free(currNode);
  1035. //
  1036. // Reload the device list
  1037. //
  1038. vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
  1039. PostMessage(hDlg,
  1040. WM_COMMAND,
  1041. IDC_DEVICES + (CBN_SELCHANGE << 16),
  1042. (LPARAM) GetDlgItem(hDlg,IDC_DEVICES));
  1043. }
  1044. break;
  1045. default:
  1046. break;
  1047. }
  1048. break;
  1049. //
  1050. // Application specific message used to defer the unregistering of a
  1051. // file object for device change notification. This separte message
  1052. // is sent when a WM_DEVICECHANGE (DBT_DEVICEREMOVECOMPLETE) has been
  1053. // received. The Unregistering of the notification must be deferred
  1054. // until after the WM_DEVICECHANGE message has been processed or the
  1055. // system will deadlock. The handle that is to be freed will be passed
  1056. // in as lParam for this message
  1057. //
  1058. case WM_UNREGISTER_HANDLE:
  1059. UnregisterDeviceNotification ( (HDEVNOTIFY) lParam );
  1060. break;
  1061. } // end switch message
  1062. return FALSE;
  1063. } // end MainDlgProc
  1064. BOOL
  1065. bParseData(
  1066. PHID_DATA pData,
  1067. rWriteDataStruct rWriteData[],
  1068. int iCount,
  1069. int *piErrorLine
  1070. )
  1071. {
  1072. INT iCap;
  1073. PHID_DATA pWalk;
  1074. BOOL noError = TRUE;
  1075. pWalk = pData;
  1076. for (iCap = 0; (iCap < iCount) && noError; iCap++)
  1077. {
  1078. //
  1079. // Check to see if our data is a value cap or not
  1080. //
  1081. if (!pWalk->IsButtonData)
  1082. {
  1083. pWalk -> ValueData.Value = atol(rWriteData[iCap].szValue);
  1084. }
  1085. else
  1086. {
  1087. if (!bSetButtonUsages(pWalk, rWriteData[iCap].szValue) )
  1088. {
  1089. *piErrorLine = iCap;
  1090. noError = FALSE;
  1091. }
  1092. }
  1093. pWalk++;
  1094. }
  1095. return (noError);
  1096. }
  1097. BOOL
  1098. bSetButtonUsages(
  1099. PHID_DATA pCap,
  1100. PCHAR pszInputString
  1101. )
  1102. {
  1103. CHAR szTempString[128];
  1104. CHAR pszDelimiter[] = " ";
  1105. PCHAR pszToken;
  1106. INT iLoop;
  1107. PUSAGE pUsageWalk;
  1108. BOOL bNoError=TRUE;
  1109. strcpy(szTempString, pszInputString);
  1110. pszToken = strtok(szTempString, pszDelimiter);
  1111. pUsageWalk = pCap -> ButtonData.Usages;
  1112. memset(pUsageWalk, 0, pCap->ButtonData.MaxUsageLength * sizeof(USAGE));
  1113. for (iLoop = 0; ((ULONG) iLoop < pCap->ButtonData.MaxUsageLength) && (pszToken != NULL) && bNoError; iLoop++)
  1114. {
  1115. *pUsageWalk = (USAGE) atoi(pszToken);
  1116. pszToken = strtok(NULL, pszDelimiter);
  1117. pUsageWalk++;
  1118. }
  1119. return bNoError;
  1120. } //end function bSetButtonUsages//
  1121. INT
  1122. iPrepareDataFields(
  1123. PHID_DATA pData,
  1124. ULONG ulDataLength,
  1125. rWriteDataStruct rWriteData[],
  1126. int iMaxElements
  1127. )
  1128. {
  1129. INT i;
  1130. PHID_DATA pWalk;
  1131. pWalk = pData;
  1132. for (i = 0; (i < iMaxElements) && ((unsigned) i < ulDataLength); i++)
  1133. {
  1134. if (!pWalk->IsButtonData)
  1135. {
  1136. wsprintf(rWriteData[i].szLabel,
  1137. "ValueCap; ReportID: 0x%x, UsagePage=0x%x, Usage=0x%x",
  1138. pWalk->ReportID,
  1139. pWalk->UsagePage,
  1140. pWalk->ValueData.Usage);
  1141. }
  1142. else
  1143. {
  1144. wsprintf(rWriteData[i].szLabel,
  1145. "Button; ReportID: 0x%x, UsagePage=0x%x, UsageMin: 0x%x, UsageMax: 0x%x",
  1146. pWalk->ReportID,
  1147. pWalk->UsagePage,
  1148. pWalk->ButtonData.UsageMin,
  1149. pWalk->ButtonData.UsageMax);
  1150. }
  1151. pWalk++;
  1152. }
  1153. return i;
  1154. } //end function iPrepareDataFields//
  1155. INT_PTR CALLBACK
  1156. bReadDlgProc(
  1157. HWND hDlg,
  1158. UINT message,
  1159. WPARAM wParam,
  1160. LPARAM lParam
  1161. )
  1162. {
  1163. static INT iLbCounter;
  1164. static CHAR szTempBuff[1024];
  1165. static READ_THREAD_CONTEXT readContext;
  1166. static HANDLE readThread;
  1167. static HID_DEVICE syncDevice;
  1168. static HID_DEVICE asyncDevice;
  1169. static BOOL doAsyncReads;
  1170. static BOOL doSyncReads;
  1171. PHID_DEVICE pDevice;
  1172. DWORD threadID;
  1173. INT iIndex;
  1174. PHID_DATA pData;
  1175. UINT uLoop;
  1176. switch(message)
  1177. {
  1178. case WM_INITDIALOG:
  1179. //
  1180. // Initialize the list box counter, the readThread, and the
  1181. // readContext.DisplayEvent.
  1182. //
  1183. iLbCounter = 0;
  1184. readThread = NULL;
  1185. readContext.DisplayEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1186. if (NULL == readContext.DisplayEvent)
  1187. {
  1188. EndDialog(hDlg, 0);
  1189. }
  1190. //
  1191. // Get the opened device information for the device to perform
  1192. // reads upon
  1193. //
  1194. pDevice = (PHID_DEVICE) lParam;
  1195. //
  1196. // To do sync and async reads requires file handles with different
  1197. // attributes (ie. an async must be opened with the OVERLAPPED flag
  1198. // set). The device node that was passed in the context parameter
  1199. // was not opened for reading. Therefore, two more devices will
  1200. // be opened, one for async reads and one for sync reads.
  1201. //
  1202. memcpy(&syncDevice, pDevice, sizeof(HID_DEVICE));
  1203. doSyncReads = OpenHidDevice(pDevice -> DevicePath,
  1204. TRUE,
  1205. FALSE,
  1206. FALSE,
  1207. FALSE,
  1208. FALSE,
  1209. &syncDevice);
  1210. if (!doSyncReads)
  1211. {
  1212. MessageBox(hDlg,
  1213. "Unable to open device for synchronous reading",
  1214. HCLIENT_ERROR,
  1215. MB_ICONEXCLAMATION);
  1216. }
  1217. //
  1218. // For asynchronous read, default to using the same information
  1219. // passed in as the lParam. This is because data related to
  1220. // Ppd and such cannot be retrieved using the standard HidD_
  1221. // functions. However, it is necessary to parse future reports.
  1222. //
  1223. memcpy(&asyncDevice, pDevice, sizeof(HID_DEVICE));
  1224. doAsyncReads = OpenHidDevice(pDevice -> DevicePath,
  1225. TRUE,
  1226. FALSE,
  1227. TRUE,
  1228. FALSE,
  1229. FALSE,
  1230. &asyncDevice);
  1231. if (!doAsyncReads)
  1232. {
  1233. MessageBox(hDlg,
  1234. "Unable to open device for asynchronous reading",
  1235. HCLIENT_ERROR,
  1236. MB_ICONEXCLAMATION);
  1237. }
  1238. PostMessage(hDlg, WM_READ_DONE, 0, 0);
  1239. break;
  1240. case WM_DISPLAY_READ_DATA:
  1241. //
  1242. // LParam is the device that was read from
  1243. //
  1244. pDevice = (PHID_DEVICE) lParam;
  1245. //
  1246. // Display all the data stored in the Input data field for the device
  1247. //
  1248. pData = pDevice -> InputData;
  1249. SendDlgItemMessage(hDlg,
  1250. IDC_OUTPUT,
  1251. LB_ADDSTRING,
  1252. 0,
  1253. (LPARAM)"-------------------------------------------");
  1254. iLbCounter++;
  1255. if (iLbCounter > MAX_LB_ITEMS)
  1256. {
  1257. SendDlgItemMessage(hDlg,
  1258. IDC_OUTPUT,
  1259. LB_DELETESTRING,
  1260. 0,
  1261. 0);
  1262. }
  1263. for (uLoop = 0; uLoop < pDevice->InputDataLength; uLoop++)
  1264. {
  1265. ReportToString(pData, szTempBuff);
  1266. iIndex = (INT) SendDlgItemMessage(hDlg,
  1267. IDC_OUTPUT,
  1268. LB_ADDSTRING,
  1269. 0,
  1270. (LPARAM) szTempBuff);
  1271. SendDlgItemMessage(hDlg,
  1272. IDC_OUTPUT,
  1273. LB_SETCURSEL,
  1274. iIndex,
  1275. 0);
  1276. iLbCounter++;
  1277. if (iLbCounter > MAX_LB_ITEMS)
  1278. {
  1279. SendDlgItemMessage(hDlg,
  1280. IDC_OUTPUT,
  1281. LB_DELETESTRING,
  1282. 0,
  1283. 0);
  1284. }
  1285. pData++;
  1286. }
  1287. SetEvent( readContext.DisplayEvent );
  1288. break;
  1289. case WM_READ_DONE:
  1290. EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
  1291. EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), doSyncReads);
  1292. EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), doAsyncReads);
  1293. EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), doAsyncReads);
  1294. SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE),
  1295. "One Asynchronous Read");
  1296. SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT),
  1297. "Continuous Asynchronous Read");
  1298. readThread = NULL;
  1299. break;
  1300. case WM_COMMAND:
  1301. switch(LOWORD(wParam))
  1302. {
  1303. case IDC_READ_SYNCH:
  1304. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1305. EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), FALSE);
  1306. EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), FALSE);
  1307. EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), FALSE);
  1308. Read(&syncDevice);
  1309. PostMessage(hDlg, WM_DISPLAY_READ_DATA, 0, (LPARAM) &syncDevice);
  1310. PostMessage(hDlg, WM_READ_DONE, 0, 0);
  1311. break;
  1312. case IDC_READ_ASYNCH_ONCE:
  1313. case IDC_READ_ASYNCH_CONT:
  1314. //
  1315. // When these buttons are pushed there are two options:
  1316. // 1) Start a new asynch read thread (readThread == NULL)
  1317. // 2) Stop a previous asych read thread
  1318. //
  1319. if (NULL == readThread)
  1320. {
  1321. //
  1322. // Start a new read thread
  1323. //
  1324. readContext.HidDevice = &asyncDevice;
  1325. readContext.TerminateThread = FALSE;
  1326. readContext.DoOneRead = (IDC_READ_ASYNCH_ONCE == LOWORD(wParam));
  1327. readContext.DisplayWindow = hDlg;
  1328. readThread = CreateThread( NULL,
  1329. 0,
  1330. AsynchReadThreadProc,
  1331. &readContext,
  1332. 0,
  1333. &threadID);
  1334. if (NULL == readThread)
  1335. {
  1336. MessageBox(hDlg,
  1337. "Unable to create read thread",
  1338. HCLIENT_ERROR,
  1339. MB_ICONEXCLAMATION);
  1340. }
  1341. else
  1342. {
  1343. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1344. EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), FALSE);
  1345. EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE),
  1346. IDC_READ_ASYNCH_ONCE == LOWORD(wParam));
  1347. EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT),
  1348. IDC_READ_ASYNCH_CONT == LOWORD(wParam));
  1349. SetWindowText(GetDlgItem(hDlg, LOWORD(wParam)),
  1350. "Stop Asynchronous Read");
  1351. }
  1352. }
  1353. else
  1354. {
  1355. //
  1356. // Signal the terminate thread variable and
  1357. // wait for the read thread to complete.
  1358. //
  1359. readContext.TerminateThread = TRUE;
  1360. WaitForSingleObject(readThread, INFINITE);
  1361. }
  1362. break;
  1363. case IDOK:
  1364. case IDCANCEL:
  1365. if (doAsyncReads)
  1366. {
  1367. CloseHidDevice(&asyncDevice, FALSE);
  1368. }
  1369. if (doSyncReads)
  1370. {
  1371. CloseHidDevice(&syncDevice, FALSE);
  1372. }
  1373. EndDialog(hDlg,0);
  1374. break;
  1375. }
  1376. break;
  1377. } // end switch message
  1378. return FALSE;
  1379. } // end bReadDlgProc
  1380. VOID
  1381. ReportToString(
  1382. PHID_DATA pData,
  1383. PCHAR szBuff
  1384. )
  1385. {
  1386. PCHAR pszWalk;
  1387. PUSAGE pUsage;
  1388. ULONG i;
  1389. //
  1390. // For button data, all the usages in the usage list are to be displayed
  1391. //
  1392. if (pData -> IsButtonData)
  1393. {
  1394. wsprintf (szBuff,
  1395. "Usage Page: 0x%x, Usages: ",
  1396. pData -> UsagePage);
  1397. pszWalk = szBuff + strlen(szBuff);
  1398. *pszWalk = '\0';
  1399. for (i = 0, pUsage = pData -> ButtonData.Usages;
  1400. i < pData -> ButtonData.MaxUsageLength;
  1401. i++, pUsage++)
  1402. {
  1403. if (0 == *pUsage)
  1404. {
  1405. break; // A usage of zero is a non button.
  1406. }
  1407. pszWalk += wsprintf (pszWalk, " 0x%x", *pUsage);
  1408. }
  1409. }
  1410. else
  1411. {
  1412. wsprintf (szBuff,
  1413. "Usage Page: 0x%x, Usage: 0x%x, Scaled: %d Value: %d",
  1414. pData->UsagePage,
  1415. pData->ValueData.Usage,
  1416. pData->ValueData.ScaledValue,
  1417. pData->ValueData.Value);
  1418. }
  1419. }
  1420. INT_PTR CALLBACK
  1421. bFeatureDlgProc(
  1422. HWND hDlg,
  1423. UINT message,
  1424. WPARAM wParam,
  1425. LPARAM lParam
  1426. )
  1427. {
  1428. static PHID_DEVICE pDevice;
  1429. static INT iLbCounter;
  1430. static rWriteDataStruct rWriteData[MAX_WRITE_ELEMENTS];
  1431. static CHAR szTempBuff[1024];
  1432. INT iIndex;
  1433. INT iCount;
  1434. INT iErrorLine;
  1435. PHID_DATA pData;
  1436. UINT uLoop;
  1437. switch(message)
  1438. {
  1439. case WM_INITDIALOG:
  1440. iLbCounter = 0;
  1441. pDevice = (PHID_DEVICE) lParam;
  1442. break;
  1443. case WM_COMMAND:
  1444. switch(LOWORD(wParam))
  1445. {
  1446. case IDC_READ:
  1447. GetFeature(pDevice);
  1448. pData = pDevice -> FeatureData;
  1449. SendDlgItemMessage(hDlg,
  1450. IDC_OUTPUT,
  1451. LB_ADDSTRING,
  1452. 0,
  1453. (LPARAM)"------------ Read Features ---------------");
  1454. iLbCounter++;
  1455. if (iLbCounter > MAX_LB_ITEMS)
  1456. {
  1457. SendDlgItemMessage(hDlg,
  1458. IDC_OUTPUT,
  1459. LB_DELETESTRING,
  1460. 0,
  1461. 0);
  1462. }
  1463. for (uLoop = 0; uLoop < pDevice -> FeatureDataLength; uLoop++)
  1464. {
  1465. ReportToString(pData, szTempBuff);
  1466. iIndex = (INT) SendDlgItemMessage(hDlg,
  1467. IDC_OUTPUT,
  1468. LB_ADDSTRING,
  1469. 0,
  1470. (LPARAM) szTempBuff);
  1471. SendDlgItemMessage(hDlg,
  1472. IDC_OUTPUT,
  1473. LB_SETCURSEL,
  1474. iIndex,
  1475. (LPARAM) 0);
  1476. iLbCounter++;
  1477. if (iLbCounter > MAX_LB_ITEMS)
  1478. {
  1479. SendDlgItemMessage(hDlg,
  1480. IDC_OUTPUT,
  1481. LB_DELETESTRING,
  1482. 0,
  1483. 0);
  1484. }
  1485. pData++;
  1486. }
  1487. break;
  1488. case IDC_WRITE:
  1489. iCount = iPrepareDataFields(pDevice -> FeatureData,
  1490. pDevice -> FeatureDataLength,
  1491. rWriteData,
  1492. MAX_OUTPUT_ELEMENTS);
  1493. if (bGetData(rWriteData, iCount, hDlg, "WRITEFEATURE"))
  1494. {
  1495. if (!bParseData(pDevice -> FeatureData, rWriteData,iCount, &iErrorLine))
  1496. {
  1497. wsprintf(szTempBuff,
  1498. "Unable to parse line %x of output data",
  1499. iErrorLine);
  1500. MessageBox(hDlg,
  1501. szTempBuff,
  1502. HCLIENT_ERROR,
  1503. MB_ICONEXCLAMATION);
  1504. }
  1505. else
  1506. {
  1507. if ( SetFeature(pDevice) )
  1508. {
  1509. SendDlgItemMessage(hDlg,
  1510. IDC_OUTPUT,
  1511. LB_ADDSTRING,
  1512. 0,
  1513. (LPARAM)"------------ Write Feature ---------------");
  1514. }
  1515. else
  1516. {
  1517. SendDlgItemMessage(hDlg,
  1518. IDC_OUTPUT,
  1519. LB_ADDSTRING,
  1520. 0,
  1521. (LPARAM)"------------ Write Feature Error ---------------");
  1522. }
  1523. }
  1524. }
  1525. break;
  1526. case IDOK:
  1527. case IDCANCEL:
  1528. EndDialog(hDlg,0);
  1529. break;
  1530. }
  1531. break;
  1532. } //end switch message//
  1533. return FALSE;
  1534. } //end bReadDlgProc//
  1535. VOID
  1536. vDisplayDeviceCaps(
  1537. IN PHIDP_CAPS pCaps,
  1538. IN HWND hControl
  1539. )
  1540. {
  1541. static CHAR szTempBuff[128];
  1542. SendMessage(hControl, LB_RESETCONTENT, 0, 0);
  1543. wsprintf(szTempBuff, "Usage Page: 0x%x", pCaps -> UsagePage);
  1544. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1545. wsprintf(szTempBuff,"Usage: 0x%x",pCaps -> Usage);
  1546. SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1547. wsprintf(szTempBuff,"Input report byte length: %d",pCaps -> InputReportByteLength);
  1548. SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1549. wsprintf(szTempBuff,"Output report byte length: %d",pCaps -> OutputReportByteLength);
  1550. SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1551. wsprintf(szTempBuff,"Feature report byte length: %d",pCaps -> FeatureReportByteLength);
  1552. SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1553. wsprintf(szTempBuff,"Number of collection nodes %d: ", pCaps -> NumberLinkCollectionNodes);
  1554. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1555. return;
  1556. }
  1557. VOID
  1558. vDisplayDeviceAttributes(
  1559. PHIDD_ATTRIBUTES pAttrib,
  1560. HWND hControl
  1561. )
  1562. {
  1563. static CHAR szTempBuff[128];
  1564. wsprintf(szTempBuff, "Vendor ID: 0x%x", pAttrib -> VendorID);
  1565. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1566. wsprintf(szTempBuff, "Product ID: 0x%x", pAttrib -> ProductID);
  1567. SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
  1568. wsprintf(szTempBuff, "Version Number 0x%x", pAttrib -> VersionNumber);
  1569. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1570. return;
  1571. }
  1572. VOID
  1573. vDisplayDataAttributes(
  1574. PHIDP_DATA pData,
  1575. BOOL IsButton,
  1576. HWND hControl
  1577. )
  1578. {
  1579. static CHAR szTempBuff[128];
  1580. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "================");
  1581. wsprintf(szTempBuff, "Index: 0x%x", pData -> DataIndex);
  1582. SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1583. wsprintf(szTempBuff, "IsButton: %s", IsButton ? "TRUE" : "FALSE");
  1584. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1585. if (IsButton)
  1586. {
  1587. wsprintf(szTempBuff, "Button pressed: %s", pData -> On ? "TRUE" : "FALSE");
  1588. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1589. }
  1590. else
  1591. {
  1592. wsprintf(szTempBuff, "Data value: 0x%x", pData -> RawValue);
  1593. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1594. }
  1595. }
  1596. VOID
  1597. vDisplayButtonAttributes(
  1598. IN PHIDP_BUTTON_CAPS pButton,
  1599. IN HWND hControl
  1600. )
  1601. {
  1602. static CHAR szTempBuff[128];
  1603. wsprintf(szTempBuff, "Report ID: 0x%x", pButton->ReportID);
  1604. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1605. wsprintf(szTempBuff, "Usage Page: 0x%x", pButton->UsagePage);
  1606. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1607. wsprintf(szTempBuff,
  1608. "Alias: %s",
  1609. pButton -> IsAlias ? "TRUE" : "FALSE");
  1610. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1611. wsprintf(szTempBuff,
  1612. "Link Collection: %hu",
  1613. pButton -> LinkCollection);
  1614. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1615. wsprintf(szTempBuff,
  1616. "Link Usage Page: 0x%x",
  1617. pButton -> LinkUsagePage);
  1618. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1619. wsprintf(szTempBuff,
  1620. "Link Usage: 0x%x",
  1621. pButton -> LinkUsage);
  1622. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1623. if (pButton->IsRange)
  1624. {
  1625. wsprintf(szTempBuff,
  1626. "Usage Min: 0x%x, Usage Max: 0x%x",
  1627. pButton->Range.UsageMin,
  1628. pButton->Range.UsageMax);
  1629. }
  1630. else
  1631. {
  1632. wsprintf(szTempBuff,"Usage: 0x%x",pButton->NotRange.Usage);
  1633. }
  1634. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1635. if (pButton->IsRange)
  1636. {
  1637. wsprintf(szTempBuff,
  1638. "Data Index Min: 0x%x, Data Index Max: 0x%x",
  1639. pButton->Range.DataIndexMin,
  1640. pButton->Range.DataIndexMax);
  1641. }
  1642. else
  1643. {
  1644. wsprintf(szTempBuff,"DataIndex: 0x%x",pButton->NotRange.DataIndex);
  1645. }
  1646. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1647. if (pButton->IsStringRange)
  1648. {
  1649. wsprintf(szTempBuff,
  1650. "String Min: 0x%x, String Max: 0x%x",
  1651. pButton->Range.StringMin,
  1652. pButton->Range.StringMax);
  1653. }
  1654. else
  1655. {
  1656. wsprintf(szTempBuff,"String Index: 0x%x",pButton->NotRange.StringIndex);
  1657. }
  1658. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1659. if (pButton->IsDesignatorRange)
  1660. {
  1661. wsprintf(szTempBuff,
  1662. "Designator Min: 0x%x, Designator Max: 0x%x",
  1663. pButton->Range.DesignatorMin,
  1664. pButton->Range.DesignatorMax);
  1665. }
  1666. else
  1667. {
  1668. wsprintf(szTempBuff,
  1669. "Designator Index: 0x%x",
  1670. pButton->NotRange.DesignatorIndex);
  1671. }
  1672. SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
  1673. if (pButton->IsAbsolute)
  1674. {
  1675. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: Yes");
  1676. }
  1677. else
  1678. {
  1679. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: No");
  1680. }
  1681. return;
  1682. }
  1683. VOID
  1684. vDisplayValueAttributes(
  1685. IN PHIDP_VALUE_CAPS pValue,
  1686. HWND hControl
  1687. )
  1688. {
  1689. static CHAR szTempBuff[128];
  1690. wsprintf(szTempBuff, "Report ID 0x%x", pValue->ReportID);
  1691. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1692. wsprintf(szTempBuff, "Usage Page: 0x%x", pValue->UsagePage);
  1693. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1694. wsprintf(szTempBuff, "Bit size: 0x%x", pValue->BitSize);
  1695. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1696. wsprintf(szTempBuff, "Report Count: 0x%x", pValue->ReportCount);
  1697. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1698. wsprintf(szTempBuff, "Unit Exponent: 0x%x", pValue->UnitsExp);
  1699. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1700. wsprintf(szTempBuff, "Has Null: 0x%x", pValue->HasNull);
  1701. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1702. if (pValue->IsAlias)
  1703. {
  1704. wsprintf(szTempBuff, "Alias");
  1705. }
  1706. else
  1707. {
  1708. wsprintf(szTempBuff, "=====");
  1709. }
  1710. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1711. if (pValue->IsRange)
  1712. {
  1713. wsprintf(szTempBuff,
  1714. "Usage Min: 0x%x, Usage Max 0x%x",
  1715. pValue->Range.UsageMin,
  1716. pValue->Range.UsageMax);
  1717. }
  1718. else
  1719. {
  1720. wsprintf(szTempBuff, "Usage: 0x%x", pValue -> NotRange.Usage);
  1721. }
  1722. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1723. if (pValue->IsRange)
  1724. {
  1725. wsprintf(szTempBuff,
  1726. "Data Index Min: 0x%x, Data Index Max: 0x%x",
  1727. pValue->Range.DataIndexMin,
  1728. pValue->Range.DataIndexMax);
  1729. }
  1730. else
  1731. {
  1732. wsprintf(szTempBuff, "DataIndex: 0x%x", pValue->NotRange.DataIndex);
  1733. }
  1734. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1735. wsprintf(szTempBuff,
  1736. "Physical Minimum: %d, Physical Maximum: %d",
  1737. pValue->PhysicalMin,
  1738. pValue->PhysicalMax);
  1739. SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
  1740. wsprintf(szTempBuff,
  1741. "Logical Minimum: 0x%x, Logical Maximum: 0x%x",
  1742. pValue->LogicalMin,
  1743. pValue->LogicalMax);
  1744. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1745. if (pValue->IsStringRange)
  1746. {
  1747. wsprintf(szTempBuff,
  1748. "String Min: 0x%x String Max 0x%x",
  1749. pValue->Range.StringMin,
  1750. pValue->Range.StringMax);
  1751. }
  1752. else
  1753. {
  1754. wsprintf(szTempBuff,"String Index: 0x%x",pValue->NotRange.StringIndex);
  1755. }
  1756. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1757. if (pValue->IsDesignatorRange)
  1758. {
  1759. wsprintf(szTempBuff,
  1760. "Designator Minimum: 0x%x, Max: 0x%x",
  1761. pValue->Range.DesignatorMin,
  1762. pValue->Range.DesignatorMax);
  1763. }
  1764. else
  1765. {
  1766. wsprintf(szTempBuff,"Designator Index: 0x%x",pValue->NotRange.DesignatorIndex);
  1767. }
  1768. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1769. if (pValue->IsAbsolute)
  1770. {
  1771. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: Yes");
  1772. }
  1773. else
  1774. {
  1775. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: No");
  1776. }
  1777. return;
  1778. }
  1779. VOID
  1780. vDisplayInputButtons(
  1781. IN PHID_DEVICE pDevice,
  1782. IN HWND hControl
  1783. )
  1784. {
  1785. INT iLoop;
  1786. PHIDP_BUTTON_CAPS pButtonCaps;
  1787. static CHAR szTempBuff[128];
  1788. INT iIndex;
  1789. SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0);
  1790. pButtonCaps = pDevice->InputButtonCaps;
  1791. for (iLoop = 0; iLoop < pDevice->Caps.NumberInputButtonCaps; iLoop++)
  1792. {
  1793. wsprintf(szTempBuff, "Input button cap # %d", iLoop);
  1794. iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1795. if (-1 != iIndex)
  1796. {
  1797. SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pButtonCaps);
  1798. }
  1799. pButtonCaps++;
  1800. }
  1801. SendMessage(hControl, LB_SETCURSEL, 0, 0 );
  1802. }
  1803. VOID
  1804. vDisplayOutputButtons(
  1805. IN PHID_DEVICE pDevice,
  1806. IN HWND hControl
  1807. )
  1808. {
  1809. INT iLoop;
  1810. static CHAR szTempBuff[128];
  1811. INT iIndex;
  1812. PHIDP_BUTTON_CAPS pButtonCaps;
  1813. SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0);
  1814. pButtonCaps = pDevice -> OutputButtonCaps;
  1815. for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputButtonCaps; iLoop++)
  1816. {
  1817. wsprintf(szTempBuff, "Output button cap # %d", iLoop);
  1818. iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1819. if (-1 != iIndex)
  1820. {
  1821. SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps);
  1822. }
  1823. pButtonCaps++;
  1824. }
  1825. SendMessage(hControl, LB_SETCURSEL, 0, 0);
  1826. return;
  1827. }
  1828. VOID
  1829. vDisplayInputValues(
  1830. IN PHID_DEVICE pDevice,
  1831. IN HWND hControl
  1832. )
  1833. {
  1834. INT iLoop;
  1835. static CHAR szTempBuff[128];
  1836. INT iIndex;
  1837. PHIDP_VALUE_CAPS pValueCaps;
  1838. SendMessage(hControl, LB_RESETCONTENT, 0, 0);
  1839. pValueCaps = pDevice -> InputValueCaps;
  1840. for (iLoop=0; iLoop < pDevice->Caps.NumberInputValueCaps; iLoop++)
  1841. {
  1842. wsprintf(szTempBuff,"Input value cap # %d",iLoop);
  1843. iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1844. if (-1 != iIndex)
  1845. {
  1846. SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pValueCaps);
  1847. }
  1848. pValueCaps++;
  1849. }
  1850. SendMessage(hControl, LB_SETCURSEL, 0, 0);
  1851. return;
  1852. }
  1853. VOID
  1854. vDisplayOutputValues(
  1855. IN PHID_DEVICE pDevice,
  1856. IN HWND hControl)
  1857. {
  1858. INT iLoop;
  1859. static CHAR szTempBuff[128];
  1860. INT iIndex;
  1861. PHIDP_VALUE_CAPS pValueCaps;
  1862. SendMessage(hControl, LB_RESETCONTENT, 0, 0);
  1863. pValueCaps = pDevice -> OutputValueCaps;
  1864. for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputValueCaps; iLoop++)
  1865. {
  1866. wsprintf(szTempBuff, "Output value cap # %d", iLoop);
  1867. iIndex = (INT) SendMessage(hControl,
  1868. LB_ADDSTRING,
  1869. 0,
  1870. (LPARAM) szTempBuff);
  1871. if (-1 != iIndex)
  1872. {
  1873. SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps);
  1874. }
  1875. pValueCaps++;
  1876. }
  1877. SendMessage(hControl, LB_SETCURSEL, 0, 0);
  1878. return;
  1879. }
  1880. VOID
  1881. vDisplayFeatureButtons(
  1882. IN PHID_DEVICE pDevice,
  1883. IN HWND hControl
  1884. )
  1885. {
  1886. INT iLoop;
  1887. static CHAR szTempBuff[128];
  1888. INT iIndex;
  1889. PHIDP_BUTTON_CAPS pButtonCaps;
  1890. SendMessage(hControl, LB_RESETCONTENT, 0, 0);
  1891. pButtonCaps = pDevice -> FeatureButtonCaps;
  1892. for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureButtonCaps; iLoop++)
  1893. {
  1894. wsprintf(szTempBuff, "Feature button cap # %d", iLoop);
  1895. iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1896. if (-1 != iIndex)
  1897. {
  1898. SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps);
  1899. }
  1900. pButtonCaps++;
  1901. }
  1902. SendMessage(hControl, LB_SETCURSEL, 0, 0);
  1903. return;
  1904. }
  1905. VOID
  1906. vDisplayFeatureValues(
  1907. IN PHID_DEVICE pDevice,
  1908. IN HWND hControl
  1909. )
  1910. {
  1911. INT iLoop;
  1912. static CHAR szTempBuff[128];
  1913. INT iIndex;
  1914. PHIDP_VALUE_CAPS pValueCaps;
  1915. SendMessage(hControl, LB_RESETCONTENT, 0, 0);
  1916. pValueCaps = pDevice ->FeatureValueCaps;
  1917. for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureValueCaps; iLoop++)
  1918. {
  1919. wsprintf(szTempBuff, "Feature value cap # %d", iLoop);
  1920. iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  1921. if (-1 != iIndex)
  1922. {
  1923. SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps);
  1924. }
  1925. pValueCaps++;
  1926. }
  1927. SendMessage(hControl, LB_SETCURSEL, 0, 0);
  1928. return;
  1929. }
  1930. VOID
  1931. vLoadItemTypes(
  1932. IN HWND hItemTypes
  1933. )
  1934. {
  1935. INT iIndex;
  1936. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "INPUT BUTTON");
  1937. if (-1 != iIndex)
  1938. {
  1939. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_BUTTON);
  1940. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0 ,(LPARAM) "INPUT VALUE");
  1941. if (-1 != iIndex)
  1942. {
  1943. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_VALUE);
  1944. }
  1945. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT BUTTON");
  1946. if (-1 != iIndex)
  1947. {
  1948. SendMessage(hItemTypes,CB_SETITEMDATA,iIndex,OUTPUT_BUTTON);
  1949. }
  1950. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT VALUE");
  1951. if (-1 != iIndex)
  1952. {
  1953. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, OUTPUT_VALUE);
  1954. }
  1955. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE BUTTON");
  1956. if (-1 != iIndex)
  1957. {
  1958. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_BUTTON);
  1959. }
  1960. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE VALUE");
  1961. if (-1 != iIndex)
  1962. {
  1963. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_VALUE);
  1964. }
  1965. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "HID CAPS");
  1966. if (-1 != iIndex )
  1967. {
  1968. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, HID_CAPS);
  1969. }
  1970. iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "DEVICE ATTRIBUTES");
  1971. if (-1 != iIndex)
  1972. {
  1973. SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, DEVICE_ATTRIBUTES);
  1974. }
  1975. SendMessage(hItemTypes, CB_SETCURSEL, 0, 0);
  1976. }
  1977. }
  1978. VOID vLoadDevices(
  1979. HWND hDeviceCombo
  1980. )
  1981. {
  1982. PDEVICE_LIST_NODE currNode;
  1983. static CHAR szTempBuff[128];
  1984. INT iIndex;
  1985. //
  1986. // Reset the content of the device list box.
  1987. //
  1988. SendMessage(hDeviceCombo, CB_RESETCONTENT, 0, 0);
  1989. if (!IsListEmpty(&PhysicalDeviceList))
  1990. {
  1991. currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
  1992. do
  1993. {
  1994. wsprintf(szTempBuff,
  1995. "Device %d, UsagePage 0%x, Usage 0%x",
  1996. currNode -> HidDeviceInfo.HidDevice,
  1997. currNode -> HidDeviceInfo.Caps.UsagePage,
  1998. currNode -> HidDeviceInfo.Caps.Usage);
  1999. iIndex = (INT) SendMessage(hDeviceCombo, CB_ADDSTRING, 0, (LPARAM) szTempBuff);
  2000. if (CB_ERR != iIndex)
  2001. {
  2002. SendMessage(hDeviceCombo, CB_SETITEMDATA, iIndex, (LPARAM) &(currNode -> HidDeviceInfo));
  2003. }
  2004. currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
  2005. } while ((PLIST) currNode != &PhysicalDeviceList);
  2006. }
  2007. //
  2008. // Now we need to load any logical devices that might currently be in our
  2009. // logical device list
  2010. //
  2011. if (!IsListEmpty(&LogicalDeviceList))
  2012. {
  2013. currNode = (PDEVICE_LIST_NODE) GetListHead(&LogicalDeviceList);
  2014. do
  2015. {
  2016. wsprintf(szTempBuff,
  2017. "Device: Logical, UsagePage 0%x, Usage 0%x",
  2018. currNode -> HidDeviceInfo.Caps.UsagePage,
  2019. currNode -> HidDeviceInfo.Caps.Usage);
  2020. iIndex = (INT) SendMessage(hDeviceCombo, CB_ADDSTRING, 0, (LPARAM) szTempBuff);
  2021. if (CB_ERR != iIndex)
  2022. {
  2023. SendMessage(hDeviceCombo, CB_SETITEMDATA, iIndex, (LPARAM) &(currNode -> HidDeviceInfo));
  2024. }
  2025. currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
  2026. } while ((PLIST) currNode != &LogicalDeviceList);
  2027. }
  2028. SendMessage(hDeviceCombo, CB_SETCURSEL, 0, 0);
  2029. return;
  2030. }
  2031. BOOL
  2032. bGetData(
  2033. prWriteDataStruct pItems,
  2034. INT iCount,
  2035. HWND hParent,
  2036. PCHAR pszDialogName
  2037. )
  2038. {
  2039. rGetWriteDataParams rParams;
  2040. rWriteDataStruct arTempItems[MAX_WRITE_ELEMENTS];
  2041. INT iResult;
  2042. if (iCount > MAX_WRITE_ELEMENTS)
  2043. {
  2044. iCount = MAX_WRITE_ELEMENTS;
  2045. }
  2046. memcpy( &(arTempItems[0]), pItems, sizeof(rWriteDataStruct)*iCount);
  2047. rParams.iCount = iCount;
  2048. rParams.prItems = &(arTempItems[0]);
  2049. iResult = (INT) DialogBoxParam(hGInstance,
  2050. pszDialogName,
  2051. hParent,
  2052. bGetDataDlgProc,
  2053. (LPARAM) &rParams);
  2054. if (iResult)
  2055. {
  2056. memcpy(pItems, arTempItems, sizeof(rWriteDataStruct)*iCount);
  2057. }
  2058. return iResult;
  2059. }
  2060. INT_PTR CALLBACK
  2061. bGetDataDlgProc(
  2062. HWND hDlg,
  2063. UINT message,
  2064. WPARAM wParam,
  2065. LPARAM lParam
  2066. )
  2067. {
  2068. static prWriteDataStruct prData;
  2069. static prGetWriteDataParams pParams;
  2070. static INT iDisplayCount;
  2071. static INT iScrollRange;
  2072. static INT iCurrentScrollPos=0;
  2073. static HWND hScrollBar;
  2074. INT iTemp;
  2075. SCROLLINFO rScrollInfo;
  2076. INT iReturn;
  2077. switch(message)
  2078. {
  2079. case WM_INITDIALOG:
  2080. pParams = (prGetWriteDataParams) lParam;
  2081. prData = pParams -> prItems;
  2082. hScrollBar = GetDlgItem(hDlg, IDC_SCROLLBAR);
  2083. if (pParams -> iCount > CONTROL_COUNT)
  2084. {
  2085. iDisplayCount = CONTROL_COUNT;
  2086. iScrollRange = pParams -> iCount - CONTROL_COUNT;
  2087. rScrollInfo.fMask = SIF_RANGE | SIF_POS;
  2088. rScrollInfo.nPos = 0;
  2089. rScrollInfo.nMin = 0;
  2090. rScrollInfo.nMax = iScrollRange;
  2091. rScrollInfo.cbSize = sizeof(rScrollInfo);
  2092. rScrollInfo.nPage = CONTROL_COUNT;
  2093. iReturn = SetScrollInfo(hScrollBar,SB_CTL,&rScrollInfo,TRUE);
  2094. }
  2095. else
  2096. {
  2097. iDisplayCount=pParams->iCount;
  2098. EnableWindow(hScrollBar,FALSE);
  2099. }
  2100. vWriteDataToControls(hDlg, prData, 0, pParams->iCount);
  2101. break;
  2102. case WM_COMMAND:
  2103. switch(LOWORD(wParam))
  2104. {
  2105. case IDOK:
  2106. case ID_SEND:
  2107. vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
  2108. EndDialog(hDlg,1);
  2109. break;
  2110. case IDCANCEL:
  2111. EndDialog(hDlg,0);
  2112. break;
  2113. }
  2114. break;
  2115. case WM_VSCROLL:
  2116. vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
  2117. switch(LOWORD(wParam))
  2118. {
  2119. case SB_LINEDOWN:
  2120. ++iCurrentScrollPos;
  2121. break;
  2122. case SB_LINEUP:
  2123. --iCurrentScrollPos;
  2124. break;
  2125. case SB_THUMBPOSITION:
  2126. iCurrentScrollPos = HIWORD(wParam);
  2127. case SB_PAGEUP:
  2128. iCurrentScrollPos -= CONTROL_COUNT;
  2129. break;
  2130. case SB_PAGEDOWN:
  2131. iCurrentScrollPos += CONTROL_COUNT;
  2132. break;
  2133. }
  2134. if (iCurrentScrollPos < 0)
  2135. {
  2136. iCurrentScrollPos = 0;
  2137. }
  2138. if (iCurrentScrollPos > iScrollRange)
  2139. {
  2140. iCurrentScrollPos = iScrollRange;
  2141. }
  2142. SendMessage(hScrollBar, SBM_SETPOS, iCurrentScrollPos, TRUE);
  2143. iTemp = LOWORD(wParam);
  2144. if ( (iTemp == SB_LINEDOWN) || (iTemp == SB_LINEUP) || (iTemp == SB_THUMBPOSITION)|| (iTemp == SB_PAGEUP) || (iTemp==SB_PAGEDOWN) )
  2145. {
  2146. vWriteDataToControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
  2147. }
  2148. break;
  2149. }
  2150. return FALSE;
  2151. } //end function bGetDataDlgProc//
  2152. VOID
  2153. vReadDataFromControls(
  2154. HWND hDlg,
  2155. prWriteDataStruct prData,
  2156. INT iOffset,
  2157. INT iCount
  2158. )
  2159. {
  2160. INT iLoop;
  2161. INT iValueControlID = IDC_OUT_EDIT1;
  2162. prWriteDataStruct pDataWalk;
  2163. HWND hValueWnd;
  2164. pDataWalk = prData + iOffset;
  2165. for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++)
  2166. {
  2167. hValueWnd = GetDlgItem(hDlg, iValueControlID);
  2168. GetWindowText(hValueWnd, pDataWalk -> szValue, MAX_VALUE);
  2169. iValueControlID++;
  2170. pDataWalk++;
  2171. }
  2172. return;
  2173. }
  2174. VOID
  2175. vWriteDataToControls(
  2176. HWND hDlg,
  2177. prWriteDataStruct prData,
  2178. INT iOffset,
  2179. INT iCount
  2180. )
  2181. {
  2182. INT iLoop;
  2183. INT iLabelControlID = IDC_OUT_LABEL1;
  2184. INT iValueControlID = IDC_OUT_EDIT1;
  2185. HWND hLabelWnd, hValueWnd;
  2186. prWriteDataStruct pDataWalk;
  2187. pDataWalk = prData + iOffset;
  2188. for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++)
  2189. {
  2190. hLabelWnd = GetDlgItem(hDlg, iLabelControlID);
  2191. hValueWnd = GetDlgItem(hDlg, iValueControlID);
  2192. ShowWindow(hLabelWnd, SW_SHOW);
  2193. ShowWindow(hValueWnd, SW_SHOW);
  2194. SetWindowText(hLabelWnd, pDataWalk -> szLabel);
  2195. SetWindowText(hValueWnd, pDataWalk -> szValue);
  2196. iLabelControlID++;
  2197. iValueControlID++;
  2198. pDataWalk++;
  2199. }
  2200. //
  2201. // Hide the controls
  2202. //
  2203. for (; iLoop < CONTROL_COUNT; iLoop++)
  2204. {
  2205. hLabelWnd = GetDlgItem(hDlg,iLabelControlID);
  2206. hValueWnd = GetDlgItem(hDlg,iValueControlID);
  2207. ShowWindow(hLabelWnd,SW_HIDE);
  2208. ShowWindow(hValueWnd,SW_HIDE);
  2209. iLabelControlID++;
  2210. iValueControlID++;
  2211. }
  2212. }
  2213. VOID
  2214. vCreateUsageString(
  2215. IN PUSAGE pUsageList,
  2216. OUT CHAR szString[]
  2217. )
  2218. {
  2219. wsprintf(szString,
  2220. "Usage: %#04x",
  2221. *pUsageList);
  2222. return;
  2223. }
  2224. VOID
  2225. vCreateUsageAndPageString(
  2226. IN PUSAGE_AND_PAGE pUsageList,
  2227. OUT CHAR szString[]
  2228. )
  2229. {
  2230. wsprintf(szString,
  2231. "Usage Page: %#04x Usage: %#04x",
  2232. pUsageList -> UsagePage,
  2233. pUsageList -> Usage);
  2234. return;
  2235. }
  2236. VOID
  2237. vDisplayLinkCollectionNode(
  2238. IN PHIDP_LINK_COLLECTION_NODE pLCNode,
  2239. IN ULONG ulLinkIndex,
  2240. IN HWND hControl
  2241. )
  2242. {
  2243. static CHAR szTempBuff[128];
  2244. wsprintf(szTempBuff, "Index: 0x%x", ulLinkIndex);
  2245. SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
  2246. wsprintf(szTempBuff, "Usage Page: 0x%x", pLCNode -> LinkUsagePage);
  2247. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM)szTempBuff);
  2248. wsprintf(szTempBuff, "Usage: 0x%x", pLCNode -> LinkUsage);
  2249. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
  2250. wsprintf(szTempBuff, "Parent Index: 0x%x", pLCNode -> Parent);
  2251. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
  2252. wsprintf(szTempBuff, "Number of Children: 0x%x", pLCNode -> NumberOfChildren);
  2253. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
  2254. wsprintf(szTempBuff, "Next Sibling: 0x%x", pLCNode -> NextSibling);
  2255. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
  2256. wsprintf(szTempBuff, "First Child: 0x%x", pLCNode -> FirstChild);
  2257. SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
  2258. return;
  2259. }
  2260. VOID
  2261. vCreateUsageValueStringFromArray(
  2262. PCHAR pBuffer,
  2263. USHORT BitSize,
  2264. USHORT UsageIndex,
  2265. CHAR szString[]
  2266. )
  2267. /*++
  2268. Routine Description:
  2269. Given a report buffer, pBuffer, this routine extracts the given usage
  2270. at UsageIndex from the array and outputs to szString the string
  2271. representation of that value. The input parameter BitSize specifies
  2272. the number of bits representing that value in the array. This is
  2273. useful for extracting individual members of a UsageValueArray.
  2274. --*/
  2275. {
  2276. INT iByteIndex;
  2277. INT iByteOffset;
  2278. UCHAR ucLeftoverBits;
  2279. ULONG ulMask;
  2280. ULONG ulValue;
  2281. //
  2282. // Calculate the byte and byte offset into the buffer for the given
  2283. // index value
  2284. //
  2285. iByteIndex = (UsageIndex * BitSize) >> 3;
  2286. iByteOffset = (UsageIndex * BitSize) & 7;
  2287. //
  2288. // Extract the 32-bit value beginning at ByteIndex. This value
  2289. // will contain some or all of the value we are attempting to retrieve
  2290. //
  2291. ulValue = *(PULONG) (pBuffer + iByteIndex);
  2292. //
  2293. // Shift that value to the right by our byte offset..
  2294. //
  2295. ulValue = ulValue >> iByteOffset;
  2296. //
  2297. // At this point, ulValue contains the first 32-iByteOffset bits beginning
  2298. // the appropriate offset in the buffer. There are now two cases to
  2299. // look at:
  2300. //
  2301. // 1) BitSize > 32-iByteOffset -- In which case, we need to extract
  2302. // iByteOffset bits from the next
  2303. // byte in the array and OR them as
  2304. // the MSBs of ulValue
  2305. //
  2306. // 2) BitSize < 32-iByteOffset -- Need to get only the BitSize LSBs
  2307. //
  2308. //
  2309. //
  2310. // Case #1
  2311. //
  2312. if (BitSize > sizeof(ULONG)*8 - iByteOffset)
  2313. {
  2314. //
  2315. // Get the next byte of the report following the four bytes we
  2316. // retrieved earlier for ulValue
  2317. //
  2318. ucLeftoverBits = *(pBuffer+iByteIndex+4);
  2319. //
  2320. // Shift those bits to the left for anding to our previous value
  2321. //
  2322. ulMask = ucLeftoverBits << (24 + (8 - iByteOffset));
  2323. ulValue |= ulMask;
  2324. }
  2325. else if (BitSize < sizeof(ULONG)*8 - iByteOffset)
  2326. {
  2327. //
  2328. // Need to mask the most significant bits that are part of another
  2329. // value(s), not the one we are currently working with.
  2330. //
  2331. ulMask = (1 << BitSize) - 1;
  2332. ulValue &= ulMask;
  2333. }
  2334. //
  2335. // We've now got the correct value, now output to the string
  2336. //
  2337. wsprintf(szString, "Usage value: %lu", ulValue);
  2338. return;
  2339. }
  2340. BOOL
  2341. RegisterHidDevice(
  2342. IN HWND WindowHandle,
  2343. IN PDEVICE_LIST_NODE DeviceNode
  2344. )
  2345. {
  2346. DEV_BROADCAST_HANDLE broadcastHandle;
  2347. broadcastHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  2348. broadcastHandle.dbch_devicetype = DBT_DEVTYP_HANDLE;
  2349. broadcastHandle.dbch_handle = DeviceNode -> HidDeviceInfo.HidDevice;
  2350. DeviceNode -> NotificationHandle = RegisterDeviceNotification(
  2351. WindowHandle,
  2352. &broadcastHandle,
  2353. DEVICE_NOTIFY_WINDOW_HANDLE);
  2354. return (NULL != DeviceNode -> NotificationHandle);
  2355. }
  2356. VOID
  2357. DestroyDeviceListCallback(
  2358. PLIST_NODE_HDR ListNode
  2359. )
  2360. {
  2361. PDEVICE_LIST_NODE deviceNode;
  2362. deviceNode = (PDEVICE_LIST_NODE) ListNode;
  2363. //
  2364. // The callback function needs to do the following steps...
  2365. // 1) Close the HidDevice
  2366. // 2) Unregister device notification (if registered)
  2367. // 3) Free the allocated memory block
  2368. //
  2369. CloseHidDevice(&(deviceNode -> HidDeviceInfo), TRUE);
  2370. if (NULL != deviceNode -> NotificationHandle)
  2371. {
  2372. UnregisterDeviceNotification(deviceNode -> NotificationHandle);
  2373. }
  2374. free (deviceNode);
  2375. return;
  2376. }
  2377. DWORD WINAPI
  2378. AsynchReadThreadProc(
  2379. PREAD_THREAD_CONTEXT Context
  2380. )
  2381. {
  2382. HANDLE completionEvent;
  2383. BOOL readStatus;
  2384. DWORD waitStatus;
  2385. //
  2386. // Create the completion event to send to the the OverlappedRead routine
  2387. //
  2388. completionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2389. //
  2390. // If NULL returned, then we cannot proceed any farther so we just exit the
  2391. // the thread
  2392. //
  2393. if (NULL == completionEvent)
  2394. {
  2395. goto AsyncRead_End;
  2396. }
  2397. //
  2398. // Now we enter the main read loop, which does the following:
  2399. // 1) Calls ReadOverlapped()
  2400. // 2) Waits for read completion with a timeout just to check if
  2401. // the main thread wants us to terminate our the read request
  2402. // 3) If the read fails, we simply break out of the loop
  2403. // and exit the thread
  2404. // 4) If the read succeeds, we call UnpackReport to get the relevant
  2405. // info and then post a message to main thread to indicate that
  2406. // there is new data to display.
  2407. // 5) We then block on the display event until the main thread says
  2408. // it has properly displayed the new data
  2409. // 6) Look to repeat this loop if we are doing more than one read
  2410. // and the main thread has yet to want us to terminate
  2411. //
  2412. do
  2413. {
  2414. //
  2415. // Call ReadOverlapped() and if the return status is TRUE, the ReadFile
  2416. // succeeded so we need to block on completionEvent, otherwise, we just
  2417. // exit
  2418. //
  2419. readStatus = ReadOverlapped( Context -> HidDevice, completionEvent );
  2420. if (!readStatus)
  2421. {
  2422. break;
  2423. }
  2424. while (!Context -> TerminateThread)
  2425. {
  2426. //
  2427. // Wait for the completion event to be signaled or a timeout
  2428. //
  2429. waitStatus = WaitForSingleObject (completionEvent, READ_THREAD_TIMEOUT );
  2430. //
  2431. // If completionEvent was signaled, then a read just completed
  2432. // so let's leave this loop and process the data
  2433. //
  2434. if ( WAIT_OBJECT_0 == waitStatus)
  2435. {
  2436. break;
  2437. }
  2438. }
  2439. //
  2440. // Check the TerminateThread again...If it is not set, then data has
  2441. // been read. In this case, we want to Unpack the report into our
  2442. // input info and then send a message to the main thread to display
  2443. // the new data.
  2444. //
  2445. if (!Context -> TerminateThread)
  2446. {
  2447. UnpackReport(Context -> HidDevice -> InputReportBuffer,
  2448. Context -> HidDevice -> Caps.InputReportByteLength,
  2449. HidP_Input,
  2450. Context -> HidDevice -> InputData,
  2451. Context -> HidDevice -> InputDataLength,
  2452. Context -> HidDevice -> Ppd);
  2453. if (NULL != Context -> DisplayEvent)
  2454. {
  2455. PostMessage(Context -> DisplayWindow,
  2456. WM_DISPLAY_READ_DATA,
  2457. 0,
  2458. (LPARAM) Context -> HidDevice);
  2459. WaitForSingleObject( Context -> DisplayEvent, INFINITE );
  2460. }
  2461. }
  2462. } while ( !Context -> TerminateThread && !Context -> DoOneRead );
  2463. AsyncRead_End:
  2464. PostMessage( Context -> DisplayWindow, WM_READ_DONE, 0, 0);
  2465. ExitThread(0);
  2466. return (0);
  2467. }
  2468. DWORD WINAPI
  2469. SynchReadThreadProc(
  2470. PREAD_THREAD_CONTEXT Context
  2471. )
  2472. {
  2473. do
  2474. {
  2475. Read(Context -> HidDevice);
  2476. UnpackReport(Context -> HidDevice -> InputReportBuffer,
  2477. Context -> HidDevice -> Caps.InputReportByteLength,
  2478. HidP_Input,
  2479. Context -> HidDevice -> InputData,
  2480. Context -> HidDevice -> InputDataLength,
  2481. Context -> HidDevice -> Ppd);
  2482. if (NULL != Context -> DisplayEvent)
  2483. {
  2484. PostMessage(Context -> DisplayWindow,
  2485. WM_DISPLAY_READ_DATA,
  2486. 0,
  2487. (LPARAM) Context -> HidDevice);
  2488. WaitForSingleObject( Context -> DisplayEvent, INFINITE );
  2489. }
  2490. } while ( !Context -> TerminateThread && !Context -> DoOneRead );
  2491. PostMessage( Context -> DisplayWindow, WM_READ_DONE, 0, 0);
  2492. ExitThread(0);
  2493. return (0);
  2494. }