@@ -178,8 +178,7 @@ struct hid_device_ {
178178 size_t input_report_length ;
179179 USHORT feature_report_length ;
180180 unsigned char * feature_buf ;
181- void * last_error_str ;
182- DWORD last_error_num ;
181+ wchar_t * last_error_str ;
183182 BOOL read_pending ;
184183 char * read_buf ;
185184 OVERLAPPED ol ;
@@ -198,7 +197,6 @@ static hid_device *new_hid_device()
198197 dev -> feature_report_length = 0 ;
199198 dev -> feature_buf = NULL ;
200199 dev -> last_error_str = NULL ;
201- dev -> last_error_num = 0 ;
202200 dev -> read_pending = FALSE;
203201 dev -> read_buf = NULL ;
204202 memset (& dev -> ol , 0 , sizeof (dev -> ol ));
@@ -215,42 +213,101 @@ static void free_hid_device(hid_device *dev)
215213 CloseHandle (dev -> ol .hEvent );
216214 CloseHandle (dev -> write_ol .hEvent );
217215 CloseHandle (dev -> device_handle );
218- LocalFree (dev -> last_error_str );
216+ free (dev -> last_error_str );
217+ dev -> last_error_str = NULL ;
219218 free (dev -> write_buf );
220219 free (dev -> feature_buf );
221220 free (dev -> read_buf );
222221 hid_free_enumeration (dev -> device_info );
223222 free (dev );
224223}
225224
226- static void register_error ( hid_device * dev , const char * op )
225+ static void register_winapi_error_to_buffer ( wchar_t * * error_buffer , const WCHAR * op )
227226{
228- WCHAR * ptr , * msg ;
229- (void )op ;
230- FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
231- FORMAT_MESSAGE_FROM_SYSTEM |
232- FORMAT_MESSAGE_IGNORE_INSERTS ,
227+ if (!error_buffer )
228+ return ;
229+
230+ free (* error_buffer );
231+ * error_buffer = NULL ;
232+
233+ /* Only clear out error messages if NULL is passed into op */
234+ if (!op ) {
235+ return ;
236+ }
237+
238+ WCHAR system_err_buf [1024 ];
239+ DWORD error_code = GetLastError ();
240+
241+ DWORD system_err_len = FormatMessageW (
242+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
233243 NULL ,
234- GetLastError () ,
244+ error_code ,
235245 MAKELANGID (LANG_NEUTRAL , SUBLANG_DEFAULT ),
236- ( LPWSTR ) & msg , 0 /*sz*/ ,
246+ system_err_buf , ARRAYSIZE ( system_err_buf ) ,
237247 NULL );
238248
249+ DWORD op_len = (DWORD )wcslen (op );
250+
251+ DWORD op_prefix_len =
252+ op_len
253+ + 15 /*: (0x00000000) */
254+ ;
255+ DWORD msg_len =
256+ + op_prefix_len
257+ + system_err_len
258+ ;
259+
260+ * error_buffer = (WCHAR * )calloc (msg_len + 1 , sizeof (WCHAR ));
261+ WCHAR * msg = * error_buffer ;
262+
263+ if (!msg )
264+ return ;
265+
266+ int printf_written = swprintf (msg , msg_len + 1 , L"%.*ls: (0x%08X) %.*ls" , op_len , op , error_code , system_err_len , system_err_buf );
267+
268+ if (printf_written < 0 )
269+ {
270+ /* Highly unlikely */
271+ msg [0 ] = L'\0' ;
272+ return ;
273+ }
274+
239275 /* Get rid of the CR and LF that FormatMessage() sticks at the
240276 end of the message. Thanks Microsoft! */
241- ptr = msg ;
242- while (* ptr ) {
243- if (* ptr == L'\r' ) {
244- * ptr = L'\0' ;
245- break ;
246- }
247- ptr ++ ;
277+ while (msg [msg_len - 1 ] == L'\r' || msg [msg_len - 1 ] == L'\n' || msg [msg_len - 1 ] == L' ' )
278+ {
279+ msg [msg_len - 1 ] = L'\0' ;
280+ msg_len -- ;
281+ }
282+ }
283+
284+ static void register_winapi_error (hid_device * dev , const WCHAR * op )
285+ {
286+ if (!dev )
287+ return ;
288+
289+ register_winapi_error_to_buffer (& dev -> last_error_str , op );
290+ }
291+
292+ static void register_string_error_to_buffer (wchar_t * * error_buffer , const WCHAR * string_error )
293+ {
294+ if (!error_buffer )
295+ return ;
296+
297+ free (* error_buffer );
298+ * error_buffer = NULL ;
299+
300+ if (string_error ) {
301+ * error_buffer = _wcsdup (string_error );
248302 }
303+ }
304+
305+ static void register_string_error (hid_device * dev , const WCHAR * string_error )
306+ {
307+ if (!dev )
308+ return ;
249309
250- /* Store the message off in the Device entry so that
251- the hid_error() function can pick it up. */
252- LocalFree (dev -> last_error_str );
253- dev -> last_error_str = msg ;
310+ register_string_error_to_buffer (& dev -> last_error_str , string_error );
254311}
255312
256313static HANDLE open_device (const wchar_t * path , BOOL open_rw )
@@ -656,6 +713,10 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi
656713 hid_device * handle = NULL ;
657714
658715 devs = hid_enumerate (vendor_id , product_id );
716+ if (!devs ) {
717+ return NULL ;
718+ }
719+
659720 cur_dev = devs ;
660721 while (cur_dev ) {
661722 if (cur_dev -> vendor_id == vendor_id &&
@@ -759,7 +820,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
759820 unsigned char * buf ;
760821
761822 if (!data || (length == 0 )) {
762- register_error (dev , "Zero length buffer" );
823+ register_string_error (dev , L "Zero buffer/length " );
763824 return function_result ;
764825 }
765826
@@ -786,7 +847,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
786847 if (!res ) {
787848 if (GetLastError () != ERROR_IO_PENDING ) {
788849 /* WriteFile() failed. Return error. */
789- register_error (dev , "WriteFile" );
850+ register_winapi_error (dev , L "WriteFile" );
790851 goto end_of_function ;
791852 }
792853 overlapped = TRUE;
@@ -798,7 +859,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
798859 res = WaitForSingleObject (dev -> write_ol .hEvent , 1000 );
799860 if (res != WAIT_OBJECT_0 ) {
800861 /* There was a Timeout. */
801- register_error (dev , "WriteFile /WaitForSingleObject Timeout " );
862+ register_winapi_error (dev , L"hid_write /WaitForSingleObject" );
802863 goto end_of_function ;
803864 }
804865
@@ -809,7 +870,7 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
809870 }
810871 else {
811872 /* The Write operation failed. */
812- register_error (dev , "WriteFile " );
873+ register_winapi_error (dev , L"hid_write/GetOverlappedResult " );
813874 goto end_of_function ;
814875 }
815876 }
@@ -840,6 +901,7 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
840901 if (GetLastError () != ERROR_IO_PENDING ) {
841902 /* ReadFile() has failed.
842903 Clean up and return error. */
904+ register_winapi_error (dev , L"ReadFile" );
843905 CancelIo (dev -> device_handle );
844906 dev -> read_pending = FALSE;
845907 goto end_of_function ;
@@ -886,10 +948,12 @@ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char
886948 memcpy (data , dev -> read_buf , copy_len );
887949 }
888950 }
951+ if (!res ) {
952+ register_winapi_error (dev , L"hid_read_timeout/GetOverlappedResult" );
953+ }
889954
890955end_of_function :
891956 if (!res ) {
892- register_error (dev , "GetOverlappedResult" );
893957 return -1 ;
894958 }
895959
@@ -933,7 +997,7 @@ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const u
933997 res = HidD_SetFeature (dev -> device_handle , (PVOID )buf , (DWORD ) length_to_send );
934998
935999 if (!res ) {
936- register_error (dev , "HidD_SetFeature" );
1000+ register_winapi_error (dev , L "HidD_SetFeature" );
9371001 return -1 ;
9381002 }
9391003
@@ -957,7 +1021,7 @@ static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *dat
9571021 if (!res ) {
9581022 if (GetLastError () != ERROR_IO_PENDING ) {
9591023 /* DeviceIoControl() failed. Return error. */
960- register_error (dev , "Get Input/Feature Report DeviceIoControl" );
1024+ register_winapi_error (dev , L "Get Input/Feature Report DeviceIoControl" );
9611025 return -1 ;
9621026 }
9631027 }
@@ -967,7 +1031,7 @@ static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *dat
9671031 res = GetOverlappedResult (dev -> device_handle , & ol , & bytes_returned , TRUE/*wait*/ );
9681032 if (!res ) {
9691033 /* The operation failed. */
970- register_error (dev , "Get Input/Feature Report GetOverLappedResult" );
1034+ register_winapi_error (dev , L "Get Input/Feature Report GetOverLappedResult" );
9711035 return -1 ;
9721036 }
9731037
@@ -1004,8 +1068,17 @@ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
10041068
10051069int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string (hid_device * dev , wchar_t * string , size_t maxlen )
10061070{
1007- if (!dev -> device_info || !string || !maxlen )
1071+ if (!dev -> device_info )
1072+ {
1073+ register_string_error (dev , L"NULL device/info" );
1074+ return -1 ;
1075+ }
1076+
1077+ if (!string || !maxlen )
1078+ {
1079+ register_string_error (dev , L"Zero buffer/length" );
10081080 return -1 ;
1081+ }
10091082
10101083 wcsncpy (string , dev -> device_info -> manufacturer_string , maxlen );
10111084 string [maxlen ] = L'\0' ;
@@ -1015,8 +1088,18 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev
10151088
10161089int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string (hid_device * dev , wchar_t * string , size_t maxlen )
10171090{
1018- if (!dev -> device_info || !string || !maxlen )
1091+ if (!dev -> device_info )
1092+ {
1093+ register_string_error (dev , L"NULL device/info" );
10191094 return -1 ;
1095+ }
1096+
1097+ if (!string || !maxlen )
1098+ {
1099+ register_string_error (dev , L"Zero buffer/length" );
1100+ return -1 ;
1101+ }
1102+
10201103
10211104 wcsncpy (string , dev -> device_info -> product_string , maxlen );
10221105 string [maxlen ] = L'\0' ;
@@ -1026,8 +1109,18 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wch
10261109
10271110int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string (hid_device * dev , wchar_t * string , size_t maxlen )
10281111{
1029- if (!dev -> device_info || !string || !maxlen )
1112+ if (!dev -> device_info )
1113+ {
1114+ register_string_error (dev , L"NULL device/info" );
10301115 return -1 ;
1116+ }
1117+
1118+ if (!string || !maxlen )
1119+ {
1120+ register_string_error (dev , L"Zero buffer/length" );
1121+ return -1 ;
1122+ }
1123+
10311124
10321125 wcsncpy (string , dev -> device_info -> serial_number , maxlen );
10331126 string [maxlen ] = L'\0' ;
@@ -1041,7 +1134,7 @@ int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int
10411134
10421135 res = HidD_GetIndexedString (dev -> device_handle , string_index , string , sizeof (wchar_t ) * (DWORD ) MIN (maxlen , MAX_STRING_WCHARS ));
10431136 if (!res ) {
1044- register_error (dev , "HidD_GetIndexedString" );
1137+ register_winapi_error (dev , L "HidD_GetIndexedString" );
10451138 return -1 ;
10461139 }
10471140
@@ -1057,28 +1150,43 @@ int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *conta
10571150 ULONG len ;
10581151
10591152 if (!container_id )
1153+ {
1154+ register_string_error (dev , L"Invalid Container ID" );
10601155 return -1 ;
1156+ }
10611157
10621158 interface_path = hid_internal_UTF8toUTF16 (dev -> device_info -> path );
10631159 if (!interface_path )
1160+ {
1161+ register_string_error (dev , L"Path conversion failure" );
10641162 goto end ;
1163+ }
10651164
10661165 /* Get the device id from interface path */
10671166 device_id = hid_internal_get_device_interface_property (interface_path , & DEVPKEY_Device_InstanceId , DEVPROP_TYPE_STRING );
10681167 if (!device_id )
1168+ {
1169+ register_string_error (dev , L"Failed to get device interface property InstanceId" );
10691170 goto end ;
1171+ }
10701172
10711173 /* Open devnode from device id */
10721174 cr = CM_Locate_DevNodeW (& dev_node , (DEVINSTID_W )device_id , CM_LOCATE_DEVNODE_NORMAL );
10731175 if (cr != CR_SUCCESS )
1176+ {
1177+ register_string_error (dev , L"Failed to locate device node" );
10741178 goto end ;
1179+ }
10751180
10761181 /* Get the container id from devnode */
10771182 len = sizeof (* container_id );
10781183 cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_ContainerId , & property_type , (PBYTE )container_id , & len , 0 );
10791184 if (cr == CR_SUCCESS && property_type != DEVPROP_TYPE_GUID )
10801185 cr = CR_FAILURE ;
10811186
1187+ if (cr != CR_SUCCESS )
1188+ register_string_error (dev , L"Failed to read ContainerId property from device node" );
1189+
10821190end :
10831191 free (interface_path );
10841192 free (device_id );
0 commit comments