使用'WlanScan'刷新WiFi网络列表(将api语法从c#转换为vba ...或解决方法?)

ash*_*awg 5 c# winapi vba bssid wlan

我需要刷新Window的无线网络列表.

我很乐意接受任何可以直接或间接从VBA 自动化(cmdline,wmi等)的解决方法.(我正在使用Windows 7 Home 64位与Office 365 Pro 64位.)

我可以通过几种方式以编程方式列出网络netsh,或者下面的代码,但除非我实际点击,否则列表不会刷新净 任务栏的通知区域中的"网络连接"图标.

  • 该列表确实自动更新每60秒为一些文档的状态.
  • 断开连接+重新连接NIC 不是一个可行/可持续的选择.

我想我没有按照要求从WlanOpenHandle 获得句柄,而且我很擅长将C转换为VBA.

没有错误,但WlanScan返回未知代码1168.


相关位:

这是函数声明VB,适用于:

Public Shared Function WlanScan(ByVal hClientHandle As IntPtr, _
   ByRef pInterfaceGuid As Guid, ByVal pDot11Ssid As IntPtr, _
   ByVal pIeData As IntPtr, ByVal pReserved As IntPtr) As UInteger
End Function
Run Code Online (Sandbox Code Playgroud)

...以及以下功能用法C#示例:

Guid g;
//wlanHndl is the handle returned previously by calling [WlanOpenHandle]
for (int i = 0; i < infoList.dwNumberOfItems; i++)
{
g = infoList.InterfaceInfo[i].InterfaceGuid;
uint resultCode=WlanScan(wlanHndl, ref g, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (resultCode != 0)
    return;
}
Run Code Online (Sandbox Code Playgroud)

......以及如何打开手柄C++(从这里开始):

dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS) {
    wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
    return 1;
    // You can use FormatMessage here to find out why the function failed
}
Run Code Online (Sandbox Code Playgroud)

"取消隐藏"

获取(缓存)无线网络列表:

列出网络的代码效果很好 - 除了不自行刷新.(以前我正在解析netsh wlan show networks mode=bssid具有相同问题的文本输出.)

我以前删除了这一部分,因为它冗长,似乎除了刷新之外工作正常. - )

Option Explicit  'section's source: vbforums.com/showthread.php?632731
Private Const DOT11_SSID_MAX_LENGTH As Long = 32
Private Const WLAN_MAX_PHY_TYPE_NUMBER As Long = 8
Private Const WLAN_AVAILABLE_NETWORK_CONNECTED As Long = 1
Private Const WLAN_AVAILABLE_NETWORK_HAS_PROFILE As Long = 2

Private Type GUID  'from cpearson.com
    Data1 As Long: Data2 As Integer:  Data3 As Integer:  Data4(7) As Byte
End Type

Private Type WLAN_INTERFACE_INFO
    ifGuid As GUID: InterfaceDescription(255) As Byte: IsState As Long
End Type

Private Type DOT11_SSID
    uSSIDLength As Long:            ucSSID(DOT11_SSID_MAX_LENGTH - 1) As Byte
End Type

Private Type WLAN_AVAILABLE_NETWORK
    strProfileName(511) As Byte:    dot11Ssid As DOT11_SSID
    dot11BssType As Long:           uNumberOfBssids As Long
    bNetworkConnectable As Long:    wlanNotConnectableReason As Long
    uNumberOfPhyTypes As Long:      dot11PhyTypes(WLAN_MAX_PHY_TYPE_NUMBER - 1) As Long
    bMorePhyTypes As Long:          wlanSignalQuality As Long
    bSEcurityEnabled As Long:       dot11DefaultAuthAlgorithm As Long
    dot11DefaultCipherAlgorithm As Long: dwflags As Long: dwReserved As Long
End Type

Private Type WLAN_INTERFACE_INFO_LIST
    dwNumberOfItems As Long: dwIndex As Long: InterfaceInfo As WLAN_INTERFACE_INFO
End Type

Private Type WLAN_AVAILABLE_NETWORK_LIST
    dwNumberOfItems As Long:  dwIndex As Long: Network As WLAN_AVAILABLE_NETWORK
End Type

Declare PtrSafe Function WlanOpenHandle Lib "Wlanapi.dll" (ByVal dwClientVersion As Long, _
                ByVal pdwReserved As Long, ByRef pdwNegotiaitedVersion As Long, _
                ByRef phClientHandle As Long) As Long

Declare PtrSafe Function WlanEnumInterfaces Lib "Wlanapi.dll" (ByVal hClientHandle As Long, _
                ByVal pReserved As Long, ppInterfaceList As Long) As Long

Declare PtrSafe Function WlanGetAvailableNetworkList Lib "Wlanapi.dll" ( _
                ByVal hClientHandle As Long, pInterfaceGuid As GUID, ByVal dwflags As Long, _
                ByVal pReserved As Long, ppAvailableNetworkList As Long) As Long

Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, _
                Source As Any, ByVal Length As Long)

Declare PtrSafe Sub WlanFreeMemory Lib "Wlanapi.dll" (ByVal pMemory As Long)

Type WiFis
  ssid As String: signal As Single
End Type

Public Function GetWiFi() As WiFis()
'returns an array of custom type WiFis (1st interface only)

    Dim udtList As WLAN_INTERFACE_INFO_LIST, udtAvailList As WLAN_AVAILABLE_NETWORK_LIST, udtNetwork As WLAN_AVAILABLE_NETWORK
    Dim lngReturn As Long, lngHandle As Long, lngVersion As Long, lngList As Long, lngAvailable As Long
    Dim lngStart As Long, intCount As Integer, ssid As String, signal As Single, wifiOut() As WiFis
    n = 0

    lngReturn = WlanOpenHandle(2&, 0&, lngVersion, lngHandle) 'get handle
    If lngReturn <> 0 Then
        Debug.Print "Couldn't get wlan handle (Code " & lngReturn & ")"
        Exit Function
    End If

    lngReturn = WlanEnumInterfaces(ByVal lngHandle, 0&, lngList) 'enumerate <*first interface only*>
    CopyMemory udtList, ByVal lngList, Len(udtList)
    lngReturn = WlanGetAvailableNetworkList(lngHandle, udtList.InterfaceInfo.ifGuid, 2&, 0&, lngAvailable) 'get network list
    CopyMemory udtAvailList, ByVal lngAvailable, LenB(udtAvailList)
    intCount = 0
    lngStart = lngAvailable + 8

    Do
        CopyMemory udtNetwork, ByVal lngStart, Len(udtNetwork) ' Populate avail. network structure
        ssid = Replace(StrConv(udtNetwork.dot11Ssid.ucSSID, vbUnicode), Chr(0), "")
        If Len(ssid) < 4 Then ssid = "(Unnamed)"
        signal = CSng(udtNetwork.wlanSignalQuality) / 100
        '[Signal] = 0 to 100 which represents the signal strength (100 Signal)=(-100dBm RSSI), (100 Signal)=(-50dBm RSSI)

        If udtNetwork.dwflags = 0 Then
            n = n + 1
            ReDim Preserve wifiOut(n)
            wifiOut(n).ssid = ssid
            wifiOut(n).signal = signal
        Else
            'skipping networks with [dwflags] > 0
            'I *think* that's what I'm supposed to do
            'Returns 3 for currently connected network, 2 for networks that have profiles
        End If

        intCount = intCount + 1
        lngStart = lngStart + Len(udtNetwork)
    Loop Until intCount = udtAvailList.dwNumberOfItems
    WlanFreeMemory lngAvailable     'clean up memory
    WlanFreeMemory lngList

    GetWiFi = wifiOut   'Success! (function is populated with cached network list)

End Function
Run Code Online (Sandbox Code Playgroud)

......和问题:

刷新网络列表使用WlanScan

这并没有产生一个VBA错误,但不会返回代码1168(我无法辨认)/(来源)

'Added blindly:'wlanui type library (wlanui.dll) and "wlan pref iua" (wlanconn.dll)

Public Type DOT11_SSID 
   uSSIDLength As LongPtr: ucSSID As String
End Type

Private Type GUID 'from cpearson.com/excel/CreateGUID.aspx
    Data1 As LongPtr: Data2 As Integer
    Data3 As Integer: Data4(0 To 7) As Byte
End Type

#If Win64 Then 'also new to Office-64bit, but seems okay
    Declare PtrSafe Function WlanScan Lib "Wlanapi.dll" _
        (ByVal hClientHandle As LongPtr, ByRef pInterfaceGuid As GUID, _
        ByVal pDot11Ssid As LongPtr, ByVal pIeData As LongPtr, _
        ByVal pReserved As LongPtr) As LongPtr
#Else
    Private Declare WlanScan Lib "Wlanapi.dll" _
        (ByVal hClientHandle As LongPtr, ByRef pInterfaceGuid As GUID, _
        ByVal pDot11Ssid As LongPtr, ByVal pIeData As LongPtr, _
        ByVal pReserved As LongPtr) As LongPtr
#End If

Sub test_RefreshNetworkList()
    Dim hresult As LongPtr, phClientHandle As Long, pdwNegotiatedVersion As Long
    Dim retVal As Longptr, g As GUID
    hresult = WlanOpenHandle(2&, 0&, pdwNegotiatedVersion, phClientHandle)
    retVal = WlanScan(phClientHandle, g, 0, 0, 0)
    Select Case retVal
        Case 87: Debug.Print "ERROR_INVALID_PARAMETER"
        Case 6: Debug.Print "ERROR_INVALID_HANDLE"
        Case 8: Debug.Print "ERROR_NOT_ENOUGH_MEMORY"
        Case Else: Debug.Print "RPC_STATUS : " & retVal  ' "misc errors"
    End Select
End Sub
Run Code Online (Sandbox Code Playgroud)

当然有一种迂回的方式来刷新VBA的网络列表?我的解决方法很酷,我可以自动化......什么?!

爪子 谢谢!


编辑:

我改变了LongLongPtr在适用的(我认为)的斑点.同样的错误.

这是WlanOpenHandleWlanScan定义.

Declare PtrSafe Function WlanOpenHandle Lib "Wlanapi.dll" 
    (ByVal dwClientVersion As LongPtr, _
     ByVal pdwReserved As LongPtr, 
     ByRef pdwNegotiaitedVersion As LongPtr, _
     ByRef phClientHandle As LongPtr           ) As LongPtr
Run Code Online (Sandbox Code Playgroud)

(...这也是我第一次尝试使用编译器常量.)

#If Win64 Then
    Declare PtrSafe Function WlanScan Lib "Wlanapi.dll" _
        (ByVal hClientHandle As LongPtr,
         ByRef pInterfaceGuid As GUID, _
         ByVal pDot11Ssid As LongPtr, 
         ByVal pIeData As LongPtr, _
         ByVal pReserved As LongPtr) As LongPtr
#Else
    Private Declare WlanScan Lib "Wlanapi.dll" _
        (ByVal hClientHandle As LongPtr, 
         ByRef pInterfaceGuid As GUID, _
         ByVal pDot11Ssid As LongPtr, 
         ByVal pIeData As LongPtr, _
         ByVal pReserved As LongPtr     ) As LongPtr
#End If
Run Code Online (Sandbox Code Playgroud)

Eri*_*k A 4

我认为你不刷新的主要问题是你永远不会关闭打开的手柄。这可能会导致问题,因为据我所知,不应该有多个打开的句柄。

您用来WlanOpenHandle获取接口的句柄,但是在完成它并获得所需的信息后,您应该调用WlanCloseHandle以关闭该句柄和关联的连接。

Declare PtrSafe Function WlanCloseHandle Lib "Wlanapi.dll" ( _
  ByVal hClientHandle As LongPtr, _
  Optional ByVal pReserved As LongPtr) As Long
Run Code Online (Sandbox Code Playgroud)

然后在你的函数结束时:

    WlanCloseHandle lngHandle 'Close handle
    GetWiFi = wifiOut   'Success! (function is populated with cached network list)
End Function
Run Code Online (Sandbox Code Playgroud)

任何错误处理程序(如果要添加一个)都应该测试句柄是否不为 0,如果不是,则将其关闭。

我还更改了各种小事情,例如使用LongPtrfor 指针使代码兼容 64 位(注意:它兼容 VBA6,需要大量条件编译),重新设计声明以不使用可选参数,以及一些其他小事。

我在设备上对以下代码进行了 10 次迭代测试,得到了 10 个不同的结果:

代码:

Public Function GetWiFi() As wifis()
'returns an array of custom type WiFis (1st interface only)

    Dim udtList As WLAN_INTERFACE_INFO_LIST, udtAvailList As WLAN_AVAILABLE_NETWORK_LIST, udtNetwork As WLAN_AVAILABLE_NETWORK
    Dim lngReturn As Long, pHandle As LongPtr, lngVersion As Long, pList As LongPtr, pAvailable As LongPtr
    Dim pStart As LongPtr, intCount As Integer, ssid As String, signal As Single, wifiOut() As wifis
    Dim n As Long
    n = 0

    lngReturn = WlanOpenHandle(2&, 0&, lngVersion, pHandle) 'get handle
    If lngReturn <> 0 Then
        Debug.Print "Couldn't get wlan handle (Code " & lngReturn & ")"
        Exit Function
    End If

    lngReturn = WlanEnumInterfaces(ByVal pHandle, 0&, pList) 'enumerate <*first interface only*>
    CopyMemory udtList, ByVal pList, Len(udtList)
    lngReturn = WlanScan(pHandle, udtList.InterfaceInfo.ifGuid)
    lngReturn = WlanGetAvailableNetworkList(pHandle, udtList.InterfaceInfo.ifGuid, 2&, 0&, pAvailable) 'get network list
    CopyMemory udtAvailList, ByVal pAvailable, LenB(udtAvailList)
    intCount = 0
    pStart = pAvailable + 8

    Do
        CopyMemory udtNetwork, ByVal pStart, Len(udtNetwork) ' Populate avail. network structure
        ssid = Replace(StrConv(udtNetwork.dot11Ssid.ucSSID, vbUnicode), Chr(0), "")
        If Len(ssid) < 4 Then ssid = "(Unnamed)"
        signal = CSng(udtNetwork.wlanSignalQuality) / 100
        '[Signal] = 0 to 100 which represents the signal strength (100 Signal)=(-100dBm RSSI), (100 Signal)=(-50dBm RSSI)

        If udtNetwork.dwflags = 0 Then
            n = n + 1
            ReDim Preserve wifiOut(n)
            wifiOut(n).ssid = ssid
            wifiOut(n).signal = signal
        Else
            'skipping networks with [dwflags] > 0
            'I *think* that's what I'm supposed to do
            'Returns 3 for currently connected network, 2 for networks that have profiles
        End If

        intCount = intCount + 1
        pStart = pStart + Len(udtNetwork)
    Loop Until intCount = udtAvailList.dwNumberOfItems
    WlanFreeMemory pAvailable     'clean up memory
    WlanFreeMemory pList
    WlanCloseHandle pHandle 'Close handle
    GetWiFi = wifiOut   'Success! (function is populated with cached network list)
End Function
Run Code Online (Sandbox Code Playgroud)

类型和常量:

Private Const DOT11_SSID_MAX_LENGTH As Long = 32
Private Const WLAN_MAX_PHY_TYPE_NUMBER As Long = 8
Private Const WLAN_AVAILABLE_NETWORK_CONNECTED As Long = 1
Private Const WLAN_AVAILABLE_NETWORK_HAS_PROFILE As Long = 2

Public Type GUID
    Data(15) As Byte
End Type

Private Type WLAN_INTERFACE_INFO
    ifGuid As GUID: InterfaceDescription(255) As Byte: IsState As Long
End Type

Private Type DOT11_SSID
    uSSIDLength As Long:            ucSSID(DOT11_SSID_MAX_LENGTH - 1) As Byte
End Type

Private Type WLAN_AVAILABLE_NETWORK
    strProfileName(511) As Byte:    dot11Ssid As DOT11_SSID
    dot11BssType As Long:           uNumberOfBssids As Long
    bNetworkConnectable As Long:    wlanNotConnectableReason As Long
    uNumberOfPhyTypes As Long:      dot11PhyTypes(WLAN_MAX_PHY_TYPE_NUMBER - 1) As Long
    bMorePhyTypes As Long:          wlanSignalQuality As Long
    bSEcurityEnabled As Long:       dot11DefaultAuthAlgorithm As Long
    dot11DefaultCipherAlgorithm As Long: dwflags As Long: dwReserved As Long
End Type

Private Type WLAN_INTERFACE_INFO_LIST
    dwNumberOfItems As Long: dwIndex As Long: InterfaceInfo As WLAN_INTERFACE_INFO
End Type

Private Type WLAN_AVAILABLE_NETWORK_LIST
    dwNumberOfItems As Long:  dwIndex As Long: Network As WLAN_AVAILABLE_NETWORK
End Type

Public Type WiFis
  ssid As String: signal As Single
End Type
Run Code Online (Sandbox Code Playgroud)

函数声明:

Declare PtrSafe Function WlanOpenHandle Lib "Wlanapi.dll" (ByVal dwClientVersion As Long, _
                ByVal pdwReserved As LongPtr, ByRef pdwNegotiaitedVersion As Long, _
                ByRef phClientHandle As LongPtr) As Long

Declare PtrSafe Function WlanEnumInterfaces Lib "Wlanapi.dll" (ByVal hClientHandle As LongPtr, _
                ByVal pReserved As LongPtr, ByRef ppInterfaceList As LongPtr) As Long

Declare PtrSafe Function WlanGetAvailableNetworkList Lib "Wlanapi.dll" ( _
                ByVal hClientHandle As LongPtr, ByRef pInterfaceGuid As GUID, ByVal dwflags As Long, _
                ByVal pReserved As LongPtr, ByRef ppAvailableNetworkList As LongPtr) As Long


Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, _
                Source As Any, ByVal Length As Long)

Declare PtrSafe Function WlanScan Lib "Wlanapi.dll" _
        (ByVal hClientHandle As LongPtr, ByRef pInterfaceGuid As GUID, _
        Optional ByVal pDot11Ssid As LongPtr, Optional ByVal pIeData As LongPtr, _
        Optional ByVal pReserved As LongPtr) As Long

Declare PtrSafe Function WlanCloseHandle Lib "Wlanapi.dll" ( _
  ByVal hClientHandle As LongPtr, _
  Optional ByVal pReserved As LongPtr) As Long


Declare PtrSafe Sub WlanFreeMemory Lib "Wlanapi.dll" (ByVal pMemory As LongPtr)
Run Code Online (Sandbox Code Playgroud)

测试调用以打印列表:

Public Sub PrintWifis()
    Dim aWifis() As wifis
    aWifis = GetWiFi
    Dim l As Long
    For l = LBound(aWifis) To UBound(aWifis)
        Debug.Print aWifis(l).ssid; aWifis(l).signal
    Next
End Sub
Run Code Online (Sandbox Code Playgroud)

  • 调用打印列表的示例会是什么样子? (2认同)