How to get extended port information when enumerating ports using Windows API

回眸只為那壹抹淺笑 提交于 2021-01-29 16:17:56

问题


I'm using some legacy code to enumerate ports on my machine:

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

Among other information, this gives me access to port name (COM*), type (FTDI for instance), VID and PID...

However, when I have many different devices based on a FTDI chip plugged, they all have the same information (SPDRP_HARDWAREID prperty reports FTDIBUS\COMPORT&VID_0403&PID_6015 or FTDIBUS\COMPORT&VID_0403&PID_6010). So I cannot discriminate who is who.

When I use a USB sniffer ("Device Monitoring Studio"), this one is able to report more relevant information withoutestablishing any connection to the ports:

Can this kind of extended information be accessed through Windows API to discriminate by name many devices using the same FTDI chip? Or must I use FTDI driver API to achieve this?


回答1:


With the help of Ben Voigt and Simon Mourier, I could achieve this, here is the piece of code:

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

        ...


来源:https://stackoverflow.com/questions/62266445/how-to-get-extended-port-information-when-enumerating-ports-using-windows-api

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!