Закрытие WiFi-подключений с помощью управляемого API

Я пишу программу с использованием API Managed WiFi. Вот как я получаю все сети в диапазоне:

    void UpdateNetworks()
    {
        networks = new List<Wlan.WlanAvailableNetwork>();
        WlanClient client = new WlanClient();
        foreach(WlanClient.WlanInterface iface in client.Interfaces)
        {
            Wlan.WlanAvailableNetwork[] nets = iface.GetAvailableNetworkList(0);
            foreach(Wlan.WlanAvailableNetwork net in nets)
                networks.Add(net);
        }
    }

Проблема в том, что после 18 вызовов этого метода я больше не могу подключиться:

(0x80004005): Предпринята попытка установить сеанс на сетевом сервере, но для этого сервера уже установлено слишком много сеансов.

Вот конструктор, который выбрасывает исключение:

    public WlanClient()
    {
        Wlan.ThrowIfError(
            Wlan.WlanOpenHandle(Wlan.WLAN_CLIENT_VERSION_XP_SP2, IntPtr.Zero, out negotiatedVersion, out clientHandle));
        try
        {
            Wlan.WlanNotificationSource prevSrc;
            wlanNotificationCallback = new Wlan.WlanNotificationCallbackDelegate(OnWlanNotification);
            Wlan.ThrowIfError(
                Wlan.WlanRegisterNotification(clientHandle, Wlan.WlanNotificationSource.All, false, wlanNotificationCallback, IntPtr.Zero, IntPtr.Zero, out prevSrc));
        }
        catch
        {
            Wlan.WlanCloseHandle(clientHandle, IntPtr.Zero);
            throw;
        }
    }

Я считаю, что это потому, что клиент никогда не закрывает соединения, которые он открывает. Как я могу закрыть их явно? Там ручка закрывается в catch блок, но он требует доступа к частным частям клиента.

2 ответа

Решение

Поскольку вы видите проблемы только после определенного количества итераций, проблема, скорее всего, заключается в исчерпании ресурсов какого-либо рода, что звучит так, как будто ресурсы не очищаются своевременно.

Судя по комментариям выше, кажется, что вы не избавляетесь от WlanClient случаи, которые могут быть частью (или все) проблемы. Я могу понять, почему вы не избавляетесь от них, потому что они не дают вам очевидного способа сделать это. Это кажется действительно проблематичным дизайном с их стороны. Существуют всевозможные рекомендации по дизайну, в которых говорится, что подобный класс должен Dispose метод или общественность Close метод, но хотя у них есть оба этих метода, они сознательно сделали их обоих частными.

Но класс действительно реализует IDisposable, так что вы все еще можете очистить его, добавив using блок:

using (var wlanClient = new WlanClient()) {
    ....
} // wlanClient will be disposed when flow leaves the block

Это обеспечит очистку всех ресурсов объекта в тот момент, когда поток покидает using блок (даже если поток уходит из-за исключения). Ваши соединения будут закрыты, ваша неуправляемая память будет освобождена, и все остальное должно произойти.

У меня та же проблема. Я попробовал решение г-на Джо Уайта, но получил ошибку, что wlanClient не может быть преобразован в System.IDisposable.
Поскольку эта проблема связана с удалением экземпляров WlanClient, я определил только 1 экземпляр как член класса и использовал его много раз в методе [void UpdateNetworks()]. Я не получил ни одной ошибки.
Удалить строку

WlanClient client = new WlanClient();

от вашего метода и определить его в вашем классе. как следующее:

public partial class frm_main : Form
{
     private WlanClient client = new WlanClient();

     private void UpdateNetworks()
     {
         var networks = new List<Wlan.WlanAvailableNetwork>();
         foreach (WlanClient.WlanInterface iface in client.Interfaces)
         {
             Wlan.WlanAvailableNetwork[] nets = iface.GetAvailableNetworkList(0);
             foreach (Wlan.WlanAvailableNetwork net in nets)
                 networks.Add(net);
         }
         MessageBox.Show(networks.Count.ToString());
     }
}

Справка: ошибка управляемого WiFi

Другие вопросы по тегам