SAMV71 Xplained Ultra Software Package 1.3

hclient.c

00001 /*++
00002 
00003 Copyright (c) Microsoft 1998, All Rights Reserved
00004 
00005 Module Name:
00006 
00007     hclient.c
00008 
00009 Abstract:
00010 
00011     This module contains the code for handling HClient's main dialogue box and 
00012     for performing/calling the appropriate other routines.
00013 
00014 Environment:
00015 
00016     User mode
00017 
00018 Revision History:
00019 
00020     Nov-97 : Created 
00021 
00022 --*/
00023 
00024 #define __HCLIENT_C__
00025 #define LOG_FILE_NAME   NULL
00026 
00027 //****************************************************************************
00028 // HClient include files
00029 //****************************************************************************
00030 
00031 #include <windows.h>
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <wtypes.h>
00035 #include <math.h>
00036 #include <assert.h>
00037 #include <dbt.h>
00038 #include "hidsdi.h"
00039 #include "hid.h"
00040 #include "resource.h"
00041 #include "resrc1.h"
00042 #include "hclient.h"
00043 #include "buffers.h"
00044 #include "ecdisp.h"
00045 #include "list.h"
00046 #include <strsafe.h>
00047 
00048 //****************************************************************************
00049 // Local display macro definitions
00050 //****************************************************************************
00051 
00052 #define INPUT_BUTTON    1
00053 #define INPUT_VALUE     2
00054 #define OUTPUT_BUTTON   3
00055 #define OUTPUT_VALUE    4
00056 #define FEATURE_BUTTON  5
00057 #define FEATURE_VALUE   6
00058 #define HID_CAPS        7
00059 #define DEVICE_ATTRIBUTES 8
00060                            
00061 #define MAX_LB_ITEMS 200
00062 
00063 #define MAX_WRITE_ELEMENTS 100
00064 #define MAX_OUTPUT_ELEMENTS 50
00065 
00066 #define CONTROL_COUNT 9
00067 #define MAX_LABEL 128
00068 #define MAX_VALUE 128
00069 #define SMALL_BUFF 128
00070 
00071 //****************************************************************************
00072 // Macro definition to get device block from the main dialogue box procedure
00073 //****************************************************************************
00074 
00075 #define GET_CURRENT_DEVICE(hDlg, pDevice)   \
00076 { \
00077     pDevice = NULL; \
00078     iIndex = (INT) SendDlgItemMessage(hDlg, \
00079                                       IDC_DEVICES, \
00080                                       CB_GETCURSEL, \
00081                                       0, \
00082                                       0); \
00083     if (CB_ERR != iIndex) { \
00084         pDevice = (PHID_DEVICE) SendDlgItemMessage(hDlg, \
00085                                                    IDC_DEVICES, \
00086                                                    CB_GETITEMDATA, \
00087                                                    iIndex, \
00088                                                    0); \
00089     } \
00090 }
00091 
00092 //****************************************************************************
00093 // Data types local to the HClient display routines
00094 //****************************************************************************
00095 
00096 typedef struct rWriteDataStruct_type
00097 {
00098 
00099     char szLabel[MAX_LABEL];
00100     char szValue[MAX_VALUE];
00101 
00102 } rWriteDataStruct, *prWriteDataStruct;
00103 
00104 typedef struct rGetWriteDataParams_type
00105 {
00106         prWriteDataStruct   prItems;
00107         int                 iCount;
00108         
00109 } rGetWriteDataParams, *prGetWriteDataParams;
00110 
00111 typedef struct _DEVICE_LIST_NODE
00112 {
00113     LIST_NODE_HDR   Hdr;
00114     HDEVNOTIFY      NotificationHandle;
00115     HID_DEVICE      HidDeviceInfo;
00116     BOOL            DeviceOpened;
00117 
00118 } DEVICE_LIST_NODE, *PDEVICE_LIST_NODE;
00119 
00120 //****************************************************************************
00121 // Global program variables
00122 //****************************************************************************
00123 
00124 //
00125 // Pointers to the HID.DLL functions that were added into the Win98 OSR and 
00126 //  Windows 2000 but we're not included in the original implementation of 
00127 //  HID.DLL in Windows 98.  By getting pointers to these functions instead of
00128 //  statically linking with them, we can avoid the link error that would 
00129 //  occur when this runs on Windows 98.  The typedefs to make this easier to
00130 //  declare are also included below.
00131 //
00132 
00133 PGETEXTATTRIB pfnHidP_GetExtendedAttributes = NULL;
00134 
00135 PINITREPORT   pfnHidP_InitializeReportForID = NULL;
00136 
00137    
00138 //****************************************************************************
00139 // Global module variables
00140 //****************************************************************************
00141 static HINSTANCE          hGInstance; //global application instance handle
00142 
00143 static HANDLE             HIDDLLModuleHandle;
00144 
00145 //
00146 // Variables for handling the two different types of devices that can be loaded
00147 //   into the system.  PhysicalDeviceList contains all the actual HID devices
00148 //   attached via the USB bus. 
00149 //
00150 
00151 static LIST               PhysicalDeviceList;
00152 
00153 //****************************************************************************
00154 // Local data routine declarations
00155 //****************************************************************************
00156 
00157 VOID 
00158 vReadDataFromControls(
00159     HWND hDlg,
00160     prWriteDataStruct prData,
00161     int iOffset,
00162     int iCount
00163 );
00164 
00165 INT_PTR CALLBACK 
00166 bGetDataDlgProc(
00167     HWND hDlg, 
00168     UINT message, 
00169     WPARAM wParam, 
00170     LPARAM lParam
00171 );
00172 
00173 INT_PTR CALLBACK 
00174 bMainDlgProc(
00175     HWND hDlg, 
00176     UINT message, 
00177     WPARAM wParam, 
00178     LPARAM lParam
00179 );
00180 
00181 INT_PTR CALLBACK 
00182 bFeatureDlgProc(
00183     HWND hDlg, 
00184     UINT message, 
00185     WPARAM wParam, 
00186     LPARAM lParam
00187 );
00188 
00189 INT_PTR CALLBACK 
00190 bReadDlgProc(
00191     HWND hDlg, 
00192     UINT message, 
00193     WPARAM wParam, 
00194     LPARAM lParam
00195 );
00196 
00197 VOID 
00198 vLoadItemTypes(
00199     HWND hItemTypes
00200 );
00201 
00202 BOOL 
00203 bGetData(
00204     prWriteDataStruct,
00205     int iCount,
00206     HWND hParent, 
00207     char *pszDialogName
00208 );
00209 
00210 VOID 
00211 vLoadDevices(
00212     HWND hDeviceCombo
00213 );
00214 
00215 VOID 
00216 vFreeDeviceList(
00217     PHID_DEVICE  DeviceList,
00218     ULONG nDevices
00219 );
00220 
00221 VOID 
00222 vDisplayInputButtons(
00223     PHID_DEVICE pDevice,
00224     HWND hControl
00225 );
00226 
00227 VOID 
00228 vDisplayInputValues(
00229     PHID_DEVICE pDevice,
00230     HWND hControl
00231 );
00232 
00233 VOID 
00234 vDisplayOutputButtons(
00235     PHID_DEVICE pDevice,
00236     HWND hControl
00237 );
00238 
00239 VOID 
00240 vDisplayOutputValues(
00241     PHID_DEVICE pDevice,
00242     HWND hControl
00243 );
00244 
00245 VOID 
00246 vDisplayFeatureButtons(
00247     PHID_DEVICE pDevice,
00248     HWND hControl
00249 );
00250 
00251 VOID 
00252 vDisplayFeatureValues(
00253     PHID_DEVICE pDevice,
00254     HWND hControl
00255 );
00256 
00257 VOID 
00258 vWriteDataToControls(
00259     HWND hDlg,
00260     prWriteDataStruct prData,
00261     int iOffset,
00262     int iCount
00263 );
00264 
00265 int 
00266 iPrepareDataFields(
00267     PHID_DATA pData, 
00268     ULONG ulDataLength, 
00269     rWriteDataStruct rWriteData[],
00270     int iMaxElements
00271 );
00272 
00273 BOOL 
00274 bParseData(
00275     PHID_DATA pData,
00276     rWriteDataStruct rWriteData[],
00277     INT iCount,
00278     INT *piErrorLine
00279 );
00280 
00281 BOOL 
00282 bSetButtonUsages(
00283     PHID_DATA pCap,
00284     PCHAR     pszInputString
00285 );
00286 
00287 VOID
00288 BuildReportIDList(
00289     IN  PHIDP_BUTTON_CAPS  phidButtonCaps,
00290     IN  USHORT             nButtonCaps,
00291     IN  PHIDP_VALUE_CAPS   phidValueCaps,
00292     IN  USHORT             nValueCaps,
00293     OUT UCHAR            **ppReportIDList,
00294     OUT INT               *nReportIDs
00295 );
00296 
00297 VOID
00298 ReportToString(
00299    PHID_DATA    pData,
00300    PCHAR        szBuff,
00301    UINT          iBuffSize
00302 );
00303 
00304 BOOL
00305 RegisterHidDevice(
00306     IN  HWND                WindowHandle,
00307     IN  PDEVICE_LIST_NODE   DeviceNode
00308 );
00309 
00310 VOID
00311 DestroyDeviceListCallback(
00312     IN  PLIST_NODE_HDR   ListNode
00313 );
00314 
00315 char
00316 HalfBtoHex(
00317     IN BYTE chr
00318 );
00319 
00320 int
00321 Hex2Int(
00322     IN char * str
00323 );
00324 
00325 //****************************************************************************
00326 // Function Definitions
00327 //****************************************************************************
00328 
00329 /*******************************
00330 *WinMain: Windows Entry point  *
00331 *******************************/
00332 int PASCAL 
00333 WinMain(
00334     HINSTANCE hInstance,
00335     HINSTANCE hPrevInstance,
00336     LPSTR     lpCmdLine,
00337     int       nCmdShow
00338 )
00339 {
00340     //
00341     // Save instance of the application for further reference
00342     //
00343 
00344     hGInstance = hInstance;
00345 
00346     //
00347     // Attempt to load HID.DLL...This should already be loaded due to the 
00348     //  static linking of HID.DLL to this application on compilation.  However,
00349     //  to insure that this application runs on Windows 98 gold, we cannot
00350     //  directly reference the new functions HidP_GetExtendedAttributes and 
00351     //  HidP_InitializeReportForID so to use them, we'll get pointers to their
00352     //  functions instead.
00353     //
00354 
00355     HIDDLLModuleHandle = LoadLibrary("HID.DLL");
00356 
00357     if (NULL == HIDDLLModuleHandle) 
00358     {
00359         //
00360         // Something really bad happened here...Throw up and error dialog
00361         //  and bolt.
00362         //
00363 
00364         MessageBox(NULL, 
00365                    "Unable to open HID.DLL\n"
00366                    "This should never occur",
00367                    HCLIENT_ERROR,
00368                    MB_ICONSTOP);
00369 
00370         return (0);
00371     }
00372 
00373     //
00374     // Get the function pointers,
00375     //
00376 
00377     pfnHidP_GetExtendedAttributes = (PGETEXTATTRIB) GetProcAddress(HIDDLLModuleHandle,
00378                                                                    "HidP_GetExtendedAttributes");
00379 
00380     pfnHidP_InitializeReportForID = (PINITREPORT) GetProcAddress(HIDDLLModuleHandle,
00381                                                                  "HidP_InitializeReportForID");
00382 
00383     //
00384     // Try to create the main dialog box.  Cannot do much else if it fails
00385     //   so we'll throw up a message box and then exit the application
00386     //
00387     if (-1 == DialogBox(hInstance, "MAIN_DIALOG", NULL, bMainDlgProc)) 
00388     {
00389         MessageBox(NULL,
00390                    "Unable to create root dialog!",
00391                    "DialogBox failure",
00392                    MB_ICONSTOP);
00393     }
00394 
00395     FreeLibrary (HIDDLLModuleHandle);
00396 
00397     return (0);
00398 }
00399  
00400 /*************************************************
00401  * Main Dialog process                              *
00402  *************************************************/
00403 
00404 //
00405 // This the dialog box procedure for the main dialog display.
00406 //
00407 
00408 INT_PTR CALLBACK 
00409 bMainDlgProc(
00410     HWND hDlg, 
00411     UINT message, 
00412     WPARAM wParam, 
00413     LPARAM lParam
00414 )
00415 {
00416     static HWND                             hComboCtrl;
00417     static rWriteDataStruct                 rWriteData[MAX_OUTPUT_ELEMENTS];
00418     static HDEVNOTIFY                       diNotifyHandle;
00419 
00420     static HID_DEVICE           hidDevice;
00421     static READ_THREAD_CONTEXT  readContext;
00422     static HANDLE               readThread;
00423     
00424            INT                              iIndex;
00425            INT                              iCount;
00426            CHAR                             szTempBuff[SMALL_BUFF];
00427            PHID_DEVICE                      pDevice;
00428            PHIDP_BUTTON_CAPS                pButtonCaps;
00429            PHIDP_VALUE_CAPS                 pValueCaps;
00430            INT                              iErrorLine;
00431            INT                              iItemType;
00432            PHID_DEVICE                      tempDeviceList;
00433            ULONG                            numberDevices;
00434            PDEVICE_LIST_NODE                listNode;
00435            DEV_BROADCAST_DEVICEINTERFACE    broadcastInterface;
00436            HID_DEVICE                       writeDevice;
00437            BOOL                             status;
00438            HRESULT                          stringReturn;
00439            DWORD                threadID;
00440 
00441     switch (message)
00442     {
00443         case WM_INITDIALOG:
00444 
00445             //
00446             // Initialize the device list.
00447             //  -- PhysicalDeviceList is for devices that are actually attached
00448             //     to the HID bus
00449             //
00450             
00451             InitializeList(&PhysicalDeviceList);
00452             
00453             //
00454             // Begin by finding all the Physical HID devices currently attached to
00455             //  the system. If that fails, exit the dialog box.  
00456             //
00457             
00458             if (!FindKnownHidDevices(&tempDeviceList, &numberDevices)) 
00459             {
00460                 EndDialog(hDlg, 0);
00461                 return FALSE;                
00462             }
00463           
00464             //
00465             // For each device in the newly acquired list, create a device list
00466             //  node and add it the the list of physical device on the system  
00467             //
00468             
00469             pDevice = tempDeviceList;
00470             for (iIndex = 0; (ULONG) iIndex < numberDevices; iIndex++, pDevice++)
00471             {
00472                 listNode = malloc(sizeof(DEVICE_LIST_NODE));
00473 
00474                 if (NULL == listNode) {
00475 
00476                     //
00477                     // When freeing up the device list, we need to kill those
00478                     //  already in the Physical Device List and close
00479                     //  that have not been added yet in the enumerated list
00480                     //
00481                     
00482                     DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
00483 
00484                     CloseHidDevices(pDevice, numberDevices - iIndex);
00485 
00486                     free(tempDeviceList);
00487                     
00488                     EndDialog(hDlg, 0);
00489                     return FALSE;
00490                 }
00491 
00492                 listNode -> HidDeviceInfo = *pDevice;
00493                 listNode -> DeviceOpened = TRUE;
00494 
00495                 //
00496                 // Register this device node with the PnP system so the dialog
00497                 //  window can receive notification if this device is unplugged.
00498                 //
00499                 
00500                 if (!RegisterHidDevice(hDlg, listNode)) 
00501                 {
00502                     DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
00503 
00504                     CloseHidDevices(pDevice, numberDevices - iIndex);
00505 
00506                     free(tempDeviceList);
00507                     free(listNode);
00508                     
00509                     EndDialog(hDlg, 0);
00510                     return FALSE;
00511                 }                    
00512 
00513                 InsertTail(&PhysicalDeviceList, listNode);
00514             }
00515 
00516             //
00517             // Free the temporary device list...It is no longer needed
00518             //
00519             
00520             free(tempDeviceList);
00521             
00522             //
00523             // Register for notification from the HidDevice class.  Doing so 
00524             //  allows the dialog box to receive device change notifications 
00525             //  whenever a new HID device is added to the system
00526             //  
00527 
00528             broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
00529             broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
00530 
00531             HidD_GetHidGuid(&broadcastInterface.dbcc_classguid);
00532 
00533             diNotifyHandle = RegisterDeviceNotification(hDlg,
00534                                                         &broadcastInterface,
00535                                                         DEVICE_NOTIFY_WINDOW_HANDLE
00536                                                        );
00537             if (NULL == diNotifyHandle)
00538             {
00539                 DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
00540                            
00541                 EndDialog(hDlg, 0);
00542                 return FALSE;
00543             }
00544                     
00545             //
00546             // Update the device list box...
00547             // 
00548             //
00549 
00550             vLoadDevices(GetDlgItem(hDlg, IDC_DEVICES));
00551 
00552             //
00553             // Load the types box
00554             //
00555             
00556             vLoadItemTypes(GetDlgItem(hDlg, IDC_TYPE));
00557                           
00558             //
00559             // Post a message that the device changed so the appropriate
00560             //   data for the first device in the system can be displayed
00561             //
00562 
00563             PostMessage(hDlg,
00564                         WM_COMMAND,
00565                         IDC_DEVICES + (CBN_SELCHANGE<<16),
00566                         (LPARAM) GetDlgItem(hDlg, IDC_DEVICES));
00567 
00568             // Initialize display settings
00569             SendDlgItemMessage(hDlg, IDC_CHECK_OH, BM_SETCHECK, BST_UNCHECKED, 0);
00570             SendDlgItemMessage(hDlg, IDC_CHECK_IH, BM_SETCHECK, BST_CHECKED, 0);
00571             SendDlgItemMessage(hDlg, IDC_EDIT_OUT, WM_SETTEXT, 0, (LPARAM)"Enter Output");
00572 
00573             break; // end WM_INITDIALOG case
00574 
00575         case WM_DISPLAY_READ_DATA:
00576 
00577             //
00578             // LParam is the device that was read from
00579             // 
00580 
00581             pDevice = (PHID_DEVICE) lParam;
00582 
00583             SetEvent( readContext.DisplayEvent );
00584             break;
00585 
00586         case WM_READ_DONE:
00587 
00588             readThread = NULL;
00589             break;
00590 
00591         case WM_COMMAND:
00592 
00593             switch(LOWORD(wParam))
00594             {
00595                 //
00596                 // For a read, simply get the current device instance
00597                 //   from the DEVICES combo box and call the read procedure
00598                 //   with the HID_DEVICE block 
00599                 //
00600 
00601                 case IDC_READ:
00602                     GET_CURRENT_DEVICE(hDlg, pDevice);
00603 
00604                     if (NULL != pDevice)
00605                     {
00606                         iIndex = (INT) DialogBoxParam(hGInstance,
00607                                                       "READDATA",
00608                                                       hDlg,
00609                                                       bReadDlgProc,
00610                                                       (LPARAM) pDevice);
00611                     } 
00612                     break;
00613 
00614                 //
00615                 // For a write, the following steps are performed:
00616                 //   1) Get the current device data from the combo box
00617                 //   2) Prepare the data fields for display based on the data
00618                 //       output data stored in the device data
00619                 //   3) Retrieve the data the from the user that is to be sent
00620                 //       to the device
00621                 //   4) If all goes well and the data parses correctly, send the
00622                 //        the new data values to the device
00623                 //
00624 
00625                 case IDC_WRITE:
00626 
00627                     GET_CURRENT_DEVICE(hDlg, pDevice);
00628 
00629                     if (NULL != pDevice) 
00630                     {
00631                         //
00632                         // In order to write to the device, need to get a
00633                         //  writeable handle to the device.  In this case, the
00634                         //  write will be a synchronous write.  Begin by
00635                         //  trying to open a second instance of this device with
00636                         //  write access
00637                         //
00638                         
00639                         status = OpenHidDevice(pDevice -> DevicePath, 
00640                                                 FALSE,
00641                                                 TRUE,
00642                                                 FALSE,
00643                                                 FALSE,
00644                                                 &writeDevice);
00645                                             
00646                         if (!status) 
00647                         {
00648                             MessageBox(hDlg,
00649                                        "Couldn't open device for write access",
00650                                        HCLIENT_ERROR,
00651                                        MB_ICONEXCLAMATION);
00652                         }
00653                         else 
00654                         {
00655                             iCount = iPrepareDataFields(writeDevice.OutputData,
00656                                                         writeDevice.OutputDataLength,
00657                                                         rWriteData,
00658                                                         MAX_OUTPUT_ELEMENTS);
00659 
00660                             if (bGetData(rWriteData, iCount, hDlg, "WRITEDATA"))
00661                             {
00662 
00663                                 if (bParseData(writeDevice.OutputData, rWriteData, iCount, &iErrorLine))
00664                                 {
00665                                     Write(&writeDevice);
00666                                 }
00667                                 else
00668                                 {
00669                                     stringReturn = StringCbPrintf(szTempBuff,
00670                                                    SMALL_BUFF,
00671                                                    "Unable to parse line %x of output data",
00672                                                    iErrorLine);
00673 
00674                                     MessageBox(hDlg,
00675                                                szTempBuff,
00676                                                HCLIENT_ERROR,
00677                                                MB_ICONEXCLAMATION);
00678                                 }
00679                             }
00680                             CloseHidDevice(&writeDevice);
00681                         }                            
00682                         
00683                     } 
00684                     break; //end case IDC_WRITE//
00685                                           
00686                 //
00687                 // If there was a device change, issue an IDC_TYPE
00688                 //   change to insure that the currently displayed types are
00689                 //    updated to reflect the values of the device that has
00690                 //    been selected
00691                 //
00692 
00693                 case IDC_DEVICES:
00694                     switch (HIWORD(wParam)) 
00695                     {
00696                         case CBN_SELCHANGE:
00697 
00698                             GET_CURRENT_DEVICE(hDlg, pDevice);
00699 
00700                             EnableWindow(GetDlgItem(hDlg, IDC_READ), 
00701                                          (pDevice != NULL) && 
00702                                          (pDevice -> Caps.InputReportByteLength));
00703 
00704                             EnableWindow(GetDlgItem(hDlg, IDC_WRITE), 
00705                                          (pDevice != NULL) && 
00706                                          (pDevice -> Caps.OutputReportByteLength));
00707                                          
00708                             EnableWindow(GetDlgItem(hDlg, IDC_FEATURES),
00709                                          (pDevice != NULL) && 
00710                                          (pDevice -> Caps.FeatureReportByteLength));
00711                                          
00712                             PostMessage(hDlg,
00713                                         WM_COMMAND,
00714                                         IDC_TYPE + (CBN_SELCHANGE<<16),
00715                                         (LPARAM) GetDlgItem(hDlg,IDC_TYPE));
00716                             break;
00717 
00718                     } 
00719                     break;
00720 
00721                 //
00722                 // On a type change, retrieve the currently active device
00723                 //   from the IDC_DEVICES box and display the data that 
00724                 //   corresponds to the item just selected
00725                 //
00726                 
00727                 case IDC_TYPE:
00728                     switch (HIWORD(wParam))
00729                     {
00730                         case CBN_SELCHANGE:
00731                             GET_CURRENT_DEVICE(hDlg, pDevice);
00732                             
00733                             SendDlgItemMessage(hDlg,
00734                                                IDC_ITEMS,
00735                                                LB_RESETCONTENT,
00736                                                0,
00737                                                0);
00738 
00739                             SendDlgItemMessage(hDlg,
00740                                                IDC_ATTRIBUTES,
00741                                                LB_RESETCONTENT,
00742                                                0,
00743                                                0);
00744                             
00745                             if (NULL != pDevice)
00746                             {
00747                                 iIndex = (INT) SendDlgItemMessage(hDlg,
00748                                                                   IDC_TYPE,
00749                                                                   CB_GETCURSEL,
00750                                                                   0,
00751                                                                   0);
00752 
00753                                 iItemType = (INT) SendDlgItemMessage(hDlg,
00754                                                                      IDC_TYPE,
00755                                                                      CB_GETITEMDATA,
00756                                                                      iIndex,
00757                                                                      0);
00758 
00759                                 switch(iItemType)
00760                                 {
00761                                     case INPUT_BUTTON:
00762                                         vDisplayInputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
00763                                         break;
00764 
00765                                     case INPUT_VALUE:
00766                                          vDisplayInputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
00767                                          break;
00768 
00769                                     case OUTPUT_BUTTON:
00770                                         vDisplayOutputButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
00771                                         break;
00772 
00773                                     case OUTPUT_VALUE:
00774                                         vDisplayOutputValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
00775                                         break;
00776 
00777                                     case FEATURE_BUTTON:
00778                                         vDisplayFeatureButtons(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
00779                                         break;
00780 
00781                                     case FEATURE_VALUE:
00782                                         vDisplayFeatureValues(pDevice,GetDlgItem(hDlg,IDC_ITEMS));
00783                                         break;
00784                                 } 
00785 
00786                                 PostMessage(hDlg,
00787                                             WM_COMMAND,
00788                                             IDC_ITEMS + (LBN_SELCHANGE << 16),
00789                                             (LPARAM) GetDlgItem(hDlg,IDC_ITEMS));
00790                             } 
00791                             break; // case CBN_SELCHANGE
00792 
00793                     } //end switch HIWORD wParam
00794                     break; //case IDC_TYPE control
00795 
00796                 case IDC_ITEMS:
00797                     switch(HIWORD(wParam))
00798                     {
00799                         case LBN_SELCHANGE:
00800 
00801                             iItemType = 0;
00802 
00803                             iIndex = (INT) SendDlgItemMessage(hDlg,
00804                                                               IDC_TYPE,
00805                                                               CB_GETCURSEL,
00806                                                               0,
00807                                                               0);
00808 
00809                             if (-1 != iIndex)
00810                             {
00811                                 iItemType = (INT) SendDlgItemMessage(hDlg,
00812                                                                      IDC_TYPE,
00813                                                                      CB_GETITEMDATA,
00814                                                                      iIndex,
00815                                                                      0);
00816                             }
00817 
00818                             iIndex = (INT) SendDlgItemMessage(hDlg,
00819                                                               IDC_ITEMS,
00820                                                               LB_GETCURSEL,
00821                                                               0,
00822                                                               0);
00823 
00824                             switch (iItemType)
00825                             {
00826                                 case INPUT_BUTTON:
00827                                 case OUTPUT_BUTTON:
00828                                 case FEATURE_BUTTON:
00829 
00830                                     pButtonCaps = NULL;
00831 
00832                                     if (-1 != iIndex)
00833                                     {
00834                                         pButtonCaps = (PHIDP_BUTTON_CAPS) SendDlgItemMessage(hDlg,
00835                                                                                              IDC_ITEMS,
00836                                                                                              LB_GETITEMDATA,
00837                                                                                              iIndex,
00838                                                                                              0);
00839                                     }
00840 
00841                                     SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
00842                                     if (NULL != pButtonCaps)
00843                                     {
00844                                         vDisplayButtonAttributes(pButtonCaps, GetDlgItem(hDlg,IDC_ATTRIBUTES));
00845                                     }
00846                                     break;
00847 
00848                                 case INPUT_VALUE:
00849                                 case OUTPUT_VALUE:
00850                                 case FEATURE_VALUE:
00851 
00852                                     pValueCaps = NULL;
00853 
00854                                     if (-1 != iIndex)
00855                                     {
00856                                         pValueCaps = (PHIDP_VALUE_CAPS) SendDlgItemMessage(hDlg,
00857                                                                                              IDC_ITEMS,
00858                                                                                              LB_GETITEMDATA,
00859                                                                                              iIndex,
00860                                                                                              0);
00861                                     }
00862 
00863                                     SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
00864 
00865                                     if (NULL != pValueCaps) 
00866                                     {
00867                                         vDisplayValueAttributes(pValueCaps,GetDlgItem(hDlg,IDC_ATTRIBUTES));
00868                                     }
00869                                     break;
00870 
00871                                 case HID_CAPS:
00872                                     GET_CURRENT_DEVICE(hDlg, pDevice);
00873 
00874                                     if (NULL != pDevice)
00875                                     {
00876                                         vDisplayDeviceCaps(&(pDevice -> Caps),GetDlgItem(hDlg,IDC_ATTRIBUTES));
00877                                     }
00878                                     break;
00879 
00880                                 case DEVICE_ATTRIBUTES:
00881                                     GET_CURRENT_DEVICE(hDlg, pDevice);
00882 
00883                                     if (NULL != pDevice) 
00884                                     {
00885                                         SendDlgItemMessage(hDlg, IDC_ATTRIBUTES, LB_RESETCONTENT, 0, 0);
00886 
00887                                         vDisplayDeviceAttributes(&(pDevice -> Attributes) ,GetDlgItem(hDlg,IDC_ATTRIBUTES));
00888                                     }
00889                                     break;
00890 
00891                             } //end switch iItemType//
00892                             break; //end case LBN_SELCHANGE in IDC_ITEMS//
00893 
00894                     } //end switch HIWORD wParam//
00895                     break; //case IDC_ITEMS//
00896 
00897                 case IDC_CHECK_LED1:
00898                 case IDC_CHECK_LED2:
00899 
00900                     // LB_: List box, CB_: Combo box, SS_:Static Styles
00901                     // BM_: Button
00902                     {
00903                     int bst1 = (int)SendDlgItemMessage(hDlg, IDC_CHECK_LED1, BM_GETCHECK, 0, 0);
00904                     int bst2 = (int)SendDlgItemMessage(hDlg, IDC_CHECK_LED2, BM_GETCHECK, 0, 0);
00905                     BYTE tmpBuffer[64 * 6];
00906                     DWORD bytesWritten;
00907 
00908                         GET_CURRENT_DEVICE(hDlg, pDevice);
00909 
00910                         if (NULL == pDevice) break;
00911                         if (!OpenHidDevice(pDevice->DevicePath,
00912                             FALSE, TRUE, FALSE, FALSE, &hidDevice) ) {
00913                             MessageBox(hDlg, "Can not open HID Device!", "Err LED", MB_ICONSTOP);
00914                             break;
00915                         }
00916 
00917                         tmpBuffer[0] = 0;
00918                         tmpBuffer[1] = 0x80;
00919                         if (bst1) tmpBuffer[1] |= 0x01;
00920                         if (bst2) tmpBuffer[1] |= 0x02;
00921                         if (!WriteFile(hidDevice.HidDevice,
00922                                         tmpBuffer,
00923                                         hidDevice.Caps.OutputReportByteLength,
00924                                         &bytesWritten, NULL)) {
00925                             MessageBox(hDlg, "Failed to write!", "Err LED", MB_ICONSTOP);
00926                             CheckDlgButton(hDlg, LOWORD(wParam), BST_UNCHECKED);
00927                         }
00928 
00929                         CloseHidDevice(&hidDevice);
00930                     }
00931                     break;
00932 
00933                 case IDC_BUTTON_WR:
00934                     GET_CURRENT_DEVICE(hDlg, pDevice);
00935 
00936                     if (NULL != pDevice)
00937                     {
00938                         BYTE tmpBuffer[64 * 6];
00939                         DWORD     bytesWritten;
00940                         int i;
00941                         if (!OpenHidDevice(pDevice -> DevicePath, 
00942                                             FALSE,
00943                                             TRUE,
00944                                             FALSE,
00945                                             FALSE,
00946                                             &hidDevice)) {
00947                             MessageBox(hDlg, "Can not open HID device!", "Err Write", MB_ICONSTOP);
00948                             break;
00949                         }
00950                         else {
00951 
00952                             tmpBuffer[0] = 0;
00953                             SendDlgItemMessage(hDlg, IDC_EDIT_OUT, WM_GETTEXT, 64*6 - 1, (LPARAM)(&tmpBuffer[1]));
00954                             if (!WriteFile(hidDevice.HidDevice,
00955                                         tmpBuffer,
00956                                         hidDevice.Caps.OutputReportByteLength,
00957                                         &bytesWritten,
00958                                         NULL)) {
00959                                 MessageBox(hDlg, "Failed to write!", "Err Write", MB_ICONSTOP);
00960                             }
00961                         }
00962                         CloseHidDevice(&hidDevice);
00963                     }
00964 
00965                     break;
00966 
00967                 case IDC_CHECK_MON:
00968                     {
00969                         int mon = (int)SendDlgItemMessage(hDlg, IDC_CHECK_MON, BM_GETCHECK, 0, 0);
00970                         // Start monitor
00971                         if (mon == BST_CHECKED) {
00972 
00973                             GET_CURRENT_DEVICE(hDlg, pDevice);
00974                             if (NULL == pDevice) break;
00975                             
00976                             if (!OpenHidDevice(pDevice->DevicePath,
00977                                                 TRUE, FALSE, FALSE, FALSE, &hidDevice)) {
00978                                 MessageBox(hDlg, "Can not open HID device!", "Err Monitor", MB_ICONSTOP);
00979                                 CheckDlgButton(hDlg, IDC_CHECK_MON, BST_UNCHECKED);
00980                                 break;
00981                             }
00982 
00983                             EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_RD), FALSE);
00984 
00985                             readContext.HidDevice = pDevice;
00986                             readContext.TerminateThread = FALSE;
00987                             readContext.DoOneRead = FALSE;
00988                             readContext.DisplayEvent = NULL;
00989                             readContext.DisplayWindow = hDlg;
00990 
00991                             readThread = CreateThread(NULL,
00992                                                         0,
00993                                                         MyReadThreadProc,
00994                                                         (LPVOID) &readContext,
00995                                                         0,
00996                                                         &threadID);
00997                             if (NULL == readThread) {
00998                                 MessageBox(hDlg, "Fail to create read thread", "Err MON", MB_ICONEXCLAMATION);
00999                                 CloseHidDevice(&hidDevice);
01000                                 SendDlgItemMessage(hDlg, IDC_CHECK_MON, BM_SETCHECK, BST_UNCHECKED, 0);
01001                             }
01002                         }
01003                         else {
01004                             readContext.TerminateThread = TRUE;
01005                             WaitForSingleObject(readThread, INFINITE);
01006                             EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_RD), TRUE);
01007                             CloseHidDevice(&hidDevice);
01008                         }
01009                     }
01010                     break;
01011 
01012                 case IDC_BUTTON_RD:
01013                     GET_CURRENT_DEVICE(hDlg, pDevice);
01014 
01015                     if (NULL != pDevice)
01016                     {
01017                         if (!OpenHidDevice(pDevice -> DevicePath, 
01018                                             TRUE,
01019                                             FALSE,
01020                                             FALSE,
01021                                             FALSE,
01022                                             &hidDevice)) {
01023                             MessageBox(hDlg, "Can not open HID device!", "Err GetReport", MB_ICONSTOP);
01024                             break;
01025                         }
01026                         if (!Read(&hidDevice)) {
01027                             MessageBox(hDlg, "Failed to read!", "Err read", MB_ICONSTOP);
01028                         }
01029                         else {
01030                             // Dump buffer
01031                             int i;
01032                             char * pBuff = szTempBuff, tmpChar;
01033                             for(i = 1; i <= hidDevice.Caps.InputReportByteLength; i ++) {
01034 
01035                                 *pBuff ++ = HalfBtoHex(hidDevice.InputReportBuffer[i] >> 4);
01036                                 *pBuff ++ = HalfBtoHex(hidDevice.InputReportBuffer[i]);
01037                                 *pBuff ++ = ' ';
01038                             }
01039                             *pBuff = 0;
01040 
01041                             SendDlgItemMessage(hDlg, IDC_EDIT_IN, WM_SETTEXT, 0, (LPARAM)szTempBuff);
01042 
01043                             // Change status of BUTTONs
01044                             if (hidDevice.InputReportBuffer[1] & 0x80) {
01045 
01046                                 if (hidDevice.InputReportBuffer[1] & 0x01) {
01047                                     SendDlgItemMessage(hDlg, IDC_CHECK_BTN1, BM_SETCHECK, BST_CHECKED, 0);
01048                                 }
01049                                 else {
01050                                     SendDlgItemMessage(hDlg, IDC_CHECK_BTN1, BM_SETCHECK, BST_UNCHECKED, 0);
01051                                 }
01052                                 if (hidDevice.InputReportBuffer[1] & 0x02) {
01053                                     SendDlgItemMessage(hDlg, IDC_CHECK_BTN2, BM_SETCHECK, BST_CHECKED, 0);
01054                                 }
01055                                 else {
01056                                     SendDlgItemMessage(hDlg, IDC_CHECK_BTN2, BM_SETCHECK, BST_UNCHECKED, 0);
01057                                 }
01058                                 CheckDlgButton(hDlg,
01059                                                IDC_CHECK_LEFT,
01060                                                (hidDevice.InputReportBuffer[1] & 0x04) ?
01061                                                 BST_CHECKED : BST_UNCHECKED);
01062                                 CheckDlgButton(hDlg,
01063                                                IDC_CHECK_UP,
01064                                                (hidDevice.InputReportBuffer[1] & 0x08) ?
01065                                                 BST_CHECKED : BST_UNCHECKED);
01066                                 CheckDlgButton(hDlg,
01067                                                IDC_CHECK_DOWN,
01068                                                (hidDevice.InputReportBuffer[1] & 0x10) ?
01069                                                 BST_CHECKED : BST_UNCHECKED);
01070                                 CheckDlgButton(hDlg,
01071                                                IDC_CHECK_RIGHT,
01072                                                (hidDevice.InputReportBuffer[1] & 0x20) ?
01073                                                 BST_CHECKED : BST_UNCHECKED);
01074                             }
01075                         }
01076                         CloseHidDevice(&hidDevice);
01077                     } 
01078                     break;
01079 
01080                 case IDC_BUTTON_SET:
01081                     GET_CURRENT_DEVICE(hDlg, pDevice);
01082 
01083                     if (NULL != pDevice)
01084                     {
01085                         BYTE tmpBuffer[64 * 6];
01086                         if (!OpenHidDevice(pDevice -> DevicePath, 
01087                                             FALSE,
01088                                             TRUE,
01089                                             FALSE,
01090                                             FALSE,
01091                                             &hidDevice)) {
01092                             MessageBox(hDlg, "Can not open HID device!", "Err Write", MB_ICONSTOP);
01093                             break;
01094                         }
01095                         else {
01096 
01097                             tmpBuffer[0] = 0;
01098                             SendDlgItemMessage(hDlg, IDC_EDIT_OUT, WM_GETTEXT, 64 * 6 - 1, (LPARAM)(&tmpBuffer[1]));
01099                             if (!HidD_SetOutputReport(hidDevice.HidDevice,
01100                                                       tmpBuffer,
01101                                                       hidDevice.Caps.OutputReportByteLength)) {
01102                                 MessageBox(hDlg, "Failed to set report!", "Err SetReport", MB_ICONSTOP);
01103                             }
01104                         }
01105                         CloseHidDevice(&hidDevice);
01106                     }
01107                     break;
01108 
01109                 case IDC_BUTTON_GET:
01110                     GET_CURRENT_DEVICE(hDlg, pDevice);
01111 
01112                     if (NULL != pDevice)
01113                     {
01114                         BYTE tmpBuffer[66];
01115                         if (!OpenHidDevice(pDevice -> DevicePath, 
01116                                             TRUE,
01117                                             FALSE,
01118                                             FALSE,
01119                                             FALSE,
01120                                             &hidDevice)) {
01121                             MessageBox(hDlg, "Can not open HID device!", "Err GetReport", MB_ICONSTOP);
01122                             break;
01123                         }
01124                         
01125                         tmpBuffer[0] = 0;
01126                         if (!HidD_GetInputReport(hidDevice.HidDevice,
01127                                                  tmpBuffer,
01128                                                  hidDevice.Caps.InputReportByteLength)) {
01129                             MessageBox(hDlg, "Failed to get report!", "Err GetReport", MB_ICONSTOP);
01130                         }
01131                         else {
01132                             // Dump buffer
01133                             int i;
01134                             char * pBuff = szTempBuff, tmpChar;
01135                             for(i = 1; i < hidDevice.Caps.InputReportByteLength; i ++) {
01136 
01137                                 *pBuff ++ = HalfBtoHex(tmpBuffer[i] >> 4);
01138                                 *pBuff ++ = HalfBtoHex(tmpBuffer[i]);
01139                                 *pBuff ++ = ' ';
01140                             }
01141                             *pBuff = 0;
01142 
01143                             SendDlgItemMessage(hDlg, IDC_EDIT_IN, WM_SETTEXT, 0, (LPARAM)szTempBuff);
01144                         }
01145                         CloseHidDevice(&hidDevice);
01146                     } 
01147                     break;
01148 
01149                 case IDC_ABOUT:
01150 
01151                     MessageBox(hDlg,
01152                                "Sample HID Test Application\nBased on MS DDK - hClient",
01153                                "About HID Test",
01154                                MB_ICONINFORMATION);
01155                     break;
01156 
01157                 case IDOK:
01158                 case IDCANCEL:
01159 
01160                     //
01161                     // Destroy the physical device list for exit
01162                     //
01163 
01164                     DestroyListWithCallback(&PhysicalDeviceList, DestroyDeviceListCallback);
01165 
01166                     EndDialog(hDlg,0);
01167 
01168                     break;
01169 
01170             } //end switch wParam//
01171             break;
01172 
01173         //
01174         // For a device change message, we are only concerned about the 
01175         //    DBT_DEVICEREMOVECOMPLETE and DBT_DEVICEARRIVAL events. I have
01176         //    yet to determine how to process the device change message
01177         //    only for HID devices.  Therefore, there are two problems
01178         //    with the below implementation.  First of all, we must reload
01179         //    the device list any time a device is added to the system.  
01180         //    Secondly, at least two DEVICEARRIVAL messages are received 
01181         //    per HID.  One corresponds to the physical device.  The second
01182         //    change and any more correspond to each collection on the 
01183         //    physical device so a system that has one HID device with
01184         //    two top level collections (a keyboard and a mouse) will receive
01185         //    three DEVICEARRIVAL/REMOVALs causing the program to reload it's
01186         //    device list more than once.
01187         //
01188 
01189         //
01190         // To handle dynamic changing of devices, we have already registered
01191         //    notification for both HID class changes and for notification 
01192         //    for our open file objects.  Since we are only concerned about
01193         //    arrival/removal of devices, we only need to process those wParam.
01194         //    lParam points to some sort of DEV_BROADCAST_HDR struct.  For device
01195         //    arrival, we only deal with the message if that struct is a 
01196         //    DEV_BROADCAST_DEVICEINTERFACE structure.  For device removal, we're
01197         //    only concerned if the struct is a DEV_BROADCAST_HANDLE structure.
01198         //
01199 
01200         case WM_DEVICECHANGE:
01201             switch (wParam) 
01202             {
01203                 PDEV_BROADCAST_HDR broadcastHdr;
01204 
01205                 case DBT_DEVICEARRIVAL:
01206 
01207                     broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
01208 
01209                     if (DBT_DEVTYP_DEVICEINTERFACE == broadcastHdr -> dbch_devicetype)
01210                     {
01211                         PDEV_BROADCAST_DEVICEINTERFACE  pbroadcastInterface;
01212                         PDEVICE_LIST_NODE               currNode, lastNode;
01213                         
01214                         pbroadcastInterface = (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
01215 
01216                         //
01217                         // Search for a previous instance of this device
01218                         //  in the device list...In some cases, multiple
01219                         //  messages are received for the same device.  We
01220                         //  obviously only want one instance of the device
01221                         //  showing up in the dialog box.
01222                         //
01223 
01224                         if (!IsListEmpty(&PhysicalDeviceList)) 
01225                         {
01226                             currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
01227                             lastNode = (PDEVICE_LIST_NODE) GetListTail(&PhysicalDeviceList);
01228                             
01229                             //
01230                             // This loop should always terminate since the device 
01231                             //  handle should be somewhere in the physical device list
01232                             //
01233                             
01234                             while (1)
01235                             {
01236                                 if (0 == strcmp(currNode -> HidDeviceInfo.DevicePath, 
01237                                                 pbroadcastInterface -> dbcc_name)) 
01238                                 {
01239                                     return (TRUE);
01240                                 }
01241                                 
01242                                 if (currNode == lastNode) 
01243                                 {
01244                                     break;
01245                                 }
01246 
01247                                 currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
01248                             }
01249                         }
01250 
01251                         //
01252                         // In this structure, we are given the name of the device
01253                         //    to open.  So all that needs to be done is open 
01254                         //    a new hid device with the string
01255                         //
01256 
01257                         listNode = (PDEVICE_LIST_NODE) malloc(sizeof(DEVICE_LIST_NODE));
01258 
01259                         if (NULL == listNode)
01260                         {
01261                             MessageBox(hDlg,
01262                                "Error -- Couldn't allocate memory for new device list node",
01263                                HCLIENT_ERROR,
01264                                MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
01265 
01266                             break;
01267 
01268                         }
01269                        
01270                         //
01271                         // Open the hid device for query access
01272                         //
01273                         
01274                         if (!OpenHidDevice (pbroadcastInterface -> dbcc_name,
01275                                             FALSE,
01276                                             FALSE,
01277                                             FALSE,
01278                                             FALSE,
01279                                             &(listNode -> HidDeviceInfo)))
01280                         {
01281 
01282                             MessageBox(hDlg,
01283                                "Error -- Couldn't open HID device",
01284                                HCLIENT_ERROR,
01285                                MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
01286                             
01287                             free(listNode);
01288 
01289                             break;
01290                         }
01291 
01292                         if (!RegisterHidDevice(hDlg, listNode))
01293                         {
01294                             MessageBox(hDlg,
01295                                "Error -- Couldn't register handle notification",
01296                                HCLIENT_ERROR,
01297                                MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
01298 
01299                             CloseHidDevice(&(listNode -> HidDeviceInfo));
01300 
01301                             free(listNode);
01302 
01303                             break;
01304 
01305                         }                         
01306 
01307                         listNode -> DeviceOpened = TRUE;
01308 
01309                         InsertTail(&PhysicalDeviceList, listNode);
01310 
01311                         vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
01312 
01313                         PostMessage(hDlg,
01314                                    WM_COMMAND,
01315                                    IDC_DEVICES + (CBN_SELCHANGE << 16),
01316                                    (LPARAM) GetDlgItem(hDlg,IDC_DEVICES));
01317                                    
01318                     }
01319                     break;
01320 
01321                 case DBT_DEVICEQUERYREMOVE:
01322 
01323                     //
01324                     // If this message is received, the device is either
01325                     //  being disabled or removed through device manager.
01326                     //  To properly handle this request, we need to close
01327                     //  the handle to the device.
01328                     //
01329 
01330                     broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
01331 
01332                     if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype)
01333                     {
01334                         PDEV_BROADCAST_HANDLE broadcastHandle;
01335                         PDEVICE_LIST_NODE     currNode;
01336                         HANDLE                deviceHandle;
01337                         
01338                         broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam;
01339 
01340                         //
01341                         // Get the file handle of the device that was removed
01342                         //  from the system
01343                         //
01344                         
01345                         deviceHandle = (HANDLE) broadcastHandle -> dbch_handle;
01346 
01347                         //
01348                         // Search the physical device list for the handle that
01349                         //  was removed...
01350                         //
01351 
01352                         currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
01353 
01354                         //
01355                         // This loop should always terminate since the device 
01356                         //  handle should be somewhere in the physical device list
01357                         //
01358                         
01359                         while (currNode -> HidDeviceInfo.HidDevice != deviceHandle)
01360                         {
01361                             currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
01362                         }
01363 
01364                         CloseHidDevice(&(currNode -> HidDeviceInfo));
01365 
01366                         currNode -> DeviceOpened = FALSE;
01367                     }
01368                     return (TRUE);
01369 
01370                 case DBT_DEVICEREMOVEPENDING:
01371                 case DBT_DEVICEREMOVECOMPLETE:
01372 
01373                     //
01374                     // Do the same steps for DBT_DEVICEREMOVEPENDING and 
01375                     //   DBT_DEVICEREMOVECOMPLETE.  We do not receive the 
01376                     //   remove complete request for a device if it is
01377                     //   disabled or removed via Device Manager.  However,
01378                     //   in that case will receive the remove pending.  
01379                     //   We remove the device from our currently displayed
01380                     //   list of devices and unregister notification.
01381                     //
01382                     
01383                     broadcastHdr = (PDEV_BROADCAST_HDR) lParam;
01384 
01385                     if (DBT_DEVTYP_HANDLE == broadcastHdr -> dbch_devicetype)
01386                     {
01387                         PDEV_BROADCAST_HANDLE broadcastHandle;
01388                         PDEVICE_LIST_NODE     currNode;
01389                         HANDLE                deviceHandle;
01390                         
01391                         broadcastHandle = (PDEV_BROADCAST_HANDLE) lParam;
01392 
01393                         //
01394                         // Get the file handle of the device that was removed
01395                         //  from the system
01396                         //
01397                         
01398                         deviceHandle = (HANDLE) broadcastHandle -> dbch_handle;
01399 
01400                         //
01401                         // Search the physical device list for the handle that
01402                         //  was removed...
01403                         //
01404 
01405                         currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
01406 
01407                         //
01408                         // This loop should always terminate since the device 
01409                         //  handle should be somewhere in the physical device list
01410                         //
01411                         
01412                         while (currNode -> HidDeviceInfo.HidDevice != deviceHandle)
01413                         {
01414                             currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
01415                         }
01416 
01417                         //
01418                         // Node in PhysicalDeviceList has been found, do:
01419                         //  1) Unregister notification
01420                         //  2) Close the hid device
01421                         //  3) Remove the entry from the list
01422                         //  4) Free the memory for the entry
01423                         // 
01424                         //
01425 
01426                         PostMessage(hDlg, 
01427                                     WM_UNREGISTER_HANDLE, 
01428                                     0, 
01429                                     (LPARAM) currNode -> NotificationHandle);
01430 
01431                         //
01432                         // Close the device if still opened...This would 
01433                         //  occur on surprise removal.
01434                         //
01435 
01436                         if (currNode -> DeviceOpened) 
01437                         {
01438                             CloseHidDevice(&(currNode -> HidDeviceInfo));
01439                         }
01440 
01441                         RemoveNode(currNode);
01442 
01443                         free(currNode);
01444                 
01445                         //
01446                         // Reload the device list
01447                         //
01448                         
01449                         vLoadDevices(GetDlgItem(hDlg,IDC_DEVICES));
01450 
01451                         PostMessage(hDlg,
01452                                    WM_COMMAND,
01453                                    IDC_DEVICES + (CBN_SELCHANGE << 16),
01454                                    (LPARAM) GetDlgItem(hDlg,IDC_DEVICES));
01455                     }
01456                     break;
01457     
01458                 default:
01459                     break;
01460             }
01461             break;
01462 
01463         //
01464         // Application specific message used to defer the unregistering of a 
01465         //  file object for device change notification.  This separte message
01466         //  is sent when a WM_DEVICECHANGE (DBT_DEVICEREMOVECOMPLETE) has been
01467         //  received.  The Unregistering of the notification must be deferred
01468         //  until after the WM_DEVICECHANGE message has been processed or the 
01469         //  system will deadlock.  The handle that is to be freed will be passed
01470         //  in as lParam for this message
01471         //
01472         
01473         case WM_UNREGISTER_HANDLE:
01474             UnregisterDeviceNotification ( (HDEVNOTIFY) lParam ); 
01475             break;
01476                            
01477    } // end switch message
01478    return FALSE;
01479 } // end MainDlgProc
01480 
01481 
01482 BOOL 
01483 bParseData(
01484     PHID_DATA           pData,
01485     rWriteDataStruct    rWriteData[],
01486     int                 iCount,
01487     int                 *piErrorLine
01488 )
01489 {  
01490     INT       iCap;
01491     PHID_DATA pWalk;
01492     BOOL      noError = TRUE;
01493 
01494     pWalk = pData;
01495 
01496     for (iCap = 0; (iCap < iCount) && noError; iCap++)
01497     {
01498         //
01499         // Check to see if our data is a value cap or not
01500         //
01501 
01502         if (!pWalk->IsButtonData)
01503         {
01504             pWalk -> ValueData.Value = atol(rWriteData[iCap].szValue);
01505         } 
01506         else
01507         {
01508             if (!bSetButtonUsages(pWalk, rWriteData[iCap].szValue) )
01509             {
01510                *piErrorLine = iCap;
01511 
01512                noError = FALSE;
01513             } 
01514         } 
01515         pWalk++;
01516     }
01517     return (noError);
01518 }
01519 
01520 BOOL 
01521 bSetButtonUsages(
01522     PHID_DATA pCap,
01523     PCHAR     pszInputString
01524 )
01525 {
01526     CHAR   szTempString[SMALL_BUFF];
01527     CHAR   pszDelimiter[] = " ";
01528     PCHAR  pszToken;
01529     INT    iLoop;
01530     PUSAGE pUsageWalk;
01531     BOOL   bNoError=TRUE;
01532     HRESULT    stringReturn;
01533 
01534     stringReturn = StringCbCopy(szTempString, SMALL_BUFF, pszInputString);
01535 
01536     pszToken = strtok(szTempString, pszDelimiter);
01537     
01538     pUsageWalk = pCap -> ButtonData.Usages;
01539 
01540     memset(pUsageWalk, 0, pCap->ButtonData.MaxUsageLength * sizeof(USAGE));
01541 
01542     for (iLoop = 0; ((ULONG) iLoop < pCap->ButtonData.MaxUsageLength) && (pszToken != NULL) && bNoError; iLoop++)
01543     {
01544         *pUsageWalk = (USAGE) atoi(pszToken);
01545 
01546         pszToken = strtok(NULL, pszDelimiter);
01547 
01548         pUsageWalk++;
01549     } 
01550 
01551      return bNoError;
01552 } //end function bSetButtonUsages//
01553 
01554 
01555 INT 
01556 iPrepareDataFields(
01557     PHID_DATA           pData,
01558     ULONG               ulDataLength, 
01559     rWriteDataStruct    rWriteData[],
01560     int                 iMaxElements
01561 )
01562 {
01563     INT i;
01564     PHID_DATA pWalk;
01565     HRESULT   stringReturn;
01566 
01567     pWalk = pData;
01568 
01569     for (i = 0; (i < iMaxElements) && ((unsigned) i < ulDataLength); i++)
01570     {
01571         if (!pWalk->IsButtonData) 
01572         {
01573             stringReturn = StringCbPrintf(rWriteData[i].szLabel,
01574                            MAX_LABEL,
01575                            "ValueCap; ReportID: 0x%x, UsagePage=0x%x, Usage=0x%x",
01576                            pWalk->ReportID,
01577                            pWalk->UsagePage,
01578                            pWalk->ValueData.Usage);
01579         }
01580         else
01581         {
01582             stringReturn = StringCbPrintf(rWriteData[i].szLabel,
01583                            MAX_LABEL,
01584                            "Button; ReportID: 0x%x, UsagePage=0x%x, UsageMin: 0x%x, UsageMax: 0x%x",
01585                            pWalk->ReportID,
01586                            pWalk->UsagePage,
01587                            pWalk->ButtonData.UsageMin,
01588                            pWalk->ButtonData.UsageMax);
01589         }
01590         pWalk++;
01591      } 
01592      return i;
01593 }  //end function iPrepareDataFields//
01594 
01595 
01596 INT_PTR CALLBACK 
01597 bReadDlgProc(
01598     HWND hDlg, 
01599     UINT message, 
01600     WPARAM wParam, 
01601     LPARAM lParam
01602 )
01603 {
01604     static INT                  iLbCounter;
01605     static CHAR                 szTempBuff[1024];
01606     static READ_THREAD_CONTEXT  readContext;
01607     static HANDLE               readThread;
01608     static HID_DEVICE           syncDevice;
01609     static HID_DEVICE           asyncDevice;
01610     static BOOL                 doAsyncReads;
01611     static BOOL                 doSyncReads;
01612 
01613            PHID_DEVICE          pDevice;
01614            DWORD                threadID;
01615            INT                  iIndex;
01616            PHID_DATA            pData;
01617            UINT                 uLoop;
01618 
01619 
01620     switch(message)
01621     {
01622         case WM_INITDIALOG:
01623 
01624             //
01625             // Initialize the list box counter, the readThread, and the 
01626             //  readContext.DisplayEvent.
01627             //
01628             
01629             iLbCounter = 0;
01630             readThread = NULL;
01631             readContext.DisplayEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
01632 
01633             if (NULL == readContext.DisplayEvent)
01634             {
01635                 EndDialog(hDlg, 0);
01636             } 
01637             
01638             //
01639             // Get the opened device information for the device to perform
01640             //  reads upon
01641             //
01642             
01643             pDevice = (PHID_DEVICE) lParam;
01644 
01645             //
01646             // To do sync and async reads requires file handles with different
01647             //  attributes (ie. an async must be opened with the OVERLAPPED flag
01648             //  set).  The device node that was passed in the context parameter
01649             //  was not opened for reading.  Therefore, two more devices will
01650             //  be opened, one for async reads and one for sync reads.
01651             //
01652             
01653             doSyncReads = OpenHidDevice(pDevice -> DevicePath, 
01654                                        TRUE,
01655                                        FALSE,
01656                                        FALSE,
01657                                        FALSE,
01658                                        &syncDevice);
01659 
01660             if (!doSyncReads)
01661             {
01662                 MessageBox(hDlg, 
01663                            "Unable to open device for synchronous reading",
01664                            HCLIENT_ERROR,
01665                            MB_ICONEXCLAMATION);
01666             }
01667 
01668             //
01669             // For asynchronous read, default to using the same information
01670             //    passed in as the lParam.  This is because data related to
01671             //    Ppd and such cannot be retrieved using the standard HidD_ 
01672             //    functions.  However, it is necessary to parse future reports.
01673             //
01674             
01675             doAsyncReads = OpenHidDevice(pDevice -> DevicePath, 
01676                                        TRUE,
01677                                        FALSE,
01678                                        TRUE,
01679                                        FALSE,
01680                                        &asyncDevice);
01681 
01682             if (!doAsyncReads) 
01683             {
01684                 MessageBox(hDlg, 
01685                            "Unable to open device for asynchronous reading",
01686                            HCLIENT_ERROR,
01687                            MB_ICONEXCLAMATION);
01688             }
01689 
01690             PostMessage(hDlg, WM_READ_DONE, 0, 0);
01691             break; 
01692 
01693         case WM_DISPLAY_READ_DATA:
01694 
01695             //
01696             // LParam is the device that was read from
01697             // 
01698 
01699             pDevice = (PHID_DEVICE) lParam;
01700 
01701             //
01702             // Display all the data stored in the Input data field for the device
01703             //
01704             
01705             pData = pDevice -> InputData;
01706 
01707             SendDlgItemMessage(hDlg,
01708                                IDC_OUTPUT,
01709                                LB_ADDSTRING,
01710                                0,
01711                                (LPARAM)"-------------------------------------------");
01712                                
01713             iLbCounter++;
01714 
01715             if (iLbCounter > MAX_LB_ITEMS)
01716             {
01717                 SendDlgItemMessage(hDlg,
01718                                    IDC_OUTPUT,
01719                                    LB_DELETESTRING,
01720                                    0,
01721                                    0);
01722             }
01723 
01724             for (uLoop = 0; uLoop < pDevice->InputDataLength; uLoop++)
01725             {
01726                 ReportToString(pData, szTempBuff, sizeof(szTempBuff));
01727           
01728                 iIndex = (INT) SendDlgItemMessage(hDlg,
01729                                                   IDC_OUTPUT,
01730                                                   LB_ADDSTRING,
01731                                                   0,
01732                                                   (LPARAM) szTempBuff);
01733 
01734                 SendDlgItemMessage(hDlg,
01735                                    IDC_OUTPUT,
01736                                    LB_SETCURSEL,
01737                                    iIndex,
01738                                    0);
01739 
01740                 iLbCounter++;
01741 
01742                 if (iLbCounter > MAX_LB_ITEMS)
01743                 {
01744                     SendDlgItemMessage(hDlg,
01745                                        IDC_OUTPUT,
01746                                        LB_DELETESTRING,
01747                                        0,
01748                                        0);
01749                 }
01750                 pData++;
01751             }
01752             SetEvent( readContext.DisplayEvent );
01753             break;
01754 
01755         case WM_READ_DONE:
01756             EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
01757             EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), doSyncReads);
01758             EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), doAsyncReads);
01759             EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), doAsyncReads);
01760 
01761             SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), 
01762                           "One Asynchronous Read");
01763 
01764             SetWindowText(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT),
01765                           "Continuous Asynchronous Read");
01766 
01767             readThread = NULL;
01768             break;
01769             
01770         case WM_COMMAND:
01771             switch(LOWORD(wParam))
01772             {
01773                 case IDC_READ_SYNCH:
01774 
01775                     EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
01776                     EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), FALSE);
01777                     EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE), FALSE);
01778                     EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT), FALSE);
01779 
01780                     Read(&syncDevice);
01781 
01782                     PostMessage(hDlg, WM_DISPLAY_READ_DATA, 0, (LPARAM) &syncDevice);
01783                     PostMessage(hDlg, WM_READ_DONE, 0, 0);
01784 
01785                     break;
01786 
01787                 case IDC_READ_ASYNCH_ONCE:
01788                 case IDC_READ_ASYNCH_CONT:
01789 
01790                     //
01791                     // When these buttons are pushed there are two options:
01792                     //  1) Start a new asynch read thread (readThread == NULL)
01793                     //  2) Stop a previous asynch read thread
01794                     //
01795                     
01796                     if (NULL == readThread) 
01797                     {
01798                         //
01799                         // Start a new read thread
01800                         //
01801 
01802                         readContext.HidDevice = &asyncDevice;
01803                         readContext.TerminateThread = FALSE;
01804                         readContext.DoOneRead = (IDC_READ_ASYNCH_ONCE == LOWORD(wParam));
01805                         readContext.DisplayWindow = hDlg;
01806                         
01807                         readThread = CreateThread(  NULL,
01808                                                     0,
01809                                                     AsynchReadThreadProc,
01810                                                     &readContext,
01811                                                     0,
01812                                                     &threadID);
01813 
01814                         if (NULL == readThread)
01815                         {
01816                             MessageBox(hDlg,
01817                                        "Unable to create read thread",
01818                                        HCLIENT_ERROR,
01819                                        MB_ICONEXCLAMATION);
01820                         }
01821                         else
01822                         {
01823                             EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
01824                             EnableWindow(GetDlgItem(hDlg, IDC_READ_SYNCH), FALSE);
01825                             EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_ONCE),
01826                                          IDC_READ_ASYNCH_ONCE == LOWORD(wParam));
01827 
01828                             EnableWindow(GetDlgItem(hDlg, IDC_READ_ASYNCH_CONT),
01829                                          IDC_READ_ASYNCH_CONT == LOWORD(wParam)); 
01830 
01831                             SetWindowText(GetDlgItem(hDlg, LOWORD(wParam)), 
01832                                           "Stop Asynchronous Read");
01833                         }
01834                     }
01835                     else
01836                     {
01837                         //
01838                         // Signal the terminate thread variable and
01839                         //  wait for the read thread to complete.
01840                         //
01841                         
01842                         readContext.TerminateThread = TRUE;
01843                         WaitForSingleObject(readThread, INFINITE);
01844                     }                        
01845                     break;
01846                         
01847                 case IDCANCEL:
01848                     readContext.TerminateThread = TRUE;
01849                     WaitForSingleObject(readThread, INFINITE);
01850                     //Fall through!!!
01851 
01852                 case IDOK:                
01853                     CloseHidDevice(&asyncDevice);
01854                     EndDialog(hDlg,0);
01855                     break;
01856             }
01857             break;
01858      } // end switch message 
01859      return FALSE;
01860 } // end bReadDlgProc 
01861 
01862 VOID
01863 ReportToString(
01864    PHID_DATA pData,
01865    PCHAR     szBuff,
01866    UINT      iBuffSize
01867 )
01868 {
01869     PCHAR   pszWalk;
01870     PUSAGE  pUsage;
01871     ULONG   i;
01872     UINT    iRemainingBuffer;
01873     UINT    iStringLength;
01874     HRESULT stringReturn;
01875 
01876     //
01877     // For button data, all the usages in the usage list are to be displayed
01878     //
01879     
01880     if (pData -> IsButtonData)
01881     {
01882         stringReturn = StringCbPrintf (szBuff,
01883                         iBuffSize,
01884                         "Usage Page: 0x%x, Usages: ",
01885                         pData -> UsagePage);
01886 
01887         iRemainingBuffer = 0;
01888         iStringLength = strlen(szBuff);
01889         pszWalk = szBuff + iStringLength;
01890         if (iStringLength < iBuffSize)
01891         {
01892             iRemainingBuffer = iBuffSize - iStringLength;
01893         }
01894         
01895 
01896         for (i = 0, pUsage = pData -> ButtonData.Usages;
01897                      i < pData -> ButtonData.MaxUsageLength;
01898                          i++, pUsage++) 
01899         {
01900             if (0 == *pUsage)
01901             {
01902                 break; // A usage of zero is a non button.
01903             }
01904             stringReturn = StringCbPrintf (pszWalk, iRemainingBuffer, " 0x%x", *pUsage);
01905             iRemainingBuffer -= strlen(pszWalk);
01906             pszWalk += strlen(pszWalk);
01907         }   
01908     }
01909     else
01910     {
01911         stringReturn = StringCbPrintf (szBuff,
01912                         iBuffSize,
01913                         "Usage Page: 0x%x, Usage: 0x%x, Scaled: %d Value: %d",
01914                         pData->UsagePage,
01915                         pData->ValueData.Usage,
01916                         pData->ValueData.ScaledValue,
01917                         pData->ValueData.Value);
01918     }
01919 }
01920 
01921 INT_PTR CALLBACK 
01922 bFeatureDlgProc(
01923     HWND hDlg, 
01924     UINT message, 
01925     WPARAM wParam, 
01926     LPARAM lParam
01927 )
01928 {
01929     static PHID_DEVICE       pDevice;
01930     static INT               iLbCounter;
01931     static rWriteDataStruct  rWriteData[MAX_WRITE_ELEMENTS];
01932     static CHAR              szTempBuff[1024];
01933            INT               iIndex;
01934            INT               iCount;
01935            INT               iErrorLine;
01936            PHID_DATA         pData;
01937            UINT              uLoop;
01938            HRESULT             stringReturn;
01939 
01940     switch(message)
01941     {
01942         case WM_INITDIALOG:
01943             iLbCounter = 0;
01944             pDevice = (PHID_DEVICE) lParam;
01945             break; 
01946 
01947         case WM_COMMAND:
01948             switch(LOWORD(wParam))
01949             {
01950                 case IDC_READ:
01951 
01952                     GetFeature(pDevice);
01953 
01954                     pData = pDevice -> FeatureData;
01955 
01956                     SendDlgItemMessage(hDlg,
01957                                        IDC_OUTPUT,
01958                                        LB_ADDSTRING,
01959                                        0,
01960                                        (LPARAM)"------------ Read Features ---------------");
01961 
01962                     iLbCounter++;
01963 
01964                     if (iLbCounter > MAX_LB_ITEMS) 
01965                     {
01966                         SendDlgItemMessage(hDlg,
01967                                            IDC_OUTPUT,
01968                                            LB_DELETESTRING,
01969                                            0,
01970                                            0);
01971                     }
01972 
01973                     for (uLoop = 0; uLoop < pDevice -> FeatureDataLength; uLoop++)
01974                     {
01975                         ReportToString(pData, szTempBuff, sizeof(szTempBuff));
01976 
01977                         iIndex = (INT) SendDlgItemMessage(hDlg,
01978                                                           IDC_OUTPUT,
01979                                                           LB_ADDSTRING,
01980                                                           0,
01981                                                           (LPARAM) szTempBuff);
01982                                                    
01983                         SendDlgItemMessage(hDlg,
01984                                            IDC_OUTPUT,
01985                                            LB_SETCURSEL,
01986                                            iIndex,
01987                                            (LPARAM) 0);
01988 
01989                         iLbCounter++;
01990                         if (iLbCounter > MAX_LB_ITEMS)
01991                         {
01992                             SendDlgItemMessage(hDlg,
01993                                                IDC_OUTPUT,
01994                                                LB_DELETESTRING,
01995                                                0,
01996                                                0);
01997                         }
01998                         pData++;
01999                     } 
02000                     break;
02001 
02002                 case IDC_WRITE:
02003                     iCount = iPrepareDataFields(pDevice -> FeatureData, 
02004                                                 pDevice -> FeatureDataLength,
02005                                                 rWriteData,
02006                                                 MAX_OUTPUT_ELEMENTS);
02007 
02008                     if (bGetData(rWriteData, iCount, hDlg, "WRITEFEATURE"))
02009                     {
02010                         if (!bParseData(pDevice -> FeatureData, rWriteData,iCount, &iErrorLine)) 
02011                         {
02012                             stringReturn = StringCbPrintf(szTempBuff,
02013                                            sizeof(szTempBuff),
02014                                            "Unable to parse line %x of output data",
02015                                            iErrorLine);
02016                             
02017                             MessageBox(hDlg,
02018                                         szTempBuff,
02019                                         HCLIENT_ERROR,
02020                                         MB_ICONEXCLAMATION);
02021                         }
02022                         else
02023                         {
02024                             if ( SetFeature(pDevice) )
02025                             {
02026                                 SendDlgItemMessage(hDlg,
02027                                                    IDC_OUTPUT,
02028                                                    LB_ADDSTRING,
02029                                                    0,
02030                                                    (LPARAM)"------------ Write Feature ---------------");
02031                             }
02032                             else
02033                             {
02034                                  SendDlgItemMessage(hDlg,
02035                                                     IDC_OUTPUT,
02036                                                     LB_ADDSTRING,
02037                                                     0,
02038                                                     (LPARAM)"------------ Write Feature Error ---------------");
02039                             }                                                             
02040                         }
02041                      }
02042                      break;
02043                       
02044                  case IDOK:
02045                  case IDCANCEL:
02046                      EndDialog(hDlg,0);
02047                      break;
02048             }
02049             break;
02050    } //end switch message//
02051    return FALSE;
02052 } //end bReadDlgProc//
02053 
02054 VOID 
02055 vDisplayDeviceCaps(
02056     IN PHIDP_CAPS pCaps,
02057     IN HWND hControl
02058 )
02059 {
02060     static CHAR szTempBuff[SMALL_BUFF];
02061     HRESULT        stringReturn;
02062 
02063     SendMessage(hControl, LB_RESETCONTENT, 0, 0);
02064 
02065     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pCaps -> UsagePage);
02066     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02067 
02068     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x",pCaps -> Usage);
02069     SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02070 
02071     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Input report byte length: %d",pCaps -> InputReportByteLength);
02072     SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02073 
02074     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Output report byte length: %d",pCaps -> OutputReportByteLength);
02075     SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02076 
02077     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Feature report byte length: %d",pCaps -> FeatureReportByteLength);
02078     SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02079 
02080     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Number of collection nodes %d: ", pCaps -> NumberLinkCollectionNodes);
02081     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02082 
02083     return;
02084 }
02085 
02086 VOID
02087 vDisplayDeviceAttributes(
02088     PHIDD_ATTRIBUTES pAttrib,
02089     HWND hControl
02090 )
02091 {
02092     static CHAR szTempBuff[SMALL_BUFF];
02093     HRESULT        stringReturn;
02094 
02095     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Vendor ID: 0x%x", pAttrib -> VendorID);
02096     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02097 
02098     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Product ID: 0x%x", pAttrib -> ProductID);
02099     SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
02100 
02101     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Version Number  0x%x", pAttrib -> VersionNumber);
02102     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02103 
02104     return;
02105 }
02106 
02107 VOID
02108 vDisplayDataAttributes(
02109     PHIDP_DATA pData, 
02110     BOOL IsButton, 
02111     HWND hControl
02112 )
02113 {
02114     static CHAR szTempBuff[SMALL_BUFF];
02115     HRESULT        stringReturn;
02116 
02117     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "================");
02118 
02119     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Index: 0x%x", pData -> DataIndex);
02120     SendMessage(hControl,LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02121     
02122     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "IsButton: %s", IsButton ? "TRUE" : "FALSE");
02123     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02124 
02125     if (IsButton) 
02126     {
02127         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Button pressed: %s", pData -> On ? "TRUE" : "FALSE");
02128         SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02129     }
02130     else
02131     {
02132         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Data value: 0x%x", pData -> RawValue);
02133         SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02134     }
02135 }
02136 
02137 VOID 
02138 vDisplayButtonAttributes(
02139     IN PHIDP_BUTTON_CAPS pButton,
02140     IN HWND hControl
02141 )
02142 {
02143     static CHAR szTempBuff[SMALL_BUFF];
02144     HRESULT        stringReturn;
02145    
02146     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Report ID: 0x%x", pButton->ReportID);
02147     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02148      
02149     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pButton->UsagePage);
02150     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02151         
02152     stringReturn = StringCbPrintf(szTempBuff,
02153                    SMALL_BUFF, 
02154                    "Alias: %s",
02155                    pButton -> IsAlias ? "TRUE" : "FALSE");
02156     
02157     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02158    
02159     stringReturn = StringCbPrintf(szTempBuff,
02160                    SMALL_BUFF,
02161                    "Link Collection: %hu",
02162                    pButton -> LinkCollection);
02163 
02164     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02165    
02166     stringReturn = StringCbPrintf(szTempBuff,
02167                    SMALL_BUFF,
02168                    "Link Usage Page: 0x%x",
02169                    pButton -> LinkUsagePage);
02170  
02171     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);        
02172    
02173     stringReturn = StringCbPrintf(szTempBuff,
02174                    SMALL_BUFF,
02175                    "Link Usage: 0x%x",
02176                    pButton -> LinkUsage);
02177 
02178     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02179 
02180     if (pButton->IsRange) 
02181     {
02182         stringReturn = StringCbPrintf(szTempBuff,
02183                        SMALL_BUFF,
02184                        "Usage Min: 0x%x, Usage Max: 0x%x",
02185                        pButton->Range.UsageMin, 
02186                        pButton->Range.UsageMax);
02187     } 
02188     else
02189     {
02190         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x",pButton->NotRange.Usage);
02191 
02192     } 
02193     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02194 
02195     if (pButton->IsRange)
02196     {
02197          stringReturn = StringCbPrintf(szTempBuff,
02198                         SMALL_BUFF,
02199                         "Data Index Min: 0x%x, Data Index Max: 0x%x",
02200                         pButton->Range.DataIndexMin, 
02201                         pButton->Range.DataIndexMax);
02202 
02203     } 
02204     else 
02205     {
02206         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "DataIndex: 0x%x",pButton->NotRange.DataIndex);
02207     } 
02208 
02209     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02210 
02211     if (pButton->IsStringRange)
02212     {
02213         stringReturn = StringCbPrintf(szTempBuff,
02214                        SMALL_BUFF,
02215                        "String Min: 0x%x, String Max: 0x%x",
02216                        pButton->Range.StringMin, 
02217                        pButton->Range.StringMax);
02218     } 
02219     else
02220     {
02221         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "String Index: 0x%x",pButton->NotRange.StringIndex);
02222     } 
02223     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02224 
02225     if (pButton->IsDesignatorRange) 
02226     {
02227         stringReturn = StringCbPrintf(szTempBuff,
02228                        SMALL_BUFF,
02229                        "Designator Min: 0x%x, Designator Max: 0x%x",
02230                        pButton->Range.DesignatorMin, 
02231                        pButton->Range.DesignatorMax);
02232 
02233     } 
02234     else
02235     {
02236         stringReturn = StringCbPrintf(szTempBuff,
02237                        SMALL_BUFF,
02238                        "Designator Index: 0x%x",
02239                        pButton->NotRange.DesignatorIndex);
02240     } 
02241     SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
02242 
02243     if (pButton->IsAbsolute)
02244     {
02245         SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: Yes");
02246     }
02247     else
02248     {
02249         SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) "Absolute: No");
02250     }
02251     return;
02252 } 
02253 
02254 VOID
02255 vDisplayValueAttributes(
02256     IN PHIDP_VALUE_CAPS pValue,
02257     HWND hControl
02258 )
02259 {
02260     static CHAR szTempBuff[SMALL_BUFF];
02261     HRESULT        stringReturn;
02262 
02263     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Report ID 0x%x", pValue->ReportID);
02264     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02265  
02266     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pValue->UsagePage);
02267     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02268 
02269     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Bit size: 0x%x", pValue->BitSize);
02270     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02271 
02272     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Report Count: 0x%x", pValue->ReportCount);
02273     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02274 
02275     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Unit Exponent: 0x%x", pValue->UnitsExp);
02276     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02277 
02278     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Has Null: 0x%x", pValue->HasNull);
02279     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);    
02280 
02281  
02282     if (pValue->IsAlias)
02283     {
02284         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Alias");
02285     }
02286     else 
02287     {
02288         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "=====");
02289     }
02290     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02291 
02292     if (pValue->IsRange)
02293     {
02294         stringReturn = StringCbPrintf(szTempBuff,
02295                        SMALL_BUFF,
02296                        "Usage Min: 0x%x, Usage Max 0x%x",
02297                        pValue->Range.UsageMin, 
02298                        pValue->Range.UsageMax);
02299     } 
02300     else
02301     {
02302         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x", pValue -> NotRange.Usage);
02303     } 
02304     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02305 
02306     if (pValue->IsRange)
02307     {
02308         stringReturn = StringCbPrintf(szTempBuff,
02309                        SMALL_BUFF,
02310                        "Data Index Min: 0x%x, Data Index Max: 0x%x",
02311                        pValue->Range.DataIndexMin, 
02312                        pValue->Range.DataIndexMax);
02313     } 
02314     else
02315     {
02316         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "DataIndex: 0x%x", pValue->NotRange.DataIndex);
02317     } 
02318     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02319 
02320     stringReturn = StringCbPrintf(szTempBuff,
02321                    SMALL_BUFF,
02322                    "Physical Minimum: %d, Physical Maximum: %d",
02323                    pValue->PhysicalMin, 
02324                    pValue->PhysicalMax);
02325 
02326     SendMessage(hControl, LB_ADDSTRING, 0,(LPARAM) szTempBuff);
02327 
02328     stringReturn = StringCbPrintf(szTempBuff,
02329                    SMALL_BUFF,
02330                    "Logical Minimum: 0x%x, Logical Maximum: 0x%x",
02331                    pValue->LogicalMin,
02332                    pValue->LogicalMax);
02333 
02334     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02335 
02336     if (pValue->IsStringRange) 
02337     {
02338        stringReturn = StringCbPrintf(szTempBuff,
02339                       SMALL_BUFF,
02340                       "String  Min: 0x%x String Max 0x%x",
02341                       pValue->Range.StringMin,
02342                       pValue->Range.StringMax);
02343     } 
02344     else
02345     {
02346         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "String Index: 0x%x",pValue->NotRange.StringIndex);
02347     } 
02348     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02349 
02350     if (pValue->IsDesignatorRange) 
02351     {
02352         stringReturn = StringCbPrintf(szTempBuff,
02353                        SMALL_BUFF,
02354                        "Designator Minimum: 0x%x, Max: 0x%x",
02355                        pValue->Range.DesignatorMin, 
02356                        pValue->Range.DesignatorMax);
02357     } 
02358     else 
02359     {
02360         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Designator Index: 0x%x",pValue->NotRange.DesignatorIndex);
02361     } 
02362     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02363  
02364     if (pValue->IsAbsolute) 
02365     { 
02366         SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: Yes");
02367     }
02368     else
02369     {
02370         SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) "Absolute: No");
02371     }
02372     return;
02373 }
02374 
02375 VOID 
02376 vDisplayInputButtons(
02377     IN PHID_DEVICE pDevice,
02378     IN HWND hControl
02379 )
02380 {
02381     INT               iLoop;
02382     PHIDP_BUTTON_CAPS pButtonCaps;
02383     static CHAR       szTempBuff[SMALL_BUFF];
02384     INT               iIndex;
02385     HRESULT              stringReturn;
02386 
02387     SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0);
02388 
02389     pButtonCaps = pDevice->InputButtonCaps;
02390     for (iLoop = 0; iLoop < pDevice->Caps.NumberInputButtonCaps; iLoop++) 
02391     {
02392         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Input button cap # %d", iLoop);
02393 
02394         iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02395 
02396         if (-1 != iIndex)
02397         {
02398             SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pButtonCaps);
02399         }
02400 
02401         pButtonCaps++;
02402     } 
02403     SendMessage(hControl, LB_SETCURSEL, 0, 0 );
02404 }
02405 
02406 VOID 
02407 vDisplayOutputButtons(
02408    IN PHID_DEVICE pDevice,
02409    IN HWND hControl
02410 )
02411 {
02412     INT               iLoop;
02413     static CHAR       szTempBuff[SMALL_BUFF];
02414     INT               iIndex;
02415     PHIDP_BUTTON_CAPS pButtonCaps;
02416     HRESULT              stringReturn;
02417 
02418     SendMessage(hControl, LB_RESETCONTENT, 0, (LPARAM) 0);
02419 
02420     pButtonCaps = pDevice -> OutputButtonCaps;
02421 
02422     for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputButtonCaps; iLoop++) 
02423     {
02424         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Output button cap # %d", iLoop);
02425         iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02426 
02427         if (-1 != iIndex)
02428         {
02429             SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps);
02430         }
02431         pButtonCaps++;
02432     }
02433 
02434     SendMessage(hControl, LB_SETCURSEL, 0, 0);
02435     return;
02436 }
02437 
02438 VOID 
02439 vDisplayInputValues(
02440     IN PHID_DEVICE pDevice,
02441     IN HWND hControl
02442 )
02443 {
02444     INT              iLoop;
02445     static CHAR      szTempBuff[SMALL_BUFF];
02446     INT              iIndex;
02447     PHIDP_VALUE_CAPS pValueCaps;
02448     HRESULT             stringReturn;
02449 
02450     SendMessage(hControl, LB_RESETCONTENT, 0, 0);
02451 
02452     pValueCaps = pDevice -> InputValueCaps;
02453 
02454     for (iLoop=0; iLoop < pDevice->Caps.NumberInputValueCaps; iLoop++) 
02455     {
02456         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Input value cap # %d",iLoop);
02457         iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02458 
02459         if (-1 != iIndex) 
02460         {
02461            SendMessage(hControl, LB_SETITEMDATA, iIndex,(LPARAM) pValueCaps);
02462         }
02463         pValueCaps++;
02464     }
02465 
02466     SendMessage(hControl, LB_SETCURSEL, 0, 0);
02467     return;
02468 }
02469 
02470 VOID
02471 vDisplayOutputValues(
02472     IN PHID_DEVICE pDevice,
02473     IN HWND hControl)
02474 {
02475     INT              iLoop;
02476     static CHAR      szTempBuff[SMALL_BUFF];
02477     INT              iIndex;
02478     PHIDP_VALUE_CAPS pValueCaps;
02479     HRESULT             stringReturn;
02480    
02481     SendMessage(hControl, LB_RESETCONTENT, 0, 0);
02482     pValueCaps = pDevice -> OutputValueCaps;
02483    
02484     for (iLoop = 0; iLoop < pDevice->Caps.NumberOutputValueCaps; iLoop++) 
02485     {
02486         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Output value cap # %d", iLoop);
02487         iIndex = (INT) SendMessage(hControl, 
02488                                    LB_ADDSTRING, 
02489                                    0, 
02490                                    (LPARAM) szTempBuff);
02491        
02492         if (-1 != iIndex) 
02493         {
02494             SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps);
02495         }
02496         pValueCaps++;
02497     }
02498 
02499     SendMessage(hControl, LB_SETCURSEL, 0, 0);
02500 
02501     return;
02502 }
02503 
02504 VOID
02505 vDisplayFeatureButtons(
02506     IN PHID_DEVICE pDevice,
02507     IN HWND hControl
02508 )
02509 {
02510     INT               iLoop;
02511     static CHAR       szTempBuff[SMALL_BUFF];
02512     INT               iIndex;
02513     PHIDP_BUTTON_CAPS pButtonCaps;
02514     HRESULT              stringReturn;
02515 
02516     SendMessage(hControl, LB_RESETCONTENT, 0, 0);
02517 
02518     pButtonCaps = pDevice -> FeatureButtonCaps;
02519 
02520     for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureButtonCaps; iLoop++) 
02521     {
02522         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Feature button cap # %d", iLoop);
02523         iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02524 
02525         if (-1 != iIndex) 
02526         {
02527             SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pButtonCaps);
02528         }
02529         pButtonCaps++;
02530     } 
02531     SendMessage(hControl, LB_SETCURSEL, 0, 0);
02532     return;
02533 }
02534 
02535 VOID
02536 vDisplayFeatureValues(
02537     IN PHID_DEVICE pDevice,
02538     IN HWND hControl
02539 )
02540 {
02541     INT              iLoop;
02542     static CHAR      szTempBuff[SMALL_BUFF];
02543     INT              iIndex;
02544     PHIDP_VALUE_CAPS pValueCaps;
02545     HRESULT             stringReturn;
02546 
02547     SendMessage(hControl, LB_RESETCONTENT, 0, 0);
02548     pValueCaps = pDevice ->FeatureValueCaps;
02549 
02550     for (iLoop = 0; iLoop < pDevice->Caps.NumberFeatureValueCaps; iLoop++) 
02551     {
02552         stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Feature value cap # %d", iLoop);
02553         iIndex = (INT) SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02554 
02555         if (-1 != iIndex) 
02556         {
02557             SendMessage(hControl, LB_SETITEMDATA, iIndex, (LPARAM) pValueCaps);
02558         }
02559 
02560         pValueCaps++;
02561     } 
02562     SendMessage(hControl, LB_SETCURSEL, 0, 0);
02563     return;
02564 }
02565 
02566 VOID
02567 vLoadItemTypes(
02568     IN HWND hItemTypes
02569 )
02570 {
02571     INT iIndex;
02572 
02573     iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "INPUT BUTTON");
02574 
02575     if (-1 != iIndex) 
02576     {
02577         SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_BUTTON);
02578 
02579         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0 ,(LPARAM) "INPUT VALUE");
02580         if (-1 != iIndex) 
02581         {
02582             SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, INPUT_VALUE);
02583         }
02584 
02585         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT BUTTON");
02586         if (-1 != iIndex)
02587         {
02588             SendMessage(hItemTypes,CB_SETITEMDATA,iIndex,OUTPUT_BUTTON);
02589         }
02590 
02591         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "OUTPUT VALUE");
02592         if (-1 != iIndex)
02593         {
02594             SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, OUTPUT_VALUE);
02595         }
02596 
02597         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE BUTTON");
02598         if (-1 != iIndex) 
02599         {
02600             SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_BUTTON);
02601         }
02602 
02603         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "FEATURE VALUE");
02604         if (-1 != iIndex)
02605         {
02606             SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, FEATURE_VALUE);
02607         }
02608 
02609         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "HID CAPS");
02610         if (-1 != iIndex )
02611         {
02612             SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, HID_CAPS);
02613         }
02614 
02615         iIndex = (INT) SendMessage(hItemTypes, CB_ADDSTRING, 0, (LPARAM) "DEVICE ATTRIBUTES");
02616         if (-1 != iIndex)
02617         {
02618             SendMessage(hItemTypes, CB_SETITEMDATA, iIndex, DEVICE_ATTRIBUTES);
02619         }
02620 
02621         SendMessage(hItemTypes, CB_SETCURSEL, 0, 0);
02622     }
02623 } 
02624 
02625 VOID vLoadDevices(
02626     HWND    hDeviceCombo
02627 )
02628 {
02629     PDEVICE_LIST_NODE   currNode;
02630     
02631     static CHAR szTempBuff[SMALL_BUFF];
02632     INT         iIndex;
02633     HRESULT        stringReturn;
02634 
02635     //
02636     // Reset the content of the device list box.
02637     //
02638 
02639     SendMessage(hDeviceCombo, CB_RESETCONTENT, 0, 0);
02640 
02641 
02642     if (!IsListEmpty(&PhysicalDeviceList))
02643     {
02644         currNode = (PDEVICE_LIST_NODE) GetListHead(&PhysicalDeviceList);
02645           
02646         do
02647         {
02648             stringReturn = StringCbPrintf(szTempBuff,
02649                            SMALL_BUFF,
02650                            "Device %d, UsagePage 0%x, Usage 0%x",
02651                            HandleToULong(currNode -> HidDeviceInfo.HidDevice),
02652                            currNode -> HidDeviceInfo.Caps.UsagePage,
02653                            currNode -> HidDeviceInfo.Caps.Usage);
02654 
02655             iIndex = (INT) SendMessage(hDeviceCombo, CB_ADDSTRING, 0, (LPARAM) szTempBuff);
02656 
02657             if (CB_ERR != iIndex) 
02658             {
02659                 SendMessage(hDeviceCombo, CB_SETITEMDATA, iIndex, (LPARAM) &(currNode -> HidDeviceInfo));
02660             }
02661 
02662             currNode = (PDEVICE_LIST_NODE) GetNextEntry(currNode);
02663             
02664         } while ((PLIST) currNode != &PhysicalDeviceList);
02665        
02666     } 
02667 
02668    
02669     SendMessage(hDeviceCombo, CB_SETCURSEL, 0, 0);
02670   
02671     return;
02672 }
02673 
02674 BOOL
02675 bGetData(
02676     prWriteDataStruct pItems,
02677     INT               iCount,
02678     HWND              hParent, 
02679     PCHAR             pszDialogName
02680 )
02681 {
02682     rGetWriteDataParams        rParams;
02683     static rWriteDataStruct    arTempItems[MAX_WRITE_ELEMENTS];
02684     INT                        iResult;
02685 
02686 
02687     if (iCount > MAX_WRITE_ELEMENTS) 
02688     {
02689         iCount = MAX_WRITE_ELEMENTS;
02690     }
02691 
02692     memcpy( &(arTempItems[0]), pItems, sizeof(rWriteDataStruct)*iCount);
02693 
02694     rParams.iCount = iCount;
02695     rParams.prItems = &(arTempItems[0]);
02696 
02697     iResult = (INT) DialogBoxParam(hGInstance,
02698                                    pszDialogName,
02699                                    hParent,
02700                                    bGetDataDlgProc,
02701                                    (LPARAM) &rParams);
02702     if (iResult) 
02703     {
02704        memcpy(pItems, arTempItems, sizeof(rWriteDataStruct)*iCount);
02705     }
02706     return iResult;
02707 } 
02708 
02709 INT_PTR CALLBACK 
02710 bGetDataDlgProc(
02711     HWND hDlg, 
02712     UINT message, 
02713     WPARAM wParam, 
02714     LPARAM lParam
02715 )
02716 {
02717     static prWriteDataStruct    prData;
02718     static prGetWriteDataParams pParams;
02719     static INT                  iDisplayCount;
02720     static INT                  iScrollRange;
02721     static INT                  iCurrentScrollPos=0;
02722     static HWND                 hScrollBar;
02723            INT                  iTemp;
02724            SCROLLINFO           rScrollInfo;
02725            INT                  iReturn;
02726 
02727     switch(message) 
02728     {
02729         case WM_INITDIALOG:
02730 
02731             pParams = (prGetWriteDataParams) lParam;
02732             prData = pParams -> prItems;
02733             hScrollBar = GetDlgItem(hDlg, IDC_SCROLLBAR);
02734 
02735             if (pParams -> iCount > CONTROL_COUNT) 
02736             {
02737                 iDisplayCount = CONTROL_COUNT;
02738                 iScrollRange = pParams -> iCount - CONTROL_COUNT;
02739                 rScrollInfo.fMask = SIF_RANGE | SIF_POS;
02740                 rScrollInfo.nPos = 0;
02741                 rScrollInfo.nMin = 0;
02742                 rScrollInfo.nMax = iScrollRange;
02743                 rScrollInfo.cbSize = sizeof(rScrollInfo);
02744                 rScrollInfo.nPage = CONTROL_COUNT;
02745                 iReturn = SetScrollInfo(hScrollBar,SB_CTL,&rScrollInfo,TRUE);
02746             }
02747             else
02748             {
02749                 iDisplayCount=pParams->iCount;
02750                 EnableWindow(hScrollBar,FALSE);
02751             }
02752             vWriteDataToControls(hDlg, prData, 0, pParams->iCount);
02753             break;
02754 
02755         case WM_COMMAND:
02756             switch(LOWORD(wParam)) 
02757             {
02758                 case IDOK:
02759                 case ID_SEND:
02760                     vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
02761                     EndDialog(hDlg,1);
02762                     break;
02763 
02764                 case IDCANCEL:
02765                     EndDialog(hDlg,0);
02766                     break;
02767              } 
02768              break;
02769 
02770         case WM_VSCROLL:
02771             vReadDataFromControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
02772 
02773             switch(LOWORD(wParam)) 
02774             {
02775                 case SB_LINEDOWN:
02776                     ++iCurrentScrollPos;
02777                     break;
02778 
02779                 case SB_LINEUP:
02780                     --iCurrentScrollPos;
02781                     break;
02782 
02783                 case SB_THUMBPOSITION:
02784                     iCurrentScrollPos = HIWORD(wParam);
02785 
02786                 case SB_PAGEUP:
02787                     iCurrentScrollPos -= CONTROL_COUNT;
02788                     break;
02789 
02790                 case SB_PAGEDOWN:
02791                     iCurrentScrollPos += CONTROL_COUNT;
02792                     break;
02793             }
02794 
02795             if (iCurrentScrollPos < 0) 
02796             {
02797                 iCurrentScrollPos = 0;
02798             }
02799              
02800             if (iCurrentScrollPos > iScrollRange)
02801             {
02802                 iCurrentScrollPos = iScrollRange; 
02803             }
02804 
02805             SendMessage(hScrollBar, SBM_SETPOS, iCurrentScrollPos, TRUE);
02806             iTemp = LOWORD(wParam);
02807 
02808             if ( (iTemp == SB_LINEDOWN) || (iTemp == SB_LINEUP) || (iTemp == SB_THUMBPOSITION)|| (iTemp == SB_PAGEUP) || (iTemp==SB_PAGEDOWN) )
02809             {
02810                 vWriteDataToControls(hDlg, prData, iCurrentScrollPos, iDisplayCount);
02811             }
02812             break; 
02813     } 
02814     return FALSE;
02815 } //end function bGetDataDlgProc//
02816 
02817 VOID
02818 vReadDataFromControls(
02819     HWND hDlg,
02820     prWriteDataStruct prData,
02821     INT iOffset,
02822     INT iCount
02823 )
02824 {
02825     INT               iLoop;
02826     INT               iValueControlID = IDC_OUT_EDIT1;
02827     prWriteDataStruct pDataWalk;
02828     HWND              hValueWnd;
02829 
02830     pDataWalk = prData + iOffset;
02831     for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++) 
02832     {
02833         hValueWnd = GetDlgItem(hDlg, iValueControlID);
02834 
02835         GetWindowText(hValueWnd, pDataWalk -> szValue, MAX_VALUE);
02836 
02837         iValueControlID++;
02838 
02839         pDataWalk++;
02840     } 
02841 
02842     return;
02843 } 
02844 
02845 VOID
02846 vWriteDataToControls(
02847     HWND                hDlg,
02848     prWriteDataStruct   prData,
02849     INT                 iOffset,
02850     INT                 iCount
02851 )
02852 {
02853     INT               iLoop;
02854     INT               iLabelControlID = IDC_OUT_LABEL1;
02855     INT               iValueControlID = IDC_OUT_EDIT1;
02856     HWND              hLabelWnd, hValueWnd;
02857     prWriteDataStruct pDataWalk;
02858 
02859     pDataWalk = prData + iOffset;
02860 
02861     for (iLoop = 0; (iLoop < iCount) && (iLoop < CONTROL_COUNT); iLoop++) 
02862     {
02863          hLabelWnd = GetDlgItem(hDlg, iLabelControlID);
02864          hValueWnd = GetDlgItem(hDlg, iValueControlID);
02865          
02866          ShowWindow(hLabelWnd, SW_SHOW);
02867          ShowWindow(hValueWnd, SW_SHOW);
02868          
02869          SetWindowText(hLabelWnd, pDataWalk -> szLabel);
02870          SetWindowText(hValueWnd, pDataWalk -> szValue);
02871          
02872          iLabelControlID++;
02873          iValueControlID++;
02874          pDataWalk++;
02875     }     
02876      
02877     //
02878     // Hide the controls
02879     //
02880 
02881     for (; iLoop < CONTROL_COUNT; iLoop++) 
02882     {
02883         hLabelWnd = GetDlgItem(hDlg,iLabelControlID);
02884         hValueWnd = GetDlgItem(hDlg,iValueControlID);
02885         
02886         ShowWindow(hLabelWnd,SW_HIDE);
02887         ShowWindow(hValueWnd,SW_HIDE);
02888         
02889         iLabelControlID++;
02890         iValueControlID++;
02891      } 
02892 } 
02893 
02894 VOID
02895 vCreateUsageString(
02896     IN  PUSAGE   pUsageList,
02897     OUT CHAR     szString[]
02898 )
02899 {
02900     HRESULT stringReturn;
02901     
02902     stringReturn = StringCbPrintf(szString,
02903                    SMALL_BUFF,
02904                    "Usage: %#04x",
02905                    *pUsageList);
02906 
02907     return;
02908 }
02909 
02910 VOID
02911 vCreateUsageAndPageString(
02912     IN  PUSAGE_AND_PAGE pUsageList,
02913     OUT CHAR            szString[]
02914 )
02915 {
02916     HRESULT stringReturn;
02917     
02918     stringReturn = StringCbPrintf(szString,
02919                    SMALL_BUFF,
02920                    "Usage Page: %#04x  Usage: %#04x",
02921                    pUsageList -> UsagePage,
02922                    pUsageList -> Usage);
02923 
02924     return;
02925 }
02926 
02927 VOID
02928 vDisplayLinkCollectionNode(
02929     IN  PHIDP_LINK_COLLECTION_NODE  pLCNode,
02930     IN  ULONG                       ulLinkIndex,
02931     IN  HWND                        hControl
02932 )
02933 {
02934     static CHAR szTempBuff[SMALL_BUFF];
02935     HRESULT        stringReturn;
02936 
02937     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Index: 0x%x", ulLinkIndex);
02938     SendMessage(hControl, LB_ADDSTRING, 0, (LPARAM) szTempBuff);
02939     
02940     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage Page: 0x%x", pLCNode -> LinkUsagePage);
02941     SendMessage(hControl, LB_ADDSTRING,0, (LPARAM)szTempBuff);
02942 
02943     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Usage: 0x%x", pLCNode -> LinkUsage);
02944     SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
02945 
02946     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Parent Index: 0x%x", pLCNode -> Parent);
02947     SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
02948 
02949     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Number of Children: 0x%x", pLCNode -> NumberOfChildren);
02950     SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
02951 
02952     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "Next Sibling: 0x%x", pLCNode -> NextSibling);
02953     SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
02954 
02955     stringReturn = StringCbPrintf(szTempBuff, SMALL_BUFF, "First Child: 0x%x", pLCNode -> FirstChild);
02956     SendMessage(hControl, LB_ADDSTRING,0, (LPARAM) szTempBuff);
02957 
02958     return;
02959 }
02960 
02961 VOID
02962 vCreateUsageValueStringFromArray(
02963     PCHAR       pBuffer,
02964     USHORT      BitSize,
02965     USHORT      UsageIndex,
02966     CHAR        szString[]
02967 )
02968 /*++
02969 Routine Description:
02970     Given a report buffer, pBuffer, this routine extracts the given usage
02971     at UsageIndex from the array and outputs to szString the string
02972     representation of that value.  The input parameter BitSize specifies
02973     the number of bits representing that value in the array.  This is
02974     useful for extracting individual members of a UsageValueArray.
02975 --*/
02976 {
02977     INT         iByteIndex;
02978     INT         iByteOffset;
02979     UCHAR       ucLeftoverBits;
02980     ULONG       ulMask;
02981     ULONG       ulValue;
02982     HRESULT        stringReturn;
02983 
02984     //
02985     // Calculate the byte and byte offset into the buffer for the given
02986     //   index value
02987     //
02988     
02989     iByteIndex = (UsageIndex * BitSize) >> 3;
02990     iByteOffset = (UsageIndex * BitSize) & 7;
02991 
02992     //
02993     // Extract the 32-bit value beginning at ByteIndex.  This value
02994     //   will contain some or all of the value we are attempting to retrieve
02995     //
02996     
02997     ulValue = *(PULONG) (pBuffer + iByteIndex);
02998 
02999     //
03000     // Shift that value to the right by our byte offset..
03001     //
03002     
03003     ulValue = ulValue >> iByteOffset;
03004 
03005     //
03006     // At this point, ulValue contains the first 32-iByteOffset bits beginning
03007     //    the appropriate offset in the buffer.  There are now two cases to 
03008     //    look at:
03009     //      
03010     //    1) BitSize > 32-iByteOffset -- In which case, we need to extract
03011     //                                   iByteOffset bits from the next
03012     //                                   byte in the array and OR them as
03013     //                                   the MSBs of ulValue
03014     //
03015     //    2) BitSize < 32-iByteOffset -- Need to get only the BitSize LSBs
03016     //                                   
03017     //
03018 
03019     //
03020     // Case #1
03021     //
03022     
03023     if (BitSize > sizeof(ULONG)*8 - iByteOffset) 
03024     {
03025         //
03026         // Get the next byte of the report following the four bytes we
03027         //   retrieved earlier for ulValue
03028         //
03029         
03030         ucLeftoverBits =  *(pBuffer+iByteIndex+4);
03031 
03032         //
03033         // Shift those bits to the left for anding to our previous value
03034         //
03035         
03036         ulMask = ucLeftoverBits << (24 + (8 - iByteOffset));
03037         ulValue |= ulMask;
03038 
03039     }
03040     else if (BitSize < sizeof(ULONG)*8 - iByteOffset) 
03041     {
03042         //
03043         // Need to mask the most significant bits that are part of another
03044         //    value(s), not the one we are currently working with.
03045         //
03046         
03047         ulMask = (1 << BitSize) - 1;
03048         ulValue &= ulMask;
03049     }
03050     
03051     //
03052     // We've now got the correct value, now output to the string
03053     //
03054 
03055     stringReturn = StringCbPrintf(szString, SMALL_BUFF, "Usage value: %lu", ulValue);
03056 
03057     return;
03058 }
03059 
03060 
03061 BOOL
03062 RegisterHidDevice(
03063     IN  HWND                WindowHandle,
03064     IN  PDEVICE_LIST_NODE   DeviceNode
03065 )
03066 {
03067     DEV_BROADCAST_HANDLE broadcastHandle;
03068     
03069     broadcastHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
03070     broadcastHandle.dbch_devicetype = DBT_DEVTYP_HANDLE;
03071     broadcastHandle.dbch_handle = DeviceNode -> HidDeviceInfo.HidDevice;
03072 
03073     DeviceNode -> NotificationHandle = RegisterDeviceNotification( 
03074                                                 WindowHandle,
03075                                                 &broadcastHandle,
03076                                                 DEVICE_NOTIFY_WINDOW_HANDLE);
03077 
03078     return (NULL != DeviceNode -> NotificationHandle);
03079 }   
03080 
03081 VOID
03082 DestroyDeviceListCallback(
03083     PLIST_NODE_HDR   ListNode
03084 )
03085 {
03086     PDEVICE_LIST_NODE   deviceNode;
03087 
03088     deviceNode = (PDEVICE_LIST_NODE) ListNode;
03089     
03090     //
03091     // The callback function needs to do the following steps...
03092     //   1) Close the HidDevice
03093     //   2) Unregister device notification (if registered)
03094     //   3) Free the allocated memory block
03095     //
03096 
03097     CloseHidDevice(&(deviceNode -> HidDeviceInfo));
03098 
03099     if (NULL != deviceNode -> NotificationHandle) 
03100     {
03101         UnregisterDeviceNotification(deviceNode -> NotificationHandle);
03102     }
03103 
03104     free (deviceNode);
03105 
03106     return;
03107 }
03108 
03109 DWORD WINAPI
03110 AsynchReadThreadProc( 
03111     PREAD_THREAD_CONTEXT    Context
03112 )
03113 {
03114     HANDLE  completionEvent;
03115     BOOL    readStatus;
03116     DWORD   waitStatus;
03117     
03118     //
03119     // Create the completion event to send to the the OverlappedRead routine
03120     //
03121 
03122     completionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
03123 
03124     //
03125     // If NULL returned, then we cannot proceed any farther so we just exit the 
03126     //  the thread
03127     //
03128     
03129     if (NULL == completionEvent) 
03130     {
03131         goto AsyncRead_End;
03132     }
03133 
03134     //
03135     // Now we enter the main read loop, which does the following:
03136     //  1) Calls ReadOverlapped()
03137     //  2) Waits for read completion with a timeout just to check if 
03138     //      the main thread wants us to terminate our the read request
03139     //  3) If the read fails, we simply break out of the loop
03140     //      and exit the thread
03141     //  4) If the read succeeds, we call UnpackReport to get the relevant
03142     //      info and then post a message to main thread to indicate that
03143     //      there is new data to display.
03144     //  5) We then block on the display event until the main thread says
03145     //      it has properly displayed the new data
03146     //  6) Look to repeat this loop if we are doing more than one read
03147     //      and the main thread has yet to want us to terminate
03148     //
03149 
03150     do 
03151     {
03152         //
03153         // Call ReadOverlapped() and if the return status is TRUE, the ReadFile
03154         //  succeeded so we need to block on completionEvent, otherwise, we just
03155         //  exit
03156         //
03157 
03158         readStatus = ReadOverlapped( Context -> HidDevice, completionEvent );
03159 
03160     
03161         if (!readStatus) 
03162         {
03163            break;
03164         }
03165 
03166         while (!Context -> TerminateThread) 
03167         {
03168             //
03169             // Wait for the completion event to be signalled or a timeout
03170             //
03171             
03172             waitStatus = WaitForSingleObject (completionEvent, READ_THREAD_TIMEOUT );
03173 
03174             //
03175             // If completionEvent was signalled, then a read just completed
03176             //   so let's leave this loop and process the data
03177             //
03178             
03179             if ( WAIT_OBJECT_0 == waitStatus)
03180             { 
03181                 break;
03182             }
03183         }
03184 
03185         //
03186         // Check the TerminateThread again...If it is not set, then data has
03187         //  been read.  In this case, we want to Unpack the report into our
03188         //  input info and then send a message to the main thread to display
03189         //  the new data.
03190         //
03191         
03192         if (!Context -> TerminateThread) 
03193         {
03194             UnpackReport(Context -> HidDevice -> InputReportBuffer,
03195                           Context -> HidDevice -> Caps.InputReportByteLength,
03196                           HidP_Input,
03197                           Context -> HidDevice -> InputData,
03198                           Context -> HidDevice -> InputDataLength,
03199                           Context -> HidDevice -> Ppd);
03200             
03201             if (NULL != Context -> DisplayEvent) 
03202             { 
03203                 PostMessage(Context -> DisplayWindow,
03204                             WM_DISPLAY_READ_DATA,
03205                             0,
03206                             (LPARAM) Context -> HidDevice);
03207 
03208                 WaitForSingleObject( Context -> DisplayEvent, INFINITE );
03209             }
03210         }
03211     } while ( !Context -> TerminateThread && !Context -> DoOneRead );
03212 
03213 
03214 AsyncRead_End:
03215 
03216     PostMessage( Context -> DisplayWindow, WM_READ_DONE, 0, 0);
03217     ExitThread(0);
03218     return (0);
03219 }
03220 
03221 DWORD WINAPI
03222 SynchReadThreadProc(
03223     PREAD_THREAD_CONTEXT    Context
03224 )
03225 {
03226     do 
03227     {
03228         Read(Context -> HidDevice);
03229 
03230         UnpackReport(Context -> HidDevice -> InputReportBuffer,
03231                      Context -> HidDevice -> Caps.InputReportByteLength,
03232                      HidP_Input,
03233                      Context -> HidDevice -> InputData,
03234                      Context -> HidDevice -> InputDataLength,
03235                      Context -> HidDevice -> Ppd);
03236 
03237         if (NULL != Context -> DisplayEvent) 
03238         {
03239             PostMessage(Context -> DisplayWindow,
03240                         WM_DISPLAY_READ_DATA,
03241                         0,
03242                         (LPARAM) Context -> HidDevice);
03243 
03244             WaitForSingleObject( Context -> DisplayEvent, INFINITE );
03245         }
03246     } while ( !Context -> TerminateThread && !Context -> DoOneRead );
03247 
03248     PostMessage( Context -> DisplayWindow, WM_READ_DONE, 0, 0);
03249     ExitThread(0);
03250     return (0);
03251 }  
03252 
03253 DWORD WINAPI
03254 MyReadThreadProc(
03255     PREAD_THREAD_CONTEXT    Context
03256 )
03257 {
03258 #if 1
03259     do {
03260         PostMessage(Context->DisplayWindow, WM_COMMAND, IDC_BUTTON_RD, IDC_BUTTON_RD);
03261         Sleep(100);
03262     } while ( !Context->TerminateThread && !Context->DoOneRead );
03263 #else
03264     do 
03265     {
03266         Read(Context -> HidDevice);
03267 
03268         UnpackReport(Context -> HidDevice -> InputReportBuffer,
03269                      Context -> HidDevice -> Caps.InputReportByteLength,
03270                      HidP_Input,
03271                      Context -> HidDevice -> InputData,
03272                      Context -> HidDevice -> InputDataLength,
03273                      Context -> HidDevice -> Ppd);
03274 
03275         if (NULL != Context -> DisplayEvent) 
03276         {
03277             PostMessage(Context -> DisplayWindow,
03278                         WM_DISPLAY_READ_DATA,
03279                         0,
03280                         (LPARAM) Context -> HidDevice);
03281 
03282             WaitForSingleObject( Context -> DisplayEvent, INFINITE );
03283         }
03284     } while ( !Context -> TerminateThread && !Context -> DoOneRead );
03285 #endif
03286     ExitThread(0);
03287     return (0);
03288 }  
03289 
03290 char
03291 HalfBtoHex(IN BYTE chr)
03292 {
03293     BYTE tmp = 0xF & chr;
03294     if (tmp <= 9) {
03295         return (tmp + '0');
03296     }
03297     else {
03298         return (tmp - 10 + 'A');
03299     }
03300 }
03301 
03302 int 
03303 Hex2Int(IN char* str)
03304 {
03305     int result = 0;
03306     while(1) {
03307         char tmp = *str ++;
03308         if(tmp >= '0' && tmp <= '9') {
03309             result <<= 4;
03310             result += (tmp - '0');
03311         }
03312         else if(tmp >= 'A' && tmp <= 'F') {
03313             result <<= 4;
03314             result += (tmp - 'A' + 10);
03315         }
03316         else if(tmp >= 'a' && tmp <= 'f') {
03317             result <<= 4;
03318             result += (tmp - 'a' + 10);
03319         }
03320         else {
03321             break;
03322         }
03323     }
03324     return result;
03325 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines