WPFでBluetooth

今回はポンコツ2人組がC#のWPFでBluetoothを使ってファイルを送受信するプログラムに挑戦してみました! 開発環境はVisualStudio2019を使用し、Bluetoothのライブラリは「32feet.NETのInTheHand.Net.Bluetooth」を利用しました。バージョンは「4.1.40」です。 NuGetパッケージマネージャーで「InTheHand.Net.Bluetooth」と検索すれば表示されるのでインストールしてください。 C#初心者が制作したものなのでいろいろとおかしい部分が多いと思います。プログラムを流用する際は適宜修正してください。

※この記事は2023/11/19時点の情報です。

MainWindow.xaml
Bluetoothデバイスを表示するためのListBoxとファイル送信ボタン、ファイル受信ボタンを配置しています。

<Window x:Class="BluetoothSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Bluetooth File Transfer" Height="350" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal" Grid.Row="0" Margin="10">
            <Button Content="Send File" Width="100" Margin="5" Click="SendFileButton_Click"/>
            <Button Content="Receive File" Width="100" Margin="5" Click="ReceiveFileButton_Click"/>
        </StackPanel>

        <ListBox x:Name="DiscoveredDevicesListBox" Grid.Row="1" Margin="10"
                 DisplayMemberPath="DeviceName" SelectionMode="Single"/>
    </Grid>
</Window>

MainWindow.xaml.cs
プログラム実行前に各端末をペアリング登録しておく必要があります。Windowsの設定から実施しておいてください。 プログラムを実行するとBluetoothデバイスを検索して一覧に表示します。 一覧から相手のデバイスを選択し、受信側はファイル受信ボタンをクリックするとファイルが受信されるのを待ちます。 送信側はファイルを選択すると相手にファイルを送信します。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
using InTheHand.Net;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;

namespace BluetoothSample
{
    public partial class MainWindow : Window
    {
        private BluetoothClient _bluetoothClient;
        private readonly Guid _uuid = new Guid("00001101-0000-1000-8000-00805F9B34FB"); // SPP UUID
        private ObservableCollection<BluetoothDeviceInfo> _discoveredDevices;

        public MainWindow()
        {
            InitializeComponent();
            _bluetoothClient = new BluetoothClient();
            _discoveredDevices = new ObservableCollection<BluetoothDeviceInfo>();

            DiscoveredDevicesListBox.ItemsSource = _discoveredDevices;
            Loaded += MainWindow_Loaded; // MainWindowのLoadedイベントにハンドラを追加
        }

        private async Task DiscoverDevices()
        {
            try
            {
                IReadOnlyCollection<BluetoothDeviceInfo> devices = _bluetoothClient.DiscoverDevices();

                if (devices != null && devices.Count > 0)
                {
                    List<BluetoothDeviceInfo> deviceList = devices.ToList();

                    await Dispatcher.InvokeAsync(() =>
                    {
                        _discoveredDevices.Clear();
                        foreach (BluetoothDeviceInfo device in deviceList)
                        {
                            _discoveredDevices.Add(device);
                        }
                    });
                }
                else
                {
                    MessageBox.Show("Bluetooth デバイスが見つかりません。");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"デバイスの検出エラー: {ex.Message}");
            }
        }

        private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            await DiscoverDevices();
            await PairDevices();
        }

        private Task PairDevices()
        {
            foreach (BluetoothDeviceInfo device in _discoveredDevices)
            {
                try
                {
                    if (!device.Authenticated)
                    {
                        if (!BluetoothSecurity.PairRequest(device.DeviceAddress, null))
                        {
                            MessageBox.Show("デバイスとのペアリングに失敗しました: " + device.DeviceName);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"デバイスとのペアリングエラー {device.DeviceName}: {ex.Message}");
                }
            }

            return Task.CompletedTask;
        }

        private async void SendFileButton_Click(object sender, RoutedEventArgs e)
        {
            if (DiscoveredDevicesListBox.SelectedItem is BluetoothDeviceInfo selectedDevice)
            {
                OpenFileDialog openFileDialog = new OpenFileDialog();
                if (openFileDialog.ShowDialog() == true)
                {
                    string selectedFile = openFileDialog.FileName;
                    await SendFileOverBluetooth(selectedFile, selectedDevice);

                    // 受信側でファイルを受け入れるために受信メソッドを呼び出す
                    string saveFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "ReceivedFile.txt");
                    await ReceiveFileOverBluetooth(saveFilePath);
                }
            }
            else
            {
                MessageBox.Show("Bluetooth デバイスを選択してください。");
            }
        }

        private async void ReceiveFileButton_Click(object sender, RoutedEventArgs e)
        {
            if (DiscoveredDevicesListBox.SelectedItem is BluetoothDeviceInfo selectedDevice)
            {
                try
                {
                    var saveFileDialog = new SaveFileDialog();
                    if (saveFileDialog.ShowDialog() == true)
                    {
                        string saveFilePath = saveFileDialog.FileName;

                        MessageBox.Show("ファイル転送が開始されることを待機しています...");

                        using (var listener = new BluetoothListener(_uuid))
                        {
                            listener.Start();

                            using (var client = await Task.Run(() => listener.AcceptBluetoothClient()))
                            {
                                using (var fileStream = new FileStream(saveFilePath, FileMode.Create))
                                using (var bluetoothStream = client.GetStream())
                                {
                                    await bluetoothStream.CopyToAsync(fileStream);
                                    MessageBox.Show("ファイルは正常に受信され、次の場所に保存されました。 " + saveFilePath);
                                }
                            }

                            listener.Stop();
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"ファイル受信エラー: {ex.Message}");
                }
            }
            else
            {
                MessageBox.Show("Bluetooth デバイスを選択してください。");
            }
        }

        private async Task<bool> SendFileOverBluetooth(string filePath, BluetoothDeviceInfo device)
        {
            try
            {
                using (var fileStream = new FileStream(filePath, FileMode.Open))
                {
                    var peer = new BluetoothEndPoint(device.DeviceAddress, BluetoothService.SerialPort);

                    using (var client = new BluetoothClient())
                    {
                        client.Connect(peer);

                        var bluetoothClientStream = client.GetStream();
                        if (bluetoothClientStream != null)
                        {
                            await fileStream.CopyToAsync(bluetoothClientStream);
                            MessageBox.Show("ファイルは正常に送信されました。");
                            return true;
                        }
                        else
                        {
                            MessageBox.Show("Bluetooth 接続の確立に失敗しました。");
                            return false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"ファイル送信エラー: {ex.Message}");
                return false;
            }
        }

        private async Task<bool> ReceiveFileOverBluetooth(string saveFilePath)
        {
            try
            {
                using (var listener = new BluetoothListener(_uuid))
                {
                    listener.Start();

                    using (var client = await Task.Run(() => listener.AcceptBluetoothClient()))
                    {
                        using (var fileStream = new FileStream(saveFilePath, FileMode.Create))
                        using (var bluetoothStream = client.GetStream())
                        {
                            await bluetoothStream.CopyToAsync(fileStream);
                            MessageBox.Show("ファイルは正常に受信され、次の場所に保存されました。 " + saveFilePath);
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"ファイル受信エラー: {ex.Message}");
                return false;
            }
        }
    }
}

今回、Bluetoothデバイスの検出とファイルの送信受信を行うサンプルプログラムを簡易的に作成してみましたが、 実行した結果、一応ファイルの送受信をすることができました!

管理人情報