Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

some win10 could not enum all avaiable ports with function availablePortInfos() #41

Closed
itas109 opened this issue Nov 18, 2020 · 8 comments
Labels

Comments

@itas109
Copy link
Owner

itas109 commented Nov 18, 2020

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):

  • OS: Win10 64bit
  • Compiler: vs2019
  • Version: 4.1.0.201010

Additional context
Add any other context about the problem here.

@itas109 itas109 added the bug label Nov 18, 2020
@itas109
Copy link
Owner Author

itas109 commented Dec 10, 2020

compile with mingw730_64(Qt5.12.9)

this application listTest.exe can enum port info with five method.

listPortTest

listPortTest-20201210.zip

@itas109
Copy link
Owner Author

itas109 commented Dec 10, 2020

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 

@itas109
Copy link
Owner Author

itas109 commented Jan 20, 2021

Maybe bluetooth problem.

设备管理器中有蓝牙转的串口会出现只能枚举部分串口的情况

Standard Serial over Bluetooth link(COM5)
蓝牙链接上的标准串行(COM5)

@itas109
Copy link
Owner Author

itas109 commented Jan 20, 2021

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
);

@itas109
Copy link
Owner Author

itas109 commented Jan 21, 2021

when has bluetooth serial port.

DEFINE_GUID(GUID_DEVINTERFACE_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);

  1. use cmake compile

enum success

  1. use CSerialPort\examples\CommNoGui\compile-MinGW.bat compile

enum success

  1. use CSerialPort\examples\CommNoGui\compile-MSVC.bat compile

mfc 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

@itas109
Copy link
Owner Author

itas109 commented Jan 21, 2021

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;
}

@itas109
Copy link
Owner Author

itas109 commented Jan 22, 2021

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;
}

@itas109
Copy link
Owner Author

itas109 commented Jan 30, 2021

CEnumerateSerial v1.40 A C++ class to enumerate serial ports

http://www.naughter.com/enumser.html

EnumSer.zip

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant