2008-11-20 152 views
12

我有一个通过USB连接的GSM调制解调器。调制解调器创建2个串行端口。第一个端口自动连接到调制解调器,第二个端口在设备管理器中显示为“HUAWEI Mobile Connect - 3G PC UI接口(COM6)”如何在Windows中获得COM端口的友好名称?

第二个端口用于获取调制解调器的重要信息,如信号质量;发送和接收短信;和许多其他功能。

我正在编写一个应用程序,它将包装第二个端口提供的一些功能。我需要的是确定哪个COM端口是备用端口的确定火灾方法。迭代端口并检查对“ATE0”的响应是不够的。调制解调器的端口通常是编号较小的端口,当拨号连接未激活时,它将响应“ATE0”,与第二个端口相同。

我在做的是迭代端口并检查它们的友好名称,如在设备管理器中显示的那样。这样我可以将我的应用程序中的端口连接到设备管理器中标有“HUAWEI Mobile Connect - 3G PC UI Interface(COM6)”的端口。我还没有找到任何信息可以让我以编程方式获得该名称。

回答

7

很久以前,我为客户写了一个实用程序来做这件事,但对于GPS而不是调制解调器。

我刚才看了一下,那跳跃出为可能是有帮助的位是:

GUID guid = GUID_DEVCLASS_PORTS; 

SP_DEVICE_INTERFACE_DATA interfaceData; 
ZeroMemory(&interfaceData, sizeof(interfaceData)); 
interfaceData.cbSize = sizeof(interfaceData); 

SP_DEVINFO_DATA devInfoData; 
ZeroMemory(&devInfoData, sizeof(devInfoData)); 
devInfoData.cbSize = sizeof(devInfoData); 

if(SetupDiEnumDeviceInfo(
    hDeviceInfo,   // Our device tree 
    nDevice,   // The member to look for 
    &devInfoData 
    )) 
{ 
    DWORD regDataType; 

    BYTE hardwareId[300]; 
    if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), NULL)) 
    { 
... 

(你调用一个循环此位与递增n设备)

然后

BYTE friendlyName[300]; 
     if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, friendlyName, sizeof(friendlyName), NULL)) 
     { 
      strFriendlyNames += (LPCTSTR)friendlyName; 
      strFriendlyNames += '\n'; 
     } 

它找到设备的名称。

希望这会帮助你在正确的方向。

+0

这看起来可能只是伎俩。我正在写一个测试。感谢百万:) – RichieACC 2008-11-20 11:53:43

2

发布的信息Will Dean是最有帮助的。这是最终为我工作的代码。 PInvoke类中的所有内容都是从http://www.pinvoke.net逐字记录的。我必须在这里或那里更改数据类型才能使其工作(如使用枚举而不是uint),但应该很容易理解。

internal static string GetComPortByDescription(string Description) 
{ 
    string Result = string.Empty; 
    Guid guid = PInvoke.GUID_DEVCLASS_PORTS; 
    uint nDevice = 0; 
    uint nBytes = 300; 
    byte[] retval = new byte[nBytes]; 
    uint RequiredSize = 0; 
    uint PropertyRegDataType = 0; 

    PInvoke.SP_DEVINFO_DATA devInfoData = new PInvoke.SP_DEVINFO_DATA(); 
    devInfoData.cbSize = Marshal.SizeOf(typeof(PInvoke.SP_DEVINFO_DATA)); 

    IntPtr hDeviceInfo = PInvoke.SetupDiGetClassDevs(
     ref guid, 
     null, 
     IntPtr.Zero, 
     PInvoke.DIGCF.DIGCF_PRESENT); 

    while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData)) 
    { 
     if (PInvoke.SetupDiGetDeviceRegistryProperty(
       hDeviceInfo, 
       ref devInfoData, 
       PInvoke.SPDRP.SPDRP_FRIENDLYNAME, 
       out PropertyRegDataType, 
       retval, 
       nBytes, 
       out RequiredSize)) 
     { 
      if (System.Text.Encoding.Unicode.GetString(retval).Substring(0, Description.Length).ToLower() == 
       Description.ToLower()) 
      { 
       string tmpstring = System.Text.Encoding.Unicode.GetString(retval); 
       Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); 
      } // if retval == description 
     } // if (PInvoke.SetupDiGetDeviceRegistryProperty(... SPDRP_FRIENDLYNAME ... 
    } // while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData)) 

    PInvoke.SetupDiDestroyDeviceInfoList(hDeviceInfo); 
    return Result; 
} 

我觉得行Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM"));有一点笨拙,如何清理建议,将不胜感激。

感谢您对此事的帮助请问,没有您,我仍然在搜索谷歌。

1

很高兴工作。

你可以尝试:

Regex.Match(tmpstring,@ “COM \ S \ d +”)的ToString()

您的字符串匹配。我会添加一个“using System.Text”,并且我不会用大写字母开始局部变量名称,如果我感觉真正有道理,我可能会将SetupDiDestroyDeviceInfoList放入一个终于{}子句。

+0

正则表达式看起来更优雅。有一件事我不得不改变:“COM \ s?\ d +”COM和数字之间不会有空格,所以它需要匹配0或更多。 再次感谢。 – RichieACC 2008-11-21 09:05:15

3

在确定串行端口的设备是你想要(通过查看其友好的名称,通过检查其父设备等)的人,正确的方式来获得端口的名称很可能是:

  • 调用SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ)得到HKEY到所谓的设备密钥
  • 查询为REG_SZ值“端口名”此注册表项
  • 不要忘记关闭HKEY :)

但是,这可能需要在C#中进行如此多的互操作,这甚至不好笑,所以如果你坚持字符串解析解决方案,我不会责怪你。

0

使用LiGenChen发布的方法。 ComPortSetupAPISetupDiClassGuids方法给出了最佳时间和友好名称。

+0

如果您通过链接中的更多相关信息修改了答案,这将有所帮助 – Hambone 2016-02-20 02:48:38

1

基于@Will Dean的C++版本答案。

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

void enumerateSerialPortsFriendlyNames() 
{ 
    SP_DEVINFO_DATA devInfoData = {}; 
    devInfoData.cbSize = sizeof(devInfoData); 

    // get the tree containing the info for the ports 
    HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 
               0, 
               nullptr, 
               DIGCF_PRESENT 
               ); 
    if (hDeviceInfo == INVALID_HANDLE_VALUE) 
    { 
     return; 
    } 

    // iterate over all the devices in the tree 
    int nDevice = 0; 
    while (SetupDiEnumDeviceInfo(hDeviceInfo,   // Our device tree 
           nDevice++,   // The member to look for 
           &devInfoData)) 
    { 
     DWORD regDataType; 
     DWORD reqSize = 0; 

     // find the size required to hold the device info 
     SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize); 
     BYTE hardwareId[reqSize > 1 ? reqSize : 1]; 
     // now store it in a buffer 
     if (SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), nullptr)) 
     { 
      // find the size required to hold the friendly name 
      reqSize = 0; 
      SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize); 
      BYTE friendlyName[reqSize > 1 ? reqSize : 1]; 
      // now store it in a buffer 
      if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, friendlyName, sizeof(friendlyName), nullptr)) 
      { 
       // device does not have this property set 
       memset(friendlyName, 0, reqSize > 1 ? reqSize : 1); 
      } 
      // use friendlyName here 
     } 
    } 
}