10

我的设备管理器中列出了以下串行端口:

  • COM3
  • COM4 (BT)
  • COM5 (BT)
  • COM6 (GlobeTrotter MO67xx - 控制接口)
  • COM7 (GlobeTrotter MO67xx - GPS 控制接口)
  • COM8 (GlobeTrotter MO67xx - GPS 数据接口)
  • COM9(GlobeTrotter MO67xx - 诊断接口)
  • COM11 (USB 串口)
  • COM12 (USB 串口)
  • COM45 (SUNIX COM 端口)
  • COM46 (SUNIX COM 端口)

SUNIX COM 端口通过内部 PCI 卡连接。USB 串行端口通过USB(FDTI 芯片)连接GlobeTrotter 端口来自通过 USB 连接的 GlobeTrotter 设备。该调制解调器还列出了一个调制解调器、一个 USB 设备和一个网络设备。

所以我有几个不同的串口来源。

我想要做的就是使用 WMI 获取包含所有这些端口的列表。

对于我的测试,我使用的是WMI Code Creator

测试1:

root\CIMV2; 查询:SELECT * FROM Win32_SerialPort只返回以下串口:

  • COM3
  • COM4
  • COM5

测试 2:

root\WMI; 查询:SELECT * FROM MSSerial_PortName只返回以下串口:

  • COM3
  • COM11
  • COM12
  • COM45
  • COM45

如何获得完整的串口列表?

4

4 回答 4

7

我找到了解决方案。

以下查询 ( root\CIMV2) 获取请求的结果:

SELECT * FROM Win32_PnPEntity WHERE ClassGuid="{4d36e978-e325-11ce-bfc1-08002be10318}"

更新

这个答案现在已经很老了。Ehen 我问它我仍然必须考虑 WinXP 并且正在使用 Windows7。由于我不再处理串行端口,因此我无法提供有关该问题的任何新信息。当时这个解决方案报告了设备管理器显示的所有端口。但我知道列出串行端口并不是那么容易,所以这个答案在所有情况下可能都不正确。

于 2014-05-14T09:56:54.807 回答
3

就我而言,我有物理串口、USB 串口和 com0com 虚拟串口。我需要全名和 COM 端口地址。

此答案中建议的查询未找到 com0com 端口。此答案中建议的查询需要管理员权限。

SELECT * FROM Win32_PnPEntity找到所有设备。它返回这样的物理设备,并且可以从以下位置解析地址Caption

Serial Port for Barcode Scanner (COM13)

但是,对于 com0com 端口Caption是这样的(无地址):

com0com - serial port emulator

SELECT * FROM Win32_SerialPort返回地址 ( DeviceID) 以及全名 ( Name)。但是,它只找到物理串口和com0com 端口,而不是USB 串口。

所以最后,我需要两个 WMI 调用:SELECT * FROM Win32_SerialPort(address is DeviceID) 和SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM%'(address can be parsed from Caption)。我已经缩小了Win32_PnPEntity调用范围,因为它只需要查找在第一次调用中没有找到的设备。

此 C++ 代码可用于查找所有串行端口:

// Return list of serial ports as (number, name)
std::map<int, std::wstring> enumerateSerialPorts()
{
    std::map<int, std::wstring> result;

    HRESULT hres;

    hres = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hres) || hres == RPC_E_CHANGED_MODE) {
        hres =  CoInitializeSecurity(
            NULL,
            -1,                          // COM authentication
            NULL,                        // Authentication services
            NULL,                        // Reserved
            RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication
            RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
            NULL,                        // Authentication info
            EOAC_NONE,                   // Additional capabilities
            NULL                         // Reserved
            );

        if (SUCCEEDED(hres) || hres == RPC_E_TOO_LATE) {
            IWbemLocator *pLoc = NULL;

            hres = CoCreateInstance(
                CLSID_WbemLocator,
                0,
                CLSCTX_INPROC_SERVER,
                IID_IWbemLocator, (LPVOID *) &pLoc);

            if (SUCCEEDED(hres)) {
                IWbemServices *pSvc = NULL;

                // Connect to the root\cimv2 namespace with
                // the current user and obtain pointer pSvc
                // to make IWbemServices calls.
                hres = pLoc->ConnectServer(
                     bstr_t(L"ROOT\\CIMV2"),  // Object path of WMI namespace
                     NULL,                    // User name. NULL = current user
                     NULL,                    // User password. NULL = current
                     0,                       // Locale. NULL indicates current
                     NULL,                    // Security flags.
                     0,                       // Authority (for example, Kerberos)
                     0,                       // Context object
                     &pSvc                    // pointer to IWbemServices proxy
                     );
                if (SUCCEEDED(hres)) {
                    hres = CoSetProxyBlanket(
                       pSvc,                        // Indicates the proxy to set
                       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
                       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
                       NULL,                        // Server principal name
                       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
                       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
                       NULL,                        // client identity
                       EOAC_NONE                    // proxy capabilities
                    );
                    if (SUCCEEDED(hres)) {
                        // Use Win32_PnPEntity to find actual serial ports and USB-SerialPort devices
                        // This is done first, because it also finds some com0com devices, but names are worse
                        IEnumWbemClassObject* pEnumerator = NULL;
                        hres = pSvc->ExecQuery(
                            bstr_t(L"WQL"),
                            bstr_t(L"SELECT Name FROM Win32_PnPEntity WHERE Name LIKE '%(COM%'"),
                            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
                            NULL,
                            &pEnumerator);

                        if (SUCCEEDED(hres)) {
                            constexpr size_t max_ports = 30;
                            IWbemClassObject *pclsObj[max_ports] = {};
                            ULONG uReturn = 0;

                            do {
                                hres = pEnumerator->Next(WBEM_INFINITE, max_ports, pclsObj, &uReturn);
                                if (SUCCEEDED(hres)) {
                                    for (ULONG jj = 0; jj < uReturn; jj++) {
                                        VARIANT vtProp;
                                        pclsObj[jj]->Get(L"Name", 0, &vtProp, 0, 0);

                                        // Name should be for example "Serial Port for Barcode Scanner (COM13)"
                                        const std::wstring deviceName = vtProp.bstrVal;
                                        const std::wstring prefix = L"(COM";
                                        size_t ind = deviceName.find(prefix);
                                        if (ind != std::wstring::npos) {
                                            std::wstring nbr;
                                            for (size_t i = ind + prefix.length();
                                                i < deviceName.length() && isdigit(deviceName[i]); i++)
                                            {
                                                nbr += deviceName[i];
                                            }
                                            try {
                                                const int portNumber = boost::lexical_cast<int>(nbr);
                                                result[portNumber] = deviceName;
                                            }
                                            catch (...) {}
                                        }
                                        VariantClear(&vtProp);

                                        pclsObj[jj]->Release();
                                    }
                                }
                            } while (hres == WBEM_S_NO_ERROR);
                            pEnumerator->Release();
                        }

                        // Use Win32_SerialPort to find physical ports and com0com virtual ports
                        // This is more reliable, because address doesn't have to be parsed from the name
                        pEnumerator = NULL;
                        hres = pSvc->ExecQuery(
                            bstr_t(L"WQL"),
                            bstr_t(L"SELECT DeviceID, Name FROM Win32_SerialPort"),
                            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
                            NULL,
                            &pEnumerator);

                        if (SUCCEEDED(hres)) {
                            constexpr size_t max_ports = 30;
                            IWbemClassObject *pclsObj[max_ports] = {};
                            ULONG uReturn = 0;

                            do {
                                hres = pEnumerator->Next(WBEM_INFINITE, max_ports, pclsObj, &uReturn);
                                if (SUCCEEDED(hres)) {
                                    for (ULONG jj = 0; jj < uReturn; jj++) {
                                        VARIANT vtProp1, vtProp2;
                                        pclsObj[jj]->Get(L"DeviceID", 0, &vtProp1, 0, 0);
                                        pclsObj[jj]->Get(L"Name", 0, &vtProp2, 0, 0);

                                        const std::wstring deviceID = vtProp1.bstrVal;
                                        if (deviceID.substr(0, 3) == L"COM") {
                                            const int portNumber = boost::lexical_cast<int>(deviceID.substr(3));
                                            const std::wstring deviceName = vtProp2.bstrVal;
                                            result[portNumber] = deviceName;
                                        }
                                        VariantClear(&vtProp1);
                                        VariantClear(&vtProp2);

                                        pclsObj[jj]->Release();
                                    }
                                }
                            } while (hres == WBEM_S_NO_ERROR);
                            pEnumerator->Release();
                        }
                    }
                    pSvc->Release();
                }
                pLoc->Release();
            }
        }
        CoUninitialize();
    }
    if (FAILED(hres)) {
        std::stringstream ss;
        ss << "Enumerating serial ports failed. Error code: " << int(hres);
        throw std::runtime_error(ss.str());
    }

    return result;
}
于 2017-11-10T11:30:23.903 回答
1

本文中使用的Win32_SerialPort类报告物理com端口,如果要枚举所有串口包括 端口,则必须使用 位于命名空间中的类。USB-Serial/COMMSSerial_PortNameroot\wmi

还可以尝试位于同一命名空间中的这些类

  • MSSerial_CommInfo
  • MSSerial_CommProperties
  • MSSerial_HardwareConfiguration
  • MSSerial_PerformanceInformation

注意:如果你想知道这个类的属性和方法,你可以使用WMI Delphi Code Creator。

于 2013-11-08T02:41:44.263 回答
1

我在尝试让应用程序找到 USB 串行设备的 COM 端口时遇到了类似的问题。

通过使用\\localhost\root\CIMV2查询范围SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0,应用程序能够通过每个返回的对象找到 COM 端口,或者通过检查设备名称来caption定位确切的端口。caption

ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(@"\\localhost\root\CIMV2", "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");

        using (comPortSearcher)
        {
            string caption = null;
            foreach (ManagementObject obj in comPortSearcher.Get())
            {
                if (obj != null)
                {
                    object captionObj = obj["Caption"];
                    if (captionObj != null)
                    {
                        caption = captionObj.ToString();
                            if (caption.Contains("CH340"))
                            {
                                _currentSerialSettings.PortName = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")", string.Empty);
                            }
                    }
                }
            }
        }

解析代码位于[C#] How to programmatically find a COM port by friendly name

于 2018-11-30T13:36:26.643 回答