2008-11-20 84 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 
     } 
    } 
}