Things I've learned about this library when calling Connect

Feb 20, 2014 at 5:37 PM
All the functions worked great, but there was a bit of stumbling. I hope the following helps others with the issues I had, such as the dreaded Network Connection Profile is Corrupted error.
  • <hex> must come before <name> element.
  • When using String.Format, I ended up having to have everything on one line, and not in a resource file. Maybe it's an encoding issue? Not sure, and didn't have time to research it.
  • You can find profiles at http://msdn.microsoft.com/en-us/library/windows/desktop/ms707341(v=vs.85).aspx, but they're missing the <hex> item.
  • You can export a profile by typing the following at a command prompt: "netsh wlan export profile NAME" where NAME is the wireless network name as listed in Windows.
Good luck!

Thanks and Best,

-Auri
Feb 22, 2015 at 3:55 PM
Edited Feb 22, 2015 at 4:23 PM
Here's the code to make everyone's life easier. It works to connect to WPA2-AES and open networks; I haven't had the opportunity to test yet with WPA2-TKIP, WPA, or WEP yet, but I'm pretty sure it will work.
I made two base XML profiles. This was required to support open networks and secured networks. I have not done anything with Enterprise networks yet, so additional ones may be needed, but this is a good start.
Note I omitted code from a class I built that contains all the SSIDs detected and all the info provided by calling managedwifi functions. This made it easier to keep track of since managedwifi has 3 different structures you have to loop thru to get all the data:
wlanIface.GetAvailableNetworkList(0)
wlanIface.GetNetworkBssList()
wlanIface.GetProfiles()
So here's the code:
    Dim WlanC As New WlanClient
    Public Const BASESECUREXMLPROFILE = "<?xml version=""1.0""?><WLANProfile xmlns=""http://www.microsoft.com/networking/WLAN/profile/v1""><name>{0}</name><SSIDConfig><SSID><hex>{1}</hex><name>{2}</name></SSID>{3}</SSIDConfig><connectionType>ESS</connectionType><connectionMode>auto</connectionMode><autoSwitch>false</autoSwitch><MSM><security><authEncryption><authentication>{4}</authentication><encryption>{5}</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>{6}</keyType><protected>false</protected><keyMaterial>{7}</keyMaterial></sharedKey><keyIndex>0</keyIndex></security></MSM></WLANProfile>"
    Public Const BASEOPENXMLPROFILE = "<?xml version=""1.0""?><WLANProfile xmlns=""http://www.microsoft.com/networking/WLAN/profile/v1""><name>{0}</name><SSIDConfig><SSID><hex>{1}</hex><name>{2}</name></SSID>{3}</SSIDConfig><connectionType>ESS</connectionType><connectionMode>auto</connectionMode><autoSwitch>false</autoSwitch><MSM><security><authEncryption><authentication>{4}</authentication><encryption>{5}</encryption><useOneX>false</useOneX></authEncryption>{6}{7}</security></MSM></WLANProfile>"
    Public Const NONBROADCASTTAG As String = "<nonBroadcast>true</nonBroadcast>"

Public Sub WiFiConnect_Click(sender As Object, e As EventArgs) Handles WiFiConnect.click()
    Dim ssid As String = sender.name
    Dim xml As String = ""
    Dim profilename As String = ""
    Dim hiddentag As Boolean = False

    If ssid = HIDDENSSID Then 'if it was the hidden ssid, prompt for the ssid name and store it in ssid variable and flip the tag as true so we put in that data
        ssid = InputBox("Please enter the Hidden Network's SSID")
        If ssid = "" Then Exit Sub 'cancel if they didn't enter a ssid
        hiddentag = True
    End If
'I omitted some code I have that references a class I built that I'm not sharing here. '
'That is what ssidinfo(0) is. There is other sample code on these forums that show you how to get this info, I just did that and complied into a class.
      if ssidinfo(0).ProfileName = "" then
            Dim key As String = ""
            Dim auth As String = ""
            Dim cipher As String = ""
            Dim keytype As String = ""
            Select Case ssidinfo(0).AuthAlog
                Case Is = Wlan.Dot11AuthAlgorithm.IEEE80211_Open
                    auth = "open"
                Case Is = Wlan.Dot11AuthAlgorithm.IEEE80211_SharedKey
                    'not implemented yet
                Case Is = Wlan.Dot11AuthAlgorithm.RSNA
                    auth = "WPA2PSK"
                Case Is = Wlan.Dot11AuthAlgorithm.RSNA_PSK
                    auth = "WPA2PSK"
                Case Is = Wlan.Dot11AuthAlgorithm.WPA
                    auth = "WPAPSK"
                Case Is = Wlan.Dot11AuthAlgorithm.WPA_None
                    auth = "WPAPSK"
                Case Is = Wlan.Dot11AuthAlgorithm.WPA_PSK
                    auth = "WPAPSK"
            End Select
            Select Case ssidinfo(0).CipherAlog
                Case Is = Wlan.Dot11CipherAlgorithm.CCMP
                    cipher = "AES"
                    keytype = "passPhrase"
                Case Is = Wlan.Dot11CipherAlgorithm.TKIP
                    cipher = "TKIP"
                    keytype = "passPhrase"
                Case Is = Wlan.Dot11CipherAlgorithm.None
                    cipher = "none"
                    keytype = ""
                    key = ""
                Case Is = Wlan.Dot11CipherAlgorithm.WEP
                    cipher = "WEP"
                    keytype = "networkKey"
                Case Is = Wlan.Dot11CipherAlgorithm.WEP40
                    cipher = "WEP"
                    keytype = "networkKey"
                Case Is = Wlan.Dot11CipherAlgorithm.WEP104
                    cipher = "WEP"
                    keytype = "networkKey"
            End Select
            profilename = ssid
            If cipher = "none" Then
                xml = AvailableSSIDs.BASEOPENXMLPROFILE
            Else
                xml = AvailableSSIDs.BASESECUREXMLPROFILE
                key = InputBox("Please enter the Network Key")
                If key = "" Then Exit Sub
            End If
            ssids.ConnectWiFi(xml, profilename, ssid, key, auth, cipher, keytype, hiddentag)
        Else
            'use saved profile found on PC
            xml = ssidinfo(0).XMLProfile
            profilename = ssidinfo(0).ProfileName
            ssids.ConnectWiFi(xml, profilename)
        End If
End Sub

    Public Sub ConnectWiFi(ByVal profileXML As String, ByVal profilename As String, ByVal ssid As String, _
                           ByVal key As String, ByVal auth As String, ByVal cipher As String, ByVal keytype As String, _
                           ByVal hiddennetwork As Boolean)
        Dim hiddenssidtag As String = ""
        If hiddennetwork Then hiddenssidtag = NONBROADCASTTAG
        Dim hex As String = ConvertToHex(ssid).ToUpper
        For Each wlanIface As WlanClient.WlanInterface In GetInterfaces()
            profileXML = String.Format(profileXML, profilename, hex, ssid, hiddenssidtag, auth, cipher, keytype, key)
            wlanIface.SetProfile(Wlan.WlanProfileFlags.AllUser, profileXML, True)
            wlanIface.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any, profilename)
        Next
    End Sub

    Public Sub ConnectWiFi(ByVal profileXML As String, ByVal profilename As String)
        For Each wlanIface As WlanClient.WlanInterface In GetInterfaces()

            wlanIface.SetProfile(Wlan.WlanProfileFlags.AllUser, profileXML, True)
            wlanIface.Connect(Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any, profilename)
        Next
    End Sub

    Public Function GetInterfaces() As WlanClient.WlanInterface()
        Return WlanC.Interfaces
    End Function

    Function ConvertToHex(ByVal asciiString As String) As String
        Dim byteArray() As Byte
        Dim hexNumbers As System.Text.StringBuilder = New System.Text.StringBuilder
        byteArray = System.Text.ASCIIEncoding.ASCII.GetBytes(asciiString)
        For i As Integer = 0 To byteArray.Length - 1
            hexNumbers.Append(byteArray(i).ToString("x"))
        Next
        Return hexNumbers.ToString
    End Function
Feb 22, 2015 at 4:49 PM
Here is the code I use to populate my class structure and my class itself:
Class AvailableSSIDs
    Public Structure SSIDInfo
        Dim DetectedTimestamp As System.DateTime
        Dim Flags As WiFiFlags
        Dim SSID As String
        Dim BSSType As Wlan.Dot11BssType
        Dim PhyType As Wlan.Dot11PhyType
        Dim AuthAlog As Wlan.Dot11AuthAlgorithm
        Dim CipherAlog As Wlan.Dot11CipherAlgorithm
        Dim SecurityOn As Boolean
        Dim NumBSSIDs As UInteger
        Dim SigQuality As UInteger
        Dim ProfileName As String
        Dim MorePhyTypes As Boolean
        Dim Connectable As Boolean
        Dim LinkQuality As UInteger
        Dim RSSI As Integer
        Dim CenterFreq As UInteger
        Dim MacAddr As String
        Dim XMLProfile As String
        Dim Key As String
        Dim Hex As String
    End Structure
    Private SSIDs As New List(Of SSIDInfo)

    Enum WiFiFlags
        Any = -1
        AvailableNetwork = 0
        HasProfile = 2
        Connected = 3
    End Enum
 end class

 Public Sub GetAPInfo(Optional byval flag as WiFiFlags = WiFiFlags.Any)
       For Each wlanIface As WlanClient.WlanInterface In GetInterfaces()
            Dim networks As Wlan.WlanAvailableNetwork() = wlanIface.GetAvailableNetworkList(0)
            For Each network As Wlan.WlanAvailableNetwork In networks
                If network.flags = flag Or flag = WiFiFlags.Any Then 'This check to filter for only the types of networks we want. Once found then grab the wifi info
                    Dim newssid As New AvailableSSIDs.SSIDInfo 'This is my class I've referred to a few times
                    newssid.menuitem = New ToolStripMenuItem
                    newssid.DetectedTimestamp = Now
                    newssid.Flags = network.flags
                    newssid.SSID = GetStringForSSID(network.dot11Ssid)
                    newssid.BSSType = network.dot11BssType
                    newssid.AuthAlog = network.dot11DefaultAuthAlgorithm
                    newssid.CipherAlog = network.dot11DefaultCipherAlgorithm
                    newssid.SecurityOn = network.securityEnabled
                    newssid.MorePhyTypes = network.morePhyTypes
                    newssid.Connectable = network.networkConnectable
                    newssid.NumBSSIDs = network.numberOfBssids
                    newssid.ProfileName = network.profileName
                    newssid.SigQuality = network.wlanSignalQuality

                    Dim wlanBssEntries2 As Wlan.WlanBssEntry() = wlanIface.GetNetworkBssList()
                    Dim bss As Wlan.WlanBssEntry = GetBSSEntryBySSID(wlanBssEntries2, newssid.SSID)
                    If bss.dot11Bssid IsNot Nothing Then
                        newssid.LinkQuality = bss.linkQuality
                        newssid.RSSI = bss.rssi
                        newssid.CenterFreq = bss.chCenterFrequency
                        newssid.PhyType = bss.dot11BssPhyType
                        newssid.MacAddr = BitConverter.ToString(bss.dot11Bssid)
                    End If

                    If newssid.ProfileName <> "" Then
                        newssid.XMLProfile = wlanIface.GetProfileXml(newssid.ProfileName) 'now we have the xml if one existed
                    End If
           End If
      Next
 Next

    Private Function GetBSSEntryBySSID(ByRef wlanBssEntries2() As Wlan.WlanBssEntry, ByVal ssid As String) As Wlan.WlanBssEntry
        Dim res As Wlan.WlanBssEntry = Nothing
        For Each bss In wlanBssEntries2
            If GetStringForSSID(bss.dot11Ssid) = ssid Then
                res = bss
                Exit For
            End If
        Next
        Return res
    End Function

    Private Function GetStringForSSID(ByVal ssid As Wlan.Dot11Ssid) As String
        Return Encoding.ASCII.GetString(ssid.SSID, 0, CInt(ssid.SSIDLength))
    End Function
Apr 26, 2015 at 1:33 PM
Edited Apr 26, 2015 at 6:37 PM
This helped me a lot!

I used this example to create an app to scan for Wifi Networks and monitor their signal strength, channel, mac address, ssid, etc. Not to connect to a network, just to monitor the network neighborhood signals. (The goal here is to tie this in with home management software so I can know when my networks are down.)

Two problems with the ManagedWifi.dll

First, it doesn't appear to dispose of resources after each call. Eventually you get a 'too many connections' error. Others have noted the same thing. I put the code in a try block, and just ignored the too many connections error, and it does seem to recover itself. Typically it does about 100 scans, then gets maybe 36 scans with the 'too many connections', then it starts working fine again.

Update: I tried opening one wlanClient on startup, and then just updating that one client, rather than 'for each' on every scan. This seems much better. hundreds of scans now with no errors, and I think this problem is now fixed.

Second, and maybe related to the above, but the first time it runs, it gets a bunch of ssids with their mac address etc., but doing another run 60 seconds later pulls up the same ssids, with the same signal strength as the first scan. It behaves like it is isn't updating anything, just using again what it picked up the first time.

I run my scanner for 100 scans over 12 minutes and the signal strength and RSSI don't change at all for 40 networks.

If I simultaneously run third-party scanner software, then this code immediately starts to properly update signal strengths, see new networks, etc. Without the third-party scanner running, this code detects about 42 networks. With the third-party scanner running, this code will continue adding new networks and get up into the 90-network range. If I then turn off the third-party scanner, this code keeps running without error, but the values don't change any more. So the third-party software seems to be doing something to the hardware that enables this code to work better??

Update: This is on a USB wireless adapter. If I disable that adapter, and turn on the internal wifi adapter, everything works fine. But it doesn't work on other systems the same way. Still a puzzle...

Still working on this. Will update if I'm able to find a way around those two problems.

Regards,
Dec 16, 2015 at 9:55 PM
Gerry,

In your update did you alter the for each from one of my functions or one of your own? If from one I posted can you please post the specific code changes?

Thanks!