示例#1
0
std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data,
                               const DEVPROPKEY* requested_property)
{
  DWORD required_size = 0;
  DEVPROPTYPE device_property_type;

  SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
                           nullptr, 0, &required_size, 0);

  std::vector<BYTE> unicode_buffer(required_size, 0);

  BOOL result =
      SetupDiGetDeviceProperty(device_info, device_data, requested_property, &device_property_type,
                               unicode_buffer.data(), required_size, nullptr, 0);
  if (!result)
  {
    return std::wstring();
  }

  return std::wstring((PWCHAR)unicode_buffer.data());
}
示例#2
0
static bool GetDiPropStr(HDEVINFO h, SP_DEVINFO_DATA *data, const DEVPROPKEY& key, WCHAR *buf, DWORD size)
{
    DEVPROPTYPE proptype;
    return SetupDiGetDeviceProperty(h, data, &key, &proptype, (PBYTE)buf, size, &size, 0) &&
        proptype == DEVPROP_TYPE_STRING;
}
示例#3
0
// Returns physical drive number that represents private.img.
BOOL GetPrivateImgDriveNumber(IN ULONG xenVbdId, OUT ULONG *driveNumber)
{
    HDEVINFO deviceInfoSet = INVALID_HANDLE_VALUE;
    SP_DEVINFO_DATA deviceInfoData;
    DEVPROPTYPE devPropType;
    GUID diskClassGuid = { 0 };
    DWORD returnedSize;
    WCHAR deviceId[MAX_DEVICE_ID_LEN];
    WCHAR deviceName[1024];
    WCHAR locationString[1024];
    WCHAR *s;
    DWORD index;

    // Enumerate disk class devices.
    UuidFromString((RPC_WSTR) DISK_CLASS_GUID, &diskClassGuid);
    deviceInfoSet = SetupDiGetClassDevs(&diskClassGuid, NULL, NULL, DIGCF_PRESENT); // only connected devices

    if (deviceInfoSet == INVALID_HANDLE_VALUE)
    {
        perror("SetupDiGetClassDevs");
        return FALSE;
    }

    deviceInfoData.cbSize = sizeof(deviceInfoData);
    for (index = 0;
        SetupDiEnumDeviceInfo(deviceInfoSet, index, &deviceInfoData);
        index++)
    {
        if (!SetupDiGetDeviceInstanceId(deviceInfoSet, &deviceInfoData, deviceId, RTL_NUMBER_OF(deviceId), &returnedSize))
        {
            perror("SetupDiGetDeviceInstanceId");
            continue;
        }

        LogDebug("DEVID: %s", deviceId);

        // Get device's location info.
        ZeroMemory(locationString, sizeof(locationString));
        if (!SetupDiGetDeviceProperty(deviceInfoSet, &deviceInfoData, &DEVPKEY_Device_LocationInfo, &devPropType,
            (BYTE *)locationString, sizeof(locationString), &returnedSize, 0))
        {
            perror("SetupDiGetDeviceProperty(location)");
            continue;
        }

        // Check if it's the disk we want.
        if (!IsPrivateDisk(locationString, xenVbdId))
            continue;

        LogDebug("backend ID match");

        // Get the user mode device name.
        StringCchPrintf(deviceName, RTL_NUMBER_OF(deviceName), L"\\\\?\\%s\\" DISK_INTERFACE_GUID, deviceId);
        // Replace all backslashes with #.
        for (s = deviceName + 4; *s; s++)
            if (*s == L'\\')
                *s = '#';
        LogDebug("Device name: %s", deviceName);

        // Get physical drive number.
        return GetPhysicalDriveNumber(deviceName, driveNumber);
    }

    // No matching drive found.
    return FALSE;
}
//------------------------------------------------------------------------------
// CDeviceContextMenu::GetDeviceHardwareID
//
//      Get device hardware id from the devnode(s) of the device. You can get 
//      device properties that cannot be obtained directly from the shell item object
//      throught the device devnode(s).
//
//      Note there are two pieces of contextual information from the shell
//      object you can use to find the devnodes for your device.
//
//      1) Function Paths (PKEY_Devices_FunctionPaths)
//          This property is a vector of strings of the Device Instance Paths
//          for your device's devnodes. This function below will show how to
//          use this property to access properties off the devnodes.
//
//      2) Interface Paths (PKEY_Devices_InterfacePaths)
//          This property is a vectory of strings of the Device Interface Paths
//          of all your device's devnodes. Use of this property use not shown in
//          this sample, but if you find the property helpful for your scenario
//          you can use it. 
//------------------------------------------------------------------------------
HRESULT CDeviceContextMenu::GetDeviceHardwareID(
    __in IShellItem2* pShellItem2,
    __out PWSTR* ppszHardwareID
    )
{
    DWORD           cbBuffer            = 0;
    HDEVINFO        devInfo             = {0}; 
    SP_DEVINFO_DATA devInfoData         = {0};
    DEVPROPTYPE     devPropType         = 0;
    HRESULT         hr                  = S_OK;
    PBYTE           pBuffer             = NULL;
    PROPVARIANT     pv                  = {0};
    PCWSTR          pszHwid             = NULL;

    PropVariantInit( &pv );

    //
    // First get the Function Paths (Device Instance Paths) needed to grab the
    // devnode info directly from PnP.
    //
    if( S_OK == hr )
    {
        hr = pShellItem2->GetProperty( PKEY_Devices_FunctionPaths, &pv );
    }
    if( S_OK == hr &&
        ((VT_VECTOR | VT_LPWSTR) != pv.vt ||
        ( 0 == pv.calpwstr.cElems ) ) )
    {
        // Function Paths doesn't exist or is the wrong type or empty. 
        // This should never happen, but its good practice to check anyway.
        hr = HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
    }

    //
    // For simplicity in the sample, we'll just work with the first path in the
    // list. i.e. the first devnode in the list.
    //
    // IMPORTANT: In a real scenario, you need to keep in mind that your device
    // shown in the Devices and Printers folder is likely made up of one or more
    // Device Functions (devnodes). In this case, you may not be able to get all
    // properties from just any devnode. You'll need to look at all devnodes and
    // figure out which one contains the properties you're after. In this sample
    // we're just attempting to get one device hardware id from the devnode who's
    // Device Instance Path is in the FunctionPaths list retreived from the shell
    // object. 
    //

    //
    // Create an empty HDEVINFO set to use for the first devnode's info
    //
    if( S_OK == hr )
    {
        devInfo = SetupDiCreateDeviceInfoList( NULL, NULL );
        if( INVALID_HANDLE_VALUE == devInfo )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    //
    // Open the devnode's info
    //
    if( S_OK == hr )
    {
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if( FALSE == SetupDiOpenDeviceInfo(
                        devInfo,
                        pv.calpwstr.pElems[0],
                        NULL, 
                        0, 
                        &devInfoData 
                        ) )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    // You can ask for properties defined in devpkey.h. Some keys in 
    // FunctionDiscoveryKey.h are also available on devnodes; For example,
    // devnodes from PnP-X (Network Devices) will have PKEY_PNPX properties
    // set on them. These can be retreived with SetupDi* calls as well.
    // PROPERTYKEY can be safely cast to DEVPROPKEY. However, keep in mind
    // the types are defined differently. Variant types are essentially a
    // superset of DEVPROPTYPEs. The mapping on many property types is
    // straight forward. DEVPROP_TYPE_STRING and VT_LPWSTR
    // are the same, for example. Below we'll get a PnP-X property so it's
    // clear how this works. 
    //
    // One case where the mapping isn't exact, is VT_VECTOR | VT_LPWSTR
    // (vector of strings), which in the devnode is stored as a 
    // DEVPROP_TYPE_STRING_LIST (REG_MULTI_SZ style string list). Keep this
    // in mind when asking for PKEY types from a devnode vs. DEVPKEY types.
    //

    //
    // Get the hardware ids
    //
    if( S_OK == hr )
    {
        // Get the required buffer size 
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        &DEVPKEY_Device_HardwareIds,
                        &devPropType,
                        NULL,
                        0,
                        &cbBuffer,
                        0 
                        ) &&
            ERROR_INSUFFICIENT_BUFFER != GetLastError() )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr )
    {
        pBuffer = new (std::nothrow) BYTE[cbBuffer];
        if( NULL == pBuffer )
        {
            hr = E_OUTOFMEMORY;
        }
        ZeroMemory( pBuffer, cbBuffer );
    }

    if( S_OK == hr )
    {
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        &DEVPKEY_Device_HardwareIds,
                        &devPropType,
                        pBuffer,
                        cbBuffer,
                        NULL,
                        0 
                        ) )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr &&
        DEVPROP_TYPE_STRING_LIST == devPropType )
    {
        //
        // Get the first Hardware ID from the list
        //
        pszHwid = reinterpret_cast<PWSTR>(pBuffer);
        hr = SHStrDup( pszHwid, ppszHardwareID );
    }

    //
    // Cleanup
    //
    if( NULL != pBuffer )
    {
        delete[] pBuffer;
        pBuffer = NULL;
    }

    if( INVALID_HANDLE_VALUE != devInfo )
    {
        (void) SetupDiDestroyDeviceInfoList( devInfo );
    }

    PropVariantClear( &pv );

    return hr;
}// CDeviceContextMenu::GetDeviceHardwareID
//------------------------------------------------------------------------------
// CDevicePropertyPage::PopulateDevnodeProperties [STATIC FUNC]
//
//      Populates the property page with some properties that come from the
//      devnode(s) of the device directly. When implementing the property page
//      for your device, this method is needed for all properties that cannot
//      be obtained directly from the shell item object.
//
//      Note there are two pieces of contextual information from the shell
//      object you can use to find the devnodes for your device and farm extra
//      properties and/or communicate with your device.
//
//      1) Function Paths (PKEY_Devices_FunctionPaths)
//          This property is a vector of strings of the Device Instance Paths
//          for your device's devnodes. This function below will show how to
//          use this property to access properties off the devnodes.
//
//      2) Interface Paths (PKEY_Devices_InterfacePaths)
//          This property is a vectory of strings of the Device Interface Paths
//          of all your device's devnodes. Use of this property use not shown in
//          this sample, but if you find the property helpful for your scenario
//          you can use it. 
//------------------------------------------------------------------------------
HRESULT CDevicePropertyPage::PopulateDevnodeProperties(
    __in HWND hWndDlg,
    __in IShellItem2* pShellItem
    )
{
    DWORD           cbBuffer            = 0;
    HDEVINFO        devInfo             = {0}; 
    SP_DEVINFO_DATA devInfoData         = {0};
    DEVPROPTYPE     devPropType         = 0;
    HRESULT         hr                  = S_OK;
    SYSTEMTIME      installTime         = {0};
    PBYTE           pBuffer             = NULL;
    PROPVARIANT     pv                  = {0};
    PCWSTR          pszHwid             = NULL;
    WCHAR           szInstallTime[1024] = {0};

    PropVariantInit( &pv );

    //
    // First get the Function Paths (Device Instance Paths) needed to grab the
    // devnode info directly from PnP.
    //
    if( S_OK == hr )
    {
        hr = pShellItem->GetProperty( PKEY_Devices_FunctionPaths, &pv );
    }
    if( S_OK == hr &&
        ((VT_VECTOR | VT_LPWSTR) != pv.vt ||
        ( 0 == pv.calpwstr.cElems ) ) )
    {
        // Function Paths doesn't exist or is the wrong type or empty. 
        // This should never happen, but its good practice to check anyway.
        hr = HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
    }

    //
    // For simplicity in the sample, we'll just work with the first path in the
    // list. i.e. the first devnode in the list.
    //
    // IMPORTANT: In a real scenario, you need to keep in mind that your device
    // shown in the Devices and Printers folder is likely made up of one or more
    // Device Functions (devnodes). In this case, you may not be able to get all
    // properties from just any devnode. You'll need to look at all devnodes and
    // figure out which one contains the properties you're after. In this sample
    // we're just attempting to get a set of properties from the devnode who's
    // Device Instance Path is in the FunctionPaths list retreived from the shell
    // object. 
    //

    //
    // Create an empty HDEVINFO set to use for the first devnode's info
    //
    if( S_OK == hr )
    {
        devInfo = SetupDiCreateDeviceInfoList( NULL, NULL );
        if( INVALID_HANDLE_VALUE == devInfo )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    //
    // Open the devnode's info
    //
    if( S_OK == hr )
    {
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if( FALSE == SetupDiOpenDeviceInfo(
                        devInfo,
                        pv.calpwstr.pElems[0],
                        NULL, 
                        0, 
                        &devInfoData 
                        ) )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    //
    // Now populate the property page with some properties from the devnode
    // 
    // You can ask for properties defined in devpkey.h. Some keys in 
    // FunctionDiscoveryKey.h are also available on devnodes; For example,
    // devnodes from PnP-X (Network Devices) will have PKEY_PNPX properties
    // set on them. These can be retreived with SetupDi* calls as well.
    // PROPERTYKEY can be safely cast to DEVPROPKEY. However, keep in mind
    // the types are defined differently. Variant types are essentially a
    // superset of DEVPROPTYPEs. The mapping on many property types is
    // straight forward. DEVPROP_TYPE_STRING and VT_LPWSTR
    // are the same, for example. Below we'll get a PnP-X property so it's
    // clear how this works. 
    //
    // One case where the mapping isn't exact, is VT_VECTOR | VT_LPWSTR
    // (vector of strings), which in the devnode is stored as a 
    // DEVPROP_TYPE_STRING_LIST (REG_MULTI_SZ style string list). Keep this
    // in mind when asking for PKEY types from a devnode vs. DEVPKEY types.
    //

    //
    // Get the hardware ids
    //
    if( S_OK == hr )
    {
        // Get the required buffer size 
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        &DEVPKEY_Device_HardwareIds,
                        &devPropType,
                        NULL,
                        0,
                        &cbBuffer,
                        0 
                        ) &&
            ERROR_INSUFFICIENT_BUFFER != GetLastError() )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr )
    {
        pBuffer = new (std::nothrow) BYTE[cbBuffer];
        if( NULL == pBuffer )
        {
            hr = E_OUTOFMEMORY;
        }
        ZeroMemory( pBuffer, cbBuffer );
    }

    if( S_OK == hr )
    {
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        &DEVPKEY_Device_HardwareIds,
                        &devPropType,
                        pBuffer,
                        cbBuffer,
                        NULL,
                        0 
                        ) )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr &&
        DEVPROP_TYPE_STRING_LIST == devPropType )
    {
        //
        // The UI only has slots for up to three hardware ids, so we'll
        // just set up to the first three.
        //
        pszHwid = reinterpret_cast<PWSTR>(pBuffer);

        if( NULL != *pszHwid )
        {
            SetDlgItemText(
                hWndDlg, 
                IDC_HARDWAREID_FIELD1, 
                pszHwid
                );
            pszHwid = pszHwid + wcslen(pszHwid) + 1;
        }
        if( NULL != *pszHwid )
        {
            SetDlgItemText(
                hWndDlg, 
                IDC_HARDWAREID_FIELD2, 
                pszHwid
                );
            pszHwid = pszHwid + wcslen(pszHwid) + 1;
        }
        if( NULL != *pszHwid )
        {
            SetDlgItemText(
                hWndDlg, 
                IDC_HARDWAREID_FIELD3, 
                pszHwid
                );
        }
    }
    
    if( NULL != pBuffer )
    {
        delete[] pBuffer;
        pBuffer = NULL;
    }

    //
    // Get the install date
    //
    if( S_OK == hr )
    {
        // Get the required buffer size 
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        &DEVPKEY_Device_InstallDate,
                        &devPropType,
                        NULL,
                        0,
                        &cbBuffer,
                        0 
                        ) &&
            ERROR_INSUFFICIENT_BUFFER != GetLastError() )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr )
    {
        pBuffer = new (std::nothrow) BYTE[cbBuffer];
        if( NULL == pBuffer )
        {
            hr = E_OUTOFMEMORY;
        }
    }

    if( S_OK == hr )
    {
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        &DEVPKEY_Device_InstallDate,
                        &devPropType,
                        pBuffer,
                        cbBuffer,
                        NULL,
                        0 
                        ) )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
        else if( DEVPROP_TYPE_FILETIME != devPropType )
        {
            hr = E_INVALIDARG;
        }
    }

    if( S_OK == hr )
    {
        if( FALSE == FileTimeToSystemTime(
                reinterpret_cast<FILETIME*>(pBuffer), 
                &installTime ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr )
    {
        if( 0 == GetDateFormatEx( 
                LOCALE_NAME_USER_DEFAULT,
                DATE_AUTOLAYOUT | DATE_LONGDATE,
                &installTime,
                NULL,
                szInstallTime,
                ARRAY_SIZE(szInstallTime),
                NULL
                ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr )
    {
        SetDlgItemText( hWndDlg, IDC_INSTALLDATE_FIELD, szInstallTime );
    }
    
    if( NULL != pBuffer )
    {
        delete[] pBuffer;
        pBuffer = NULL;
    }

    //
    // Now get PKEY_** property instead of a DEVPKEY property
    // to show how that's done.  This would typically just be done
    // for PNPX properties, but other properties in FunctionDisocovery.h
    // might be available on the devnode.
    //
    // Let's attempt to get the IP Address, though it won't be available on
    // Mice (which is what this sample property page binds to). It at least
    // shows how the process would work. Also, as stated above, only *some*
    // of the devnodes that make up your PnP-X device may contain the 
    // IP Address, so you might have to look through all the devnodes by
    // iterating the FunctionPaths list. 
    //
    // This property won't be set on the property page itself since a mouse
    // will never have an IP Address.
    //
    if( S_OK == hr )
    {
        // Get the required buffer size 
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        (const DEVPROPKEY*)&PKEY_PNPX_IpAddress,
                        &devPropType,
                        NULL,
                        0,
                        &cbBuffer,
                        0 
                        ) &&
            ERROR_INSUFFICIENT_BUFFER != GetLastError() )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr )
    {
        pBuffer = new (std::nothrow) BYTE[cbBuffer];
        if( NULL == pBuffer )
        {
            hr = E_OUTOFMEMORY;
        }
    }

    if( S_OK == hr )
    {
        if( FALSE == SetupDiGetDeviceProperty(
                        devInfo,
                        &devInfoData,
                        (const DEVPROPKEY*)&PKEY_PNPX_IpAddress,
                        &devPropType,
                        pBuffer,
                        cbBuffer,
                        NULL,
                        0 
                        ) )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
        }
    }

    if( S_OK == hr &&
        DEVPROP_TYPE_STRING == devPropType
        )
    {
        // pBuffer now contains the IP Address if this is a PnP-X device and
        // this was one of the devnodes that had the property set.
    }

    //
    // Cleanup
    //
    if( NULL != pBuffer )
    {
        delete[] pBuffer;
    }

    if( INVALID_HANDLE_VALUE != devInfo )
    {
        (void) SetupDiDestroyDeviceInfoList( devInfo );
    }

    PropVariantClear( &pv );

    return hr;
}// CDevicePropertyPage::PopulateDevnodeProperties
/*
 * The sequence of entries in array must match with what java layer expect (6 informations
 * per USB device). If a particular USB attribute is not set in descriptor or can not be
 * obtained "---" is placed in its place.
 *
 * Returns array of USB device's information found, empty array if no USB device is found,
 * NULL if an error occurs (additionally throws exception).
 */
jobjectArray list_usb_devices(JNIEnv *env, jint vendor_to_match) {

	int x = 0;
	int i = 0;
	int vid = 0;
	BOOL ret = FALSE;
	DWORD error_code = 0;
	DWORD size = 0;
	TCHAR *ptrend;
	DWORD usb_member_index = 0;
	HDEVINFO usb_dev_info_set;
	SP_DEVINFO_DATA usb_dev_instance;
	DEVPROPTYPE proptype;
	DWORD regproptype;
	TCHAR buffer[1024];
	TCHAR charbuffer[1024];

	struct jstrarray_list list = { 0 };
	jstring usb_dev_info;
	jclass strClass = NULL;
	jobjectArray usbDevicesFound = NULL;

	init_jstrarraylist(&list, 50);

	/* get information set for all usb devices matching the GUID */
	usb_dev_info_set = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if (usb_dev_info_set == INVALID_HANDLE_VALUE) {
		SetupDiDestroyDeviceInfoList(usb_dev_info_set);
		free_jstrarraylist(&list);
		throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
		return NULL;
	}

	/* enumerate all devices in this information set */
	usb_member_index = 0;
	while (1) {
		ZeroMemory(&usb_dev_instance, sizeof(usb_dev_instance));
		usb_dev_instance.cbSize = sizeof(usb_dev_instance);

		/* from information set, get device by index */
		ret = SetupDiEnumDeviceInfo(usb_dev_info_set, usb_member_index, &usb_dev_instance);
		if (ret == FALSE) {
			error_code = GetLastError();
			if (error_code == ERROR_NO_MORE_ITEMS) {
				break;
			}
			else {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				free_jstrarraylist(&list);
				throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(error_code), NULL);
				return NULL;
			}
		}

		/* for this device find its instance ID (USB\VID_04D8&PID_00DF\000098037)
		 * this is the variable 'Device Instance Path' in device manager. */
		memset(buffer, '\0', sizeof(buffer));
		ret = SetupDiGetDeviceInstanceId(usb_dev_info_set, &usb_dev_instance, buffer, sizeof(buffer), &size);
		if (ret == FALSE) {
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
			return NULL;
		}

		/* USB-IF vendor ID, extract and match, if matched continue further otherwise loop back */
		x = 0;
		while (buffer[x] != '\0') {
			if((buffer[x] == 'V') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
				break;
			}
			x++;
		}
		x = x + 4;
		i = 0;
		while (buffer[x] != '&') {
			charbuffer[i] = buffer[x];
			i++;
			x++;
		}
		charbuffer[i] = '\0'; /* indicate end of string */

		vid = (int)_tcstol(charbuffer, &ptrend, 16);

		if(vendor_to_match != 0) {
			/* we need to apply filter for identify specific vendor */
			if(vid != vendor_to_match) {
				usb_member_index++;
				continue;
			}
		}

		usb_dev_info = (*env)->NewString(env, charbuffer, (jsize) _tcslen(charbuffer));
		if((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
			(*env)->ExceptionClear(env);
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 3, 0, E_NEWSTRSTR);
			return NULL;
		}
		insert_jstrarraylist(&list, usb_dev_info);

		/* USB product ID */
		x = 6;
		while (buffer[x] != '\0') {
			if ((buffer[x] == 'P') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
				break;
			}
			x++;
		}
		x = x + 4;
		i = 0;
		while (buffer[x] != '\\') {
			charbuffer[i] = buffer[x];
			i++;
			x++;
		}
		charbuffer[i] = '\0';

		usb_dev_info = (*env)->NewString(env, charbuffer, (jsize) _tcslen(charbuffer));
		if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
			(*env)->ExceptionClear(env);
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 3, 0, E_NEWSTRSTR);
			return NULL;
		}
		insert_jstrarraylist(&list, usb_dev_info);

		/* SERIAL NUMBER */
		x++;
		i = 0;
		while (buffer[x] != '\0') {
			charbuffer[i] = buffer[x];
			i++;
			x++;
		}
		charbuffer[i] = '\0';

		usb_dev_info = (*env)->NewString(env, charbuffer, (jsize) _tcslen(charbuffer));
		if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
			(*env)->ExceptionClear(env);
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 3, 0, E_NEWSTRSTR);
			return NULL;
		}
		insert_jstrarraylist(&list, usb_dev_info);

		/* PRODUCT (idProduct field of USB device descriptor) */
		memset(buffer, '\0', sizeof(buffer));
		ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_BusReportedDeviceDesc, &proptype, (BYTE *)buffer, sizeof(buffer), &size, 0);
		if (ret == FALSE) {
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
			return NULL;
		}
		usb_dev_info = (*env)->NewString(env, buffer, (jsize) _tcslen(buffer));
		insert_jstrarraylist(&list, usb_dev_info);

		/* MANUFACTURER */
		memset(buffer, '\0', sizeof(buffer));
		ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_Manufacturer, &proptype, (BYTE *)buffer, sizeof(buffer), &size, 0);
		if (ret == FALSE) {
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
			return NULL;
		}
		usb_dev_info = (*env)->NewString(env, buffer, (jsize) _tcslen(buffer));
		insert_jstrarraylist(&list, usb_dev_info);

		/* LOCATION (Location paths + Location info, get separately and then create a single string) */
		memset(buffer, '\0', sizeof(buffer));
		ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_PATHS, &regproptype, (BYTE *)buffer, sizeof(buffer), &size);
		if (ret == FALSE) {
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
			return NULL;
		}

		memset(charbuffer, '\0', sizeof(charbuffer));
		ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_INFORMATION, &regproptype, (BYTE *)charbuffer, sizeof(charbuffer), &size);
		if (ret == FALSE) {
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
			return NULL;
		}

		i = 0;
		x = (int)_tcslen(buffer);
		buffer[x] = '-';
		x++;
		for (i = 0; i < (int)_tcslen(charbuffer); i++) {
			buffer[x] = charbuffer[i];
			x++;
		}
		buffer[x] = '\0';

		usb_dev_info = (*env)->NewString(env, buffer, (jsize)_tcslen(buffer));
		insert_jstrarraylist(&list, usb_dev_info);

		/* loop to get next USB device */
		usb_member_index++;
	}

	SetupDiDestroyDeviceInfoList(usb_dev_info_set);

	strClass = (*env)->FindClass(env, JAVALSTRING);
	if((strClass == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		(*env)->ExceptionClear(env);
		free_jstrarraylist(&list);
		throw_serialcom_exception(env, 3, 0, E_FINDCLASSSSTRINGSTR);
		return NULL;
	}

	usbDevicesFound = (*env)->NewObjectArray(env, (jsize)list.index, strClass, NULL);
	if((usbDevicesFound == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		(*env)->ExceptionClear(env);
		free_jstrarraylist(&list);
		throw_serialcom_exception(env, 3, 0, E_NEWOBJECTARRAYSTR);
		return NULL;
	}

	for (x = 0; x < list.index; x++) {
		(*env)->SetObjectArrayElement(env, usbDevicesFound, x, list.base[x]);
		if ((*env)->ExceptionOccurred(env)) {
			(*env)->ExceptionClear(env);
			free_jstrarraylist(&list);
			throw_serialcom_exception(env, 3, 0, E_SETOBJECTARRAYSTR);
			return NULL;
		}
	}

	free_jstrarraylist(&list);
	return usbDevicesFound;
}
/*
 * Finds information about USB HID devices using setup class API.
 *
 * The sequence of entries in array must match with what java layer expect. If a particular USB
 * attribute is not set in descriptor or can not be obtained "---" is placed in its place.
 *
 * The array returned will be in following sequence; transport, device node, vendor ID,
 * product ID, serial, product, manufacturer, USB bus number, USB device number, location.
 *
 * For an HID interface in a USB device, Windows create a device instance for the USB interface
 * (GUID_DEVINTERFACE_HID_DEVICE) and another device instance for the HID collection (GUID_DEVINTERFACE_HID).
 * This function relate HID collection device instance to its USB interface (physical USB device) through
 * HardwareID. A hardware ID is a vendor-defined identification string that Windows uses to match a
 * device to an INF file. In most cases, a device has associated with it a list of hardware IDs.
 * (However, there are exceptions − see Identifiers for 1394 Devices). When an enumerator reports a
 * list of hardware IDs for a device, the hardware IDs should be listed in order of decreasing suitability.
 *
 * This key contains symbolic links to HID device instances :
 * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\{4d1e55b2-f16f-11cf-88cb-001111000030}
 * 
 * This function basically collect information from USB and HID subsystems and relate them to identify a device
 * and then create a unified information to be sent to java application.
 */
jobjectArray enumerate_usb_hid_devices(JNIEnv *env, jint vendor_to_match) {

	int q = 0;
	int i = 0;
	int x = 0;
	BOOL ret = FALSE;
	LONG status = 0;
	DWORD error_code = 0;
	DWORD errorVal = 0;
	DWORD size = 0;
	DWORD charbuffer_size = 0;
	DWORD driver_name_size = 0;
	ULONG buffer_size = 0;
	ULONG devprop_buffer_size = 0;
	DEVPROPTYPE proptype;
	DWORD regproptype;

	CONFIGRET cmret = 0;
	DEVINST firstchild = 0;
	DEVINST next_sibling = 0;
	DEVINST current_sibling = 0;

	struct hiddev_inst_cont_id *instidinfo;
	struct hiddev_instance_list hiddevinst_list = { 0 };
	struct jstrarray_list list = { 0 };

	DWORD hid_member_index = 0;
	HDEVINFO hid_dev_info_set;
	SP_DEVINFO_DATA hid_dev_instance;

	DWORD usb_member_index = 0;
	HDEVINFO usb_dev_info_set;
	SP_DEVINFO_DATA usb_dev_instance;

	/* size of these buffers is hardcoded in functions using them */
	TCHAR buffer[1024];
	TCHAR devprop_buffer[1024];
	TCHAR keybuf[1024];
	TCHAR charbuffer[512];
	TCHAR tmpbuf[128];
	char cmerror[256];

	jstring usb_dev_info;
	jclass strClass = NULL;
	jobjectArray usbHidDevicesFound = NULL;

	/* allocate memory to hold information used during processing and returning information
	   to caller. */
	x = init_hiddev_instance_list(&hiddevinst_list, 25);
	if (x < 0) {
		return clean_throw_exp_usbenumeration(env, 0, 1, 0, E_CALLOCSTR, NULL, NULL, NULL, NULL);
	}

	/* ~~~~~~~~~~~~~ ENUMERATE ALL HID DEVICES ~~~~~~~~~~~~~ */

	/* get information set for all HID devices matching the GUID. It an array of 
	   structures containing information about all attached and enumerated HID devices.	*/
	hid_dev_info_set = SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if (hid_dev_info_set == INVALID_HANDLE_VALUE) {
		return clean_throw_exp_usbenumeration(env, 1, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, NULL, &hiddevinst_list, NULL, &hid_dev_info_set);
	}

	/* enumerate all devices in this information set starting from 0th index */
	hid_member_index = 0;
	while (1) {
		ZeroMemory(&hid_dev_instance, sizeof(hid_dev_instance));
		hid_dev_instance.cbSize = sizeof(hid_dev_instance);

		/* from information set, get device by index */
		ret = SetupDiEnumDeviceInfo(hid_dev_info_set, hid_member_index, &hid_dev_instance);
		if (ret == FALSE) {
			error_code = GetLastError();
			if (error_code == ERROR_NO_MORE_ITEMS) {
				break;
			}else {
				return clean_throw_exp_usbenumeration(env, 1, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, NULL, &hiddevinst_list, NULL, &hid_dev_info_set);
			}
		}

		/* for this device find its instance ID, for example; HID\VID_04D8&PID_00DF&MI_02\7&33842C3F&0&0000
		 * this is variable 'Device Instance Path' in device manager. */
		memset(buffer, '\0', 1024);
		ret = SetupDiGetDeviceInstanceId(hid_dev_info_set, &hid_dev_instance, buffer, 1024, &size);
		if (ret == FALSE) {
			return clean_throw_exp_usbenumeration(env, 1, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, NULL, &hiddevinst_list, NULL, &hid_dev_info_set);
		}

		/* get HardwareID of this device;
		   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\HID\VID_04D8&PID_00DF&MI_02\7&33842C3F&0&0000\HardwareID */
		memset(keybuf, '\0', 1024);
		_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s"), buffer);

		charbuffer_size = sizeof(charbuffer);
		memset(charbuffer, '\0', 512);

		status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("HardwareID"), RRF_RT_REG_MULTI_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
		if (status != ERROR_SUCCESS) {
			return clean_throw_exp_usbenumeration(env, 1, 2, GetLastError(), NULL, NULL, &hiddevinst_list, NULL, &hid_dev_info_set);
		}

		/* save device instance and hardware id (including terminating null character) in the
		   list for later comparision */
		instidinfo = NULL;
		instidinfo = (struct hiddev_inst_cont_id *) malloc(sizeof(struct hiddev_inst_cont_id));
		if (instidinfo == NULL) {
			return clean_throw_exp_usbenumeration(env, 1, 1, 0, E_MALLOCSTR, NULL, &hiddevinst_list, NULL, &hid_dev_info_set);
		}
		_tcscpy_s(instidinfo->instance, 512, buffer);
		_tcscpy_s(instidinfo->hwid, 512, charbuffer);

		insert_hiddev_instance_list(&hiddevinst_list, instidinfo);

		/* increment to get the next HID device instance */
		hid_member_index++;
	}

	/* release HID info set as it is no longer needed */
	SetupDiDestroyDeviceInfoList(hid_dev_info_set);

	/* allocate memory to hold information used during processing and returning information
	to caller. */
	x = init_jstrarraylist(&list, 100);
	if (x < 0) {
		return clean_throw_exp_usbenumeration(env, 2, 1, 0, E_CALLOCSTR, NULL, &hiddevinst_list, NULL, NULL);
	}

	/* From here onwards, enumerate over all USB interfaces looking for HID interface and try to
	   associate with its device instance and then create information that will be passed to
	   application. */

	/* ~~~~~~~~~~~~~ ENUMERATE ALL USB DEVICES ~~~~~~~~~~~~~ */

	/* get information set for all usb devices matching the GUID */
	usb_dev_info_set = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if (usb_dev_info_set == INVALID_HANDLE_VALUE) {
		return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
	}

	/* enumerate all devices in this information set */
	usb_member_index = 0;
	while (1) {
		ZeroMemory(&usb_dev_instance, sizeof(usb_dev_instance));
		usb_dev_instance.cbSize = sizeof(usb_dev_instance);

		/* from information set, get device by index */
		ret = SetupDiEnumDeviceInfo(usb_dev_info_set, usb_member_index, &usb_dev_instance);
		if (ret == FALSE) {
			error_code = GetLastError();
			if (error_code == ERROR_NO_MORE_ITEMS) {
				break;
			}else {
				return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}
		}

		/* for this device find its instance ID (USB\VID_04D8&PID_00DF\000098037)
		 * this is the variable 'Device Instance Path' in device manager. */
		memset(buffer, '\0', sizeof(buffer));
		ret = SetupDiGetDeviceInstanceId(usb_dev_info_set, &usb_dev_instance, buffer, 1024, &size);
		if (ret == FALSE) {
			return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
		}

		/* fetch and examine USB interface */
		cmret = CM_Get_Child(&firstchild, usb_dev_instance.DevInst, 0);
		if (cmret != CR_SUCCESS) {
			if (cmret == CR_NO_SUCH_DEVNODE) {
				/* this device does not have any child, so check if this is a HID class device or not */
				memset(devprop_buffer, '\0', 1024);
				ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_CLASSGUID, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}

				/* check if this is a HID device interface, if it is not than loop back to examine next USB device */
				ret = _tcsicmp(devprop_buffer, TEXT("{745A17A0-74D3-11D0-B6FE-00A0C90F57DA}"));
				if (ret != 0) {
					usb_member_index++;
					continue;
				}

				/* reaching here means that the device is a HID device, so create all the information
				that will be passed to java layer. */

				/* get the HardwareID of this USB HID interface. HardwareID is multi-sz, however
				   we use only 1st string from multi-string HardwareID for our matching.
				   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_04D8&PID_00DF&MI_02\7&33842C3F&0&0000\HardwareID 
				   The buffer contains device instance path of USB device */
				memset(keybuf, '\0', 1024);
				_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s"), buffer);

				charbuffer_size = sizeof(charbuffer);
				memset(charbuffer, '\0', 512);

				/* USB\VID_04D8&PID_00DF&REV_0101 and USB\VID_04D8&PID_00DF and so on */
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("HardwareID"), RRF_RT_REG_MULTI_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
				if (status != ERROR_SUCCESS) {
					return clean_throw_exp_usbenumeration(env, 3, 2, GetLastError(), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}

				/* charbuffer now contains hardwareID, cook it a little bit to enable suitable matching */
				if ((charbuffer[0] == 'U') && (charbuffer[1] == 'S') && (charbuffer[2] == 'B')) {
					charbuffer[0] = 'H';
					charbuffer[1] = 'I';
					charbuffer[2] = 'D';
				}

				for (q = 0; q < hiddevinst_list.index; q++) {

					/* check association between HID collection device instance and USB device instance */
					ret = _tcsicmp(charbuffer, hiddevinst_list.base[q]->hwid);
					if (ret != 0) {
						continue;
					}

					/* reaching here means this HID collection belongs to this USB HID device, so glean information
					   to be passed to java layer. */

					/* TRANSPORT */
					usb_dev_info = (*env)->NewStringUTF(env, "USB");
					if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
						return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					insert_jstrarraylist(&list, usb_dev_info);

					/* DEVICE NODE */
					usb_dev_info = (*env)->NewString(env, hiddevinst_list.base[q]->instance, (jsize)_tcslen(hiddevinst_list.base[q]->instance));
					if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
						return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					insert_jstrarraylist(&list, usb_dev_info);

					/* USB-IF VENDOR ID
					   (extracted from USB device instance for example: USB\VID_04D8&PID_00DF\000098037) */
					x = 0;
					while (buffer[x] != '\0') {
						if ((buffer[x] == 'V') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
							break;
						}
						x++;
					}
					x = x + 4;
					i = 0;
					while (buffer[x] != '&') {
						tmpbuf[i] = buffer[x];
						i++;
						x++;
					}
					tmpbuf[i] = '\0'; /* indicate end of string */
					usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
					if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
						return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					insert_jstrarraylist(&list, usb_dev_info);

					/* USB product ID
					   (extracted from USB device instance for example: USB\VID_04D8&PID_00DF\000098037) */
					x = 6;
					while (buffer[x] != '\0') {
						if ((buffer[x] == 'P') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
							break;
						}
						x++;
					}
					x = x + 4;
					i = 0;
					while (buffer[x] != '\\') {
						tmpbuf[i] = buffer[x];
						i++;
						x++;
					}
					tmpbuf[i] = '\0'; /* indicate end of string */
					usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
					if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
						return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					insert_jstrarraylist(&list, usb_dev_info);

					/* SERIAL NUMBER */
					x++;
					i = 0;
					while (buffer[x] != '\0') {
						tmpbuf[i] = buffer[x];
						i++;
						x++;
					}
					tmpbuf[i] = '\0';
					usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
					if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
						return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					insert_jstrarraylist(&list, usb_dev_info);

					/* PRODUCT
					   (iProduct field of USB device descriptor) */
					memset(devprop_buffer, '\0', sizeof(devprop_buffer));
					ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_BusReportedDeviceDesc, &proptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size, 0);
					if (ret == FALSE) {
						/* fallback to SPDRP_DEVICEDESC if DEVPKEY_Device_BusReportedDeviceDesc fails */
						ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_DEVICEDESC, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
						if (ret == FALSE) {
							/* if second attempt fails, throw error, we need to investigate drivers/firmware etc */
							return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
						}
					}
					usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
					insert_jstrarraylist(&list, usb_dev_info);

					/* MANUFACTURER */
					memset(devprop_buffer, '\0', sizeof(devprop_buffer));
					ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_Manufacturer, &proptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size, 0);
					if (ret == FALSE) {
						return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
					insert_jstrarraylist(&list, usb_dev_info);

					/* LOCATION
					   (Location paths + Location info, get separately and then create a single string) */

					// PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(3)
					memset(devprop_buffer, '\0', sizeof(devprop_buffer));
					ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_PATHS, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
					if (ret == FALSE) {
						return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					// Port_#0003.Hub_#0001
					memset(charbuffer, '\0', sizeof(charbuffer));
					ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_INFORMATION, &regproptype, (BYTE *)charbuffer, sizeof(charbuffer), &size);
					if (ret == FALSE) {
						return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}

					i = 0;
					x = (int)_tcslen(devprop_buffer);
					devprop_buffer[x] = '-';
					x++;
					for (i = 0; i < (int)_tcslen(charbuffer); i++) {
						devprop_buffer[x] = charbuffer[i];
						x++;
					}
					devprop_buffer[x] = '\0';

					usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
					insert_jstrarraylist(&list, usb_dev_info);
				}

				/* loop back to get next USB device */
				usb_member_index++;
				continue;
			}else {
				/* error happend when getting child of USB device */
				_snprintf_s(cmerror, 256, 256, "CM_Get_Child failed with CR_xxxx error code : 0x%X\0", cmret);
				return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}
		}

		/* reaching here means that this USB device has at-least one child device node, examine first child now */
		devprop_buffer_size = sizeof(devprop_buffer);
		memset(devprop_buffer, '\0', 1024);

		cmret = CM_Get_DevNode_Registry_Property(firstchild, CM_DRP_CLASSGUID, &proptype, (PVOID)devprop_buffer, &devprop_buffer_size, 0);
		if (cmret != CR_SUCCESS) {
			_snprintf_s(cmerror, 256, 256, "CM_Get_DevNode_Registry_Property failed with CR_xxxx error code : 0x%X\0", cmret);
			return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
		}

		/* check if first child is a HID device interface */
		ret = _tcsicmp(devprop_buffer, TEXT("{745A17A0-74D3-11D0-B6FE-00A0C90F57DA}"));
		if (ret == 0) {
			/* reaching here means that this sibling (interface) is a HID type, get its device instance path */
			memset(devprop_buffer, '\0', 1024);
			cmret = CM_Get_Device_ID(firstchild, devprop_buffer, 1024, 0);
			if (cmret != CR_SUCCESS) {
				_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID failed with CR_xxxx error code : 0x%X\0", cmret);
				return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}

			/* get the HardwareID of this USB HID interface. HardwareID is multi-sz, however
			   we use only 1st string from multi-string HardwareID for our matching.
			   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_04D8&PID_00DF&MI_02\7&33842C3F&0&0000\HardwareID */
			memset(charbuffer, '\0', 512);
			buffer_size = sizeof(charbuffer);
			cmret = CM_Get_DevNode_Registry_Property(firstchild, CM_DRP_HARDWAREID, NULL, (PVOID)charbuffer, &buffer_size, 0);
			if (cmret != CR_SUCCESS) {
				_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID failed with CR_xxxx error code : 0x%X\0", cmret);
				return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}

			if ((charbuffer[0] == 'U') && (charbuffer[1] == 'S') && (charbuffer[2] == 'B')) {
				charbuffer[0] = 'H';
				charbuffer[1] = 'I';
				charbuffer[2] = 'D';
			}

			for (q = 0; q < hiddevinst_list.index; q++) {

				/* check association between HID collection device instance and USB interface device instance */
				ret = _tcsncicmp(charbuffer, hiddevinst_list.base[q]->hwid, 512);
				if (ret != 0) {
					continue;
				}

				/* reaching here means this HID collection belongs to this USB HID interface, so glean information
				   to be passed to java layer. */

				/* TRANSPORT */
				usb_dev_info = (*env)->NewStringUTF(env, "USB");
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* DEVICE NODE */
				usb_dev_info = (*env)->NewString(env, hiddevinst_list.base[q]->instance, (jsize)_tcslen(hiddevinst_list.base[q]->instance));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* USB-IF VENDOR ID
				   (extracted from USB device instance for example: USB\VID_04D8&PID_00DF\000098037) */
				x = 0;
				while (buffer[x] != '\0') {
					if ((buffer[x] == 'V') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
						break;
					}
					x++;
				}
				x = x + 4;
				i = 0;
				while (buffer[x] != '&') {
					tmpbuf[i] = buffer[x];
					i++;
					x++;
				}
				tmpbuf[i] = '\0'; /* indicate end of string */
				usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* USB product ID
				   (extracted from USB device instance for example: USB\VID_04D8&PID_00DF\000098037) */
				x = 6;
				while (buffer[x] != '\0') {
					if ((buffer[x] == 'P') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
						break;
					}
					x++;
				}
				x = x + 4;
				i = 0;
				while (buffer[x] != '\\') {
					tmpbuf[i] = buffer[x];
					i++;
					x++;
				}
				tmpbuf[i] = '\0'; /* indicate end of string */
				usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* SERIAL NUMBER */
				x++;
				i = 0;
				while (buffer[x] != '\0') {
					tmpbuf[i] = buffer[x];
					i++;
					x++;
				}
				tmpbuf[i] = '\0';
				usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* PRODUCT
				   (iProduct field of USB device descriptor) */
				memset(devprop_buffer, '\0', sizeof(devprop_buffer));
				ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_BusReportedDeviceDesc, &proptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size, 0);
				if (ret == FALSE) {
					/* fallback to SPDRP_DEVICEDESC if DEVPKEY_Device_BusReportedDeviceDesc fails */
					ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_DEVICEDESC, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
					if (ret == FALSE) {
						/* if second attempt fails, throw error, we need to investigate drivers/firmware etc */
						return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
				}
				usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
				insert_jstrarraylist(&list, usb_dev_info);

				/* MANUFACTURER */
				memset(devprop_buffer, '\0', sizeof(devprop_buffer));
				ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_Manufacturer, &proptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size, 0);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
				insert_jstrarraylist(&list, usb_dev_info);

				/* LOCATION
				  (Location paths + Location info, get separately and then create a single string) */

				// PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(3)
				memset(devprop_buffer, '\0', sizeof(devprop_buffer));
				ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_PATHS, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				// Port_#0003.Hub_#0001
				memset(charbuffer, '\0', sizeof(charbuffer));
				ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_INFORMATION, &regproptype, (BYTE *)charbuffer, sizeof(charbuffer), &size);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}

				i = 0;
				x = (int)_tcslen(devprop_buffer);
				devprop_buffer[x] = '-';
				x++;
				for (i = 0; i < (int)_tcslen(charbuffer); i++) {
					devprop_buffer[x] = charbuffer[i];
					x++;
				}
				devprop_buffer[x] = '\0';

				usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
				insert_jstrarraylist(&list, usb_dev_info);
			}
		}

		/* check if this usb device has more than one interface. if it has enumerate over each
		   one by one and collecting information for every HID interface found and sending it to 
		   java layer. */
		current_sibling = firstchild;
		while (1) {
			cmret = CM_Get_Sibling(&next_sibling, current_sibling, 0);
			if (cmret != CR_SUCCESS) {
				if (cmret == CR_NO_SUCH_DEVNODE) {
					/* done iterating over all interfaces, move to next examine next USB device */
					break;
				}else {
					_snprintf_s(cmerror, 256, 256, "CM_Get_Sibling failed with CR_xxxx error code : 0x%X\0", cmret);
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
			}

			/* reaching here means USB device has more than 1 interfaces, get class of this interface (sibling) */
			devprop_buffer_size = sizeof(devprop_buffer);
			memset(devprop_buffer, '\0', sizeof(devprop_buffer));
			cmret = CM_Get_DevNode_Registry_Property(next_sibling, CM_DRP_CLASSGUID, &proptype, (VOID *)devprop_buffer, &devprop_buffer_size, 0);
			if (cmret != CR_SUCCESS) {
				_snprintf_s(cmerror, 256, 256, "CM_Get_DevNode_Registry_Property failed with CR_xxxx error code : 0x%X\0", cmret);
				return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}

			/* check if this is a HID device interface */
			ret = _tcsicmp(devprop_buffer, TEXT("{745A17A0-74D3-11D0-B6FE-00A0C90F57DA}"));
			if (ret != 0) {
				/* this is not HID interface, move to check next interface */
				current_sibling = next_sibling;
				continue;
			}

			/* reaching here means that this sibling (interface) is a HID type, get its device instance path */
			memset(devprop_buffer, '\0', 1024);
			cmret = CM_Get_Device_ID(next_sibling, devprop_buffer, 1024, 0);
			if (cmret != CR_SUCCESS) {
				_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID failed with CR_xxxx error code : 0x%X\0", cmret);
				return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}

			/* get the HardwareID of this USB HID interface. HardwareID is multi-sz, however
			   we use only 1st string from multi-string HardwareID for our matching.
			   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_04D8&PID_00DF&MI_02\7&33842C3F&0&0000\HardwareID */
			memset(charbuffer, '\0', 512);
			buffer_size = sizeof(charbuffer);

			cmret = CM_Get_DevNode_Registry_Property(next_sibling, CM_DRP_HARDWAREID, NULL, (PVOID)charbuffer, &buffer_size, 0);
			if (cmret != CR_SUCCESS) {
				_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID failed with CR_xxxx error code : 0x%X\0", cmret);
				return clean_throw_exp_usbenumeration(env, 3, 1, 0, cmerror, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
			}

			if ((charbuffer[0] == 'U') && (charbuffer[1] == 'S') && (charbuffer[2] == 'B')) {
				charbuffer[0] = 'H';
				charbuffer[1] = 'I';
				charbuffer[2] = 'D';
			}

			for (q = 0; q < hiddevinst_list.index; q++) {

				/* check association between HID collection device instance and USB interface device instance */
				ret = _tcsncicmp(charbuffer, hiddevinst_list.base[q]->hwid, 512);
				if (ret != 0) {
					continue;
				}

				/* reaching here means this HID collection belongs to this USB HID interface, so glean information
				   to be passed to java layer. */

				/* TRANSPORT */
				usb_dev_info = (*env)->NewStringUTF(env, "USB");
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* DEVICE NODE */
				usb_dev_info = (*env)->NewString(env, hiddevinst_list.base[q]->instance, (jsize)_tcslen(hiddevinst_list.base[q]->instance));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* USB-IF VENDOR ID
				   (extracted from USB device instance for example: USB\VID_04D8&PID_00DF\000098037) */
				x = 0;
				while (buffer[x] != '\0') {
					if ((buffer[x] == 'V') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
						break;
					}
					x++;
				}
				x = x + 4;
				i = 0;
				while (buffer[x] != '&') {
					tmpbuf[i] = buffer[x];
					i++;
					x++;
				}
				tmpbuf[i] = '\0'; /* indicate end of string */
				usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* USB product ID
				   (extracted from USB device instance for example: USB\VID_04D8&PID_00DF\000098037) */
				x = 6;
				while (buffer[x] != '\0') {
					if ((buffer[x] == 'P') && (buffer[x + 1] == 'I') && (buffer[x + 2] == 'D') && (buffer[x + 3] == '_')) {
						break;
					}
					x++;
				}
				x = x + 4;
				i = 0;
				while (buffer[x] != '\\') {
					tmpbuf[i] = buffer[x];
					i++;
					x++;
				}
				tmpbuf[i] = '\0'; /* indicate end of string */
				usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* SERIAL NUMBER */
				x++;
				i = 0;
				while (buffer[x] != '\0') {
					tmpbuf[i] = buffer[x];
					i++;
					x++;
				}
				tmpbuf[i] = '\0';
				usb_dev_info = (*env)->NewString(env, tmpbuf, (jsize)_tcslen(tmpbuf));
				if ((usb_dev_info == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWSTRUTFSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				insert_jstrarraylist(&list, usb_dev_info);

				/* PRODUCT
				   (iProduct field of USB device descriptor) */
				memset(devprop_buffer, '\0', sizeof(devprop_buffer));
				ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_BusReportedDeviceDesc, &proptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size, 0);
				if (ret == FALSE) {
					/* fallback to SPDRP_DEVICEDESC if DEVPKEY_Device_BusReportedDeviceDesc fails */
					ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_DEVICEDESC, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
					if (ret == FALSE) {
						/* if second attempt fails, throw error, we need to investigate drivers/firmware etc */
						return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
					}
					usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
					insert_jstrarraylist(&list, usb_dev_info);
				}else {
					usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
					insert_jstrarraylist(&list, usb_dev_info);
				}

				/* MANUFACTURER */
				memset(devprop_buffer, '\0', sizeof(devprop_buffer));
				ret = SetupDiGetDeviceProperty(usb_dev_info_set, &usb_dev_instance, &DEVPKEY_Device_Manufacturer, &proptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size, 0);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
				insert_jstrarraylist(&list, usb_dev_info);

				/* LOCATION
				   (Location paths + Location info, get separately and then create a single string) */

				// PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(3)
				memset(devprop_buffer, '\0', sizeof(devprop_buffer));
				ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_PATHS, &regproptype, (BYTE *)devprop_buffer, sizeof(devprop_buffer), &size);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}
				// Port_#0003.Hub_#0001
				memset(charbuffer, '\0', sizeof(charbuffer));
				ret = SetupDiGetDeviceRegistryProperty(usb_dev_info_set, &usb_dev_instance, SPDRP_LOCATION_INFORMATION, &regproptype, (BYTE *)charbuffer, sizeof(charbuffer), &size);
				if (ret == FALSE) {
					return clean_throw_exp_usbenumeration(env, 3, 2, HRESULT_FROM_SETUPAPI(GetLastError()), NULL, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
				}

				i = 0;
				x = (int)_tcslen(devprop_buffer);
				devprop_buffer[x] = '-';
				x++;
				for (i = 0; i < (int)_tcslen(charbuffer); i++) {
					devprop_buffer[x] = charbuffer[i];
					x++;
				}
				devprop_buffer[x] = '\0';

				usb_dev_info = (*env)->NewString(env, devprop_buffer, (jsize)_tcslen(devprop_buffer));
				insert_jstrarraylist(&list, usb_dev_info);
			}

			/* set this sibling as base sibling for fetching next sibling, loop over to get and check next
			   interface (sibling) */
			current_sibling = next_sibling;
		}

		/* increment to get and examine the next usb device for HID class */
		usb_member_index++;
	}

	strClass = (*env)->FindClass(env, JAVALSTRING);
	if ((strClass == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_FINDCLASSSSTRINGSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
	}

	usbHidDevicesFound = (*env)->NewObjectArray(env, (jsize)list.index, strClass, NULL);
	if ((usbHidDevicesFound == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_NEWOBJECTARRAYSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
	}

	for (x = 0; x < list.index; x++) {
		(*env)->SetObjectArrayElement(env, usbHidDevicesFound, x, list.base[x]);
		if ((*env)->ExceptionOccurred(env)) {
			return clean_throw_exp_usbenumeration(env, 3, 1, 0, E_SETOBJECTARRAYSTR, &list, &hiddevinst_list, &usb_dev_info_set, NULL);
		}
	}

	/* clean up and return result to java layer application */
	free_jstrarraylist(&list);
	free_hiddev_instance_list(&hiddevinst_list);
	SetupDiDestroyDeviceInfoList(usb_dev_info_set);
	return usbHidDevicesFound;
}
示例#8
0
void NiashLibUsbInit(TFnReportDevice* const pfnReportDevice)
{
	class HDEVINFODeleter //RAII wrapper
	{
	public:
		typedef HDEVINFO pointer;
		void operator()(HDEVINFO h) {::SetupDiDestroyDeviceInfoList(h);}
	};

	//Get device
	std::unique_ptr<HDEVINFO, HDEVINFODeleter> hDevInfo(SetupDiGetClassDevs(&s_NiashInterfaceClassGUID, NULL, NULL, DIGCF_PRESENT|DIGCF_PROFILE|DIGCF_DEVICEINTERFACE));
	if(hDevInfo.get() == INVALID_HANDLE_VALUE)
	{
		wprintf_s(L"SetupDiGetClassDevs: %s\n", _com_error(GetLastError()).ErrorMessage());
		return;
	}
	
	//Get device info for the devices
	SP_DEVINFO_DATA DeviceInfoData;
	DeviceInfoData.cbSize = sizeof(DeviceInfoData);
	SetupDiEnumDeviceInfo(hDevInfo.get(),0,&DeviceInfoData);
	if(GetLastError()==ERROR_NO_MORE_ITEMS)
	{
		puts("No devices with the driver installed found.");
	}
	else
	{
		wprintf_s(L"SetupDiEnumDeviceInfo: %s\n", _com_error(GetLastError()).ErrorMessage());
	}

	//Get the first matching device interface of that device
	SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
	DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);	
	if(!SetupDiEnumDeviceInterfaces(hDevInfo.get(), &DeviceInfoData, &s_NiashInterfaceClassGUID, 0, &DeviceInterfaceData))
	{
		wprintf_s(L"SetupDiEnumDeviceInterfaces: %s\n", _com_error(GetLastError()).ErrorMessage());
		return;
	}

	//Get size of detailed device interface data
	DWORD dwRequiredSize;
	if(!SetupDiGetDeviceInterfaceDetail(hDevInfo.get(), &DeviceInterfaceData, nullptr, 0, &dwRequiredSize, nullptr) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
	{
		wprintf_s(L"SetupDiGetDeviceInterfaceDetail: %s\n", _com_error(GetLastError()).ErrorMessage());
		return;
	}

	//SP_DEVICE_INTERFACE_DETAIL_DATA's actual size isn't declared
	std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA_A> pInterfaceDetailData(reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_A*>(new BYTE[dwRequiredSize]));
	pInterfaceDetailData->cbSize = sizeof(*pInterfaceDetailData);
	if(!SetupDiGetDeviceInterfaceDetailA(hDevInfo.get(), &DeviceInterfaceData, pInterfaceDetailData.get(), dwRequiredSize, nullptr, nullptr))
	{
		wprintf_s(L"SetupDiGetDeviceInterfaceDetail: %s\n", _com_error(GetLastError()).ErrorMessage());
		return;
	}

	//Get name size
	ULONG ulPropType = DEVPROP_TYPE_STRING;
	if(!SetupDiGetDeviceProperty(hDevInfo.get(), &DeviceInfoData, &DEVPKEY_NAME, &ulPropType, nullptr, 0, &dwRequiredSize, 0) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
	{
		wprintf_s(L"SetupDiGetDeviceProperty: %s\n", _com_error(GetLastError()).ErrorMessage());
		return;
	}

	//Get device name
	std::vector<TCHAR> Buf(dwRequiredSize);
	if(!SetupDiGetDeviceProperty(hDevInfo.get(), &DeviceInfoData, &DEVPKEY_NAME, &ulPropType, reinterpret_cast<PBYTE>(Buf.data()), dwRequiredSize, 0, 0))
	{
		wprintf_s(L"SetupDiGetDeviceProperty: %s\n", _com_error(GetLastError()).ErrorMessage());
		return;
	}
	wprintf_s(L"Found device: %s ", Buf.data());
	printf_s("%s\n", pInterfaceDetailData->DevicePath);

	//Let driver recognize the device so it knows what parameters to use
	int vid = 0;
	int pid = 0;
	if(sscanf_s(pInterfaceDetailData->DevicePath,"\\\\?\\usb#vid_%x&pid_%x#", &vid, &pid) == 2 && MatchUsbDevice(vid,pid,&s_pScannerModel))
	{
		pfnReportDevice(s_pScannerModel, pInterfaceDetailData->DevicePath);
	}
}