1 /*******************************************************
2  HIDAPI - Multi-Platform library for
3  communication with HID devices.
4 
5  Alan Ott
6  Signal 11 Software
7 
8  8/22/2009
9 
10  Copyright 2009, All Rights Reserved.
11 
12  At the discretion of the user of this library,
13  this software may be licensed under the terms of the
14  GNU General Public License v3, a BSD-Style license, or the
15  original HIDAPI license as outlined in the LICENSE.txt,
16  LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
17  files located at the root of the source distribution.
18  These files may also be found in the public source
19  code repository located at:
20         https://github.com/libusb/hidapi .
21 ********************************************************/
22 
23 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
24 // Do not warn about mbsrtowcs and wcsncpy usage.
25 // https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt
26 #define _CRT_SECURE_NO_WARNINGS
27 #endif
28 
29 #include <windows.h>
30 
31 #ifndef _NTDEF_
32 typedef LONG NTSTATUS;
33 #endif
34 
35 #ifdef __MINGW32__
36 #include <ntdef.h>
37 #include <winbase.h>
38 #endif
39 
40 #ifdef __CYGWIN__
41 #include <ntdef.h>
42 #define _wcsdup wcsdup
43 #endif
44 
45 /* The maximum number of characters that can be passed into the
46    HidD_Get*String() functions without it failing.*/
47 #define MAX_STRING_WCHARS 0xFFF
48 
49 /*#define HIDAPI_USE_DDK*/
50 
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54 	#include <setupapi.h>
55 	#include <winioctl.h>
56 	#ifdef HIDAPI_USE_DDK
57 		#include <hidsdi.h>
58 	#endif
59 
60 	/* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
61 	#define HID_OUT_CTL_CODE(id)  \
62 		CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
63 	#define IOCTL_HID_GET_FEATURE                   HID_OUT_CTL_CODE(100)
64 	#define IOCTL_HID_GET_INPUT_REPORT              HID_OUT_CTL_CODE(104)
65 
66 #ifdef __cplusplus
67 } /* extern "C" */
68 #endif
69 
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <wctype.h>
74 
75 #include "hidapi.h"
76 
77 #undef MIN
78 #define MIN(x,y) ((x) < (y)? (x): (y))
79 
80 #ifdef __cplusplus
81 extern "C" {
82 #endif
83 
84 static struct hid_api_version api_version = {
85 	.major = HID_API_VERSION_MAJOR,
86 	.minor = HID_API_VERSION_MINOR,
87 	.patch = HID_API_VERSION_PATCH
88 };
89 
90 #ifndef HIDAPI_USE_DDK
91 	/* Since we're not building with the DDK, and the HID header
92 	   files aren't part of the SDK, we have to define all this
93 	   stuff here. In lookup_functions(), the function pointers
94 	   defined below are set. */
95 	typedef struct _HIDD_ATTRIBUTES{
96 		ULONG Size;
97 		USHORT VendorID;
98 		USHORT ProductID;
99 		USHORT VersionNumber;
100 	} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
101 
102 	typedef USHORT USAGE;
103 	typedef struct _HIDP_CAPS {
104 		USAGE Usage;
105 		USAGE UsagePage;
106 		USHORT InputReportByteLength;
107 		USHORT OutputReportByteLength;
108 		USHORT FeatureReportByteLength;
109 		USHORT Reserved[17];
110 		USHORT fields_not_used_by_hidapi[10];
111 	} HIDP_CAPS, *PHIDP_CAPS;
112 	typedef void* PHIDP_PREPARSED_DATA;
113 	#define HIDP_STATUS_SUCCESS 0x110000
114 
115 	typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
116 	typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
117 	typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
118 	typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
119 	typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
120 	typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
121 	typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
122 	typedef BOOLEAN (__stdcall *HidD_GetInputReport_)(HANDLE handle, PVOID data, ULONG length);
123 	typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
124 	typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
125 	typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
126 	typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
127 	typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
128 
129 	static HidD_GetHidGuid_ HidD_GetHidGuid;
130 	static HidD_GetAttributes_ HidD_GetAttributes;
131 	static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
132 	static HidD_GetManufacturerString_ HidD_GetManufacturerString;
133 	static HidD_GetProductString_ HidD_GetProductString;
134 	static HidD_SetFeature_ HidD_SetFeature;
135 	static HidD_GetFeature_ HidD_GetFeature;
136 	static HidD_GetInputReport_ HidD_GetInputReport;
137 	static HidD_GetIndexedString_ HidD_GetIndexedString;
138 	static HidD_GetPreparsedData_ HidD_GetPreparsedData;
139 	static HidD_FreePreparsedData_ HidD_FreePreparsedData;
140 	static HidP_GetCaps_ HidP_GetCaps;
141 	static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
142 
143 	static HMODULE lib_handle = NULL;
144 	static BOOLEAN initialized = FALSE;
145 
146 	typedef DWORD RETURN_TYPE;
147 	typedef RETURN_TYPE CONFIGRET;
148 	typedef DWORD DEVNODE, DEVINST;
149 	typedef DEVNODE* PDEVNODE, * PDEVINST;
150 	typedef WCHAR* DEVNODEID_W, * DEVINSTID_W;
151 
152 #define CR_SUCCESS (0x00000000)
153 #define CR_BUFFER_SMALL (0x0000001A)
154 
155 #define CM_LOCATE_DEVNODE_NORMAL 0x00000000
156 
157 #define DEVPROP_TYPEMOD_LIST 0x00002000
158 
159 #define DEVPROP_TYPE_STRING 0x00000012
160 #define DEVPROP_TYPE_STRING_LIST (DEVPROP_TYPE_STRING|DEVPROP_TYPEMOD_LIST)
161 
162 	typedef CONFIGRET(__stdcall* CM_Locate_DevNodeW_)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags);
163 	typedef CONFIGRET(__stdcall* CM_Get_Parent_)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
164 	typedef CONFIGRET(__stdcall* CM_Get_DevNode_PropertyW_)(DEVINST dnDevInst, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
165 	typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_PropertyW_)(LPCWSTR pszDeviceInterface, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
166 
167 	static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
168 	static CM_Get_Parent_ CM_Get_Parent = NULL;
169 	static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW = NULL;
170 	static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW = NULL;
171 
172 	static HMODULE cfgmgr32_lib_handle = NULL;
173 #endif /* HIDAPI_USE_DDK */
174 
175 struct hid_device_ {
176 		HANDLE device_handle;
177 		BOOL blocking;
178 		USHORT output_report_length;
179 		unsigned char *write_buf;
180 		size_t input_report_length;
181 		USHORT feature_report_length;
182 		unsigned char *feature_buf;
183 		void *last_error_str;
184 		DWORD last_error_num;
185 		BOOL read_pending;
186 		char *read_buf;
187 		OVERLAPPED ol;
188 		OVERLAPPED write_ol;
189 		struct hid_device_info* device_info;
190 };
191 
new_hid_device()192 static hid_device *new_hid_device()
193 {
194 	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
195 	dev->device_handle = INVALID_HANDLE_VALUE;
196 	dev->blocking = TRUE;
197 	dev->output_report_length = 0;
198 	dev->write_buf = NULL;
199 	dev->input_report_length = 0;
200 	dev->feature_report_length = 0;
201 	dev->feature_buf = NULL;
202 	dev->last_error_str = NULL;
203 	dev->last_error_num = 0;
204 	dev->read_pending = FALSE;
205 	dev->read_buf = NULL;
206 	memset(&dev->ol, 0, sizeof(dev->ol));
207 	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
208 	memset(&dev->write_ol, 0, sizeof(dev->write_ol));
209 	dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);
210 	dev->device_info = NULL;
211 
212 	return dev;
213 }
214 
free_hid_device(hid_device * dev)215 static void free_hid_device(hid_device *dev)
216 {
217 	CloseHandle(dev->ol.hEvent);
218 	CloseHandle(dev->write_ol.hEvent);
219 	CloseHandle(dev->device_handle);
220 	LocalFree(dev->last_error_str);
221 	free(dev->write_buf);
222 	free(dev->feature_buf);
223 	free(dev->read_buf);
224 	free(dev->device_info);
225 	free(dev);
226 }
227 
register_error(hid_device * dev,const char * op)228 static void register_error(hid_device *dev, const char *op)
229 {
230 	WCHAR *ptr, *msg;
231 	(void)op; // unreferenced  param
232 	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
233 		FORMAT_MESSAGE_FROM_SYSTEM |
234 		FORMAT_MESSAGE_IGNORE_INSERTS,
235 		NULL,
236 		GetLastError(),
237 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
238 		(LPWSTR)&msg, 0/*sz*/,
239 		NULL);
240 
241 	/* Get rid of the CR and LF that FormatMessage() sticks at the
242 	   end of the message. Thanks Microsoft! */
243 	ptr = msg;
244 	while (*ptr) {
245 		if (*ptr == L'\r') {
246 			*ptr = L'\0';
247 			break;
248 		}
249 		ptr++;
250 	}
251 
252 	/* Store the message off in the Device entry so that
253 	   the hid_error() function can pick it up. */
254 	LocalFree(dev->last_error_str);
255 	dev->last_error_str = msg;
256 }
257 
258 #ifndef HIDAPI_USE_DDK
lookup_functions()259 static int lookup_functions()
260 {
261 	lib_handle = LoadLibraryA("hid.dll");
262 	if (lib_handle) {
263 #if defined(__GNUC__)
264 # pragma GCC diagnostic push
265 # pragma GCC diagnostic ignored "-Wcast-function-type"
266 #endif
267 #define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
268 		RESOLVE(HidD_GetHidGuid);
269 		RESOLVE(HidD_GetAttributes);
270 		RESOLVE(HidD_GetSerialNumberString);
271 		RESOLVE(HidD_GetManufacturerString);
272 		RESOLVE(HidD_GetProductString);
273 		RESOLVE(HidD_SetFeature);
274 		RESOLVE(HidD_GetFeature);
275 		RESOLVE(HidD_GetInputReport);
276 		RESOLVE(HidD_GetIndexedString);
277 		RESOLVE(HidD_GetPreparsedData);
278 		RESOLVE(HidD_FreePreparsedData);
279 		RESOLVE(HidP_GetCaps);
280 		RESOLVE(HidD_SetNumInputBuffers);
281 #undef RESOLVE
282 #if defined(__GNUC__)
283 # pragma GCC diagnostic pop
284 #endif
285 	}
286 	else
287 		return -1;
288 
289 	cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
290 	if (cfgmgr32_lib_handle) {
291 #if defined(__GNUC__)
292 # pragma GCC diagnostic push
293 # pragma GCC diagnostic ignored "-Wcast-function-type"
294 #endif
295 #define RESOLVE(x) x = (x##_)GetProcAddress(cfgmgr32_lib_handle, #x);
296 		RESOLVE(CM_Locate_DevNodeW);
297 		RESOLVE(CM_Get_Parent);
298 		RESOLVE(CM_Get_DevNode_PropertyW);
299 		RESOLVE(CM_Get_Device_Interface_PropertyW);
300 #undef RESOLVE
301 #if defined(__GNUC__)
302 # pragma GCC diagnostic pop
303 #endif
304 	}
305 	else {
306 		CM_Locate_DevNodeW = NULL;
307 		CM_Get_Parent = NULL;
308 		CM_Get_DevNode_PropertyW = NULL;
309 		CM_Get_Device_Interface_PropertyW = NULL;
310 	}
311 
312 	return 0;
313 }
314 #endif
315 
open_device(const char * path,BOOL open_rw)316 static HANDLE open_device(const char *path, BOOL open_rw)
317 {
318 	HANDLE handle;
319 	DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0;
320 	DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
321 
322 	handle = CreateFileA(path,
323 		desired_access,
324 		share_mode,
325 		NULL,
326 		OPEN_EXISTING,
327 		FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
328 		0);
329 
330 	return handle;
331 }
332 
hid_version()333 HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version()
334 {
335 	return &api_version;
336 }
337 
hid_version_str()338 HID_API_EXPORT const char* HID_API_CALL hid_version_str()
339 {
340 	return HID_API_VERSION_STR;
341 }
342 
hid_init(void)343 int HID_API_EXPORT hid_init(void)
344 {
345 #ifndef HIDAPI_USE_DDK
346 	if (!initialized) {
347 		if (lookup_functions() < 0) {
348 			hid_exit();
349 			return -1;
350 		}
351 		initialized = TRUE;
352 	}
353 #endif
354 	return 0;
355 }
356 
hid_exit(void)357 int HID_API_EXPORT hid_exit(void)
358 {
359 #ifndef HIDAPI_USE_DDK
360 	if (lib_handle)
361 		FreeLibrary(lib_handle);
362 	lib_handle = NULL;
363 	if (cfgmgr32_lib_handle)
364 		FreeLibrary(cfgmgr32_lib_handle);
365 	cfgmgr32_lib_handle = NULL;
366 	initialized = FALSE;
367 #endif
368 	return 0;
369 }
370 
hid_internal_get_ble_info(struct hid_device_info * dev,DEVINST dev_node)371 static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
372 {
373 	ULONG len;
374 	CONFIGRET cr;
375 	DEVPROPTYPE property_type;
376 
377 	static DEVPROPKEY DEVPKEY_NAME = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac }, 10 }; // DEVPROP_TYPE_STRING
378 	static DEVPROPKEY PKEY_DeviceInterface_Bluetooth_DeviceAddress = { { 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A }, 1 }; // DEVPROP_TYPE_STRING
379 	static DEVPROPKEY PKEY_DeviceInterface_Bluetooth_Manufacturer = { { 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A }, 4 }; // DEVPROP_TYPE_STRING
380 
381 	/* Manufacturer String */
382 	len = 0;
383 	cr = CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_Manufacturer, &property_type, NULL, &len, 0);
384 	if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
385 		free(dev->manufacturer_string);
386 		dev->manufacturer_string = (wchar_t*)calloc(len, sizeof(BYTE));
387 		CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_Manufacturer, &property_type, (PBYTE)dev->manufacturer_string, &len, 0);
388 	}
389 
390 	/* Serial Number String (MAC Address) */
391 	len = 0;
392 	cr = CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_DeviceAddress, &property_type, NULL, &len, 0);
393 	if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
394 		free(dev->serial_number);
395 		dev->serial_number = (wchar_t*)calloc(len, sizeof(BYTE));
396 		CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_DeviceAddress, &property_type, (PBYTE)dev->serial_number, &len, 0);
397 	}
398 
399 	/* Get devnode grandparent to reach out Bluetooth LE device node */
400 	cr = CM_Get_Parent(&dev_node, dev_node, 0);
401 	if (cr != CR_SUCCESS)
402 		return;
403 
404 	/* Product String */
405 	len = 0;
406 	cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_NAME, &property_type, NULL, &len, 0);
407 	if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
408 		free(dev->product_string);
409 		dev->product_string = (wchar_t*)calloc(len, sizeof(BYTE));
410 		CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_NAME, &property_type, (PBYTE)dev->product_string, &len, 0);
411 	}
412 }
413 
hid_internal_get_info(struct hid_device_info * dev)414 static void hid_internal_get_info(struct hid_device_info* dev)
415 {
416 	const char *tmp = NULL;
417 	wchar_t *interface_path = NULL, *device_id = NULL, *compatible_ids = NULL;
418 	mbstate_t state;
419 	ULONG len;
420 	CONFIGRET cr;
421 	DEVPROPTYPE property_type;
422 	DEVINST dev_node;
423 
424 	static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57 }, 256 }; // DEVPROP_TYPE_STRING
425 	static DEVPROPKEY DEVPKEY_Device_CompatibleIds = { { 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}, 4 }; // DEVPROP_TYPE_STRING_LIST
426 
427 	if (!CM_Get_Device_Interface_PropertyW ||
428 		!CM_Locate_DevNodeW ||
429 		!CM_Get_Parent ||
430 		!CM_Get_DevNode_PropertyW)
431 		goto end;
432 
433 	tmp = dev->path;
434 
435 	len = (ULONG)strlen(tmp);
436 	interface_path = (wchar_t*)calloc(len + 1, sizeof(wchar_t));
437 	memset(&state, 0, sizeof(state));
438 
439 	if (mbsrtowcs(interface_path, &tmp, len, &state) == (size_t)-1)
440 		goto end;
441 
442 	/* Get the device id from interface path */
443 	len = 0;
444 	cr = CM_Get_Device_Interface_PropertyW(interface_path, &DEVPKEY_Device_InstanceId, &property_type, NULL, &len, 0);
445 	if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
446 		device_id = (wchar_t*)calloc(len, sizeof(BYTE));
447 		cr = CM_Get_Device_Interface_PropertyW(interface_path, &DEVPKEY_Device_InstanceId, &property_type, (PBYTE)device_id, &len, 0);
448 	}
449 	if (cr != CR_SUCCESS)
450 		goto end;
451 
452 	/* Open devnode from device id */
453 	cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
454 	if (cr != CR_SUCCESS)
455 		goto end;
456 
457 	/* Get devnode parent */
458 	cr = CM_Get_Parent(&dev_node, dev_node, 0);
459 	if (cr != CR_SUCCESS)
460 		goto end;
461 
462 	/* Get the compatible ids from parent devnode */
463 	len = 0;
464 	cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_CompatibleIds, &property_type, NULL, &len, 0);
465 	if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING_LIST) {
466 		compatible_ids = (wchar_t*)calloc(len, sizeof(BYTE));
467 		cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_CompatibleIds, &property_type, (PBYTE)compatible_ids, &len, 0);
468 	}
469 	if (cr != CR_SUCCESS)
470 		goto end;
471 
472 	/* Now we can parse parent's compatible IDs to find out the device bus type */
473 	for (wchar_t* compatible_id = compatible_ids; *compatible_id; compatible_id += wcslen(compatible_id) + 1) {
474 		/* Normalize to upper case */
475 		for (wchar_t* p = compatible_id; *p; ++p) *p = towupper(*p);
476 
477 		/* Bluetooth LE devices */
478 		if (wcsstr(compatible_id, L"BTHLEDEVICE") != NULL) {
479 			/* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
480 			   Request this info via dev node properties instead.
481 			   https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
482 			hid_internal_get_ble_info(dev, dev_node);
483 			break;
484 		}
485 	}
486 end:
487 	free(interface_path);
488 	free(device_id);
489 	free(compatible_ids);
490 }
491 
hid_get_device_info(const char * path,HANDLE handle)492 static struct hid_device_info *hid_get_device_info(const char *path, HANDLE handle)
493 {
494 	struct hid_device_info *dev = NULL; /* return object */
495 
496 	BOOL res;
497 	HIDD_ATTRIBUTES attrib;
498 	PHIDP_PREPARSED_DATA pp_data = NULL;
499 	HIDP_CAPS caps;
500 
501 	#define WSTR_LEN 512
502 	wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
503 
504 	/* Create the record. */
505 	dev = (struct hid_device_info*)calloc(1, sizeof(struct hid_device_info));
506 
507 	/* Fill out the record */
508 	dev->next = NULL;
509 
510 	if (path) {
511 		size_t len = strlen(path);
512 		dev->path = (char*)calloc(len + 1, sizeof(char));
513 		memcpy(dev->path, path, len + 1);
514 	}
515 	else
516 		dev->path = NULL;
517 
518 	attrib.Size = sizeof(HIDD_ATTRIBUTES);
519 	res = HidD_GetAttributes(handle, &attrib);
520 	if (res) {
521 		/* VID/PID */
522 		dev->vendor_id = attrib.VendorID;
523 		dev->product_id = attrib.ProductID;
524 
525 		/* Release Number */
526 		dev->release_number = attrib.VersionNumber;
527 	}
528 
529 	/* Get the Usage Page and Usage for this device. */
530 	res = HidD_GetPreparsedData(handle, &pp_data);
531 	if (res) {
532 		NTSTATUS nt_res = HidP_GetCaps(pp_data, &caps);
533 		if (nt_res == HIDP_STATUS_SUCCESS) {
534 			dev->usage_page = caps.UsagePage;
535 			dev->usage = caps.Usage;
536 		}
537 
538 		HidD_FreePreparsedData(pp_data);
539 	}
540 
541 	/* Serial Number */
542 	wstr[0] = L'\0';
543 	res = HidD_GetSerialNumberString(handle, wstr, sizeof(wstr));
544 	wstr[WSTR_LEN - 1] = L'\0';
545 	dev->serial_number = _wcsdup(wstr);
546 
547 	/* Manufacturer String */
548 	wstr[0] = L'\0';
549 	res = HidD_GetManufacturerString(handle, wstr, sizeof(wstr));
550 	wstr[WSTR_LEN - 1] = L'\0';
551 	dev->manufacturer_string = _wcsdup(wstr);
552 
553 	/* Product String */
554 	wstr[0] = L'\0';
555 	res = HidD_GetProductString(handle, wstr, sizeof(wstr));
556 	wstr[WSTR_LEN - 1] = L'\0';
557 	dev->product_string = _wcsdup(wstr);
558 
559 	/* Interface Number. It can sometimes be parsed out of the path
560 	   on Windows if a device has multiple interfaces. See
561 	   https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
562 	   or search for "HIDClass Hardware IDs for Top-Level Collections" at Microsoft Docs. If it's not
563 	   in the path, it's set to -1. */
564 	dev->interface_number = -1;
565 	if (dev->path) {
566 		char* interface_component = strstr(dev->path, "&mi_");
567 		if (interface_component) {
568 			char* hex_str = interface_component + 4;
569 			char* endptr = NULL;
570 			dev->interface_number = strtol(hex_str, &endptr, 16);
571 			if (endptr == hex_str) {
572 				/* The parsing failed. Set interface_number to -1. */
573 				dev->interface_number = -1;
574 			}
575 		}
576 	}
577 
578 	hid_internal_get_info(dev);
579 
580 	return dev;
581 }
582 
hid_enumerate(unsigned short vendor_id,unsigned short product_id)583 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
584 {
585 	BOOL res;
586 	struct hid_device_info *root = NULL; /* return object */
587 	struct hid_device_info *cur_dev = NULL;
588 	GUID interface_class_guid;
589 
590 	/* Windows objects for interacting with the driver. */
591 	SP_DEVINFO_DATA devinfo_data;
592 	SP_DEVICE_INTERFACE_DATA device_interface_data;
593 	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
594 	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
595 	char driver_name[256];
596 	int device_index = 0;
597 
598 	if (hid_init() < 0)
599 		return NULL;
600 
601 	/* Retrieve HID Interface Class GUID
602 	   https://docs.microsoft.com/windows-hardware/drivers/install/guid-devinterface-hid */
603 	HidD_GetHidGuid(&interface_class_guid);
604 
605 	/* Initialize the Windows objects. */
606 	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
607 	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
608 	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
609 
610 	/* Get information for all the devices belonging to the HID class. */
611 	device_info_set = SetupDiGetClassDevsA(&interface_class_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
612 
613 	/* Iterate over each device in the HID class, looking for the right one. */
614 
615 	for (;;) {
616 		HANDLE read_handle = INVALID_HANDLE_VALUE;
617 		DWORD required_size = 0;
618 		HIDD_ATTRIBUTES attrib;
619 
620 		res = SetupDiEnumDeviceInterfaces(device_info_set,
621 			NULL,
622 			&interface_class_guid,
623 			device_index,
624 			&device_interface_data);
625 
626 		if (!res) {
627 			/* A return of FALSE from this function means that
628 			   there are no more devices. */
629 			break;
630 		}
631 
632 		/* Call with 0-sized detail size, and let the function
633 		   tell us how long the detail struct needs to be. The
634 		   size is put in &required_size. */
635 		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
636 			&device_interface_data,
637 			NULL,
638 			0,
639 			&required_size,
640 			NULL);
641 
642 		/* Allocate a long enough structure for device_interface_detail_data. */
643 		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
644 		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
645 
646 		/* Get the detailed data for this device. The detail data gives us
647 		   the device path for this device, which is then passed into
648 		   CreateFile() to get a handle to the device. */
649 		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
650 			&device_interface_data,
651 			device_interface_detail_data,
652 			required_size,
653 			NULL,
654 			NULL);
655 
656 		if (!res) {
657 			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
658 			   Continue to the next device. */
659 			goto cont;
660 		}
661 
662 		/* Populate devinfo_data. This function will return failure
663 		   when the device with such index doesn't exist. We've already checked it does. */
664 		res = SetupDiEnumDeviceInfo(device_info_set, device_index, &devinfo_data);
665 		if (!res)
666 			goto cont;
667 
668 
669 		/* Make sure this device has a driver bound to it. */
670 		res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
671 			   SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
672 		if (!res)
673 			goto cont;
674 
675 		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
676 
677 		/* Open read-only handle to the device */
678 		read_handle = open_device(device_interface_detail_data->DevicePath, FALSE);
679 
680 		/* Check validity of read_handle. */
681 		if (read_handle == INVALID_HANDLE_VALUE) {
682 			/* Unable to open the device. */
683 			//register_error(dev, "CreateFile");
684 			goto cont;
685 		}
686 
687 		/* Get the Vendor ID and Product ID for this device. */
688 		attrib.Size = sizeof(HIDD_ATTRIBUTES);
689 		HidD_GetAttributes(read_handle, &attrib);
690 		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
691 
692 		/* Check the VID/PID to see if we should add this
693 		   device to the enumeration list. */
694 		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
695 		    (product_id == 0x0 || attrib.ProductID == product_id)) {
696 
697 			/* VID/PID match. Create the record. */
698 			struct hid_device_info *tmp = hid_get_device_info(device_interface_detail_data->DevicePath, read_handle);
699 
700 			if (tmp == NULL) {
701 				goto cont_close;
702 			}
703 
704 			if (cur_dev) {
705 				cur_dev->next = tmp;
706 			}
707 			else {
708 				root = tmp;
709 			}
710 			cur_dev = tmp;
711 		}
712 
713 cont_close:
714 		CloseHandle(read_handle);
715 cont:
716 		/* We no longer need the detail data. It can be freed */
717 		free(device_interface_detail_data);
718 
719 		device_index++;
720 
721 	}
722 
723 	/* Close the device information handle. */
724 	SetupDiDestroyDeviceInfoList(device_info_set);
725 
726 	return root;
727 }
728 
hid_free_enumeration(struct hid_device_info * devs)729 void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
730 {
731 	/* TODO: Merge this with the Linux version. This function is platform-independent. */
732 	struct hid_device_info *d = devs;
733 	while (d) {
734 		struct hid_device_info *next = d->next;
735 		free(d->path);
736 		free(d->serial_number);
737 		free(d->manufacturer_string);
738 		free(d->product_string);
739 		free(d);
740 		d = next;
741 	}
742 }
743 
744 
hid_open(unsigned short vendor_id,unsigned short product_id,const wchar_t * serial_number)745 HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
746 {
747 	/* TODO: Merge this functions with the Linux version. This function should be platform independent. */
748 	struct hid_device_info *devs, *cur_dev;
749 	const char *path_to_open = NULL;
750 	hid_device *handle = NULL;
751 
752 	devs = hid_enumerate(vendor_id, product_id);
753 	cur_dev = devs;
754 	while (cur_dev) {
755 		if (cur_dev->vendor_id == vendor_id &&
756 		    cur_dev->product_id == product_id) {
757 			if (serial_number) {
758 				if (cur_dev->serial_number && wcscmp(serial_number, cur_dev->serial_number) == 0) {
759 					path_to_open = cur_dev->path;
760 					break;
761 				}
762 			}
763 			else {
764 				path_to_open = cur_dev->path;
765 				break;
766 			}
767 		}
768 		cur_dev = cur_dev->next;
769 	}
770 
771 	if (path_to_open) {
772 		/* Open the device */
773 		handle = hid_open_path(path_to_open);
774 	}
775 
776 	hid_free_enumeration(devs);
777 
778 	return handle;
779 }
780 
hid_open_path(const char * path)781 HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
782 {
783 	hid_device *dev;
784 	HIDP_CAPS caps;
785 	PHIDP_PREPARSED_DATA pp_data = NULL;
786 	BOOLEAN res;
787 	NTSTATUS nt_res;
788 
789 	if (hid_init() < 0) {
790 		return NULL;
791 	}
792 
793 	dev = new_hid_device();
794 
795 	/* Open a handle to the device */
796 	dev->device_handle = open_device(path, TRUE);
797 
798 	/* Check validity of write_handle. */
799 	if (dev->device_handle == INVALID_HANDLE_VALUE) {
800 		/* System devices, such as keyboards and mice, cannot be opened in
801 		   read-write mode, because the system takes exclusive control over
802 		   them.  This is to prevent keyloggers.  However, feature reports
803 		   can still be sent and received.  Retry opening the device, but
804 		   without read/write access. */
805 		dev->device_handle = open_device(path, FALSE);
806 
807 		/* Check the validity of the limited device_handle. */
808 		if (dev->device_handle == INVALID_HANDLE_VALUE) {
809 			/* Unable to open the device, even without read-write mode. */
810 			register_error(dev, "CreateFile");
811 			goto err;
812 		}
813 	}
814 
815 	/* Set the Input Report buffer size to 64 reports. */
816 	res = HidD_SetNumInputBuffers(dev->device_handle, 64);
817 	if (!res) {
818 		register_error(dev, "HidD_SetNumInputBuffers");
819 		goto err;
820 	}
821 
822 	/* Get the Input Report length for the device. */
823 	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
824 	if (!res) {
825 		register_error(dev, "HidD_GetPreparsedData");
826 		goto err;
827 	}
828 	nt_res = HidP_GetCaps(pp_data, &caps);
829 	if (nt_res != HIDP_STATUS_SUCCESS) {
830 		register_error(dev, "HidP_GetCaps");
831 		goto err_pp_data;
832 	}
833 	dev->output_report_length = caps.OutputReportByteLength;
834 	dev->input_report_length = caps.InputReportByteLength;
835 	dev->feature_report_length = caps.FeatureReportByteLength;
836 	HidD_FreePreparsedData(pp_data);
837 
838 	dev->read_buf = (char*) malloc(dev->input_report_length);
839 
840 	dev->device_info = hid_get_device_info(path, dev->device_handle);
841 
842 	return dev;
843 
844 err_pp_data:
845 		HidD_FreePreparsedData(pp_data);
846 err:
847 		free_hid_device(dev);
848 		return NULL;
849 }
850 
hid_write(hid_device * dev,const unsigned char * data,size_t length)851 int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
852 {
853 	DWORD bytes_written = 0;
854 	int function_result = -1;
855 	BOOL res;
856 	BOOL overlapped = FALSE;
857 
858 	unsigned char *buf;
859 
860 	if (!data || (length==0)) {
861 		register_error(dev, "Zero length buffer");
862 		return function_result;
863 	}
864 
865 	/* Make sure the right number of bytes are passed to WriteFile. Windows
866 	   expects the number of bytes which are in the _longest_ report (plus
867 	   one for the report number) bytes even if the data is a report
868 	   which is shorter than that. Windows gives us this value in
869 	   caps.OutputReportByteLength. If a user passes in fewer bytes than this,
870 	   use cached temporary buffer which is the proper size. */
871 	if (length >= dev->output_report_length) {
872 		/* The user passed the right number of bytes. Use the buffer as-is. */
873 		buf = (unsigned char *) data;
874 	} else {
875 		if (dev->write_buf == NULL)
876 			dev->write_buf = (unsigned char *) malloc(dev->output_report_length);
877 		buf = dev->write_buf;
878 		memcpy(buf, data, length);
879 		memset(buf + length, 0, dev->output_report_length - length);
880 		length = dev->output_report_length;
881 	}
882 
883 	res = WriteFile(dev->device_handle, buf, (DWORD) length, NULL, &dev->write_ol);
884 
885 	if (!res) {
886 		if (GetLastError() != ERROR_IO_PENDING) {
887 			/* WriteFile() failed. Return error. */
888 			register_error(dev, "WriteFile");
889 			goto end_of_function;
890 		}
891 		overlapped = TRUE;
892 	}
893 
894 	if (overlapped) {
895 		/* Wait for the transaction to complete. This makes
896 		   hid_write() synchronous. */
897 		res = WaitForSingleObject(dev->write_ol.hEvent, 1000);
898 		if (res != WAIT_OBJECT_0) {
899 			/* There was a Timeout. */
900 			register_error(dev, "WriteFile/WaitForSingleObject Timeout");
901 			goto end_of_function;
902 		}
903 
904 		/* Get the result. */
905 		res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*wait*/);
906 		if (res) {
907 			function_result = bytes_written;
908 		}
909 		else {
910 			/* The Write operation failed. */
911 			register_error(dev, "WriteFile");
912 			goto end_of_function;
913 		}
914 	}
915 
916 end_of_function:
917 	return function_result;
918 }
919 
920 
hid_read_timeout(hid_device * dev,unsigned char * data,size_t length,int milliseconds)921 int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
922 {
923 	DWORD bytes_read = 0;
924 	size_t copy_len = 0;
925 	BOOL res = FALSE;
926 	BOOL overlapped = FALSE;
927 
928 	/* Copy the handle for convenience. */
929 	HANDLE ev = dev->ol.hEvent;
930 
931 	if (!dev->read_pending) {
932 		/* Start an Overlapped I/O read. */
933 		dev->read_pending = TRUE;
934 		memset(dev->read_buf, 0, dev->input_report_length);
935 		ResetEvent(ev);
936 		res = ReadFile(dev->device_handle, dev->read_buf, (DWORD) dev->input_report_length, &bytes_read, &dev->ol);
937 
938 		if (!res) {
939 			if (GetLastError() != ERROR_IO_PENDING) {
940 				/* ReadFile() has failed.
941 				   Clean up and return error. */
942 				CancelIo(dev->device_handle);
943 				dev->read_pending = FALSE;
944 				goto end_of_function;
945 			}
946 			overlapped = TRUE;
947 		}
948 	}
949 	else {
950 		overlapped = TRUE;
951 	}
952 
953 	if (overlapped) {
954 		if (milliseconds >= 0) {
955 			/* See if there is any data yet. */
956 			res = WaitForSingleObject(ev, milliseconds);
957 			if (res != WAIT_OBJECT_0) {
958 				/* There was no data this time. Return zero bytes available,
959 				   but leave the Overlapped I/O running. */
960 				return 0;
961 			}
962 		}
963 
964 		/* Either WaitForSingleObject() told us that ReadFile has completed, or
965 		   we are in non-blocking mode. Get the number of bytes read. The actual
966 		   data has been copied to the data[] array which was passed to ReadFile(). */
967 		res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
968 	}
969 	/* Set pending back to false, even if GetOverlappedResult() returned error. */
970 	dev->read_pending = FALSE;
971 
972 	if (res && bytes_read > 0) {
973 		if (dev->read_buf[0] == 0x0) {
974 			/* If report numbers aren't being used, but Windows sticks a report
975 			   number (0x0) on the beginning of the report anyway. To make this
976 			   work like the other platforms, and to make it work more like the
977 			   HID spec, we'll skip over this byte. */
978 			bytes_read--;
979 			copy_len = length > bytes_read ? bytes_read : length;
980 			memcpy(data, dev->read_buf+1, copy_len);
981 		}
982 		else {
983 			/* Copy the whole buffer, report number and all. */
984 			copy_len = length > bytes_read ? bytes_read : length;
985 			memcpy(data, dev->read_buf, copy_len);
986 		}
987 	}
988 
989 end_of_function:
990 	if (!res) {
991 		register_error(dev, "GetOverlappedResult");
992 		return -1;
993 	}
994 
995 	return (int) copy_len;
996 }
997 
hid_read(hid_device * dev,unsigned char * data,size_t length)998 int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
999 {
1000 	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
1001 }
1002 
hid_set_nonblocking(hid_device * dev,int nonblock)1003 int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
1004 {
1005 	dev->blocking = !nonblock;
1006 	return 0; /* Success */
1007 }
1008 
hid_send_feature_report(hid_device * dev,const unsigned char * data,size_t length)1009 int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
1010 {
1011 	BOOL res = FALSE;
1012 	unsigned char *buf;
1013 	size_t length_to_send;
1014 
1015 	/* Windows expects at least caps.FeatureReportByteLength bytes passed
1016 	   to HidD_SetFeature(), even if the report is shorter. Any less sent and
1017 	   the function fails with error ERROR_INVALID_PARAMETER set. Any more
1018 	   and HidD_SetFeature() silently truncates the data sent in the report
1019 	   to caps.FeatureReportByteLength. */
1020 	if (length >= dev->feature_report_length) {
1021 		buf = (unsigned char *) data;
1022 		length_to_send = length;
1023 	} else {
1024 		if (dev->feature_buf == NULL)
1025 			dev->feature_buf = (unsigned char *) malloc(dev->feature_report_length);
1026 		buf = dev->feature_buf;
1027 		memcpy(buf, data, length);
1028 		memset(buf + length, 0, dev->feature_report_length - length);
1029 		length_to_send = dev->feature_report_length;
1030 	}
1031 
1032 	res = HidD_SetFeature(dev->device_handle, (PVOID)buf, (DWORD) length_to_send);
1033 
1034 	if (!res) {
1035 		register_error(dev, "HidD_SetFeature");
1036 		return -1;
1037 	}
1038 
1039 	return (int) length;
1040 }
1041 
hid_get_report(hid_device * dev,DWORD report_type,unsigned char * data,size_t length)1042 static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length)
1043 {
1044 	BOOL res;
1045 	DWORD bytes_returned = 0;
1046 
1047 	OVERLAPPED ol;
1048 	memset(&ol, 0, sizeof(ol));
1049 
1050 	res = DeviceIoControl(dev->device_handle,
1051 		report_type,
1052 		data, (DWORD) length,
1053 		data, (DWORD) length,
1054 		&bytes_returned, &ol);
1055 
1056 	if (!res) {
1057 		if (GetLastError() != ERROR_IO_PENDING) {
1058 			/* DeviceIoControl() failed. Return error. */
1059 			register_error(dev, "Get Input/Feature Report DeviceIoControl");
1060 			return -1;
1061 		}
1062 	}
1063 
1064 	/* Wait here until the write is done. This makes
1065 	   hid_get_feature_report() synchronous. */
1066 	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
1067 	if (!res) {
1068 		/* The operation failed. */
1069 		register_error(dev, "Get Input/Feature Report GetOverLappedResult");
1070 		return -1;
1071 	}
1072 
1073 	/* When numbered reports aren't used,
1074 	   bytes_returned seem to include only what is actually received from the device
1075 	   (not including the first byte with 0, as an indication "no numbered reports"). */
1076 	if (data[0] == 0x0) {
1077 		bytes_returned++;
1078 	}
1079 
1080 	return bytes_returned;
1081 }
1082 
hid_get_feature_report(hid_device * dev,unsigned char * data,size_t length)1083 int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
1084 {
1085 	/* We could use HidD_GetFeature() instead, but it doesn't give us an actual length, unfortunately */
1086 	return hid_get_report(dev, IOCTL_HID_GET_FEATURE, data, length);
1087 }
1088 
hid_get_input_report(hid_device * dev,unsigned char * data,size_t length)1089 int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
1090 {
1091 	/* We could use HidD_GetInputReport() instead, but it doesn't give us an actual length, unfortunately */
1092 	return hid_get_report(dev, IOCTL_HID_GET_INPUT_REPORT, data, length);
1093 }
1094 
hid_close(hid_device * dev)1095 void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
1096 {
1097 	if (!dev)
1098 		return;
1099 	CancelIo(dev->device_handle);
1100 	free_hid_device(dev);
1101 }
1102 
hid_get_manufacturer_string(hid_device * dev,wchar_t * string,size_t maxlen)1103 int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1104 {
1105 	if (!dev->device_info || !string || !maxlen)
1106 		return -1;
1107 
1108 	wcsncpy(string, dev->device_info->manufacturer_string, maxlen);
1109 	string[maxlen] = L'\0';
1110 
1111 	return 0;
1112 }
1113 
hid_get_product_string(hid_device * dev,wchar_t * string,size_t maxlen)1114 int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1115 {
1116 	if (!dev->device_info || !string || !maxlen)
1117 		return -1;
1118 
1119 	wcsncpy(string, dev->device_info->product_string, maxlen);
1120 	string[maxlen] = L'\0';
1121 
1122 	return 0;
1123 }
1124 
hid_get_serial_number_string(hid_device * dev,wchar_t * string,size_t maxlen)1125 int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1126 {
1127 	if (!dev->device_info || !string || !maxlen)
1128 		return -1;
1129 
1130 	wcsncpy(string, dev->device_info->serial_number, maxlen);
1131 	string[maxlen] = L'\0';
1132 
1133 	return 0;
1134 }
1135 
hid_get_indexed_string(hid_device * dev,int string_index,wchar_t * string,size_t maxlen)1136 int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1137 {
1138 	BOOL res;
1139 
1140 	res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * (DWORD) MIN(maxlen, MAX_STRING_WCHARS));
1141 	if (!res) {
1142 		register_error(dev, "HidD_GetIndexedString");
1143 		return -1;
1144 	}
1145 
1146 	return 0;
1147 }
1148 
1149 
hid_error(hid_device * dev)1150 HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
1151 {
1152 	if (dev) {
1153 		if (dev->last_error_str == NULL)
1154 			return L"Success";
1155 		return (wchar_t*)dev->last_error_str;
1156 	}
1157 
1158 	// Global error messages are not (yet) implemented on Windows.
1159 	return L"hid_error for global errors is not implemented yet";
1160 }
1161 
1162 
1163 /*#define PICPGM*/
1164 /*#define S11*/
1165 #define P32
1166 #ifdef S11
1167   unsigned short VendorID = 0xa0a0;
1168 	unsigned short ProductID = 0x0001;
1169 #endif
1170 
1171 #ifdef P32
1172   unsigned short VendorID = 0x04d8;
1173 	unsigned short ProductID = 0x3f;
1174 #endif
1175 
1176 
1177 #ifdef PICPGM
1178   unsigned short VendorID = 0x04d8;
1179   unsigned short ProductID = 0x0033;
1180 #endif
1181 
1182 
1183 #if 0
1184 int __cdecl main(int argc, char* argv[])
1185 {
1186 	int res;
1187 	unsigned char buf[65];
1188 
1189 	UNREFERENCED_PARAMETER(argc);
1190 	UNREFERENCED_PARAMETER(argv);
1191 
1192 	/* Set up the command buffer. */
1193 	memset(buf,0x00,sizeof(buf));
1194 	buf[0] = 0;
1195 	buf[1] = 0x81;
1196 
1197 
1198 	/* Open the device. */
1199 	int handle = open(VendorID, ProductID, L"12345");
1200 	if (handle < 0)
1201 		printf("unable to open device\n");
1202 
1203 
1204 	/* Toggle LED (cmd 0x80) */
1205 	buf[1] = 0x80;
1206 	res = write(handle, buf, 65);
1207 	if (res < 0)
1208 		printf("Unable to write()\n");
1209 
1210 	/* Request state (cmd 0x81) */
1211 	buf[1] = 0x81;
1212 	write(handle, buf, 65);
1213 	if (res < 0)
1214 		printf("Unable to write() (2)\n");
1215 
1216 	/* Read requested state */
1217 	read(handle, buf, 65);
1218 	if (res < 0)
1219 		printf("Unable to read()\n");
1220 
1221 	/* Print out the returned buffer. */
1222 	for (int i = 0; i < 4; i++)
1223 		printf("buf[%d]: %d\n", i, buf[i]);
1224 
1225 	return 0;
1226 }
1227 #endif
1228 
1229 #ifdef __cplusplus
1230 } /* extern "C" */
1231 #endif
1232