Skip to content

Commit 08563a0

Browse files
add better windows error handling (#388)
1 parent 68bcbfc commit 08563a0

File tree

1 file changed

+143
-35
lines changed

1 file changed

+143
-35
lines changed

windows/hid.c

Lines changed: 143 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -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

256313
static 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

890955
end_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

10051069
int 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

10161089
int 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

10271110
int 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+
10821190
end:
10831191
free(interface_path);
10841192
free(device_id);

0 commit comments

Comments
 (0)