【问题标题】:How to get extended port information when enumerating ports using Windows API使用 Windows API 枚举端口时如何获取扩展端口信息
【发布时间】:2023-04-04 20:19:01
【问题描述】:

我正在使用一些遗留代码来枚举我机器上的端口:

#include <windows.h>
#include <devguid.h>
#include <setupapi.h>

#include <string>
#include <iostream>
#include <assert.h>

bool GetTextProperty( std::string& sProperty, 
                      HDEVINFO dev, 
                      _SP_DEVINFO_DATA* pDeviceInfoData,
                      DWORD prop )
{
    char szBuf[MAX_PATH];
    DWORD iPropertySize = 0;
    if (SetupDiGetDeviceRegistryProperty(dev, pDeviceInfoData,
                                         prop, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
    {
        sProperty = szBuf;
        assert( iPropertySize >= sProperty.size() + 1 );
        return true;
    }     
    return false;
}

inline bool readRegistryKeyValue( HKEY hKey, const std::string& key, std::string& value )
{
    bool res = false;
    CHAR szBuffer[512];
    DWORD dwBufferSize = sizeof(szBuffer);
    ULONG nError = RegQueryValueEx(hKey, key.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
    if (ERROR_SUCCESS == nError)
    {
        value = szBuffer;
        res = true;
    }
    return res;
}

void ListPorts()
{
    HDEVINFO        hDevInfo;
    SP_DEVINFO_DATA DeviceInfoData;
    DWORD           i;

    hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0L, 0L, DIGCF_PRESENT);
    if ( hDevInfo == INVALID_HANDLE_VALUE )
    {
        //Medoc_ReportError(MEDOC_ERROR_HARDWARE_DRIVER_API_FAILED,
        //                  &hDevInfo, sizeof hDevInfo);
        assert( false );
    }
    else
    {
        // Enumerate through all devices in Set.
        DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
        for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData) != 0; i++)
        {
            char szBuf[MAX_PATH];
            short wImageIdx   = 0;
            short wItem       = 0;
            DWORD iPropertySize;

            if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData,
                                                 SPDRP_FRIENDLYNAME, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
            {
                std::cout << "Smart name: " << szBuf << std::endl;

                HKEY hKey = SetupDiOpenDevRegKey(
                                hDevInfo,
                                &DeviceInfoData,
                                DICS_FLAG_GLOBAL,
                                0,
                                DIREG_DEV,
                                KEY_READ );
                if ( hKey )
                {
                    std::string portName;
                    readRegistryKeyValue( hKey, "PortName", portName );
                    std::cout << "Port name: " << szBuf << std::endl;

                    for ( DWORD prop = 0; prop != SPDRP_MAXIMUM_PROPERTY; ++prop )
                    {
                        std::string temp;
                        GetTextProperty( temp, hDevInfo, &DeviceInfoData, prop );
                        std::cout << prop << " : " << temp << std::endl;
                    }

                    RegCloseKey(hKey);
                }
            }            
        }
    }

    // Cleanup
    SetupDiDestroyDeviceInfoList(hDevInfo);
}

int main( int argc, char* argv[] )
{
    ListPorts();
    return 0;
}

除其他信息外,这让我可以访问端口名称 (COM*)、类型(例如 FTDI)、VIDPID...

但是,当我插入许多基于 FTDI 芯片的不同设备时,它们都具有相同的信息(SPDRP_HARDWAREID prperty 报告FTDIBUS\COMPORT&amp;VID_0403&amp;PID_6015FTDIBUS\COMPORT&amp;VID_0403&amp;PID_6010)。所以我分不清谁是谁。

当我使用 USB 嗅探器(“Device Monitoring Studio”)时,它能够报告更多相关信息,而无需与端口建立任何连接:

是否可以通过 Windows API 访问这种扩展信息,以通过名称区分使用相同 FTDI 芯片的许多设备?还是我必须使用 FTDI 驱动程序 API 来实现这一点?

【问题讨论】:

  • 您在屏幕截图中显示的内容是否与来自SPDRP_FRIENDLYNAME 的结果不匹配?也许从父级而不是从虚拟 COM 端口本身获取友好名称?但它仍然不会是独一无二的,正如您的屏幕截图所示......
  • GUID_DEVCLASS_PORTS 将为您提供 LPT1、COM1 等。如果您需要 USB 控制器,您可以使用 GUID_DEVCLASS_USB。
  • @BenVoigt: SPDRP_FRIENDLYNAME 给了我USB Serial Port (COM12) 这不是那么友好;-)。我不是在寻找唯一的名称,而是比“FTDI”更多的信息。 “父母”是什么意思?
  • @SimonMourier:当使用GUID_DEVCLASS_USB 时,我只有一个设备 (USBXHCI),而我连接了 3 个设备。所以这无济于事。
  • 是的,因为您的循环在不使用 GUID_DEVCLASS_PORTS 时退出得太早,我已经修改了您的程序(并且也更改为 unicode):pastebin.com/raw/UzbWS07D,它似乎可以工作。

标签: c++ windows winapi usb ftdi


【解决方案1】:

在 Ben Voigt 和 Simon Mourier 的帮助下,我可以做到这一点,下面是一段代码:

// More includes:
#include <initguid.h>
#include <devpkey.h>
#include <cfgmgr32.h>
// A new dependency:
#pragma comment (lib, "Cfgmgr32.lib")

bool GetDeviceProperty( const std::string& what, 
                        DEVINST dev, 
                        DEVPROPKEY prop )
{
    char szDeviceBuf[MAX_PATH];
    DEVPROPTYPE type;
    ULONG iDevicePropertySize = MAX_PATH;
    if ( CM_Get_DevNode_PropertyW(dev,
                                  &prop,
                                  &type,
                                  (PBYTE) szDeviceBuf,
                                  &iDevicePropertySize,
                                  0) == CR_SUCCESS )
    {
        wchar_t* txt = (wchar_t*) szDeviceBuf;
        std::wstring ws(txt);
        std::cout << what << " : " << std::string(ws.begin(), ws.end()) << std::endl;
        return true;
    }
    else
    {
        return false;
    }
}

void ListPorts()
{
        ...

                DEVINST devInstParent;
                auto status = CM_Get_Parent(&devInstParent, DeviceInfoData.DevInst, 0);
                if (status == CR_SUCCESS) 
                {
                    ShowDeviceProperty( "Bus reported device description", devInstParent, DEVPKEY_Device_BusReportedDeviceDesc );
                    ShowDeviceProperty( "Device description", devInstParent, DEVPKEY_Device_DeviceDesc );
                }
                else 
                {
                    continue;
                }

        ...

【讨论】:

  • 您还需要知道的是,某些 FTDI 设备在单个芯片上具有 2 个或 4 个串行端口。然后设备管理器“查看->按连接”将显示3层层次结构... USB设备,“USB串行转换器”功能和串行端口,现在总线报告的设备描述在串行的祖父母上港口。要知道调用CM_GetParent 的次数,您可以使用“枚举器”属性...对于您要查找的项目,它将是“USB”,并带有有意义的“总线报告设备描述”,中间层将有“FTDIBUS”作为枚举器。
  • @BenVoigt:感谢您的评论,这正是我使用 FTDI 设备观察到的,它有 2 个串行端口。
猜你喜欢
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-07
  • 1970-01-01
  • 2014-12-26
  • 1970-01-01
相关资源
最近更新 更多