Esempio n. 1
0
UINT
pxDiMsiInstallNetworkComponent(
	__in MSIHANDLE hInstall, 
	__in const XDIMSI_PROCESS_RECORD* ProcessRecord)
{
	//
	// InfPath: <inf-path>   e.g. c:\program files\ndas\drivers\netlpx.inf
	// Param: <component-id> e.g. nkc_lpx
	//

	HRESULT hr;
	GUID classGuid;
	WCHAR className[MAX_CLASS_NAME_LEN];

	BOOL success = SetupDiGetINFClassW(
		ProcessRecord->InfPath,
		&classGuid,
		className,
		MAX_CLASS_NAME_LEN,
		NULL);

	if (!success)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		//
		// Invalid Class GUID in the inf file
		//
		pxMsiTraceW(hInstall, L"SetupDiGetINFClass failed, hr=0x%x\n", hr);
		return ERROR_INSTALL_FAILURE;
	}

	//
	// Pre-install the OEM INF file to trigger the installation of
	// the component by the component id later (xDiInstallNetComponent)
	//

	WCHAR oemInfPath[MAX_PATH];
	DWORD oemInfPathLength;
	LPWSTR oemInfName;

	XDIMSI_DIALOG_ACTIVATOR_CONTEXT daContext;

	pxDiMsiDialogActivatorStart(&daContext);

	success = SetupCopyOEMInfW(
		ProcessRecord->InfPath,
		NULL,
		SPOST_PATH,
		0,
		oemInfPath,
		RTL_NUMBER_OF(oemInfPath),
		NULL,
		NULL);

	pxDiMsiDialogActivatorStop(&daContext);

	if (!success)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		pxMsiTraceW(hInstall, L"SetupCopyOEMInf failed, hr=0x%x\n", hr);
		return ERROR_INSTALL_FAILURE;
	}

	hr = pxDiMsiSetInfPathInRegistry(
		hInstall, 
		oemInfPath, 
		ProcessRecord->RegRoot, 
		ProcessRecord->RegKey, 
		ProcessRecord->RegName);

	if (FAILED(hr))
	{
		pxMsiTraceW(hInstall, L"pxMsiSetInfPathInRegistry failed, hr=0x%x\n", hr);
	}

	while (TRUE)
	{
		pxDiMsiDialogActivatorStart(&daContext);

		hr = xDiInstallNetComponent(
			&classGuid,
			ProcessRecord->HardwareId, 
			15*1000,
			L"Windows Installer", 
			NULL);

		pxDiMsiDialogActivatorStop(&daContext);

		if (FAILED(hr))
		{
			pxMsiTraceW(hInstall, L"InstallNetComponent failed, hr=0x%x\n", hr);

			// 0, IDABORT, IDRETRY, IDIGNORE
			UINT response = pxMsiErrorMessageBox(hInstall, ProcessRecord->ErrorNumber, hr);
			switch (response)
			{
			case IDRETRY:
				continue;
			case IDIGNORE:
				break;
			case 0:
			case IDABORT:
			default:
				return ERROR_INSTALL_FAILURE;
			}
		}

		break;
	}

	//
	// The followings actions are not critical ones
	// Just log errors if any and return ERROR_SUCCESS
	//

	if (XDI_S_REBOOT == hr) 
	{
		pxMsiQueueScheduleReboot(hInstall);
	}

	return ERROR_SUCCESS;
}
Esempio n. 2
0
UINT
pxDiMsiInstallPnpDeviceInf(
	__in MSIHANDLE hInstall, 
	__in const XDIMSI_PROCESS_RECORD* ProcessRecord)
{
	WCHAR oemInfPath[MAX_PATH];
	DWORD oemInfPathLength = 0;
	LPWSTR oemInfName = NULL;
	
	HRESULT hr;

	while (TRUE)
	{
		XDIMSI_DIALOG_ACTIVATOR_CONTEXT daContext;

		pxDiMsiDialogActivatorStart(&daContext);

		BOOL success = SetupCopyOEMInfW(
			ProcessRecord->InfPath,
			NULL,
			SPOST_PATH,
			0,
			oemInfPath,
			RTL_NUMBER_OF(oemInfPath),
			&oemInfPathLength,
			&oemInfName);

		pxDiMsiDialogActivatorStop(&daContext);

		if (!success)
		{
			hr = HRESULT_FROM_SETUPAPI(GetLastError());
			
			pxMsiTraceW(hInstall, L"SetupCopyOEMInf(%s) failed, hr=0x%x\n", 
				ProcessRecord->InfPath, hr);

			// 0, IDABORT, IDRETRY, IDIGNORE
			UINT response = pxMsiErrorMessageBox(hInstall, ProcessRecord->ErrorNumber, hr);
			switch (response)
			{
			case IDRETRY:
				continue;
			case IDIGNORE:
				break;
			case 0:
			case IDABORT:
			default:
				return ERROR_INSTALL_FAILURE;
			}
		}
		else
		{
			pxMsiTraceW(hInstall, L"Copied %s to %s\n", ProcessRecord->InfPath, oemInfPath);

			hr = pxDiMsiSetInfPathInRegistry(
				hInstall, 
				oemInfPath, 
				ProcessRecord->RegRoot, 
				ProcessRecord->RegKey, 
				ProcessRecord->RegName);

			if (FAILED(hr))
			{
				pxMsiTraceW(hInstall, L"pxMsiSetInfPathInRegistry failed, hr=0x%x\n", hr);
			}
		}
		break;
	}

	return ERROR_SUCCESS;
}
Esempio n. 3
0
HRESULT
xDiEnumDriverFiles(
	__in_opt HWND Owner,
	__in LPCWSTR OemInfFullPath,
	__in DWORD Flags,
	__in XDI_ENUM_DRIVER_FILE_CALLBACK EnumCallback,
	__in LPVOID EnumContext)
{
	HRESULT hr;
	BOOL success;

	WCHAR infFullPath[MAX_PATH];

	DWORD n = GetFullPathNameW(OemInfFullPath, MAX_PATH, infFullPath, NULL);
	if (0 == n)
	{
		hr = HRESULT_FROM_WIN32(GetLastError());
		hr = (SUCCEEDED(hr)) ? E_FAIL : hr;
		goto error0;
	}

	HDEVINFO devInfoSet = SetupDiCreateDeviceInfoList(NULL, Owner);
	if (INVALID_HANDLE_VALUE == devInfoSet)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		goto error0;
	}

	SP_DEVINFO_DATA devInfoData = { sizeof(SP_DEVINFO_DATA) };

	success = SetupDiCreateDeviceInfoW(
		devInfoSet,
		L"XDI_Temporary_Enumerator",
		&GUID_NULL,
		NULL,
		NULL,
		DICD_GENERATE_ID,
		&devInfoData);

	if (!success)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		goto error1;
	}

	HSPFILEQ fileQueueHandle = SetupOpenFileQueue();

	if (INVALID_HANDLE_VALUE == fileQueueHandle)
	{
		// Error from SetupOpenFileQueue is only from out-of-memory situation
		// without the last error set
		hr = E_OUTOFMEMORY;
		goto error2;
	}

	SP_DEVINSTALL_PARAMS devInstallParams = {sizeof(SP_DEVINSTALL_PARAMS)};

	success = SetupDiGetDeviceInstallParamsW(
		devInfoSet,
		&devInfoData,
		&devInstallParams);

	if (!success)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		goto error3;
	}

	//
	// Specify the search path
	//

	hr = StringCchCopyW(
		devInstallParams.DriverPath,
		MAX_PATH,
		infFullPath);

	if (FAILED(hr))
	{
		goto error3;
	}

	devInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
	devInstallParams.FileQueue = fileQueueHandle;
	devInstallParams.Flags |= DI_NOVCP;
	devInstallParams.Flags |= DI_ENUMSINGLEINF;

	success = SetupDiSetDeviceInstallParamsW(
		devInfoSet,
		&devInfoData,
		&devInstallParams);

	if (!success)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		goto error3;
	}

	//
	// use DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE if possible 
	// to ensure we look at duplicate nodes (which is broken in itself)
	//
#ifndef DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE
#define DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE  0x08000000L  // Don't remove identical driver nodes from the class list
#endif

	if (xDipWindowsXPOrLater())
	{
		devInstallParams.FlagsEx |= DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE;

		success = SetupDiSetDeviceInstallParamsW(
			devInfoSet,
			&devInfoData,
			&devInstallParams);

		if (!success)
		{
			devInstallParams.FlagsEx &= ~DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE;
		}
	}

	//
	// Build a class driver list with every driver
	//

	success = SetupDiBuildDriverInfoList(
		devInfoSet,
		&devInfoData,
		SPDIT_CLASSDRIVER);

	if (!success)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		goto error3;
	}

	SP_DRVINFO_DATA drvInfoData = { sizeof(SP_DRVINFO_DATA) };

	for (DWORD index = 0; ; ++index)
	{
		success = SetupDiEnumDriverInfoW(
			devInfoSet, 
			&devInfoData, 
			SPDIT_CLASSDRIVER, 
			index, 
			&drvInfoData);

		if (!success)
		{
			break;
		}

		SP_DRVINFO_DETAIL_DATA drvInfoDetail = { sizeof(SP_DRVINFO_DETAIL_DATA) };

		success = SetupDiGetDriverInfoDetailW(
			devInfoSet, 
			&devInfoData,
			&drvInfoData,
			&drvInfoDetail,
			sizeof(SP_DRVINFO_DETAIL_DATA),
			NULL);

		if (!success && ERROR_INSUFFICIENT_BUFFER != GetLastError())
		{
			hr = HRESULT_FROM_SETUPAPI(GetLastError());
			goto error4;
		}

		success = SetupDiSetSelectedDriverW(
			devInfoSet,
			&devInfoData,
			&drvInfoData);

		if (!success)
		{
			hr = HRESULT_FROM_SETUPAPI(GetLastError());
			goto error4;
		}

		if (Flags & XDI_EDF_NO_CLASS_INSTALLER)
		{
			success = SetupDiInstallDriverFiles(
				devInfoSet, &devInfoData);

			if (!success)
			{
				hr = HRESULT_FROM_SETUPAPI(GetLastError());
				goto error4;
			}
		}
		else
		{
			success = SetupDiCallClassInstaller(
				DIF_INSTALLDEVICEFILES, devInfoSet, &devInfoData);

			if (!success)
			{
				hr = HRESULT_FROM_SETUPAPI(GetLastError());
				goto error4;
			}
		}
	}

	//
	// SPQ_SCAN_USE_CALLBACK_EX checks the digital signature of the file
	// We do not want to check the signature here.
	//
	// SPQ_SCAN_FILE_PRESENCE avoids checking the digital signature of the file
	// in Windows XP or later. (Not in Windows 2000) when used 
	// with SPQ_SCAN_USE_CALLBACK_EX
	//

	XDI_ENUM_FQS_CONTEXT fqsContext = {0};
	fqsContext.Callback = EnumCallback;
	fqsContext.CallbackContext = EnumContext;

	DWORD scanResult;
	success = SetupScanFileQueueW(
		fileQueueHandle, 
		SPQ_SCAN_USE_CALLBACK,
		// SPQ_SCAN_USE_CALLBACKEX | SPQ_SCAN_FILE_PRESENCE,
		Owner,
		xDipEnumFileQueueScanCallback,
		&fqsContext,
		&scanResult);

	if (!success)
	{
		//
		// SetupScanFileQueue may fail using SPQ_SCAN_FILE_PRESENSE flag
		// Try again without SPQ_SCAN_FILE_PRESENSE
		// (when using SPQ_SCAN_USE_CALLBACKEX)
		//
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		goto error4;
	}

	hr = S_OK;

#pragma warning(disable: 4533) // to use goto in cpp

error4:

	SetupDiDestroyDriverInfoList(
		devInfoSet, &devInfoData, SPDIT_CLASSDRIVER);

error3:

	SetupCloseFileQueue(fileQueueHandle);

error2:

	SetupDiDeleteDeviceInfo(devInfoSet, &devInfoData);

error1:

	SetupDiDestroyDeviceInfoList(devInfoSet);

error0:

#pragma warning(default: 4533)

	return hr;
}
Esempio n. 4
0
UINT
pxDiMsiInstallLegacyPnpDevice(
	__in MSIHANDLE hInstall, 
	__in const XDIMSI_PROCESS_RECORD* ProcessRecord)
{
	BOOL success = FALSE;
	BOOL reboot = FALSE;

	HRESULT hr;

	while (TRUE) 
	{
		WCHAR oemInfPath[MAX_PATH];
		DWORD oemInfPathLength = 0;
		LPWSTR oemInfName = NULL;

		XDIMSI_DIALOG_ACTIVATOR_CONTEXT daContext;

		pxDiMsiDialogActivatorStart(&daContext);

		success = SetupCopyOEMInfW(
			ProcessRecord->InfPath,
			NULL,
			SPOST_PATH,
			0,
			oemInfPath,
			RTL_NUMBER_OF(oemInfPath),
			&oemInfPathLength,
			&oemInfName);

		pxDiMsiDialogActivatorStop(&daContext);

		if (!success)
		{
			hr = HRESULT_FROM_SETUPAPI(GetLastError());
			pxMsiTraceW(hInstall, L"SetupCopyOEMInf(%s) failed, hr=0x%x\n", hr);
		}
		else
		{
			pxMsiTraceW(hInstall, L"hardwareId=%ls, oemInfPath=%ls\n", 
				ProcessRecord->HardwareId, oemInfPath);

			hr = pxDiMsiSetInfPathInRegistry(
				hInstall, 
				oemInfPath, 
				ProcessRecord->RegRoot, 
				ProcessRecord->RegKey, 
				ProcessRecord->RegName);

			if (FAILED(hr))
			{
				pxMsiTraceW(hInstall, L"pxMsiSetInfPathInRegistry failed, hr=0x%x\n", hr);
			}

			//
			// Specifying INSTALLFLAG_FORCE will overwrite the
			// existing device driver with the current one
			// irrespective of existence of higher version
			//
			pxDiMsiDialogActivatorStart(&daContext);

			hr = xDiInstallLegacyPnpDevice(
				NULL,
				ProcessRecord->HardwareId,
				ProcessRecord->InfPath,
				NULL,
				INSTALLFLAG_FORCE);

			pxDiMsiDialogActivatorStop(&daContext);

			if (FAILED(hr))
			{
				pxMsiTraceW(hInstall, L"xDiInstallLegacyPnpDevice failed, hr=0x%x\n", hr);
			}
		}

		if (FAILED(hr)) 
		{
			UINT response = pxMsiErrorMessageBox(hInstall, ProcessRecord->ErrorNumber, hr);
			switch (response)
			{
			case IDRETRY:
				continue;
			case IDIGNORE:
				break;
			case 0:
			case IDABORT:
			default:
				return ERROR_INSTALL_FAILURE;
			}
		}

		break;
	}

	return ERROR_SUCCESS;
}
Esempio n. 5
0
HRESULT
pGetNdasPortHandle(__out HANDLE* NdasportHandle)
{
    HRESULT hr;

    *NdasportHandle = INVALID_HANDLE_VALUE;

    HDEVINFO devInfoSet = SetupDiGetClassDevs(
                              &GUID_DEVINTERFACE_NDASPORT,
                              NULL,
                              NULL,
                              DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

    if (INVALID_HANDLE_VALUE == devInfoSet)
    {
        hr = HRESULT_FROM_SETUPAPI(GetLastError());
        fprintf(stderr, "SetupDiGetClassDevs failed, hr=0x%X\n", hr);
        return hr;
    }

    SP_DEVICE_INTERFACE_DATA devIntfData;
    devIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    BOOL success = SetupDiEnumDeviceInterfaces(
                       devInfoSet,
                       NULL,
                       &GUID_DEVINTERFACE_NDASPORT,
                       0,
                       &devIntfData);

    if (!success)
    {
        hr = HRESULT_FROM_SETUPAPI(GetLastError());
        fprintf(stderr, "SetupDiEnumDeviceInterfaces failed, hr=0x%X\n", hr);
        SetupDiDestroyDeviceInfoList(devInfoSet);
        return hr;
    }

    DWORD devIntfDetailSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) +
                              sizeof(TCHAR) * MAX_PATH;

    PSP_DEVICE_INTERFACE_DETAIL_DATA devIntfDetail =
        static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(devIntfDetailSize));

    if (NULL == devIntfDetail)
    {
        hr = E_OUTOFMEMORY;
        fprintf(stderr, "Memory allocation failed, size=0x%X\n", devIntfDetailSize);
        SetupDiDestroyDeviceInfoList(devInfoSet);
        return hr;
    }

    devIntfDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    success = SetupDiGetDeviceInterfaceDetail(
                  devInfoSet,
                  &devIntfData,
                  devIntfDetail,
                  devIntfDetailSize,
                  &devIntfDetailSize,
                  NULL);

    if (!success)
    {
        if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
        {
            hr = HRESULT_FROM_SETUPAPI(GetLastError());
            fprintf(stderr, "SetupDiGetDeviceInterfaceDetail failed, hr=0x%X\n", hr);
            free(devIntfDetail);
            SetupDiDestroyDeviceInfoList(devInfoSet);
            return hr;
        }

        PVOID p = realloc(devIntfDetail, devIntfDetailSize);

        if (NULL == p)
        {
            hr = E_OUTOFMEMORY;
            fprintf(stderr, "Memory allocation failed, size=0x%X\n", devIntfDetailSize);
            free(devIntfDetail);
            SetupDiDestroyDeviceInfoList(devInfoSet);
            return hr;
        }

        devIntfDetail = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(p);

        success = SetupDiGetDeviceInterfaceDetail(
                      devInfoSet,
                      &devIntfData,
                      devIntfDetail,
                      devIntfDetailSize,
                      &devIntfDetailSize,
                      NULL);
    }

    if (!success)
    {
        hr = HRESULT_FROM_SETUPAPI(GetLastError());
        fprintf(stderr, "SetupDiGetDeviceInterfaceDetail2 failed, hr=0x%X\n", hr);
        free(devIntfDetail);
        SetupDiDestroyDeviceInfoList(devInfoSet);
        return hr;
    }

    printf("ndasport: %s\n", devIntfDetail->DevicePath);

    HANDLE h = CreateFile(
                   devIntfDetail->DevicePath,
                   GENERIC_READ,
                   FILE_SHARE_READ | FILE_SHARE_WRITE,
                   NULL,
                   OPEN_EXISTING,
                   FILE_ATTRIBUTE_DEVICE,
                   NULL);

    free(devIntfDetail);
    SetupDiDestroyDeviceInfoList(devInfoSet);

    if (INVALID_HANDLE_VALUE == h)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        fprintf(stderr, "CreateFile(%s) failed, hr=0x%X\n", hr);
        return hr;
    }

    *NdasportHandle = h;
    return S_OK;
}
/*
 * Get the current latency timer value for ftdi devices.
 * return value read on success or -1 if any error occurs.
 */
jint get_latency_timer_value(JNIEnv *env, jstring comPortName) {

	const jchar* port_name = NULL;
	int x = 0;
	BOOL ret = FALSE;
	LONG status = 0;
	DWORD error_code = 0;
	DWORD size = 0;
	DWORD regproptype;
	DWORD charbuffer_size = 0;
	DWORD driver_name_size = 0;
	ULONG buffer_size = 0;
	DWORD usb_member_index = 0;
	HDEVINFO usb_dev_info_set;
	SP_DEVINFO_DATA usb_dev_instance;
	ULONG devprop_buffer_size = 0;
	DEVPROPTYPE proptype;
	CONFIGRET cmret = 0;
	DEVINST firstchild = 0;
	DEVINST next_sibling = 0;
	DEVINST current_sibling = 0;
	DWORD timer_value;
	DWORD timervalue_size;

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

	/* extract com port name to match (as an array of Unicode characters) */
	port_name = (*env)->GetStringChars(env, comPortName, JNI_FALSE);
	if ((port_name == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		throw_serialcom_exception(env, 3, 0, E_GETSTRUTFCHARSTR);
		return -1;
	}

	/* 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);
		(*env)->ReleaseStringChars(env, comPortName, port_name);
		throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
		return -1;
	}

	/* 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);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(error_code), NULL);
				return -1;
			}
		}

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

		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 device itself is a "Ports" 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) {
					SetupDiDestroyDeviceInfoList(usb_dev_info_set);
					(*env)->ReleaseStringChars(env, comPortName, port_name);
					throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
					return -1;
				}

				/* match GUID */
				ret = _tcsicmp(devprop_buffer, TEXT("{4D36E978-E325-11CE-BFC1-08002BE10318}"));
				if (ret != 0) {
					usb_member_index++;
					continue;
				}

				/* reaching here means that the device is COM port device (CDC/ACM), get its COM port name/number
				 * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_VID+PID_PID+Serial_Number\0000\DeviceParameters\PortName
				 * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_VID+PID_PID\Serial_Number\DeviceParameters\PortName */
				memset(keybuf, '\0', 1024);
				_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s\\Device Parameters"), buffer);

				charbuffer_size = sizeof(charbuffer);
				memset(charbuffer, '\0', 128);
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("PortName"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
				if (status != ERROR_SUCCESS) {
					SetupDiDestroyDeviceInfoList(usb_dev_info_set);
					(*env)->ReleaseStringChars(env, comPortName, port_name);
					throw_serialcom_exception(env, 4, GetLastError(), NULL);
					return -1;
				}

				/* match port name */
				ret = _tcsicmp(charbuffer, port_name);
				if (ret != 0) {
					usb_member_index++;
					continue;
				}

				/* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_VID+PID_PID+Serial_Number\0000\DeviceParameters\LatencyTimer */
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("LatencyTimer"), RRF_RT_REG_DWORD, NULL, &timer_value, &timervalue_size);
				if (status != ERROR_SUCCESS) {
					SetupDiDestroyDeviceInfoList(usb_dev_info_set);
					(*env)->ReleaseStringChars(env, comPortName, port_name);
					throw_serialcom_exception(env, 4, status, NULL);
					return -1;
				}

				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				return (jint)timer_value;
			}else {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				_snprintf_s(cmerror, 256, 256, "CM_Get_DevNode_Registry_Property CR_xxxx error code : 0x%X\0", cmret);
				throw_serialcom_exception(env, 3, 0, cmerror);
				return -1;
			}
		}

		/* reaching here means that this USB device has at-least one child device node, examine child now */

		devprop_buffer_size = sizeof(devprop_buffer);
		memset(devprop_buffer, '\0', sizeof(devprop_buffer));
		cmret = CM_Get_DevNode_Registry_Property(firstchild, CM_DRP_CLASSGUID, &proptype, (PVOID)devprop_buffer, &devprop_buffer_size, 0);
		if (cmret != CR_SUCCESS) {
			SetupDiDestroyDeviceInfoList(usb_dev_info_set);
			(*env)->ReleaseStringChars(env, comPortName, port_name);
			_snprintf_s(cmerror, 256, 256, "CM_Get_DevNode_Registry_Property CR_xxxx error code : 0x%X\0", cmret);
			throw_serialcom_exception(env, 3, 0, cmerror);
			return -1;
		}

		/* match GUID */
		ret = _tcsicmp(devprop_buffer, TEXT("{4D36E978-E325-11CE-BFC1-08002BE10318}"));
		if (ret == 0) {
			/* reaching here means that the child device is COM port device (CDC/ACM), get its COM port name/number */
			memset(buffer, '\0', 1024);
			cmret = CM_Get_Device_ID(firstchild, buffer, 1024, 0);
			if (cmret != CR_SUCCESS) {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID CR_xxxx error code : 0x%X\0", cmret);
				throw_serialcom_exception(env, 3, 0, cmerror);
				return -1;
			}

			memset(keybuf, '\0', 1024);
			_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s\\Device Parameters"), buffer);

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

			status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("PortName"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
			if (status != ERROR_SUCCESS) {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				throw_serialcom_exception(env, 4, GetLastError(), NULL);
				return -1;
			}

			/* match port name */
			ret = _tcsicmp(charbuffer, port_name);
			if (ret == 0) {
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("LatencyTimer"), RRF_RT_REG_DWORD, NULL, &timer_value, &timervalue_size);
				if (status != ERROR_SUCCESS) {
					SetupDiDestroyDeviceInfoList(usb_dev_info_set);
					(*env)->ReleaseStringChars(env, comPortName, port_name);
					throw_serialcom_exception(env, 4, GetLastError(), NULL);
					return -1;
				}

				/* clean up and return timer value found */
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				return (jint)timer_value;
			}
		}

		/* reaching here means first child of this USB device was not CDC/ACM interface, need to
		   iterate over all the interfaces (siblings) this device has examining them for matching our criteria */
		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 {
					SetupDiDestroyDeviceInfoList(usb_dev_info_set);
					_snprintf_s(cmerror, 256, 256, "CM_Get_Sibling failed with CR_xxxx error code : 0x%X\0", cmret);
					(*env)->ReleaseStringChars(env, comPortName, port_name);
					throw_serialcom_exception(env, 3, 0, cmerror);
					return -1;
				}

			}

			/* 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) {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				_snprintf_s(cmerror, 256, 256, "CM_Get_DevNode_Registry_Property failed with CR_xxxx error code : 0x%X\0", cmret);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				throw_serialcom_exception(env, 3, 0, cmerror);
				return -1;
			}

			/* match GUID for this sibling */
			ret = _tcsicmp(devprop_buffer, TEXT("{4D36E978-E325-11CE-BFC1-08002BE10318}"));
			if (ret != 0) {
				/* this interface is not CDC/ACM, loop over to next interface */
				current_sibling = next_sibling;
				continue;
			}

			/* reaching here means that this sibling (interface) is a CDC/ACM type, get its COM port name/number */
			buffer_size = (ULONG)_tcslen(buffer);
			memset(buffer, '\0', 1024);
			cmret = CM_Get_Device_ID(next_sibling, buffer, 1024, 0);
			if (cmret != CR_SUCCESS) {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID failed with CR_xxxx error code : 0x%X\0", cmret);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				throw_serialcom_exception(env, 3, 0, cmerror);
				return -1;
			}

			memset(keybuf, '\0', 1024);
			_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s\\Device Parameters"), buffer);

			charbuffer_size = sizeof(charbuffer);
			memset(charbuffer, '\0', 128);
			status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("PortName"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
			if (status != ERROR_SUCCESS) {
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				throw_serialcom_exception(env, 4, GetLastError(), NULL);
				return -1;
			}

			/* match port name */
			ret = _tcsicmp(charbuffer, port_name);
			if (ret == 0) {
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("LatencyTimer"), RRF_RT_REG_DWORD, NULL, &timer_value, &timervalue_size);
				if (status != ERROR_SUCCESS) {
					SetupDiDestroyDeviceInfoList(usb_dev_info_set);
					(*env)->ReleaseStringChars(env, comPortName, port_name);
					throw_serialcom_exception(env, 4, GetLastError(), NULL);
					return -1;
				}

				/* clean up and return timer value found */
				SetupDiDestroyDeviceInfoList(usb_dev_info_set);
				(*env)->ReleaseStringChars(env, comPortName, port_name);
				return (jint)timer_value;
			}

			/* 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 COM ports class */
		usb_member_index++;
	}

	/* reaching here means that probably given com port does not represent ftdi device or does not exist at all */
	SetupDiDestroyDeviceInfoList(usb_dev_info_set);
	(*env)->ReleaseStringChars(env, comPortName, port_name);
	throw_serialcom_exception(env, 3, 0, E_NOTFTDIPORT);
	return -1;
}
Esempio n. 7
0
HRESULT
pEnumerateNdasportLogicalUnits(
    __inout CSimpleArray<HDEVNOTIFY>& DevNotifyHandles,
    __in HWND hWnd,
    __in HDEVINFO DevInfoSet,
    __in LPCGUID InterfaceGuid)
{
    HRESULT hr;
    BOOL success;
    DWORD index = 0;
    SP_DEVICE_INTERFACE_DATA devIntfData;

    DWORD devIntfDetailSize =
        offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) +
        sizeof(TCHAR) * MAX_PATH;

    PSP_DEVICE_INTERFACE_DETAIL_DATA devIntfDetail =
        static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(devIntfDetailSize));

    if (NULL == devIntfDetail)
    {
        hr = E_OUTOFMEMORY;
        fprintf(stderr, "Memory allocation failed, size=0x%X\n", devIntfDetailSize);
        return hr;
    }

    for (DWORD index = 0; ; ++index)
    {
        devIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

        success = SetupDiEnumDeviceInterfaces(
                      DevInfoSet,
                      NULL,
                      InterfaceGuid,
                      index,
                      &devIntfData);

        if (!success)
        {
            if (ERROR_NO_MORE_ITEMS == GetLastError())
            {
                if (0 == index) fprintf(stderr, "No devices\n");
                hr = S_OK;
            }
            else
            {
                hr = HRESULT_FROM_SETUPAPI(GetLastError());
                fprintf(stderr, "SetupDiEnumDeviceInterfaces failed, hr=0x%X\n", hr);
            }
            break;
        }

        devIntfDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        success = SetupDiGetDeviceInterfaceDetail(
                      DevInfoSet,
                      &devIntfData,
                      devIntfDetail,
                      devIntfDetailSize,
                      &devIntfDetailSize,
                      NULL);

        if (!success)
        {
            if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
            {
                hr = HRESULT_FROM_SETUPAPI(GetLastError());
                fprintf(stderr, "SetupDiGetDeviceInterfaceDetail failed, hr=0x%X\n", hr);
                continue;
            }

            PVOID p = realloc(devIntfDetail, devIntfDetailSize);

            if (NULL == p)
            {
                hr = E_OUTOFMEMORY;
                fprintf(stderr, "Memory allocation failed, size=0x%X\n", devIntfDetailSize);
                continue;
            }

            devIntfDetail = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(p);

            success = SetupDiGetDeviceInterfaceDetail(
                          DevInfoSet,
                          &devIntfData,
                          devIntfDetail,
                          devIntfDetailSize,
                          &devIntfDetailSize,
                          NULL);
        }

        if (!success)
        {
            hr = HRESULT_FROM_SETUPAPI(GetLastError());
            fprintf(stderr, "SetupDiGetDeviceInterfaceDetail2 failed, hr=0x%X\n", hr);
            continue;
        }

        //
        // Now we have devIntfDetail->DevicePath
        //
        HANDLE h = CreateFile(
                       devIntfDetail->DevicePath,
                       GENERIC_READ,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_DEVICE,
                       NULL);

        if (INVALID_HANDLE_VALUE == h)
        {
            hr = HRESULT_FROM_SETUPAPI(GetLastError());
            fprintf(stderr, "CreateFile(%s) failed, hr=0x%X\n",
                    devIntfDetail->DevicePath, hr);
            continue;
        }

        if (!pIsNdasPortLogicalUnit(h))
        {
            ATLVERIFY( CloseHandle(h) );
            continue;
        }

        HDEVNOTIFY devNotifyHandle;

        hr = pRegisterDeviceHandleNotification(hWnd, h, &devNotifyHandle);

        if (FAILED(hr))
        {
            fprintf(stderr, "RegisterDeviceHandleNotification(%s) failed, hr=0x%X\n",
                    devIntfDetail->DevicePath, hr);
        }
        else
        {
            ATLVERIFY( DevNotifyHandles.Add(devNotifyHandle) );
            printf("Registered DevNotifyHandle=%p, Path=%s\n",
                   devNotifyHandle,
                   devIntfDetail->DevicePath);
        }

        ATLVERIFY( CloseHandle(h) );
    }

    free(devIntfDetail);
    return S_OK;
}
Esempio n. 8
0
HRESULT
pEnumerateNdasportLogicalUnits(
    __inout CSimpleArray<HDEVNOTIFY>& DevNotifyHandles,
    __in HWND hWnd)
{
    HRESULT hr;

    HDEVINFO devInfoSet = SetupDiGetClassDevsW(
                              NULL,
                              NULL,
                              NULL,
                              DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

    if (INVALID_HANDLE_VALUE == devInfoSet)
    {
        hr = HRESULT_FROM_SETUPAPI(GetLastError());
        fprintf(stderr, "SetupDiGetClassDevs failed, hr=0x%X\n", hr);
        return hr;
    }

    SP_DEVINFO_DATA devInfoData;

    for (DWORD index = 0; ; ++index)
    {
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
        BOOL success = SetupDiEnumDeviceInfo(devInfoSet, index, &devInfoData);
        if (!success)
        {
            if (ERROR_NO_MORE_ITEMS != GetLastError())
            {
                hr = HRESULT_FROM_SETUPAPI(GetLastError());
                fprintf(stderr, "SetupDiEnumDeviceInfo failed, hr=0x%X\n", hr);
            }
            break;
        }
        devInfoData.ClassGuid;
    }

    fprintf(stdout, "Enumerating DISK...\n");

    hr = pEnumerateNdasportLogicalUnits(
             DevNotifyHandles,
             hWnd,
             devInfoSet,
             &GUID_DEVINTERFACE_DISK);

    fprintf(stdout, "Enumerating CDROM...\n");

    hr = pEnumerateNdasportLogicalUnits(
             DevNotifyHandles,
             hWnd,
             devInfoSet,
             &GUID_DEVINTERFACE_CDROM);

    fprintf(stdout, "Enumerating TAPE...\n");

    hr = pEnumerateNdasportLogicalUnits(
             DevNotifyHandles,
             hWnd,
             devInfoSet,
             &GUID_DEVINTERFACE_TAPE);

    fprintf(stdout, "Enumerating WRITEONCEDISK...\n");

    hr = pEnumerateNdasportLogicalUnits(
             DevNotifyHandles,
             hWnd,
             devInfoSet,
             &GUID_DEVINTERFACE_WRITEONCEDISK);

    fprintf(stdout, "Enumerating MEDIUMCHANGER...\n");

    hr = pEnumerateNdasportLogicalUnits(
             DevNotifyHandles,
             hWnd,
             devInfoSet,
             &GUID_DEVINTERFACE_MEDIUMCHANGER);

    fprintf(stdout, "Enumerating CDCHANGER...\n");

    hr = pEnumerateNdasportLogicalUnits(
             DevNotifyHandles,
             hWnd,
             devInfoSet,
             &GUID_DEVINTERFACE_CDCHANGER);

    ATLVERIFY( SetupDiDestroyDeviceInfoList(devInfoSet) );

    return S_OK;
}
/*
 * 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;
}
/*
 * Find the name of the most specific driver which is currently associated with the 
 * given HID device instance.
 *
 * A HID device can be on USB, I2C, BLUETOOTH or pseudo.
 */
jstring find_driver_for_given_hiddevice(JNIEnv *env, jstring hidDevNode) {

	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;
	DWORD hid_member_index = 0;
	HDEVINFO hid_dev_info_set;
	SP_DEVINFO_DATA hid_dev_instance;
	ULONG devprop_buffer_size = 0;
	const jchar* device_node = NULL;
	jstring driver_name = NULL;

	/* size of these buffers is hardcoded in functions using them */
	TCHAR buffer[1024];
	TCHAR keybuf[1024];
	TCHAR charbuffer[128];

	/* extract HID device name to match (as an array of Unicode characters) */
	device_node = (*env)->GetStringChars(env, hidDevNode, JNI_FALSE);
	if ((device_node == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		throw_serialcom_exception(env, 3, 0, E_GETSTRCHARSTR);
		return NULL;
	}

	/* get information set for all usb devices matching the GUID */
	hid_dev_info_set = SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if (hid_dev_info_set == INVALID_HANDLE_VALUE) {
		SetupDiDestroyDeviceInfoList(hid_dev_info_set);
		(*env)->ReleaseStringChars(env, hidDevNode, device_node);
		throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
		return NULL;
	}

	/* enumerate all devices in this information set */
	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 {
				SetupDiDestroyDeviceInfoList(hid_dev_info_set);
				(*env)->ReleaseStringChars(env, hidDevNode, device_node);
				throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(error_code), NULL);
				return NULL;
			}
		}

		/* 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) {
			SetupDiDestroyDeviceInfoList(hid_dev_info_set);
			(*env)->ReleaseStringChars(env, hidDevNode, device_node);
			throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
			return NULL;
		}

		/* match device path */
		ret = _tcsicmp(device_node, buffer);
		if (ret != 0) {
			hid_member_index++;
			continue;
		}

		/* reaching here means this is the device for which driver is to be found. 
		   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\HID\VID_VID+PID_PID\Serial_Number */
		memset(keybuf, '\0', 1024);
		_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s"), buffer);

		/* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\HID\VID_VID+PID_PID\Serial_Number\Service */
		charbuffer_size = sizeof(charbuffer);
		memset(charbuffer, '\0', 128);
		status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("Service"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
		if (status != ERROR_SUCCESS) {
			errorVal = GetLastError();
			if (errorVal == 0x00) {
				/* this indicates Service registery entry does not exist, we assume windows provided 
				   default HidClass driver is driving this device */
				driver_name = (*env)->NewStringUTF(env, "HidClass");
				if ((driver_name == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
					(*env)->ExceptionClear(env);
					SetupDiDestroyDeviceInfoList(hid_dev_info_set);
					(*env)->ReleaseStringChars(env, hidDevNode, device_node);
					throw_serialcom_exception(env, 3, 0, E_NEWSTRUTFSTR);
					return NULL;
				}
				return driver_name;
			}else {
				SetupDiDestroyDeviceInfoList(hid_dev_info_set);
				(*env)->ReleaseStringChars(env, hidDevNode, device_node);
				throw_serialcom_exception(env, 4, errorVal, NULL);
				return NULL;
			}
		}

		/* return the driver name found as indicated by Service registry entry */
		driver_name = (*env)->NewString(env, charbuffer, (jsize)_tcslen(charbuffer));
		if ((driver_name == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
			(*env)->ExceptionClear(env);
			SetupDiDestroyDeviceInfoList(hid_dev_info_set);
			(*env)->ReleaseStringChars(env, hidDevNode, device_node);
			throw_serialcom_exception(env, 3, 0, E_NEWSTRUTFSTR);
			return NULL;
		}

		SetupDiDestroyDeviceInfoList(hid_dev_info_set);
		(*env)->ReleaseStringChars(env, hidDevNode, device_node);
		return driver_name;
	}

	/* reaching here means that the no driver was found for given device path, 
	   return empty string */
	driver_name = (*env)->NewStringUTF(env, "");
	if ((driver_name == NULL) || ((*env)->ExceptionOccurred(env) != NULL)) {
		(*env)->ExceptionClear(env);
		throw_serialcom_exception(env, 3, 0, E_NEWSTRUTFSTR);
		return NULL;
	}
	return driver_name;
}
/*
 * 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;
}
Esempio n. 12
0
HRESULT
CNdasServiceDeviceEventHandler::pRegisterLogicalUnit(
	__in HDEVINFO DevInfoSet,
	__in LPCGUID InterfaceGuid)
{
	HRESULT hr;
	BOOL success;
	DWORD index = 0;
	SP_DEVICE_INTERFACE_DATA devIntfData;

	DWORD devIntfDetailSize = 
		offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + 
		sizeof(TCHAR) * MAX_PATH;

	PSP_DEVICE_INTERFACE_DETAIL_DATA devIntfDetail = 
		static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(devIntfDetailSize));

	if (NULL == devIntfDetail)
	{
		hr = E_OUTOFMEMORY;
		XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR, 
			"Memory allocation failed, size=0x%X\n", devIntfDetailSize);
		return hr;
	}

	for (DWORD index = 0; ; ++index)
	{
		devIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
		
		success = SetupDiEnumDeviceInterfaces(
			DevInfoSet,
			NULL,
			InterfaceGuid,
			index,
			&devIntfData);

		if (!success)
		{
			if (ERROR_NO_MORE_ITEMS == GetLastError())
			{
				if (0 == index) 
				{
					XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_WARNING,
						"No devices\n");
				}
				hr = S_OK;
			}
			else
			{
				hr = HRESULT_FROM_SETUPAPI(GetLastError());
				XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
					"SetupDiEnumDeviceInterfaces failed, hr=0x%X\n", hr);
			}
			break;
		}

		devIntfDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

		success = SetupDiGetDeviceInterfaceDetail(
			DevInfoSet,
			&devIntfData,
			devIntfDetail,
			devIntfDetailSize,
			&devIntfDetailSize,
			NULL);

		if (!success)
		{
			if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
			{
				hr = HRESULT_FROM_SETUPAPI(GetLastError());
				XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
					"SetupDiGetDeviceInterfaceDetail failed, hr=0x%X\n", hr);
				continue;
			}

			PVOID p = realloc(devIntfDetail, devIntfDetailSize);

			if (NULL == p)
			{
				hr = E_OUTOFMEMORY;
				XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
					"Memory allocation failed, size=0x%X\n", devIntfDetailSize);
				continue;
			}

			devIntfDetail = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(p);

			success = SetupDiGetDeviceInterfaceDetail(
				DevInfoSet,
				&devIntfData,
				devIntfDetail,
				devIntfDetailSize,
				&devIntfDetailSize,
				NULL);
		}

		if (!success)
		{
			hr = HRESULT_FROM_SETUPAPI(GetLastError());
			XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
				"SetupDiGetDeviceInterfaceDetail2 failed, hr=0x%X\n", hr);
			continue;
		}

		//
		// Now we have devIntfDetail->DevicePath
		//
		HANDLE h = CreateFile(
			devIntfDetail->DevicePath,
			GENERIC_READ,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_DEVICE,
			NULL);

		if (INVALID_HANDLE_VALUE == h)
		{
			hr = HRESULT_FROM_SETUPAPI(GetLastError());
			XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
				"CreateFile(%ls) failed, hr=0x%X\n", 
				devIntfDetail->DevicePath, hr);
			continue;
		}

		NDAS_LOGICALUNIT_ADDRESS luAddress;

		hr = pNdasPortGetLogicalUnitAddress(h, &luAddress);

		if (FAILED(hr))
		{
			XTLVERIFY( CloseHandle(h) );
			continue;
		}

		NDAS_LOCATION ndasLocation = 
			NdasLogicalUnitAddressToLocation(luAddress);

		RegisterDeviceHandleNotification(
			h, 
			ndasLocation,
			devIntfDetail->DevicePath);

		XTLVERIFY( CloseHandle(h) );
	}

	free(devIntfDetail);
	return S_OK;
}
Esempio n. 13
0
HRESULT
CNdasServiceDeviceEventHandler::pRegisterLogicalUnits()
{
	HRESULT hr;

	HDEVINFO devInfoSet = SetupDiGetClassDevsW(
		NULL,
		NULL,
		NULL,
		DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);

	if (INVALID_HANDLE_VALUE == devInfoSet)
	{
		hr = HRESULT_FROM_SETUPAPI(GetLastError());
		XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
			"SetupDiGetClassDevsW failed, hr=0x%X\n", hr);
		return hr;
	}

	SP_DEVINFO_DATA devInfoData;

	for (DWORD index = 0; ; ++index)
	{
		devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
		BOOL success = SetupDiEnumDeviceInfo(devInfoSet, index, &devInfoData);
		if (!success)
		{
			if (ERROR_NO_MORE_ITEMS != GetLastError())
			{
				hr = HRESULT_FROM_SETUPAPI(GetLastError());
				XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_ERROR,
					"SetupDiEnumDeviceInfo failed, hr=0x%X\n", hr);
			}
			break;
		}
		devInfoData.ClassGuid;
	}

	const struct {
		LPCGUID Guid;
		LPCSTR TypeName;
	} LogicalUnitInterfaces[] = {
		&GUID_DEVINTERFACE_DISK, "DISK",
		&GUID_DEVINTERFACE_CDROM, "CDROM",
		&GUID_DEVINTERFACE_TAPE, "TAPE",
		&GUID_DEVINTERFACE_WRITEONCEDISK, "WRITEONCEDISK",
		&GUID_DEVINTERFACE_MEDIUMCHANGER, "MEDIUMCHANGER",
		&GUID_DEVINTERFACE_CDCHANGER, "CDCHANGER",
	};

	for (DWORD i = 0; i < RTL_NUMBER_OF(LogicalUnitInterfaces); ++i)
	{
		XTLTRACE2(NDASSVC_PNP, TRACE_LEVEL_WARNING,
			"Enumerating %hs...\n", LogicalUnitInterfaces[i].TypeName);

		pRegisterLogicalUnit(
			devInfoSet, 
			LogicalUnitInterfaces[i].Guid);
	}

	XTLVERIFY( SetupDiDestroyDeviceInfoList(devInfoSet) );

	return S_OK;
}
/*
 * Last pass to find driver name. Iterate over all the devices associated with "Ports" class.
 * One by one get their device ID and check if this device has COM port we are searching.
 * If matched get the driver name and return to caller. Note that not all devices might have
 * "PortName" registry associated with them, so ignore them.
 * 
 * Return 1 if found, 0 if not found, -1 if an error occurs (also throws exception in this case).
 */
int get_driver_com_port_others(JNIEnv *env, const jchar *port_name, TCHAR *driver_name) {

	int x = 0;
	BOOL ret = FALSE;
	CONFIGRET cmret = 0;
	LONG status = 0;
	DWORD error_code = 0;
	DWORD charbuffer_size = 0;
	DWORD com_member_index = 0;
	HDEVINFO com_dev_info_set;
	SP_DEVINFO_DATA com_dev_instance;

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

	/* get information set for all multi port serial adaptor devices matching the GUID */
	com_dev_info_set = SetupDiGetClassDevs(&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, NULL, NULL, DIGCF_ALLCLASSES);
	if (com_dev_info_set == INVALID_HANDLE_VALUE) {
		SetupDiDestroyDeviceInfoList(com_dev_info_set);
		throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
		return -1;
	}

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

		/* from information set, get device by index */
		ret = SetupDiEnumDeviceInfo(com_dev_info_set, com_member_index, &com_dev_instance);
		if (ret == FALSE) {
			error_code = GetLastError();
			if (error_code == ERROR_NO_MORE_ITEMS) {
				break;
			}else {
				SetupDiDestroyDeviceInfoList(com_dev_info_set);
				throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(error_code), NULL);
				return -1;
			}
		}

		cmret = CM_Get_Device_ID(com_dev_instance.DevInst, buffer, 1024, 0);
		if (cmret != CR_SUCCESS) {
			SetupDiDestroyDeviceInfoList(com_dev_info_set);
			_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID CR_xxxx error code : 0x%X\0", cmret);
			throw_serialcom_exception(env, 3, 0, cmerror);
			return -1;
		}

		/* get its COM port name/number for this device */
		memset(keybuf, '\0', 1024);
		_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s\\Device Parameters"), buffer);

		charbuffer_size = sizeof(charbuffer);
		memset(charbuffer, '\0', 128);
		/* ignore error as some devices might not have portname registry key */
		status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("PortName"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
		if (status == ERROR_SUCCESS) {
			/* match port name */
			ret = _tcsicmp(charbuffer, port_name);
			if (ret == 0) {
				/* get driver name */
				memset(keybuf, '\0', 1024);
				_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s"), buffer);

				/* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\XXXX\XXX\XXX\Service */
				charbuffer_size = sizeof(charbuffer);
				memset(charbuffer, '\0', 128);
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("Service"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
				if (status != ERROR_SUCCESS) {
					SetupDiDestroyDeviceInfoList(com_dev_info_set);
					throw_serialcom_exception(env, 4, GetLastError(), NULL);
					return -1;
				}

				/* populate array to be returned to caller */
				memset(driver_name, '\0', 128);
				for (x = 0; x < _tcslen(charbuffer); x++) {
					driver_name[x] = charbuffer[x];
				}

				/* clean up and return 1 to indicate driver found */
				SetupDiDestroyDeviceInfoList(com_dev_info_set);
				return 1;
			}
		}

		/* increment to get and examine the next device instance */
		com_member_index++;
	}

	/* reaching here means given COM port's driver not found */
	SetupDiDestroyDeviceInfoList(com_dev_info_set);
	return 0;
}
/*
 * Check if the given COM port name belongs to a multi port serial adaptor device. If yes, get its driver name
 * and return to caller.
 *
 * Return 1 if found, 0 if not found, -1 if an error occurs (also throws exception in this case).
 */
int get_driver_com_port_multiportadaptor(JNIEnv *env, const jchar *port_name, TCHAR *driver_name) {

	int x = 0;
	BOOL ret = FALSE;
	LONG status = 0;
	DWORD error_code = 0;
	DWORD size = 0;
	DWORD regproptype;
	DWORD charbuffer_size = 0;
	DWORD driver_name_size = 0;
	ULONG buffer_size = 0;
	DWORD multiport_member_index = 0;
	HDEVINFO multiport_dev_info_set;
	SP_DEVINFO_DATA multiport_dev_instance;
	ULONG devprop_buffer_size = 0;
	DEVPROPTYPE proptype;
	CONFIGRET cmret = 0;
	DEVINST firstchild = 0;
	DEVINST next_sibling = 0;
	DEVINST current_sibling = 0;

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

	/* get information set for all multi port serial adaptor devices matching the GUID */
	multiport_dev_info_set = SetupDiGetClassDevs(&GUID_MULTIPORT_SERIAL_ADAPTOR_DEVICE, NULL, NULL, DIGCF_DEVICEINTERFACE);
	if (multiport_dev_info_set == INVALID_HANDLE_VALUE) {
		SetupDiDestroyDeviceInfoList(multiport_dev_info_set);
		throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(GetLastError()), NULL);
		return -1;
	}

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

		/* from information set, get device by index */
		ret = SetupDiEnumDeviceInfo(multiport_dev_info_set, multiport_member_index, &multiport_dev_instance);
		if (ret == FALSE) {
			error_code = GetLastError();
			if (error_code == ERROR_NO_MORE_ITEMS) {
				break;
			}else {
				SetupDiDestroyDeviceInfoList(multiport_dev_info_set);
				throw_serialcom_exception(env, 4, HRESULT_FROM_SETUPAPI(error_code), NULL);
				return -1;
			}
		}

		/* for this device find its instance ID (USB\VID_04D8&PID_00DF\000098037)
		 * this is variable 'Device Instance Path' in device manager. */
		cmret = CM_Get_Device_ID(multiport_dev_instance.DevInst, buffer, 1024, 0);
		if (cmret != CR_SUCCESS) {
			SetupDiDestroyDeviceInfoList(multiport_dev_info_set);
			_snprintf_s(cmerror, 256, 256, "CM_Get_Device_ID CR_xxxx error code : 0x%X\0", cmret);
			throw_serialcom_exception(env, 3, 0, cmerror);
			return -1;
		}

		/* get its COM port name/number for this device */
		memset(keybuf, '\0', 1024);
		_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s\\Device Parameters"), buffer);

		charbuffer_size = sizeof(charbuffer);
		memset(charbuffer, '\0', 128);
		/* ignore error as some devices might not have portname registry key */
		status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("PortName"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
		if (status == ERROR_SUCCESS) {
			/* match port name */
			ret = _tcsicmp(charbuffer, port_name);
			if (ret == 0) {
				/* get driver name */
				memset(keybuf, '\0', 1024);
				_stprintf_s(keybuf, 1024, TEXT("SYSTEM\\CurrentControlSet\\Enum\\%s"), buffer);

				/* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\XXXX\XXX\XXX\Service */
				charbuffer_size = sizeof(charbuffer);
				memset(charbuffer, '\0', 128);
				status = RegGetValue(HKEY_LOCAL_MACHINE, keybuf, TEXT("Service"), RRF_RT_REG_SZ, NULL, (PVOID)charbuffer, &charbuffer_size);
				if (status != ERROR_SUCCESS) {
					SetupDiDestroyDeviceInfoList(multiport_dev_info_set);
					throw_serialcom_exception(env, 4, GetLastError(), NULL);
					return -1;
				}

				/* populate array to be returned to caller */
				memset(driver_name, '\0', 128);
				for (x = 0; x < _tcslen(charbuffer); x++) {
					driver_name[x] = charbuffer[x];
				}

				/* clean up and return 1 to indicate driver found */
				SetupDiDestroyDeviceInfoList(multiport_dev_info_set);
				return 1;
			}
		}

		/* increment to get and examine the next multiport device for COM ports class */
		multiport_member_index++;
	}

	/* reaching here means given COM port does not belong to multi-port serial adaptor device */
	SetupDiDestroyDeviceInfoList(multiport_dev_info_set);
	return 0;
}