web-dev-qa-db-ja.com

WindowsでCOMポートのわかりやすい名前を取得するにはどうすればよいですか?

USB経由でGSMモデムを接続しています。モデムは2つのシリアルポートを作成します。 1つ目は自動的にモデムに接続され、2つ目はデバイスマネージャーに「HUAWEIモバイルコネクト-3G PC UIインターフェイス(COM6)」と表示されます。

2番目のポートは、信号品質などの重要な情報をモデムから取得するために使用されます。テキストメッセージを送受信するため。および他の機能のホスト全体。

私は、2番目のポートによって提供される機能のいくつかをまとめるアプリケーションを書いています。私が必要としているのは、どのCOMポートがスペアポートであるかを特定する確実な方法です。ポートを繰り返し、「ATE0」への応答を確認するだけでは不十分です。モデムのポートは通常小さい番号のポートであり、ダイヤルアップ接続がアクティブでない場合、2番目のポートと同じように「ATE0」に応答します。

私が考えていたのは、デバイスマネージャーに表示されるように、ポートを繰り返し、フレンドリ名を確認することです。そうすれば、アプリケーションのポートを、デバイスマネージャーの「HUAWEIモバイルコネクト-3G PC UIインターフェイス(COM6)」というラベルの付いたポートにリンクできます。プログラムでその名前を取得できる情報はまだ見つかりません。

14
RichieACC

シリアルポートデバイスが必要なデバイスであると判断した後(フレンドリ名を確認したり、親デバイスを確認したりするなど)、ポート名を取得する適切な方法は次のようになります。

  • SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ)を呼び出して、HKEYをいわゆるデバイスキーに取得します
  • このレジストリキーにREG_SZ値 "PortName"を照会します
  • HKEYを閉じることを忘れないでください:)

ただし、これにはC#で非常に多くの相互運用が必要になる可能性があり、面白くもないので、文字列解析ソリューションを続けても責任はありません。

3
Ilya

@WillDeanの回答に基づく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 = new BYTE[(reqSize > 1) ? reqSize : 1];
        // now store it in a buffer
        if (SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId) * reqSize, nullptr))
        {
            // find the size required to hold the friendly name
            reqSize = 0;
            SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize);
            BYTE* friendlyName = new BYTE[(reqSize > 1) ? reqSize : 1];
            // now store it in a buffer
            if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, friendlyName, sizeof(friendlyName) * reqSize, nullptr))
            {
                // device does not have this property set
                memset(friendlyName, 0, reqSize > 1 ? reqSize : 1);
            }
            // use friendlyName here
            delete[] friendlyName;
        }
        delete[] hardwareId;
    }
}
2
Leherenn

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"));の行は少し不器用だと思いますが、クリーンアップする方法についての提案をいただければ幸いです。

この問題であなたの助けをありがとうウィル、あなたなしで、私はまだグーグルを検索しているでしょう。

2
RichieACC

それがうまくいったことをうれしく思います。

あなたは試すことができます:

Regex.Match(tmpstring、@ "COM\s\d +")。ToString()

文字列照合用。

.NETスタイルのポイントとして、「using System.Text」を追加し、ローカル変数名を大文字で開始しません。本当に美徳を感じている場合は、SetupDiDestroyDeviceInfoListをfinally {}句に配置します。 。

1
Will Dean

LiGenChen によって投稿されたメソッドを使用しました。 ComPortSetupAPISetupDiClassGuidsメソッドは、最高の時間とわかりやすい名前を付けました。

0
Eqbal Khan