首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Windows设备信息获取:(摄像头,声卡为例)Qt,WindowsAPI对比说明(1)

Windows设备信息获取:(摄像头,声卡为例)Qt,WindowsAPI对比说明(1)

作者头像
何其不顾四月天
发布于 2023-03-10 05:34:11
发布于 2023-03-10 05:34:11
2.4K00
代码可运行
举报
文章被收录于专栏:四月天的专栏四月天的专栏
运行总次数:0
代码可运行

简介

近期一个小项目需要获取本机摄像头,声卡的信息,提供配置文件,用作软件配置。然后开始慢慢研究,说一下自己遇到的一些坑。

系统环境

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Windows:Win10
Qt:5.8.5
VS:vs2013

相关资料

USB 获取设备VID,HID

windows SetupAPI 介绍和使用

获取指定USB设备的VID PID和SerialNumber

代码片段

  • USB HID,VID说明

USB 获取设备VID,HID

里边源码说明:路径:https://github.com/signal11/hidapi , 进入下载,我选择zip,下载到本地,解压

资源结构如下:

其实Windows,主要用了两个文件,hidapi文件夹下的头文件:hidapi.h,wendows文件夹下的,hid.c资源文件,其实windows文件下有测试工程,自己可以测试下。

在上边文章里说,需要编译dll,放入工程下来调用,其实没必要,你已经拿到源码,直接把上述提到的两个文件加入到自己的工程文件里,直接调用接口就可以。

注意事项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SetupAPI.lib库记得添加到附加库目录,否则会提示为未识别符号。

因为在源码里边没有包含,所以需要注意自己手动在附加库里边添加。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
hid.c里边添加
#pragma comment(lib,"SetupAPI.lib")

因为只是查询设备信息,所以只用了一下几个相关函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int HID_API_EXPORT hid_init(void) //驱动初始化
static HANDLE open_device(const char *path, BOOL enumerate) //打开设备,enumerate打开方式,只读,只写
int HID_API_EXPORT hid_exit(void)//退出
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) //获取设备相关信息
void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)//资源信息结构体释放
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) //根据HID,PID,序列号,打开设备

设备信息结构体(链表) :hid_device_info:驱动路径,VID,PID,序列号,设备发行号,生产厂商,设备名称,设备使用页,接口编号

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
		/** hidapi info structure */
		struct hid_device_info {
			/** Platform-specific device path */
			char *path;
			/** Device Vendor ID */ 
			unsigned short vendor_id;
			/** Device Product ID */
			unsigned short product_id;
			/** Serial Number */  
			wchar_t *serial_number;
			/** Device Release Number in binary-coded decimal,
			    also known as Device Version Number */
			unsigned short release_number;
			/** Manufacturer String */
			wchar_t *manufacturer_string;
			/** Product string */
			wchar_t *product_string;
			/** Usage Page for this Device/Interface
			    (Windows/Mac only). */
			unsigned short usage_page;
			/** Usage for this Device/Interface
			    (Windows/Mac only).*/
			unsigned short usage;
			/** The USB interface which this logical device
			    represents. Valid on both Linux implementations
			    in all cases, and valid on the Windows implementation
			    only if the device contains more than one interface. */
			int interface_number;

			/** Pointer to the next device */
			struct hid_device_info *next;
		};

下面开始说,获取设备信息函数(USB设备):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
{
	BOOL res;
	struct hid_device_info *root = NULL; /* return object */
	struct hid_device_info *cur_dev = NULL;

	/* Windows objects for interacting with the driver. */

	GUID InterfaceClassGuid = { 0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 };
	//GUID InterfaceClassGuid = {0xCA3E7AB9, 0xB4C3, 0x4AE6, 0x82, 0x51, 0x57, 0x9E, 0xF9, 0x33, 0x89, 0x0F};
	//GUID InterfaceClassGuid = {0x36fc9e60, 0xc465, 0x11cf, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 };
	//GUID InterfaceClassGuid = { 0x4d36e96cL, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 };
	SP_DEVINFO_DATA devinfo_data;
	SP_DEVICE_INTERFACE_DATA device_interface_data;
	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
	int device_index = 0;
	int i;

	if (hid_init() < 0)
		return NULL;

	/* Initialize the Windows objects. */
	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

	/* Get information for all the devices belonging to the HID class. */
	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	/* Iterate over each device in the HID class, looking for the right one. */
	
	for (;;) {
		HANDLE write_handle = INVALID_HANDLE_VALUE;
		DWORD required_size = 0;
		HIDD_ATTRIBUTES attrib;	

    res = SetupDiEnumDeviceInterfaces(device_info_set,NULL,&InterfaceClassGuid,device_index,	&device_interface_data);
		
		if (!res) {
			/* A return of FALSE from this function means that
			   there are no more devices. */
			break;
		}

		/* Call with 0-sized detail size, and let the function
		   tell us how long the detail struct needs to be. The
		   size is put in &required_size. */
		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
			&device_interface_data,
			NULL,
			0,
			&required_size,
			NULL);

		/* Allocate a long enough structure for device_interface_detail_data. */
		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);

		/* Get the detailed data for this device. The detail data gives us
		   the device path for this device, which is then passed into
		   CreateFile() to get a handle to the device. */
		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
			&device_interface_data,
			device_interface_detail_data,
			required_size,
			NULL,
			NULL);

		if (!res) {
			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
			   Continue to the next device. */
			goto cont;
		}

		/* Make sure this device is of Setup Class "HIDClass" and has a
		   driver bound to it. */
		for (i = 0; ; i++) {
			char driver_name[256];

			/* Populate devinfo_data. This function will return failure
			   when there are no more interfaces left. */
			res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
			if (!res)
				goto cont;

			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
			if (!res)
				goto cont;

			if (strcmp(driver_name, "HIDClass") == 0) {
				/* See if there's a driver bound. */
				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
				if (res)
					break;
			}
		}

		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);

		/* Open a handle to the device */
		write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);

		/* Check validity of write_handle. */
		if (write_handle == INVALID_HANDLE_VALUE) {
			/* Unable to open the device. */
			//register_error(dev, "CreateFile");
			goto cont_close;
		}		


		/* Get the Vendor ID and Product ID for this device. */
		attrib.Size = sizeof(HIDD_ATTRIBUTES);
		HidD_GetAttributes(write_handle, &attrib);
		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);

		/* Check the VID/PID to see if we should add this
		   device to the enumeration list. */
		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
		    (product_id == 0x0 || attrib.ProductID == product_id)) {

			#define WSTR_LEN 512
			const char *str;
			struct hid_device_info *tmp;
			PHIDP_PREPARSED_DATA pp_data = NULL;
			HIDP_CAPS caps;
			BOOLEAN res;
			NTSTATUS nt_res;
			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
			size_t len;

			/* VID/PID match. Create the record. */
			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
			if (cur_dev) {
				cur_dev->next = tmp;
			}
			else {
				root = tmp;
			}
			cur_dev = tmp;

			/* Get the Usage Page and Usage for this device. */
			res = HidD_GetPreparsedData(write_handle, &pp_data);
			if (res) {
				nt_res = HidP_GetCaps(pp_data, &caps);
				if (nt_res == HIDP_STATUS_SUCCESS) {
					cur_dev->usage_page = caps.UsagePage;
					cur_dev->usage = caps.Usage;
				}

				HidD_FreePreparsedData(pp_data);
			}
			
			/* Fill out the record */
			cur_dev->next = NULL;
			str = device_interface_detail_data->DevicePath;
			if (str) {
				len = strlen(str);
				cur_dev->path = (char*) calloc(len+1, sizeof(char));
				strncpy(cur_dev->path, str, len+1);
				cur_dev->path[len] = '\0';
			}
			else
				cur_dev->path = NULL;

			/* Serial Number */
			res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
			wstr[WSTR_LEN-1] = 0x0000;
			if (res) {
				cur_dev->serial_number = _wcsdup(wstr);
			}

			/* Manufacturer String */
			res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
			wstr[WSTR_LEN-1] = 0x0000;
			if (res) {
				cur_dev->manufacturer_string = _wcsdup(wstr);
			}

			/* Product String */
			res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
			wstr[WSTR_LEN-1] = 0x0000;
			if (res) {
 				cur_dev->product_string = _wcsdup(wstr);
			}

			/* VID/PID */
			cur_dev->vendor_id = attrib.VendorID;
			cur_dev->product_id = attrib.ProductID;

			/* Release Number */
			cur_dev->release_number = attrib.VersionNumber;

			/* Interface Number. It can sometimes be parsed out of the path
			   on Windows if a device has multiple interfaces. See
			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
			   search for "Hardware IDs for HID Devices" at MSDN. If it's not
			   in the path, it's set to -1. */
			cur_dev->interface_number = -1;
			if (cur_dev->path) {
				char *interface_component = strstr(cur_dev->path, "&mi_");
				if (interface_component) {
					char *hex_str = interface_component + 4;
					char *endptr = NULL;
					cur_dev->interface_number = strtol(hex_str, &endptr, 16);
					if (endptr == hex_str) {
						/* The parsing failed. Set interface_number to -1. */
						cur_dev->interface_number = -1;
					}
				}
			}
		}
cont_close:
		CloseHandle(write_handle);
cont:
		/* We no longer need the detail data. It can be freed */
		free(device_interface_detail_data);
		device_index++;
	}
	/* Close the device information handle. */
	SetupDiDestroyDeviceInfoList(device_info_set);
	return root;

}

hid_enumerate(unsigned short vendor_id, unsigned short product_id),函数思路主要为:根据GUID,获取设备信息句柄,遍历符合此信息句柄的所有设备,如果没有匹配设备,则退出,查询设备信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GUIDGUID InterfaceClassGuid = { 0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 };

自己测试,这个设备GUID,只能得到鼠标和键盘的设备信息。

根据GUID获取句柄信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

下边三个函数时获取设备接口信息,设备接口详细信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
res = SetupDiEnumDeviceInterfaces(device_info_set,NULL,&InterfaceClassGuid,device_index,&device_interface_data);
res = SetupDiGetDeviceInterfaceDetailA(device_info_set,&device_interface_data,NULL,0,	&required_size,NULL);
res = SetupDiGetDeviceInterfaceDetailA(device_info_set,&device_interface_data,	device_interface_detail_data,			required_size,	NULL,	NULL);

获取设备驱动类型{SPDRP_CLASS}:注意参数变化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);

后边是根据设备信息,获取HID,VID,然后根据相关信息获取设备详细信息,得到所需要的参数。

后来我用了另一个方法,没有找到需要的设备。

获取指定USB设备的VID PID和SerialNumber

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate_all(char * DeviceClassName)
{
	BOOL res;
	struct hid_device_info *root = NULL; /* return object */
	struct hid_device_info *cur_dev = NULL;
	/* Windows objects for interacting with the driver. */
	GUID InterfaceClassGuid = {0};
	SP_DEVINFO_DATA devinfo_data;
	SP_DEVICE_INTERFACE_DATA device_interface_data;
	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
    DWORD nSize = 0 ;
	if (hid_init() < 0)
		return NULL;

	/* Initialize the Windows objects. */
	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

	/* Get information for all the devices belonging to the HID class. */
	device_info_set = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES);
	/* Iterate over each device in the HID class, looking for the right one. */
	TCHAR szDIS[MAX_PATH]; // Device Identification Strings,
		
	for (int i = 0; SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data); i++)
	{		
		nSize = 0;
		if (!SetupDiGetDeviceInstanceId(device_info_set, &devinfo_data, szDIS, sizeof(szDIS), &nSize))
		{
			break;
		}
		// 设备识别串的前三个字符是否是"USB", 模板: USB\VID_XXXX&PID_XXXX\00000xxxxxxx
		char _cClassName[MAX_PATH] = { 0 };
		wchar_t _cDeviceName[MAX_PATH] = { 0 };
		char ClassName[MAX_PATH] = { 0 };
		int _res = SetupDiGetDeviceRegistryProperty(device_info_set, &devinfo_data, SPDRP_CLASS, NULL, _cClassName, MAX_PATH, NULL);
		sprintf(ClassName, "%ls", _cClassName);
		if (strcmp(ClassName, DeviceClassName) == 0)
		{
			int res = SetupDiGetDeviceRegistryProperty(device_info_set, &devinfo_data, SPDRP_FRIENDLYNAME, NULL, _cDeviceName, sizeof(_cDeviceName), NULL);
			struct hid_device_info *tmp = NULL;
			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
			if (cur_dev) {
				cur_dev->next = tmp;
			}
			else {
				root = tmp;
			}
			cur_dev = tmp;
			tmp->product_string = _wcsdup( _cDeviceName);
			//VID-PID
			if (strcmp(ClassName, "Camera") == 0)
			{
				tmp->vendor_id = (szDIS[8] - 0x30) * 16 * 16 * 16 + (szDIS[9] - 0x30) * 16 * 16 + (szDIS[10] - 0x30) * 16 + (szDIS[11] - 0x30);
				tmp->product_id = (szDIS[17] - 0x30) * 16 * 16 * 16 + (szDIS[18] - 0x30) * 16 * 16 + (szDIS[19] - 0x30) * 16 + (szDIS[20] - 0x30);
			}		
		//	wprintf(L"%ls\n", tmp->product_string);
		}	
	}
	free(device_interface_detail_data);
	SetupDiDestroyDeviceInfoList(device_info_set);

	return root;
}

获取本机所有设备信息;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
device_info_set = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES);

拿到设备信息,设备数量,遍历

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data)

得到设备实例路径

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SetupDiGetDeviceInstanceId(device_info_set, &devinfo_data, szDIS, sizeof(szDIS), &nSize)

样例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
USB\VID_04F2&PID_B627&MI_00\6&385EEBCF&0&0000

拿到设备类名:SPDRP_CLASS

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SetupDiGetDeviceRegistryProperty(device_info_set, &devinfo_data, SPDRP_CLASS, NULL, _cClassName, MAX_PATH, NULL);

与需求设备类名做对比,相同则获取设备名称:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (strcmp(ClassName, DeviceClassName) == 0)

获取设备名称:SPDRP_FRIENDLYNAME,注意输出宽字节问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SetupDiGetDeviceRegistryProperty(device_info_set, &devinfo_data, SPDRP_FRIENDLYNAME, NULL, _cDeviceName, sizeof(_cDeviceName), NULL);

按照标准样例,获取HID,PID,为16进制,做了一个转换处理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
tmp->vendor_id = (szDIS[8] - 0x30) * 16 * 16 * 16 + (szDIS[9] - 0x30) * 16 * 16 + (szDIS[10] - 0x30) * 16 + (szDIS[11] - 0x30);
				tmp->product_id = (szDIS[17] - 0x30) * 16 * 16 * 16 + (szDIS[18] - 0x30) * 16 * 16 + (szDIS[19] - 0x30) * 16 + (szDIS[20] - 0x30);
  • setupAPI一些相关说明
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SetupDiGetDeviceRegistryProperty(device_info_set, &devinfo_data, SPDRP_FRIENDLYNAME, NULL, _cDeviceName, sizeof(_cDeviceName), NULL);

这些参数信息为:设备管理器,里边详细信息,做对照看一下即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define SPDRP_DEVICEDESC (0x00000000)
#define SPDRP_HARDWAREID (0x00000001)
#define SPDRP_COMPATIBLEIDS (0x00000002)
#define SPDRP_UNUSED0 (0x00000003)
#define SPDRP_SERVICE (0x00000004)
#define SPDRP_UNUSED1 (0x00000005)
#define SPDRP_UNUSED2 (0x00000006)
#define SPDRP_CLASS (0x00000007)
#define SPDRP_CLASSGUID (0x00000008)
#define SPDRP_DRIVER (0x00000009)
#define SPDRP_CONFIGFLAGS (0x0000000A)
#define SPDRP_MFG (0x0000000B)
#define SPDRP_FRIENDLYNAME (0x0000000C)
#define SPDRP_LOCATION_INFORMATION (0x0000000D)
#define SPDRP_PHYSICAL_DEVICE_OBJECT_NAME (0x0000000E)
#define SPDRP_CAPABILITIES (0x0000000F)
#define SPDRP_UI_NUMBER (0x00000010)
#define SPDRP_UPPERFILTERS (0x00000011)
#define SPDRP_LOWERFILTERS (0x00000012)
#define SPDRP_BUSTYPEGUID (0x00000013)
#define SPDRP_LEGACYBUSTYPE (0x00000014)
#define SPDRP_BUSNUMBER (0x00000015)
#define SPDRP_ENUMERATOR_NAME (0x00000016)
#define SPDRP_SECURITY (0x00000017)
#define SPDRP_SECURITY_SDS (0x00000018)
#define SPDRP_DEVTYPE (0x00000019)
#define SPDRP_EXCLUSIVE (0x0000001A)
#define SPDRP_CHARACTERISTICS (0x0000001B)
#define SPDRP_ADDRESS (0x0000001C)
#define SPDRP_UI_NUMBER_DESC_FORMAT (0X0000001D)
#define SPDRP_DEVICE_POWER_DATA (0x0000001E)
#define SPDRP_REMOVAL_POLICY (0x0000001F)
#define SPDRP_REMOVAL_POLICY_HW_DEFAULT (0x00000020)
#define SPDRP_REMOVAL_POLICY_OVERRIDE (0x00000021)
#define SPDRP_INSTALL_STATE (0x00000022)
#define SPDRP_LOCATION_PATHS (0x00000023)
#define SPDRP_MAXIMUM_PROPERTY (0x00000024)
#define SPCRP_SECURITY (0x00000017)
#define SPCRP_SECURITY_SDS (0x00000018)
#define SPCRP_DEVTYPE (0x00000019)
#define SPCRP_EXCLUSIVE (0x0000001A)
#define SPCRP_CHARACTERISTICS (0x0000001B)
#define SPCRP_MAXIMUM_PROPERTY (0x0000001C)
  • 样例;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//设备描述类名 根据类名查找对应设备
#define Camera  "Camera"
#define Media   "MEDIA"
#define	Audio	"AudioEndpoint"

简单调用,放入QStringList

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
QStringList FileConsole::GetAudioDeviceNames()
{
	QStringList strDeviceNames;
	struct hid_device_info *devs, *cur_dev;
	if (hid_init())
		return{};
	devs = hid_enumerate_all(Audio);
	cur_dev = devs;
	while (cur_dev) {
		QString name = QString::fromWCharArray(cur_dev->product_string);
//		qDebug() << "  Product:      " << name;
		strDeviceNames.push_back(name);
		cur_dev = cur_dev->next;
	}
	hid_free_enumeration(devs);
	return strDeviceNames;
}
  • Qt自带设备信息获取。 因为Qt自带获取,忘记把源码上传了,直接拿帮助文档来说明。 Qt下边有两个类:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
QAudioDeviceInfo Class //音频设备信息类
QCameraInfo Class //摄像头信息类

摄像头信息类获取本地所有设备:

这是帮助文档里边的一句话:关键:两个函数,一个获取默认摄像设备信息,一个是所有设备信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
The static functions defaultCamera() and availableCameras() provide you a list of all available cameras.

遍历打印所有驱动名称,即可以根据这些信息做相关处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
  foreach (const QCameraInfo &cameraInfo, cameras)
      qDebug() << cameraInfo.deviceName();

音频设备信息获取:

帮助文档的一句话:注意几个关键词:默认输入设备,默认输出设备,所有设备信息。还有 QAudio::Mode.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
The static functions defaultInputDevice(), defaultOutputDevice(), and availableDevices() let you get a list of all available devices. Devices are fetched according to the value of mode this is specified by the QAudio::Mode enum. The QAudioDeviceInfo returned are only valid for the QAudio::Mode.
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
availableDevices(QAudio::Mode) ;

Mode的枚举参数如下

如上,遍历打印所有设备的名称。注意参数:这是QAudio::AudioOutput 所有输出音频输出设备,即还要

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
      qDebug() << "Device name: " << deviceInfo.deviceName();
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioIntput))
      qDebug() << "Device name: " << deviceInfo.deviceName();

其他问题

我把编好的exe放到其他电脑上的时候,发现并没有获取他本地的一些设备信息,不管是Qt写的还是调用windowsAPI,都没有得到,所有系统兼容问题还得随后测试,调试。

如果有结果,随后发布。

源码

这次就不放源码了,已经说明的很详细了,如果有需要,留言就可以。

其他说明,见下文:Windows设备信息获取:(摄像头,声卡为例)Qt,WindowsAPI对比说明(2)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Verilog我思我用】-generate
在使用xilinx官方例程《XAPP585》实现CameraLink接口发送或者接收数据时,有个程序还是值得学习的,下面把这段程序截出来:
碎碎思
2023/08/30
8390
【Verilog我思我用】-generate
HDLBits:在线学习Verilog(八 · Problem 35-39)
Problem 35: Always nolatches(Always nolatches)
数字积木
2021/04/15
7120
一周掌握FPGA Verilog HDL语法 day 6
大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。
FPGA技术江湖
2020/12/29
5660
一周掌握FPGA Verilog HDL语法 day 6
一周掌握FPGA Verilog HDL语法 day 7
大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。
FPGA技术江湖
2020/12/29
6680
一周掌握FPGA Verilog HDL语法 day 7
HDLBits:在线学习 Verilog (四 · Problem 15-19)
Problem 15 : Vector concatenation operator
数字积木
2021/04/15
7920
基于FPGA的模拟 I²C协议系统设计(下)
今天给大侠带来基于FPGA的 模拟 I²C 协议设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序的仿真与测试。话不多说,上货。
FPGA技术江湖
2021/05/21
7580
基于FPGA的模拟 I²C协议系统设计(下)
一周掌握FPGA Verilog HDL语法 day 6
今天给大侠带来的是一周掌握FPGA Verilog HDL 语法,今天开启第六天。
FPGA技术江湖
2025/03/27
1010
一周掌握FPGA Verilog HDL语法 day 6
【收藏】FPGA数字IC刷题58个Verilog代码及讲解(状态机、跨时钟、同步/异步FIFO、DMUX、奇数/小数分频)
牛客 Verilog 刷题入门篇1~24 + 进阶篇1~34 题解代码,所有代码均能通过测试,配合视频讲解效果更佳。本文给出代码,部分题目给出必要说明。 很多题目本身出题有些问题,着重理解题目,没必要钻牛角尖。
FPGA探索者
2022/11/01
3.1K0
【收藏】FPGA数字IC刷题58个Verilog代码及讲解(状态机、跨时钟、同步/异步FIFO、DMUX、奇数/小数分频)
一周掌握FPGA Verilog HDL语法 day 4
大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。
FPGA技术江湖
2020/12/29
1.2K0
一周掌握FPGA Verilog HDL语法 day 4
HDLBits:在线学习 Verilog (九 · Problem 40 - 44)
Problem 40 Combinational for-loop: 255-bit population count
数字积木
2021/04/15
1.1K0
FPGA:Verilog HDL程序的基本结构
一般使用Primitive(内部元件)、自定义的下层模块对电路描述。主要用于层次化设计中。
timerring
2023/02/16
4000
FPGA:Verilog HDL程序的基本结构
基于FPGA的直接扩频通信系统设计(中)Verilog 实现
今天给大侠带来直接扩频通信,由于篇幅较长,分三篇。今天带来中篇,也是第二篇,系统的 verilog 实现 。话不多说,上货。
FPGA技术江湖
2021/05/21
7150
基于FPGA的直接扩频通信系统设计(中)Verilog 实现
verilog经典教程(ps入门教程自学图解)
input关键词,模块的输入信号,比如input Clk,Clk是外面关键输入的时钟信号;
全栈程序员站长
2022/08/01
1.6K0
verilog经典教程(ps入门教程自学图解)
HDLBits:在线学习Verilog( 五 · Problem 20-24)
Problem 20: Connecting ports by position(Module pos)
数字积木
2021/04/15
8410
基于迭代单元的恢复余数开方器基于迭代单元的恢复余数开方器
基于迭代单元的恢复余数开方器 基本算法 该开方器的算法与“手算”(以前并不知道开方还有这种手算的方法)算法相似,使用迭代解决,文字描述如下 将0为余数的初值a,0作为结果初值b 将被开方数前两位{I(2m + 1),I(2m)}取出,与01比较大小。若前两位大,则{I(2m + 1),I(2m)} - 01为输出余数(a(m)),输出结果1(b(m)),否则{I(2m + 1),I(2m)}为输出余数(a(m)),输出结果0(b(m)) 将被开方数的从高位数第3,4位{I(2m - 1),I(2m - 2
月见樽
2018/04/27
1.2K0
题解 | Verilog刷题解析及对应笔试面试注意点【6-9】(涉及==和===、for展开问题等)
目的:不仅仅是解题,更多的是想从真实的FPGA和数字IC实习秋招和实际工程应用角度,解读一些【笔试面试】所注意的知识点,做了一些扩展。
FPGA探索者
2022/05/26
1.3K0
题解 | Verilog刷题解析及对应笔试面试注意点【6-9】(涉及==和===、for展开问题等)
基于迭代单元的不恢复余数开方器基于迭代单元的不恢复余数开方器
基于迭代单元的不恢复余数开方器 基本算法 与恢复余数开方器类似,不恢复余数开方器也是通过迭代完成运算的,基本算法的伪代码如下所示 Ra = 被开方数(位宽2W) Re = 余数(初值为0) Dout = 0 for i in W -> 0 { if(Re > 0) { Re = {Re,Ra[2i - 1],Ra[2i]} - {Dout,2'b01} } else { Re = {Re,Ra[2i - 1],Ra[2i]} + {Dout,2'b11} } Dout = {
月见樽
2018/04/27
1.2K0
全并行流水线移位相加乘法器
基本算法 与分时复用的移位相加类似,取消分时复用,使用面积换时间,使用流水线设计,流水线填满后可以一个时钟周期计算出一个结果 分别计算乘数的移位结果,并与被乘数对应位相与 使用加法树将结果相加 RTL代码 移位部分 固定移位单元代码如下,当被乘数第n位为1时,输出乘数移位向左移位n位的结果 module shift_unit #( parameter WIDTH = 4, parameter SHIFT_NUM = 0 )( input clk, // Clock in
月见樽
2018/04/27
1.1K0
基于FPGA的VGA/LCD显示控制器系统设计(下)
今天给大侠带来基于FPGA的VGA/LCD显示控制器设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序的仿真与测试以及总结,话不多说,上货。
FPGA技术江湖
2021/05/21
8160
题解 | Verilog刷题解析及对应笔试面试注意点【1-5】(涉及复位、有符号数问题等)
目的:不仅仅是解题,更多的是想从真实的FPGA和数字IC实习秋招和实际工程应用角度,解读一些【笔试面试】所注意的知识点,做了一些扩展。
FPGA探索者
2022/05/26
8500
题解 | Verilog刷题解析及对应笔试面试注意点【1-5】(涉及复位、有符号数问题等)
推荐阅读
相关推荐
【Verilog我思我用】-generate
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档