GattServiceProviderを使用したアドバタイジングパケット内のLocal Nameの変更方法について

SS 20 評価のポイント
2024-02-02T05:27:06.62+00:00

Windows10のPCをBLEのGATTサーバーとして機能させるようなWPFアプリケーションを開発しています。

GATTサーバーとして機能させるために、以下のようにmicrosoft.windows.sdk.contractsをNuGetより取得し、GattServiceProviderを使用しています。

(Guidの値は伏せています)

private static GattServiceProvider serviceProvider = null;
private static GattLocalCharacteristicResult localCharacteristicResult = null;

private async void StartGattServiceProviderAdvertisingParameters()
{
         var gattServiceProviderResult = await GattServiceProvider.CreateAsync(new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));
         if (gattServiceProviderResult.Error != BluetoothError.Success)
         {
                 MessageBox.Show("GATT Serviceの起動に失敗");
                 Console.WriteLine("GATT Serviceの起動に失敗(Bluetooth LE対応デバイスがない?)");
                 return false;             
         }

         serviceProvider = gattServiceProviderResult.ServiceProvider;

         GattLocalCharacteristicParameters cReadWriteParam = new GattLocalCharacteristicParameters
         {
                 CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Write | GattCharacteristicProperties.Notify, //読み込み & 書き込み & 通知購読可能
                 ReadProtectionLevel = GattProtectionLevel.Plain, //誰でも読み込み可能
                 WriteProtectionLevel = GattProtectionLevel.Plain, //誰でも書き込み可能
                 UserDescription = "cReadWrite" //ユーザーに見える説明(BLEツールを使って読むことができる)
         };

             //定義した情報をもとに、指定のUUIDでサービスに登録する
             localCharacteristicResult = await serviceProvider.Service.CreateCharacteristicAsync(new Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"), cReadWriteParam);
              //読込が発生したときのコールバック定義
             localCharacteristicResult.Characteristic.ReadRequested += Characteristic_ReadRequested;
              //書き込みが発生したときのコールバック定義             localCharacteristicResult.Characteristic.WriteRequested += Characteristic_WriteRequested;
              //購読者の増減が発生したときのコールバック定義             localCharacteristicResult.Characteristic.SubscribedClientsChanged += Characteristic_SubscribedClientsChanged;

              GattServiceProviderAdvertisingParameters serviceProviderAdvertisingParameters = new GattServiceProviderAdvertisingParameters
             {
                 IsConnectable = true, //接続可能
                 IsDiscoverable = true //検出可能
             };
            
         serviceProvider.StartAdvertising(_serviceProviderAdvertisingParameters);
         return true;
}

ここからが本題ですが、アプリの中でPCから発信するアドバタイズパケットのLocal Nameを途中で変更したく、 以下のように、Microsoft.Win32.RegistryKeyを使用して、PCのBluetoothデバイス名を変更(設定)しています。

public static void ChangePCBluetoothDeviceName()
        {
             //Windows Management Instrumentation (WMI) を使ってプラグ アンド プレイ デバイスを取得
             ManagementObjectSearcher searchSerial = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE Service='BTHUSB'");

             foreach (ManagementObject obj in searchSerial.Get())
             {
                 //string name = obj["Name"] as string; // デバイスマネージャーに表示されている機器名
                 string classGuid = obj["ClassGuid"] as string; // デバイスのGUID
                 string devicePass = obj["DeviceID"] as string; // デバイスインスタンスパス
                 string service = obj["Service"] as string; // デバイスのサービス
                 if (classGuid != null && devicePass != null)
                 {
                     // デバイスインスタンスパスからUSB Bluetoothの デバイスを抽出
                     // {e0cbf06c-cd8b-4647-bb8a-263b43f0f974}がその固定値
                     // StringComparison:文字列比較の際の動作を指定するための列挙型で、InvariantCultureで、特定の言語および国・地域に依存しないカルチャを指定する
                     if (String.Equals(classGuid, "{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}", StringComparison.InvariantCulture))
                     {
                         // デバイスインスタンスパスからデバイスIDを2段階で抜き出す
                         string[] tokens = devicePass.Split('\\');
                          //BTHUSBで自身のBluetoothデバイス(インテルワイヤレスBluetoothなど)を指定
                         if (service == "BTHUSB" && tokens[0] == "USB")
                         {
                             string path = @"SYSTEM\CurrentControlSet\Enum\";
                             foreach (string token in tokens)
                             {
                                 path += token + @"\";
                             }
                             path += "Device Parameters";

                              //レジストリからデバイス名(Local Name)を取得する。
                             //registryKeyがnullだとpathに合致したレジストリがない、ということ
                             registryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(path, true);
                              //LocalNameの設定がある
                             if (registryKey != null)
                             {
                             }
                             else
                             {
                                 registryKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(path, true);                                 
                             }

                             byte[] ascii = Encoding.ASCII.GetBytes(newName);
                             registryKey.SetValue("Local Name", ascii2);
                             registryKey.Flush();
                             registryKey.Close();
                             return;
                         }
                     }
                 }
             }
          }

しかし、設定をし直した後にアドバタイズを再開すると、 アドバタイジングパケットのLocal Nameに変更後の値が反映されたりされなかったりと動作が安定しません。 PCのBluetoothデバイス名を変更後、PCのBluetoothのオンオフを切り替えすることも試しています。 ・アドバタイジングパケット(GattServiceProvider)のLocal Nameに変更が反映されたりされなかったりするのはなぜか ・そもそも、GattServiceProviderはどこの値を使用しているのか ・アプリケーション内でLocal Nameを確実に変更できる方法はあるのか という点をご教授頂きたいです。 よろしくお願いいたします。

Windows 10
Windows 10
パーソナル コンピューターとタブレットで実行される Microsoft オペレーティング システム。
100 件の質問
Visual Studio
Visual Studio
Windows、Web、モバイル デバイス用のアプリケーションを構築するための統合開発ツールの Microsoft スイートのファミリ。
88 件の質問
C#
C#
C 言語ファミリをルーツとし、コンポーネント指向プログラミングのサポートを含む、オブジェクト指向およびタイプセーフのプログラミング言語。
32 件の質問
0 件のコメント コメントはありません
{count} 件の投票

承認済みの回答
  1. gekka 9,666 評価のポイント MVP
    2024-02-02T11:25:48.6633333+00:00

    レジストリに値を書き込んだとしても、その値を読み取って使用しているプログラムは変更されたことを知ることがないので、かってに反映されることはないです。
    # メモ帳が開いているテキストファイルを他のプログラムが書き換えても、メモ帳に表示されている文字列は勝手に新ファイルの内容にはならないのと同じです。

    デバイスマネージャーの詳細設定で変更した場合は、そのパネルはデバイスドライバーが作っているので、そこで変更されたことはドライバーが知ることは可能であり、ドライバー次第で変更が即時反映されることもあるでしょう。

    そもそも、そのレジストリもWindowsの標準のBLEドライバが使っているだけで、他のドライバを使っていたら動く保証はないでしょう。

    どうしてもやりたくて他のBLE通信も止まってもいいなら、レジストリを書き換えたら、PnpUtilDevconを使ってデバイスを再起動させれば反映されるでしょう。

    pnputil /restart-device "USB\VID_############################"
    devcon.exe" restart "@USB\VID_############################"
    

    BluetoothFindFirstRadioBluetoothGetRadioInfoを使えばBLUETOOTH_RADIO_INFOが得られるので、これのszNameをポーリングで監視してください。外部プログラムの呼び出しがダメならDevconはソースコードが公開されているので、restartと同等の処理をSetupAPIをつかって実装しなおしてください。

    1 人がこの回答が役に立ったと思いました。

0 件の追加の回答

並べ替え方法: 最も役に立つ

お客様の回答

回答は、質問作成者が [承諾された回答] としてマークできます。これは、ユーザーが回答が作成者の問題を解決したことを知るのに役立ちます。