Другое

Реализация управления точкой доступа Wi-Fi в .NET Framework

Полное руководство по реализации управления точкой доступа Wi-Fi в приложениях .NET Framework на Windows 11. Включает NetworkOperatorTetheringManager, Windows Runtime Components и устранение неполадок.

Как реализовать функциональность точки доступа Wi-Fi в приложении .NET Framework для Windows 11?

Мне нужно программно запускать и останавливать точку доступа Wi-Fi из приложения .NET. Я пытался использовать пространство имен Windows.Devices.WiFi, но столкнулся с проблемами:

  1. При вызове WiFiAdapter.FindAllAdaptersAsync() я получаю ‘System.Exception: The handle is invalid.’
  2. WiFiAdapter.RequestAccessAsync() возвращает ‘DeniedBySystem’

Я понимаю, что эти ошибки указывают на проблемы с разрешениями, поэтому я попытался добавить возможности в файл package.appxmanifest с возможностями ‘wiFiControl’ и ‘onDemandHotspotControl’, но это не решило проблему.

Я хочу избежать использования loopback-адаптера, так как он предназначен для тестирования, а не для производственного использования.

Какой правильный подход к реализации управления точкой доступа Wi-Fi в приложении .NET Framework на Windows 11?

Вы можете реализовать функциональность точки доступа Wi-Fi в приложении .NET Framework для Windows 11, но вам придется обойти тот факт, что многие современные API Wi-Fi разработаны специально для приложений Universal Windows Platform (UWP). Основная проблема заключается в том, что такие API, как Windows.Devices.WiFi, требуют возможностей UWP и работают в другом контексте, чем традиционные приложения .NET Framework.

Содержание

Понимание ограничений API

Ошибки, с которыми вы сталкиваетесь - “Неверный дескриптор” (The handle is invalid) и “Отказано системой” (DeniedBySystem) - возникают потому, что API Windows.Devices.WiFi разработаны для приложений UWP и имеют специфические требования, которым традиционные приложения .NET Framework не соответствуют по умолчанию. Эти API требуют:

  • Манифест приложения UWP с правильными возможностями
  • Контекст активации Windows Runtime
  • Уровни разрешений, отличные от настольных приложений

Согласно документации Microsoft, API Windows.Devices.WiFi.WiFiAdapter является частью набора API Windows Runtime, который в первую очередь предназначен для приложений UWP, что затрудняет его прямое использование в традиционных настольных приложениях .NET Framework.

Доступные API для точки доступа Wi-Fi

Для управления точкой доступа Wi-Fi в Windows 11 доступны несколько API:

  1. WiFiOnDemandHotspotNetwork - Представляет устройство, поддерживающее функциональность точки доступа по запросу
  2. NetworkOperatorTetheringAccessPointConfiguration - Позволяет настраивать сети для раздачи интернета
  3. NetworkOperatorTetheringManager - Управляет операциями раздачи интернета

Как объясняет Microsoft, раздача интернета (tethering) позволяет устройству Windows работать как мобильная точка доступа, предоставляя интернет-соединения через Wi-Fi или Bluetooth.

Решение 1: Использование NetworkOperatorTetheringManager

Наиболее практичный подход для приложений .NET Framework - использование класса NetworkOperatorTetheringManager, к которому можно получить доступ через COM-взаимодействие или создавая оболочку Windows Runtime.

csharp
using System;
using System.Runtime.InteropServices;
using Windows.Networking.NetworkOperators;

public class HotspotManager
{
    private NetworkOperatorTetheringManager tetheringManager;
    
    public async Task InitializeHotspotAsync()
    {
        try
        {
            // Получаем первый доступный сетевой адаптер (обычно Ethernet)
            var adapters = NetworkInformation.GetConnectionProfiles();
            var selectedAdapter = adapters.FirstOrDefault(adapter => 
                adapter.NetworkAdapter != null && 
                adapter.NetworkAdapter.IanaInterfaceType == 6); // Ethernet
            
            if (selectedAdapter == null)
            {
                throw new Exception("Подходящий сетевой адаптер не найден");
            }
            
            // Создаем менеджер раздачи из профиля подключения
            tetheringManager = NetworkOperatorTetheringManager.CreateFromConnectionProfile(selectedAdapter);
            
            // Настраиваем точку доступа
            var apConfig = tetheringManager.AccessPointConfiguration;
            apConfig.Ssid = "MyHotspot";
            apConfig.Passphrase = "securepassword123";
            apConfig.IsOnDemandEnabled = true;
            
            // Применяем конфигурацию
            await tetheringManager.ConfigureAccessPointAsync(apConfig);
        }
        catch (Exception ex)
        {
            throw new Exception("Не удалось инициализировать точку доступа: " + ex.Message);
        }
    }
    
    public async Task StartHotspotAsync()
    {
        if (tetheringManager == null)
        {
            throw new InvalidOperationException("Точка доступа не инициализирована");
        }
        
        await tetheringManager.StartTetheringAsync();
    }
    
    public async Task StopHotspotAsync()
    {
        if (tetheringManager == null)
        {
            throw new InvalidOperationException("Точка доступа не инициализирована");
        }
        
        await tetheringManager.StopTetheringAsync();
    }
}

Решение 2: Использование компонентов Windows Runtime

Создайте компонент Windows Runtime, который оборачивает API UWP, и предоставьте его вашему приложению .NET Framework:

  1. Создайте новый проект компонента Windows Runtime в Visual Studio
  2. Добавьте функциональность управления точкой доступа с использованием API UWP
  3. Ссылайтесь на этот компонент из вашего приложения .NET Framework
csharp
// В проекте компонента Windows Runtime
public sealed class HotspotController
{
    public async Task<bool> StartHotspotAsync(string ssid, string password)
    {
        try
        {
            var tetheringManager = NetworkOperatorTetheringManager.CreateFromConnectionProfile(null);
            var config = tetheringManager.AccessPointConfiguration;
            
            config.Ssid = ssid;
            config.Passphrase = password;
            config.IsOnDemandEnabled = true;
            
            await tetheringManager.ConfigureAccessPointAsync(config);
            await tetheringManager.StartTetheringAsync();
            
            return true;
        }
        catch
        {
            return false;
        }
    }
    
    public async Task<bool> StopHotspotAsync()
    {
        try
        {
            var tetheringManager = NetworkOperatorTetheringManager.CreateFromConnectionProfile(null);
            await tetheringManager.StopTetheringAsync();
            return true;
        }
        catch
        {
            return false;
        }
    }
}

Решение 3: Альтернативный подход с использованием нативного кода

Для более прямого управления можно использовать P/Invoke для прямого вызова API Windows Networking:

csharp
using System;
using System.Runtime.InteropServices;

public class NativeHotspotController
{
    [DllImport("wlanapi.dll", SetLastError = true)]
    private static extern uint WlanOpenHandle(uint dwClientVersion, IntPtr pReserved, out IntPtr phClientHandle);
    
    [DllImport("wlanapi.dll", SetLastError = true)]
    private static extern uint WlanCloseHandle(IntPtr hClientHandle, IntPtr pReserved);
    
    [DllImport("wlanapi.dll", SetLastError = true)]
    private static extern uint WlanHostedNetworkStartUsing(IntPtr hClientHandle, out IntPtr pDot11Ssid, out uint dwDot11SsidNameSize, IntPtr pReserved);
    
    [DllImport("wlanapi.dll", SetLastError = true)]
    private static extern uint WlanHostedNetworkStopUsing(IntPtr hClientHandle, IntPtr pReserved);
    
    public bool StartHotspot(string ssid, string password)
    {
        IntPtr handle = IntPtr.Zero;
        try
        {
            // Открываем дескриптор WLAN
            uint result = WlanOpenHandle(2, IntPtr.Zero, out handle);
            if (result != 0)
            {
                return false;
            }
            
            // Запускаем размещенную сеть
            result = WlanHostedNetworkStartUsing(handle, IntPtr.Zero, out uint ssidSize, IntPtr.Zero);
            return result == 0;
        }
        finally
        {
            if (handle != IntPtr.Zero)
            {
                WlanCloseHandle(handle, IntPtr.Zero);
            }
        }
    }
    
    public bool StopHotspot()
    {
        IntPtr handle = IntPtr.Zero;
        try
        {
            uint result = WlanOpenHandle(2, IntPtr.Zero, out handle);
            if (result != 0)
            {
                return false;
            }
            
            result = WlanHostedNetworkStopUsing(handle, IntPtr.Zero);
            return result == 0;
        }
        finally
        {
            if (handle != IntPtr.Zero)
            {
                WlanCloseHandle(handle, IntPtr.Zero);
            }
        }
    }
}

Требования к разрешениям и конфигурации

Чтобы эти решения работали, необходимо правильно настроить ваше приложение:

  1. Запуск от имени администратора: Ваше приложение должно запускаться с повышенными привилегиями.

  2. Манифест приложения: Добавьте следующее в ваш app.manifest:

xml
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
  1. Возможности: Если используется оболочка UWP, убедитесь, что эти возможности указаны в вашем package.appxmanifest:
xml
<Capabilities>
    <Capability Name="wiFiControl" />
    <Capability Name="networkingVpnProvider" />
    <Capability Name="internetClientServer" />
</Capabilities>

Как указано в документации Microsoft, точки доступа по запросу требуют конкретной системной конфигурации и разрешений.

Полный пример реализации

Вот полный рабочий пример с использованием подхода NetworkOperatorTetheringManager:

csharp
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Networking.NetworkOperators;
using Windows.Networking.Connectivity;

public class Windows11HotspotManager
{
    private NetworkOperatorTetheringManager _tetheringManager;
    
    public async Task<bool> InitializeAsync(string ssid, string password)
    {
        try
        {
            // Получаем доступные сетевые адаптеры
            var profiles = NetworkInformation.GetConnectionProfiles();
            var ethernetProfile = profiles.FirstOrDefault(p => 
                p.NetworkAdapter != null && 
                p.NetworkAdapter.IanaInterfaceType == 6); // Ethernet
            
            if (ethernetProfile == null)
            {
                throw new InvalidOperationException("Сетевой адаптер Ethernet не найден");
            }
            
            // Создаем менеджер раздачи
            _tetheringManager = NetworkOperatorTetheringManager.CreateFromConnectionProfile(ethernetProfile);
            
            // Настраиваем точку доступа
            var apConfig = _tetheringManager.AccessPointConfiguration;
            apConfig.Ssid = ssid;
            apConfig.Passphrase = password;
            apConfig.IsOnDemandEnabled = true;
            
            // Применяем конфигурацию
            var result = await _tetheringManager.ConfigureAccessPointAsync(apConfig);
            
            return result.Status == TetheringOperationStatus.Success;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Инициализация не удалась: {ex.Message}");
            return false;
        }
    }
    
    public async Task<bool> StartHotspotAsync()
    {
        try
        {
            if (_tetheringManager == null)
            {
                throw new InvalidOperationException("Точка доступа не инициализирована");
            }
            
            var result = await _tetheringManager.StartTetheringAsync();
            return result.Status == TetheringOperationStatus.Success;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Не удалось запустить точку доступа: {ex.Message}");
            return false;
        }
    }
    
    public async Task<bool> StopHotspotAsync()
    {
        try
        {
            if (_tetheringManager == null)
            {
                throw new InvalidOperationException("Точка доступа не инициализирована");
            }
            
            var result = await _tetheringManager.StopTetheringAsync();
            return result.Status == TetheringOperationStatus.Success;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Не удалось остановить точку доступа: {ex.Message}");
            return false;
        }
    }
    
    public bool IsHotspotActive()
    {
        try
        {
            return _tetheringManager != null && _tetheringManager.TetheringOperationalState == TetheringOperationalState.On;
        }
        catch
        {
            return false;
        }
    }
}

Устранение распространенных проблем

  1. Ошибка “Неверный дескриптор” (The handle is invalid):

    • Убедитесь, что ваше приложение запускается от имени администратора
    • Проверьте, что вы используете правильный сетевой адаптер
    • Убедитесь, что контекст Windows Runtime правильно инициализирован
  2. Ошибка “Отказано системой” (DeniedBySystem):

    • Добавьте необходимые возможности в манифест
    • Проверьте системные разрешения Wi-Fi
    • Убедитесь, что служба Windows “WLAN AutoConfig” запущена
  3. Проблемы с сетевыми адаптерами:

    csharp
    // Отладка: Вывод доступных адаптеров
    var profiles = NetworkInformation.GetConnectionProfiles();
    foreach (var profile in profiles)
    {
        Console.WriteLine($"Адаптер: {profile.ProfileName}");
        Console.WriteLine($"Тип: {profile.NetworkAdapter.IanaInterfaceType}");
        Console.WriteLine($"Подключен: {profile.GetNetworkConnectivityLevel()}");
    }
    
  4. Альтернативный запасной вариант:
    Если вышеперечисленные методы не работают, рассмотрите использование встроенной в Windows мобильной точки доступа через командную строку:

    csharp
    public bool StartBuiltInHotspot()
    {
        try
        {
            var process = new System.Diagnostics.Process();
            process.StartInfo.FileName = "netsh";
            process.StartInfo.Arguments = "wlan set hostednetwork mode=allow ssid=MyHotspot key=securepassword123";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.Start();
            process.WaitForExit();
            return process.ExitCode == 0;
        }
        catch
        {
            return false;
        }
    }
    

Согласно документации Microsoft, для производственных приложений рекомендуется писать приложение UWP и использовать API аутентификации точки доступа Wi-Fi. Однако для приложений .NET Framework, описанные выше методы предоставляют жизнеспособные альтернативы.

Источники

  1. Microsoft Learn - Класс WiFiOnDemandHotspotNetwork
  2. Microsoft Learn - NetworkOperatorTetheringAccessPointConfiguration
  3. Microsoft Learn - Пример точки доступа Wi-Fi по запросу
  4. Stack Overflow - Как настроить точку доступа Wi-Fi в приложении .NET framework?
  5. Microsoft Q&A - Можно ли использовать API Windows.Devices.WiFi.WiFiAdapter в приложении WPF для настольных ПК
  6. Microsoft Learn - Архитектура оффлоадинга точки доступа Wi-Fi

Заключение

Реализация управления точкой доступа Wi-Fi в приложении .NET Framework для Windows 11 требует обхода ограничений API UWP. Ключевые подходы включают:

  1. Использование NetworkOperatorTetheringManager с правильным выбором сетевого адаптера
  2. Создание компонента-обертки Windows Runtime для API UWP
  3. Прямой вызов нативных API Windows Networking с помощью P/Invoke
  4. Запуск вашего приложения с правами администратора
  5. Правильная настройка сетевых адаптеров и системных разрешений

Для производственного использования рассмотрите возможность миграции на приложение UWP или создание гибридного подхода, при котором ваше приложение .NET Framework вызывает UWP-компонент. Всегда тщательно тестируйте с различными сетевыми конфигурациями и корректно обрабатывайте исключения, так как функциональность точки доступа Wi-Fi может зависеть от системных настроек, обновлений драйверов и политик безопасности.

Авторы
Проверено модерацией
Модерация