Closed itas109 closed 3 years ago
compile with mingw730_64(Qt5.12.9)
this application listTest.exe can enum port info with five method.
Maybe compiler or Windows 10 system version problem
some win10 version with this problem :
windows 10 Home Edition CN 10.0.18363
windows 10 ProfessionalEdition CN 10.0.18363
Maybe bluetooth problem.
设备管理器中有蓝牙转的串口会出现只能枚举部分串口的情况
Standard Serial over Bluetooth link(COM5)
蓝牙链接上的标准串行(COM5)
also maybe SetupDiGetClassDevsW use error.
v4.1.0
// Return only devices that are currently present in a system
// The GUID_DEVINTERFACE_COMPORT device interface class is defined for COM ports. GUID
// {86E0D1E0-8089-11D0-9CE4-08003E301F73}
SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
https://docs.microsoft.com/zh-cn/windows/win32/api/setupapi/nf-setupapi-setupdigetclassdevsw
WINSETUPAPI HDEVINFO SetupDiGetClassDevsW(
const GUID *ClassGuid,
PCWSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
when has bluetooth serial port.
DEFINE_GUID(GUID_DEVINTERFACE_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
enum success
CSerialPort\examples\CommNoGui\compile-MinGW.bat
compileenum success
CSerialPort\examples\CommNoGui\compile-MSVC.bat
compilemfc has same problem
enum error at
SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, pDetData, dwDetDataSize, NULL, &devdata)
GetLastError() return 122
ERROR_INSUFFICIENT_BUFFER
122 (0x7A)
The data area passed to a system call is too small.
122 - 传递到系统调用的数据区太小
when enum bluetooth serial port SetupDiGetDeviceInterfaceDetail return false
当枚举蓝牙的串口时,SetupDiGetDeviceInterfaceDetail 返回错误,使得枚举结束导致枚举不全
DWORD requiredSize = 0;
// first time get buffer size
SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, NULL, NULL, &requiredSize, NULL);
// second time require devdata
SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, pDetData, requiredSize, NULL, &devdata);
use SetupDiEnumDeviceInfo
instead of SetupDiGetDeviceInterfaceDetail
use SetupDiEnumDeviceInfo
instead of SetupDiGetDeviceInterfaceDetail
is ok.
bool enumDetailsSerialPorts(vector<SerialPortInfo> &portInfoList)
{
// https://docs.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdienumdeviceinfo
bool bRet = false;
SerialPortInfo m_serialPortInfo;
std::string strFriendlyName;
std::string strPortName;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL;
// Return only devices that are currently present in a system
// The GUID_DEVINTERFACE_COMPORT device interface class is defined for COM ports. GUID
// {86E0D1E0-8089-11D0-9CE4-08003E301F73}
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (INVALID_HANDLE_VALUE != hDevInfo)
{
SP_DEVINFO_DATA devInfoData;
// The caller must set DeviceInfoData.cbSize to sizeof(SP_DEVINFO_DATA)
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &devInfoData); i++)
{
// get port name
TCHAR portName[256];
HKEY hDevKey = SetupDiOpenDevRegKey(hDevInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (INVALID_HANDLE_VALUE != hDevKey)
{
DWORD dwCount = 255; // DEV_NAME_MAX_LEN
RegQueryValueEx(hDevKey, _T("PortName"), NULL, NULL, (BYTE *)portName, &dwCount);
RegCloseKey(hDevKey);
}
// get friendly name
TCHAR fname[256];
SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)fname,
sizeof(fname), NULL);
#ifdef UNICODE
strPortName = wstringToString(portName);
strFriendlyName = wstringToString(fname);
#else
strPortName = std::string(portName);
strFriendlyName = std::string(fname);
#endif
// remove (COMxx)
strFriendlyName = strFriendlyName.substr(0, strFriendlyName.find(("(COM")));
m_serialPortInfo.portName = strPortName;
m_serialPortInfo.description = strFriendlyName;
portInfoList.push_back(m_serialPortInfo);
}
if (ERROR_NO_MORE_ITEMS == GetLastError())
{
bRet = true; // no more item
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return bRet;
}
https://docs.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices
this code is also ok. but use SetupDiEnumDeviceInfo
instead of SetupDiGetDeviceInterfaceDetail
bool enumDetailsSerialPorts(vector<SerialPortInfo> &portInfoList)
{
// https://docs.microsoft.com/en-us/windows/win32/api/setupapi/
bool bRet = false;
SerialPortInfo m_serialPortInfo;
std::string strFriendlyName;
std::string strPortName;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL;
// Return only devices that are currently present in a system
// The GUID_DEVINTERFACE_COMPORT device interface class is defined for COM ports. GUID
// {86E0D1E0-8089-11D0-9CE4-08003E301F73}
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (INVALID_HANDLE_VALUE != hDevInfo)
{
BOOL bOk = TRUE;
SP_DEVICE_INTERFACE_DATA did = {0};
did.cbSize = sizeof(did);
for (DWORD idev = 0; bOk; idev++)
{
// enumerates the device interfaces that are contained in a device information set
bOk = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_COMPORT, idev, &did);
if (bOk)
{
SP_DEVINFO_DATA devdata;
devdata.cbSize = sizeof(SP_DEVINFO_DATA);
// get detailed information about an interface
DWORD requiredSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, NULL, NULL, &requiredSize, NULL);
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredSize);
pDetData->cbSize = sizeof(*pDetData);
bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo, &did, pDetData, requiredSize, &requiredSize, &devdata);
if (bOk)
{
TCHAR fname[256];
// retrieves a specified Plug and Play device property (include friendlyname etc.)
BOOL bSuccess = SetupDiGetDeviceRegistryProperty(hDevInfo, &devdata, SPDRP_FRIENDLYNAME, NULL,
(PBYTE)fname, sizeof(fname), NULL);
TCHAR portName[256];
// get port name
HKEY hDevKey = SetupDiOpenDevRegKey(hDevInfo, &devdata, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (INVALID_HANDLE_VALUE != hDevKey)
{
DWORD dwCount = 255; // DEV_NAME_MAX_LEN
RegQueryValueEx(hDevKey, _T("PortName"), NULL, NULL, (BYTE *)portName, &dwCount);
RegCloseKey(hDevKey);
bSuccess &= TRUE;
}
else
{
bSuccess &= FALSE;
}
if (bSuccess)
{
#ifdef UNICODE
strPortName = wstringToString(portName);
strFriendlyName = wstringToString(fname);
#else
strPortName = std::string(portName);
strFriendlyName = std::string(fname);
#endif
// remove (COMxx)
strFriendlyName = strFriendlyName.substr(0, strFriendlyName.find(("(COM")));
m_serialPortInfo.portName = strPortName;
m_serialPortInfo.description = strFriendlyName;
portInfoList.push_back(m_serialPortInfo);
bRet = true;
}
}
else
{
bRet = false;
}
}
else if (ERROR_NO_MORE_ITEMS == GetLastError())
{
bRet = false; // Enumeration failed
break;
}
else
{
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
return bRet;
}
CEnumerateSerial v1.40 A C++ class to enumerate serial ports
http://www.naughter.com/enumser.html
Notice: some method is wrong
CommName | friendlyName | PhysicalDeviceObjectName |
---|---|---|
COM1 | ELTIMA Virtual Serial Port | \Device\VSerial7_0 |
COM2 | ELTIMA Virtual Serial Port | \Device\VSerial7_1 |
COM4 | Prolific USB-to-Serial Comm Port | \Device\ProlificSerial0 |
COM6 | com0com - serial port emulator | \Device\com0com11 |
COM7 | com0com - serial port emulator | \Device\com0com21 |
CNCA0 | com0com - serial port emulator CNCA0 | \Device\com0com10 |
CNCB0 | com0com - serial port emulator CNCB0 | \Device\com0com20 |
CreateFile method reports
COM1
COM2
COM4
COM6
COM7
Time taken: 391 ms
QueryDosDevice method reports
COM1
COM6
COM2
COM7
COM4
Time taken: 0 ms
GetDefaultCommConfig method reports
COM1
COM2
COM4
COM6
COM7
Time taken: 6312 ms
Device Manager (SetupAPI - GUID_DEVINTERFACE_COMPORT) reports
COM6 <com0com - serial port emulator>
COM4 <Prolific USB-to-Serial Comm Port>
COM1 <Virtual Serial Port 7 (Eltima Software)>
COM7 <com0com - serial port emulator>
COM2 <Virtual Serial Port 7 (Eltima Software)>
Time taken: 16 ms
Device Manager (SetupAPI - Ports Device information set) reports
COM1 <Virtual Serial Port 7 (Eltima Software)>
COM2 <Virtual Serial Port 7 (Eltima Software)>
COM4 <Prolific USB-to-Serial Comm Port>
COM6 <com0com - serial port emulator>
COM7 <com0com - serial port emulator>
Time taken: 15 ms
EnumPorts method reports
COM1 <本地端口>
COM2 <本地端口>
COM3 <本地端口>
COM4 <本地端口>
COM5 <本地端口>
COM6 <本地端口>
COM7 <本地端口>
Time taken: 0 ms
WMI method reports
COM6 <com0com - serial port emulator (COM6)>
COM7 <com0com - serial port emulator (COM7)>
Time taken: 47 ms
ComDB method reports
CEnumerateSerial::UsingComDB failed, Error:5
Time taken: 0 ms
Registry method reports
CNCA0
CNCB0
COM1
COM2
COM6
COM7
COM4
Time taken: 0 ms
UsingGetCommPorts method reports
COM1
COM2
COM6
COM7
COM4
Time taken: 0 ms
Describe the bug some win10 could not enum all avaiable ports with function availablePortInfos()
To Reproduce call function availablePortInfos()
Desktop (please complete the following information):
Additional context Add any other context about the problem here.