我需要刷新 Windows 的无线网络列表。
我很乐意接受任何可以直接自动化的解决方法(cmdline、wmi 等)或间接来自VBA。 (我使用的是 Windows 7 Home 64 位和 Office 365 Pro 64 位。)
I can list the networks programmatically a couple ways including netsh
, or the code below, but the list does not refresh unless I physically click the Network Connection icon on the taskbar's Notification area.
- 该列表确实not正如一些文档所述,每 60 秒自动更新一次。
- 断开+重新连接网卡是not一个可行/可持续的选择。
我想我是没有得到句柄 from WLAN开放句柄 https://msdn.microsoft.com/27bfa0c1-4443-47a4-a374-326f553fa3bb根据需要,我不擅长将 C 转换为 VBA。
没有错误,但 WlanScan 返回未知代码1168
.
- 我这里改编自VB版本:无线扫描(wlanapi) https://www.pinvoke.net/default.aspx/wlanapi.wlanscan#
- MSDN 文档:无线扫描功能 https://learn.microsoft.com/windows/desktop/api/wlanapi/nf-wlanapi-wlanscan
相关位:
这是函数声明为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
...以及一个例子函数用法在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;
}
...and 如何打开手柄,在C++
(from here https://stackoverflow.com/a/3193613/8112776):
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
}
"Un-hidden:"
获取(缓存的)无线网络列表:
列出网络的代码效果很好- 除了不自行刷新之外。 (之前我正在解析文本输出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
...and the problem:
使用刷新网络列表WlanScan
?
这确实not生成 VBA 错误,但是does返回码1168
(我无法识别)/(Source http://pinvoke.net/default.aspx/wlanapi.wlanscan)
'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
当然有一种迂回的方法可以从 VBA 刷新网络列表吗?我对可以自动化的解决方法很满意......任何事情?!
Thanks!
Edit:
我变了Long
to LongPtr
在适用的(我认为)地点。同样的错误。
这是WlanOpenHandle
and WlanScan
定义。
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
(...这也是我第一次尝试使用编译器常量。)
#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