I’m writing a program using the Managed WiFi API. Here’s how I get all the networks in range:
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);
}
}
The problem is that after 18 calls to this method I can no longer connect:
(0x80004005): An attempt was made to
establish a session to a network
server, but there are already too many
sessions established to that server.
Here’s the constructor that’s throwing the exception:
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;
}
}
I believe this is because the client never closes the connections it opens. How do I close them explicitly? There’s handle closing in the catch block, but it requires access to the client’s private parts.
Since you’re seeing problems only after a certain number of iterations, the problem is likely resource exhaustion of some sort, which sounds like resources aren’t getting cleaned up in a timely manner.
From the comments above, it sounds like you’re not disposing your
WlanClientinstances, which may be part (or all) of the problem. I can understand why you’re not disposing them, though, because they don’t give you any obvious way to do so. This seems like a really problematic design on their part. There are all kinds of design guidelines that say a class like this should give you either a publicDisposemethod or a publicClosemethod, but even though they have both those methods, they deliberately made them both private.But the class does implement
IDisposable, so you can still clean it up by adding ausingblock:This will make sure all of the object’s resources get cleaned up at the moment flow leaves the
usingblock (even if flow is leaving because there was an exception). Your connections will be closed, your unmanaged memory released, and whatever else needs to happen.