I made a test by listing HID and Audio Renderer devices with SetupDi* APIs with a few properties that you could compare :
GUID Guid;
HidD_GetHidGuid(&Guid);
SetupDiEnumDevices(&Guid);
const GUID KSCATEGORY_RENDER = { 0x65E8773E, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} };
const GUID KSCATEGORY_AUDIO = { 0x6994AD04, 0x93EF, 0x11D0, 0xA3, 0xCC,0x00, 0xA0,0xC9,0x22, 0x31, 0x96 };
SetupDiEnumDevices(&KSCATEGORY_RENDER);
//SetupDiEnumDevices(&KSCATEGORY_AUDIO);
with :
void GetErrorMessage(HRESULT hr, __out_opt WCHAR* pwsMessage)
{
LPVOID lpMsgBuf = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
(HRESULT_FACILITY(hr) == FACILITY_WIN32) ? HRESULT_CODE(hr) : hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpMsgBuf, 0, NULL);
if (lpMsgBuf != NULL)
{
wsprintf(pwsMessage, L"%s", lpMsgBuf);
LocalFree(lpMsgBuf);
}
}
void SetupDiEnumDevices(CONST GUID* pClassGuid)
{
HDEVINFO hDI = SetupDiGetClassDevs(pClassGuid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (INVALID_HANDLE_VALUE != hDI)
{
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD dwDeviceIndex = 0; SetupDiEnumDeviceInfo(hDI, dwDeviceIndex, &DeviceInfoData); dwDeviceIndex++)
{
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (DWORD dwMemberIndex = 0; SetupDiEnumDeviceInterfaces(hDI, &DeviceInfoData, pClassGuid, dwMemberIndex, &DeviceInterfaceData); dwMemberIndex++)
{
DWORD dwDeviceInterfaceDetailDataSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + MAX_PATH * sizeof(TCHAR);
PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)new BYTE[dwDeviceInterfaceDetailDataSize];
pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDI, &DeviceInterfaceData, pDeviceInterfaceDetailData, dwDeviceInterfaceDetailDataSize, NULL, NULL))
{
CONFIGRET cRet;
WCHAR wsText[MAX_PATH] = L"";
DEVINST hDevInst = DeviceInfoData.DevInst;
DEVINST hParentDevInst;
TCHAR wsDeviceID[MAX_DEVICE_ID_LEN];
DWORD dwRegType;
WCHAR wsPropertyBuffer[MAX_PATH] = L"";
BOOL bRet = SetupDiGetDeviceRegistryProperty(hDI, &DeviceInfoData, SPDRP_FRIENDLYNAME, &dwRegType, (BYTE*)wsPropertyBuffer, MAX_PATH, NULL);
if (bRet)
{
wsprintf(wsText, L"Name : %s\r\n", wsPropertyBuffer);
OutputDebugString(wsText);
}
else
{
bRet = SetupDiGetDeviceRegistryProperty(hDI, &DeviceInfoData, SPDRP_DEVICEDESC, &dwRegType, (BYTE*)wsPropertyBuffer, MAX_PATH, NULL);
if (bRet)
{
wsprintf(wsText, L"Name (Description) : %s\r\n", wsPropertyBuffer);
OutputDebugString(wsText);
}
}
cRet = CM_Get_Device_ID(hDevInst, wsDeviceID, sizeof(wsDeviceID) / sizeof(TCHAR), 0);
if (cRet == CR_SUCCESS)
{
wsprintf(wsText, L"\tDeviceID : %s\r\n", wsDeviceID);
OutputDebugString(wsText);
wsprintf(wsText, L"\tDevice Path : %s\r\n", pDeviceInterfaceDetailData->DevicePath);
OutputDebugString(wsText);
}
cRet = CM_Get_Parent(&hParentDevInst, hDevInst, 0);
if (cRet == CR_SUCCESS)
{
TCHAR wsParentDeviceID[MAX_DEVICE_ID_LEN];
cRet = CM_Get_Device_ID(hParentDevInst, wsParentDeviceID, sizeof(wsParentDeviceID) / sizeof(TCHAR), 0);
if (cRet == CR_SUCCESS)
{
wsprintf(wsText, L"\tParent DeviceID : %s\r\n", wsParentDeviceID);
OutputDebugString(wsText);
}
}
DEVPROPTYPE PropertyType;
WCHAR wsDevNodeProperty[MAX_PATH] = L"";
DWORD nSize = 0;
cRet = CM_Get_DevNode_Property(hDevInst, &DEVPKEY_Device_ContainerId, &PropertyType, NULL, &nSize, 0);
if (cRet == CR_BUFFER_SMALL)
{
cRet = CM_Get_DevNode_Property(hDevInst, &DEVPKEY_Device_ContainerId, &PropertyType, (PBYTE)wsDevNodeProperty, &nSize, 0);
}
if (cRet == CR_SUCCESS)
{
WCHAR wsBuffer[4096];
StringFromGUID2((REFGUID)wsDevNodeProperty, wsBuffer, ARRAYSIZE(wsBuffer));
wsprintf(wsText, L"\tContainer Id : %s\r\n", wsBuffer);
OutputDebugString(wsText);
}
PropertyType = NULL;
nSize = 0;
cRet = CM_Get_DevNode_Property(hDevInst, &DEVPKEY_Device_Manufacturer, &PropertyType, NULL, &nSize, 0);
if (cRet == CR_BUFFER_SMALL)
{
cRet = CM_Get_DevNode_Property(hDevInst, &DEVPKEY_Device_Manufacturer, &PropertyType, (PBYTE)wsDevNodeProperty, &nSize, 0);
}
if (cRet == CR_SUCCESS)
{
wsprintf(wsText, L"\tManufacturer : %s\r\n", wsDevNodeProperty);
OutputDebugString(wsText);
}
HANDLE hFile = CreateFile(pDeviceInterfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
WCHAR wsVendorString[MAX_PATH] = L"";
HIDD_ATTRIBUTES attributes;
attributes.Size = sizeof(HIDD_ATTRIBUTES);
BOOL bRet = HidD_GetAttributes(hFile, &attributes);
if (bRet)
{
// https://github.com/microsoft/Windows-driver-samples/blob/main/usb/usbview/vndrlist.h
switch (attributes.VendorID)
{
case 0x045E:
{
lstrcpy(wsVendorString, L"Microsoft Corporation");
}
break;
case 0x0955:
{
lstrcpy(wsVendorString, L"NVIDIA");
}
break;
case 0x0D8C:
{
lstrcpy(wsVendorString, L"C-Media Electronics, Inc.");
}
break;
default:
wsprintf(wsVendorString, L"0x%4X", attributes.VendorID);
}
wsprintf(wsText, L"\tHid Vendor : %s\r\n", wsVendorString);
OutputDebugString(wsText);
}
CloseHandle(hFile);
}
else
{
DWORD nError = GetLastError();
WCHAR wsMessage[MAX_PATH] = L"";
GetErrorMessage(nError, wsMessage);
wsprintf(wsText, L"\tCreateFile Error : %d = %s\r\n", nError, wsMessage);
OutputDebugString(wsText);
}
}
delete[] pDeviceInterfaceDetailData;
}
}
SetupDiDestroyDeviceInfoList(hDI);
}
}