예제 #1
6
파일: devnode.c 프로젝트: kcrazy/winekit
PTSTR DriverNameToDeviceDesc (__in PCTSTR DriverName, BOOLEAN DeviceId)
{
    DEVINST     devInst;
    DEVINST     devInstNext;
    CONFIGRET   cr;
    ULONG       walkDone = 0;
    ULONG       len;

    // Get Root DevNode
    //
    cr = CM_Locate_DevNode(&devInst,
                           NULL,
                           0);

    if (cr != CR_SUCCESS)
    {
        return NULL;
    }

    // Do a depth first search for the DevNode with a matching
    // DriverName value
    //
    while (!walkDone)
    {
        // Get the DriverName value
        //
        len = sizeof(buf) / sizeof(buf[0]);
        cr = CM_Get_DevNode_Registry_Property(devInst,
                                              CM_DRP_DRIVER,
                                              NULL,
                                              buf,
                                              &len,
                                              0);

        // If the DriverName value matches, return the DeviceDescription
        //
        if (cr == CR_SUCCESS && _tcsicmp(DriverName, buf) == 0)
        {
            len = sizeof(buf) / sizeof(buf[0]);

            if (DeviceId)
            {
                cr = CM_Get_Device_ID(devInst,
                                      buf,
                                      len,
                                      0);
            }
            else
            {
                cr = CM_Get_DevNode_Registry_Property(devInst,
                                                      CM_DRP_DEVICEDESC,
                                                      NULL,
                                                      buf,
                                                      &len,
                                                      0);
            }

            if (cr == CR_SUCCESS)
            {
                return buf;
            }
            else
            {
                return NULL;
            }
        }

        // This DevNode didn't match, go down a level to the first child.
        //
        cr = CM_Get_Child(&devInstNext,
                          devInst,
                          0);

        if (cr == CR_SUCCESS)
        {
            devInst = devInstNext;
            continue;
        }

        // Can't go down any further, go across to the next sibling.  If
        // there are no more siblings, go back up until there is a sibling.
        // If we can't go up any further, we're back at the root and we're
        // done.
        //
        for (;;)
        {
            cr = CM_Get_Sibling(&devInstNext,
                                devInst,
                                0);

            if (cr == CR_SUCCESS)
            {
                devInst = devInstNext;
                break;
            }

            cr = CM_Get_Parent(&devInstNext,
                               devInst,
                               0);


            if (cr == CR_SUCCESS)
            {
                devInst = devInstNext;
            }
            else
            {
                walkDone = 1;
                break;
            }
        }
    }

    return NULL;
}
예제 #2
0
void CMStuff(char *devID, JNIEnv *env, jobject hashMap, jmethodID methPut)
{
    DEVINST devinst;
    DEVINST devinstparent;
    unsigned long buflen;

	CONFIGRET ret;

    ret = CM_Locate_DevNodeA(&devinst, devID, NULL);
	if (ret != CR_SUCCESS) {
		return;
	}
    ret = CM_Get_Parent(&devinstparent, devinst, NULL);
	if (ret != CR_SUCCESS) {
		return;
	}

	char *has = strstr(devID, "RemovableMedia");
	if (has) {
        CM_Get_Parent(&devinstparent, devinstparent, NULL);
		// if failed, devinstparent should still have previous value (I hope!)
	}

	ret = CM_Get_Device_ID_Size(&buflen, devinst, 0);
	if (ret != CR_SUCCESS) {
		return;
	}

	if (buflen < 2048) {
		buflen++; // add space for null, which CM_Get_Device_ID will add at end
		WCHAR *buffer = new WCHAR[buflen];
		ret = CM_Get_Device_ID(devinst, buffer, buflen, 0);
		if (ret != CR_SUCCESS) {
			delete[] buffer;
			return;
		}

		addToMap(env, hashMap, methPut, "DevInst_DevID", buffer, buflen);
		findVID_PID(buffer, env, hashMap, methPut);
		delete[] buffer;
	}

    ret = CM_Get_Device_ID_Size(&buflen, devinstparent, 0);
	if (ret != CR_SUCCESS) {
		return;
	}
	if (buflen < 2048) {
		buflen++; // add space for null, which CM_Get_Device_ID will add at end
		WCHAR *buffer = new WCHAR[buflen];
		ret = CM_Get_Device_ID(devinstparent, buffer, buflen, 0);
		if (ret != CR_SUCCESS) {
			delete[] buffer;
			return;
		}

		addToMap(env, hashMap, methPut, "DevInstParent_DevID", buffer, buflen);
		findVID_PID(buffer, env, hashMap, methPut);
		delete[] buffer;
	}
}
예제 #3
0
CDeviceSetup::CDeviceSetup(SP_DEVINFO_DATA devInfoData)
{
	ZeroMemory(&m_devInfoData,sizeof(m_devInfoData));
	m_hDevList=INVALID_HANDLE_VALUE;

	m_hDevList=SetupDiCreateDeviceInfoList(0,0);

	assert(m_hDevList!=INVALID_HANDLE_VALUE);
	if(m_hDevList==INVALID_HANDLE_VALUE)
		return;

	char devInstanceID[512];
	if(CM_Get_Device_ID(devInfoData.DevInst,devInstanceID,sizeof(devInstanceID),0)!=CR_SUCCESS)
	{
			SetupDiDestroyDeviceInfoList(m_hDevList);
			m_hDevList=INVALID_HANDLE_VALUE;
			return;
	}
	
	
	m_devInfoData.cbSize=sizeof(SP_DEVINFO_DATA);
	if(SetupDiOpenDeviceInfo(m_hDevList,devInstanceID,0,0,&m_devInfoData)==0)
	{
		SetupDiDestroyDeviceInfoList(m_hDevList);
		m_hDevList=INVALID_HANDLE_VALUE;
		return;
	}
	

}
static bool is_himddevice(QString devID, QString & name)
{
    DEVINST devinst;
    DEVINST devinstparent;
    unsigned long buflen;
    QString recname, devicepath;

    CM_Locate_DevNodeA(&devinst, devID.toLatin1().data(), NULL);
    CM_Get_Parent(&devinstparent, devinst, NULL);

    if(devID.contains("RemovableMedia", Qt::CaseInsensitive))    // on Windows XP: get next parent device instance
        CM_Get_Parent(&devinstparent, devinstparent, NULL);

    CM_Get_Device_ID_Size(&buflen, devinstparent, 0);
    wchar_t *buffer = new wchar_t[buflen];
    CM_Get_Device_ID(devinstparent, buffer, buflen, 0);
    devicepath = QString::fromWCharArray(buffer);
    delete[] buffer;

    if(identified( devicepath, recname))
    {
        name = recname;
        return true;
    }
    return false;
}
예제 #5
0
BOOL CDeviceSetup::DevInstToDevInfoData(DEVINST devInstance, PSP_DEVINFO_DATA pDevInfoData)
{
	assert(devInstance!=NULL);
	assert(pDevInfoData!=NULL);

	if(devInstance==NULL || pDevInfoData==NULL)
		return 0;

	HDEVINFO hDevList=SetupDiCreateDeviceInfoList(0,0);

	if(hDevList==INVALID_HANDLE_VALUE)
		return 0;

	char devInstanceID[512];

	if(CM_Get_Device_ID(devInstance,devInstanceID,sizeof(devInstanceID),0)!=CR_SUCCESS)
	{
		SetupDiDestroyDeviceInfoList(hDevList);
		return 0;
	}

	pDevInfoData->cbSize=sizeof(SP_DEVINFO_DATA);

	if(SetupDiOpenDeviceInfo(hDevList,devInstanceID,0,0,pDevInfoData)==0)
	{
		SetupDiDestroyDeviceInfoList(hDevList);
		return 0;
	}

	SetupDiDestroyDeviceInfoList(hDevList);
	return 1;
}
예제 #6
0
	bool Create(DEVINST DevInst)
	{
		wchar_t szDeviceID[MAX_DEVICE_ID_LEN];
		if (CM_Get_Device_ID(DevInst, szDeviceID, ARRAYSIZE(szDeviceID), 0) == CR_SUCCESS)
		{
			m_id = szDeviceID;
			m_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, m_id.data(), nullptr, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
		}
		// TODO: log if failed
		return m_info != INVALID_HANDLE_VALUE;
	}
nsresult
sbWinGetDeviceInstanceID(DEVINST    aDevInst,
                         nsAString& aDeviceInstanceID)
{
  CONFIGRET cr;

  // Get the device instance ID.
  TCHAR deviceInstanceID[MAX_DEVICE_ID_LEN];
  cr = CM_Get_Device_ID(aDevInst, deviceInstanceID, MAX_DEVICE_ID_LEN, 0);
  NS_ENSURE_TRUE(cr == CR_SUCCESS, NS_ERROR_FAILURE);
  aDeviceInstanceID.Assign(deviceInstanceID);

  return NS_OK;
}
예제 #8
0
// Moves up one node in the device tree and returns its device info data along with an info set only
// including that device for further processing
// See https://msdn.microsoft.com/en-us/library/windows/hardware/ff549417(v=vs.85).aspx
static bool GetParentDevice(const DEVINST& child_device_instance, HDEVINFO* parent_device_info,
                            PSP_DEVINFO_DATA parent_device_data)
{
  ULONG status;
  ULONG problem_number;
  CONFIGRET result;

  // Check if that device instance has device node present
  result = CM_Get_DevNode_Status(&status, &problem_number, child_device_instance, 0);
  if (result != CR_SUCCESS)
  {
    return false;
  }

  DEVINST parent_device;

  // Get the device instance of the parent
  result = CM_Get_Parent(&parent_device, child_device_instance, 0);
  if (result != CR_SUCCESS)
  {
    return false;
  }

  std::vector<WCHAR> parent_device_id(MAX_DEVICE_ID_LEN);
  ;

  // Get the device id of the parent, required to open the device info
  result =
      CM_Get_Device_ID(parent_device, parent_device_id.data(), (ULONG)parent_device_id.size(), 0);
  if (result != CR_SUCCESS)
  {
    return false;
  }

  // Create a new empty device info set for the device info data
  (*parent_device_info) = SetupDiCreateDeviceInfoList(nullptr, nullptr);

  // Open the device info data of the parent and put it in the emtpy info set
  if (!SetupDiOpenDeviceInfo((*parent_device_info), parent_device_id.data(), nullptr, 0,
                             parent_device_data))
  {
    SetupDiDestroyDeviceInfoList(parent_device_info);
    return false;
  }

  return true;
}
예제 #9
0
std::string CDeviceSetup::GetDevicePath()
{
	
	std::string devicePath;

	
	LPGUID guid[] = {(LPGUID) &GUID_DEVINTERFACE_DISK,
					 (LPGUID) &GUID_DEVINTERFACE_CDROM,
					 (LPGUID) &GUID_DEVINTERFACE_PARTITION,
					 (LPGUID) &GUID_DEVINTERFACE_TAPE,
					 (LPGUID) &GUID_DEVINTERFACE_WRITEONCEDISK,
					 (LPGUID) &GUID_DEVINTERFACE_VOLUME,
					 (LPGUID) &GUID_DEVINTERFACE_MEDIUMCHANGER,
					 (LPGUID) &GUID_DEVINTERFACE_CDCHANGER,
					 (LPGUID) &GUID_DEVINTERFACE_STORAGEPORT,
					  NULL};
					 

	char devInstanceID[512];
	if(CM_Get_Device_ID(m_devInfoData.DevInst,devInstanceID,sizeof(devInstanceID),0)!=CR_SUCCESS)
	{
		return devicePath;
	}
	

	for(int i=0;guid[i]!=NULL;i++)
	{

		char device_path[512];
		if(CM_Get_Device_Interface_List(
									 guid[i],
									 devInstanceID,
									 device_path,
									 sizeof(device_path),
									 CM_GET_DEVICE_INTERFACE_LIST_PRESENT)==CR_SUCCESS)
		{

			if(device_path[0]==0)
				continue;

			devicePath=device_path;
			return devicePath;
		}
	}

	return devicePath;
}
예제 #10
0
void enum_mobile_devices(pfc::list_t<device_instance_info_t> & p_out)
{
	HDEVINFO di = SetupDiGetClassDevs(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);

	if (di != INVALID_HANDLE_VALUE)
	{
		SP_DEVINFO_DATA did;
		memset(&did, 0, sizeof(did));
		did.cbSize = sizeof(did);

		DWORD i;
		for (i=0; SetupDiEnumDeviceInfo(di, i, &did); i++)
		{
			//if (did.ClassGuid == GUID_DEVCLASS_USB)
			{
				ULONG DevDiskLen=0;
				pfc::array_t<WCHAR> DevDisk;
				if (CR_SUCCESS == CM_Get_Device_ID_Size(&DevDiskLen, did.DevInst, NULL))
				{
					DevDisk.set_size(DevDiskLen+1);
					DevDisk.fill_null();
					if (CR_SUCCESS == CM_Get_Device_ID(did.DevInst, DevDisk.get_ptr(), DevDisk.get_size(), NULL))
					{
						if (g_check_devid_is_mobile_device(DevDisk.get_ptr()))
						{
							device_instance_info_t temp;
							temp.m_handle = did.DevInst;
							temp.m_path = DevDisk.get_ptr();
							p_out.add_item(temp);

							console::formatter() << "iPod manager: USB AMD enumerator: Found " << Tu(DevDisk.get_ptr());
						}
					}
				}
			}
		}

		SetupDiDestroyDeviceInfoList(di);
	}
	if (!p_out.get_count())
		console::formatter() << "iPod manager: USB AMD enumerator: No devices found!";
}
예제 #11
0
파일: enumdevices.c 프로젝트: RPG-7/reactos
static HTREEITEM
AddDeviceToTree(HWND hTreeView,
                HTREEITEM hRoot,
                DEVINST dnDevInst,
                BOOL bShowHidden)
{
    TCHAR DevName[MAX_DEV_LEN];
    TCHAR FriendlyName[MAX_DEV_LEN];
    TCHAR ClassGuidString[MAX_GUID_STRING_LEN];
    GUID ClassGuid;
    ULONG ulLength;
    LPTSTR DeviceID = NULL;
    INT ClassImage = 24;
    CONFIGRET cr;

    ulLength = MAX_GUID_STRING_LEN * sizeof(TCHAR);
    cr = CM_Get_DevNode_Registry_Property(dnDevInst,
                                          CM_DRP_CLASSGUID,
                                          NULL,
                                          ClassGuidString,
                                          &ulLength,
                                          0);
    if (cr == CR_SUCCESS)
    {
        pSetupGuidFromString(ClassGuidString, &ClassGuid);

        if (bShowHidden == FALSE &&
            (IsEqualGUID(&ClassGuid, &GUID_DEVCLASS_LEGACYDRIVER) ||
             IsEqualGUID(&ClassGuid, &GUID_DEVCLASS_VOLUME)))
            return NULL;
    }
    else
    {
        /* It's a device with no driver */
        ClassGuid = GUID_DEVCLASS_UNKNOWN;
    }

    cr = CM_Get_Device_ID(dnDevInst,
                          DevName,
                          MAX_DEV_LEN,
                          0);
    if (cr != CR_SUCCESS)
        return NULL;

    ulLength = MAX_DEV_LEN * sizeof(TCHAR);
    cr = CM_Get_DevNode_Registry_Property(dnDevInst,
                                          CM_DRP_FRIENDLYNAME,
                                          NULL,
                                          FriendlyName,
                                          &ulLength,
                                          0);
    if (cr != CR_SUCCESS)
    {
        ulLength = MAX_DEV_LEN * sizeof(TCHAR);
        cr = CM_Get_DevNode_Registry_Property(dnDevInst,
                                              CM_DRP_DEVICEDESC,
                                              NULL,
                                              FriendlyName,
                                              &ulLength,
                                              0);
        if (cr != CR_SUCCESS)
            return NULL;
    }

    if (!SetupDiGetClassImageIndex(&ImageListData,
                                   &ClassGuid,
                                   &ClassImage))
    {
        /* FIXME: can we do this?
         * Set the blank icon: IDI_SETUPAPI_BLANK = 41
         * it'll be image 24 in the imagelist */
        ClassImage = 24;
    }

    if (DevName != NULL)
    {
        DeviceID = HeapAlloc(GetProcessHeap(),
                             0,
                             (lstrlen(DevName) + 1) * sizeof(TCHAR));
        if (DeviceID == NULL)
        {
            return NULL;
        }

        lstrcpy(DeviceID, DevName);
    }

    return InsertIntoTreeView(hTreeView,
                              hRoot,
                              FriendlyName,
                              DeviceID,
                              ClassImage,
                              0);
}
/*
 * 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;
}
예제 #13
0
void build_volumes_v2(t_volumes & volumes)
{
	HDEVINFO di = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);

	if (di != INVALID_HANDLE_VALUE)
	{
		SP_DEVINFO_DATA did;
		memset(&did, 0, sizeof(did));
		did.cbSize = sizeof(did);

		DWORD i;
		for (i=0; SetupDiEnumDeviceInfo(di, i, &did); i++)
		{
			if (did.ClassGuid == GUID_DEVCLASS_DISKDRIVE)
			{
				ULONG DevLen = 0, DevDiskLen=0;
				pfc::array_t<WCHAR> Dev, DevDisk, DevRoot;
				DEVINST pParent = NULL, ppParent = NULL;
				CM_Get_Parent_Ex(&pParent, did.DevInst, NULL, NULL);
				CM_Get_Parent_Ex(&ppParent, pParent, NULL, NULL);
				CM_Get_Device_ID_Size(&DevLen, pParent, NULL);
				CM_Get_Device_ID_Size(&DevDiskLen, did.DevInst, NULL);
				Dev.set_size(DevLen+1);
				Dev.fill_null();
				DevDisk.set_size(DevDiskLen+1);
				DevDisk.fill_null();
				CM_Get_Device_ID(pParent, Dev.get_ptr(), Dev.get_size(), NULL);
				CM_Get_Device_ID(did.DevInst, DevDisk.get_ptr(), DevDisk.get_size(), NULL);

				{
					ULONG len = 0;
					CM_Get_Device_ID_Size(&len, ppParent, NULL);
					DevRoot.set_size(len+1);
					DevRoot.fill_null();
					CM_Get_Device_ID(ppParent, DevRoot.get_ptr(), len, NULL);
				}
				bool b_shuffle;
				t_ipod_model model;
				if (g_check_devid_is_ipod(Dev.get_ptr(), model, b_shuffle))
				{
					pfc::array_t<WCHAR> DriverSymbolicPath;
					if (!wcsncmp(Dev.get_ptr(), DevRoot.get_ptr(), 7))
					{
						ULONG len=0;

						CM_Get_Device_Interface_List_Size(&len, (LPGUID)&GUID_DEVINTERFACE_USBAPPL_DEVICE, DevRoot.get_ptr(), CM_GET_DEVICE_INTERFACE_LIST_PRESENT);

						DriverSymbolicPath.set_size(len+1);
						DriverSymbolicPath.fill_null();
						CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_USBAPPL_DEVICE, DevRoot.get_ptr(), DriverSymbolicPath.get_ptr(), len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
						//console::formatter() << pfc::stringcvt::string_utf8_from_os(buff.get_ptr());
					}
					else
					{
						DriverSymbolicPath.set_size(1);
						DriverSymbolicPath.fill_null();
					}

					{
						ULONG DevRemovalListSize = NULL, DevBusListSize = NULL;
						pfc::array_t<WCHAR> DevRemovalList, DevBusList;
						CM_Get_Device_ID_List_Size_Ex(&DevRemovalListSize, DevDisk.get_ptr(), CM_GETIDLIST_FILTER_REMOVALRELATIONS, NULL);
						CM_Get_Device_ID_List_Size_Ex(&DevBusListSize, DevDisk.get_ptr(), CM_GETIDLIST_FILTER_BUSRELATIONS, NULL);
						DevRemovalList.set_size(DevRemovalListSize);
						DevBusList.set_size(DevBusListSize);
						CM_Get_Device_ID_List_Ex(DevDisk.get_ptr(), DevRemovalList.get_ptr(), DevRemovalListSize, CM_GETIDLIST_FILTER_REMOVALRELATIONS, NULL);
						CM_Get_Device_ID_List_Ex(DevDisk.get_ptr(), DevBusList.get_ptr(), DevBusListSize, CM_GETIDLIST_FILTER_BUSRELATIONS, NULL);
						WCHAR * ptr = DevRemovalList.get_ptr(), *pvolume=NULL;
						{
							t_size ptrlen= NULL;
							while (ptr && (ptrlen = wcslen(ptr)))
							{
								if (!wcsicmp_partial(ptr, L"STORAGE\\"))
								{
									pvolume = ptr;
									break;
								}
								ptr+=ptrlen;
								ptr++;
							}
						}

						if (!pvolume)
						{
							ptr = DevBusList.get_ptr();
							t_size ptrlen= NULL;
							while (ptr && (ptrlen = wcslen(ptr)))
							{
								if (!wcsicmp_partial(ptr, L"STORAGE\\"))
								{
									pvolume = ptr;
									break;
								}
								ptr+=ptrlen;
								ptr++;
							}
						}

						if (pvolume)
						{
							SP_DEVINFO_DATA pdid;
							memset(&pdid, 0, sizeof(pdid));
							pdid.cbSize = sizeof(pdid);
							HDEVINFO pdi = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);;
							SetupDiOpenDeviceInfo(pdi, pvolume, NULL, NULL, &pdid);
							{
								{
									DWORD j;
									SP_DEVICE_INTERFACE_DATA dia;
									memset(&dia, 0, sizeof(dia));
									dia.cbSize = sizeof(dia);
									for (j=0; SetupDiEnumDeviceInterfaces(pdi, &pdid, &GUID_DEVINTERFACE_VOLUME, j, &dia); j++)
									{
										DWORD required_size = 0;

										pfc::array_t<t_uint8> data;

										SetupDiGetDeviceInterfaceDetail(pdi, &dia, NULL, NULL, &required_size, &pdid);
										data.set_size(required_size);
										data.fill_null();
										if (required_size >= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA))
										{
											SP_DEVICE_INTERFACE_DETAIL_DATA * didd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)data.get_ptr();
											didd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
											if (SetupDiGetDeviceInterfaceDetail(pdi, &dia, didd, required_size, NULL, &pdid))
											{

												pfc::array_t<WCHAR> path;
												t_size len = wcslen(didd->DevicePath);
												path.append_fromptr(didd->DevicePath, len);
												path.grow_size (len + sizeof(WCHAR)*2);
												path[len] = '\\';
												path[len+1] = 0;

												WCHAR volumename[129];
												memset(&volumename, 0, sizeof(volumename));
												if (GetVolumeNameForVolumeMountPoint(path.get_ptr(), volumename, 128))
												{
													volumes.add_item(t_volume(volumename, Dev.get_ptr(), model, b_shuffle, pParent, DriverSymbolicPath.get_ptr()));
												}
											}
										}
									}
								}
							}
							SetupDiDestroyDeviceInfoList(pdi);
						}
					}

				}
			}
		}

		SetupDiDestroyDeviceInfoList(di);
	}
}
예제 #14
0
파일: winutil.c 프로젝트: yeyanchao/calibre
PSP_DEVICE_INTERFACE_DETAIL_DATA
get_device_ancestors(HDEVINFO hDevInfo, DWORD index, PyObject *candidates, BOOL *iterate, BOOL ddebug) {
    SP_DEVICE_INTERFACE_DATA            interfaceData;
    SP_DEVINFO_DATA						devInfoData;
    BOOL                                status;
    PSP_DEVICE_INTERFACE_DETAIL_DATA    interfaceDetailData;
    DWORD                               interfaceDetailDataSize,
                                        reqSize;
    DEVINST                             parent, pos;
    wchar_t                             temp[BUFSIZE];
    int                                 i;
    PyObject                            *devid;

    interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
    devInfoData.cbSize   = sizeof (SP_DEVINFO_DATA);

    status = SetupDiEnumDeviceInterfaces (
                hDevInfo,               // Interface Device Info handle
                NULL,                   // Device Info data
                (LPGUID)&GUID_DEVINTERFACE_VOLUME, // Interface registered by driver
                index,                  // Member
                &interfaceData          // Device Interface Data
                );
    if ( status == FALSE ) {
        *iterate = FALSE;
        return NULL;
    }
    SetupDiGetDeviceInterfaceDetail (
                hDevInfo,           // Interface Device info handle
                &interfaceData,     // Interface data for the event class
                NULL,               // Checking for buffer size
                0,                  // Checking for buffer size
                &reqSize,           // Buffer size required to get the detail data
                NULL                // Checking for buffer size
    );

    interfaceDetailDataSize = reqSize;
    interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+50);
    if ( interfaceDetailData == NULL ) {
        PyErr_NoMemory();
        return NULL;
    }
    interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
    devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    status = SetupDiGetDeviceInterfaceDetail (
                  hDevInfo,                 // Interface Device info handle
                  &interfaceData,           // Interface data for the event class
                  interfaceDetailData,      // Interface detail data
                  interfaceDetailDataSize,  // Interface detail data size
                  &reqSize,                 // Buffer size required to get the detail data
                  &devInfoData);            // Interface device info
    if (ddebug) printf("Getting ancestors\n"); fflush(stdout);

    if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;}

    pos = devInfoData.DevInst;

    for(i = 0; i < 10; i++) {
        // Get the device instance of parent.
        if (CM_Get_Parent(&parent, pos, 0) != CR_SUCCESS) break;
        if (CM_Get_Device_ID(parent, temp, BUFSIZE, 0) == CR_SUCCESS) {
            if (ddebug) console_out(L"device id: %s\n", temp);
            devid = PyUnicode_FromWideChar(temp, wcslen(temp));
            if (devid) {
                PyList_Append(candidates, devid);
                Py_DECREF(devid);
            }
        }
        pos = parent;
    }

    return interfaceDetailData;
}
예제 #15
0
파일: drivers.cpp 프로젝트: wxsBSD/osquery
QueryData genDrivers(QueryContext& context) {
  QueryData results;

  auto devInfoset = setupDevInfoSet();
  if (devInfoset == nullptr) {
    win32LogWARNING("Error getting device handle");
    return results;
  }

  std::vector<SP_DEVINFO_DATA> devices;
  auto ret = getDeviceList(devInfoset, devices);
  if (!ret.ok()) {
    win32LogWARNING(ret.getMessage(), ret.getCode());
    return results;
  }

  for (auto& device : devices) {
    char devId[MAX_DEVICE_ID_LEN] = {0};
    if (CM_Get_Device_ID(device.DevInst, devId, MAX_DEVICE_ID_LEN, 0) !=
        CR_SUCCESS) {
      win32LogWARNING("Failed to get device ID");
      return QueryData();
    }

    SP_DRVINFO_DATA drvInfo = {0};
    SP_DRVINFO_DETAIL_DATA drvInfoDetail = {0};
    ret = getDeviceDriverInfo(devInfoset, device, drvInfo, drvInfoDetail);

    Row r;
    r["device_id"] = devId;
    r["inf"] = drvInfoDetail.InfFileName;
    r["provider"] = drvInfo.ProviderName;
    r["manufacturer"] = drvInfo.MfgName;
    r["date"] = std::to_string(osquery::filetimeToUnixtime(drvInfo.DriverDate));
    r["description"] = drvInfo.Description;
    ULARGE_INTEGER version;
    version.QuadPart = drvInfo.DriverVersion;
    r["version"] = std::to_string(HIWORD(version.HighPart)) + "." +
                   std::to_string(HIWORD(version.LowPart)) + "." +
                   std::to_string(LOWORD(version.HighPart)) + "." +
                   std::to_string(LOWORD(version.LowPart));

    for (const auto& elem : kAdditionalDeviceProps) {
      std::string val;
      ret = getDeviceProperty(devInfoset, device, elem.second, val);
      r[elem.first] = std::move(val);
    }

    if (r.count("driver_key") > 0) {
      if (!r.at("driver_key").empty()) {
        r["driver_key"].insert(0, kDriverKeyPath);
      }
    }
    if (r.count("service") > 0) {
      if (!r.at("service").empty()) {
        r["service_key"] = kServiceKeyPath + r["service"];
        r["image"] = getDriverImagePath(r["service_key"]);
      }
    }

    results.push_back(r);
  }

  return results;
}
/*
 * 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;
}
/*
 * 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;
}
예제 #18
0
void PCUtils::GetPhysicalDisks( std::vector<PCUtils::DISK_DRIVE_INFORMATION>& OutVector )
{
#ifdef _WIN32
    unsigned i;
    DWORD dwSize, dwPropertyRegDataType = SPDRP_PHYSICAL_DEVICE_OBJECT_NAME;
    CONFIGRET r;
    HDEVINFO hDevInfo;
    SP_DEVINFO_DATA DeviceInfoData;
    SP_DEVICE_INTERFACE_DATA interfaceData;

    TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
    TCHAR szDesc[1024];

    GUID HddClass;
    HddClass = GUID_DEVINTERFACE_DISK;//GUID_DEVCLASS_DISKDRIVE;

    // List all connected disk drives
    hDevInfo = SetupDiGetClassDevs (&HddClass, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (hDevInfo == INVALID_HANDLE_VALUE)
        return;

    // Find the ones that are driverless
    for (i = 0; ; i++)
    {
        DeviceInfoData.cbSize = sizeof (DeviceInfoData);
        // Get the next device info
        if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
            break;
        interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
        // Get the next device interface
        if (!SetupDiEnumInterfaceDevice(hDevInfo, NULL, &HddClass, i, &interfaceData))
        {
            break;
        }

        // Get the device ID
        r = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
        if (r != CR_SUCCESS)
            continue;

        // To add to the vector
        DISK_DRIVE_INFORMATION AddToVector;

        DWORD requiredSize = 0;

        // Get the path
        SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, NULL, NULL, &requiredSize, NULL);
        SP_INTERFACE_DEVICE_DETAIL_DATA* data = (SP_INTERFACE_DEVICE_DETAIL_DATA*) malloc(requiredSize);

        data->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);


        if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, data, requiredSize, NULL, NULL))
        {
            continue;
        }

        AddToVector.Path = nowide::convert(std::wstring(data->DevicePath));
        qDebug("Disk path: %s", AddToVector.Path.c_str());

        // Friendly name (e.g. SanDisk Cruzer USB...)
        SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME,
                                          &dwPropertyRegDataType, (BYTE*)szDesc,
                                          sizeof(szDesc),   // The size, in bytes
                                          &dwSize);
        AddToVector.FriendlyName = nowide::convert(std::wstring((TCHAR*)szDesc));
        qDebug("Friendly name: %s", AddToVector.FriendlyName.c_str());

        OutVector.push_back(AddToVector);
        delete data;
    }
#else
DIR *dir = NULL;
dirent *ent = NULL;
dir = opendir("/dev/");
if (dir != NULL)
{
    // Read the shit
    while ((ent = readdir(dir)) != NULL)
    {
        // Check the directory name, and if it starts with "disk" then keep it!
        QRegExp exp("disk*");
        exp.setPatternSyntax(QRegExp::Wildcard);
        exp.setCaseSensitivity(Qt::CaseInsensitive);
        if (exp.exactMatch(ent->d_name))
        {
            DISK_DRIVE_INFORMATION curdir;

            std::ostringstream ss;
            ss << "/dev/r";
            ss << ent->d_name;
            std::string diskPath = ss.str();

            curdir.Path = diskPath;

            int device;
            if ((device = open(diskPath.c_str(), O_RDONLY)) > 0)
            {
#ifdef __linux
                hd_driveid hd;
                if (!ioctl(device, HDIO_GET_IDENTITY, &hd))
                {
                    curdir.FriendlyName = hd.model;
                }
#elif defined __APPLE__
                curdir.FriendlyName = ent->d_name;
#endif
                OutVector.push_back(curdir);
            }
        }
    }
}
if (dir)
    closedir(dir);
if (ent)
    delete ent;
#endif
}
/*
 * 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;
}