Skip to content

Commit a9e961b

Browse files
committed
[WLANWIZ] Rewrite network scan procedure, again
Making our loops a bit less frequent thing. We are operating indexes at this point and cue ones that might be our point of interest, like index of currently connected network.
1 parent 8a6fce5 commit a9e961b

File tree

2 files changed

+122
-43
lines changed

2 files changed

+122
-43
lines changed

dll/shellext/wlanwiz/main.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* COPYRIGHT: Copyright 2024-2025 Vitaly Orekhov <[email protected]>
66
*/
77
#pragma once
8+
#include <set>
9+
810
#include <atlbase.h>
911
#include <atlcoll.h>
1012
#include <atlconv.h>
@@ -167,6 +169,9 @@ class CWlanWizard : public CDialogImpl<CWlanWizard>
167169

168170
HWND CreateToolTip(int toolID);
169171
static DWORD WINAPI ScanNetworksThread(_In_ LPVOID lpParameter);
172+
void TryInsertToAdHoc(std::set<DWORD>& setAdHoc, DWORD dwIndex);
173+
void TryInsertToKnown(std::set<DWORD>& setProfiles, DWORD dwIndex);
174+
DWORD TryFindConnected(DWORD dwIndex);
170175

171176
LRESULT OnInitDialog(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
172177
LRESULT OnDrawItem(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

dll/shellext/wlanwiz/scan.cpp

Lines changed: 117 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,55 @@
22
* PROJECT: ReactOS Shell
33
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
44
* PURPOSE: ReactOS Wizard for Wireless Network Connections (WLAN Scanning Routines)
5-
* COPYRIGHT: Copyright 2024 Vitaly Orekhov <[email protected]>
5+
* COPYRIGHT: Copyright 2024-2025 Vitaly Orekhov <[email protected]>
66
*/
77
#include "main.h"
88

9-
#include <string>
10-
#include <unordered_set>
9+
#include <algorithm>
10+
#include <numeric>
11+
#include <vector>
12+
13+
/* Convert SSID from UTF-8 to UTF-16 */
14+
static ATL::CStringW APNameToUnicode(PDOT11_SSID dot11Ssid)
15+
{
16+
int iSSIDLengthWide = MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<LPCSTR>(dot11Ssid->ucSSID), dot11Ssid->uSSIDLength, NULL, 0);
17+
18+
ATL::CStringW cswSSID = ATL::CStringW(L"", iSSIDLengthWide);
19+
MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<LPCSTR>(dot11Ssid->ucSSID), dot11Ssid->uSSIDLength, cswSSID.GetBuffer(), iSSIDLengthWide);
20+
21+
return cswSSID;
22+
}
23+
24+
void CWlanWizard::TryInsertToKnown(std::set<DWORD>& setProfiles, DWORD dwIndex)
25+
{
26+
PWLAN_AVAILABLE_NETWORK pWlanNetwork = &this->lstWlanNetworks->Network[dwIndex];
27+
28+
if ((pWlanNetwork->dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE) == WLAN_AVAILABLE_NETWORK_HAS_PROFILE)
29+
{
30+
std::wstring_view wsvSSID = APNameToUnicode(&pWlanNetwork->dot11Ssid);
31+
32+
if (wsvSSID == pWlanNetwork->strProfileName)
33+
setProfiles.insert(dwIndex);
34+
}
35+
}
36+
37+
void CWlanWizard::TryInsertToAdHoc(std::set<DWORD>& setAdHoc, DWORD dwIndex)
38+
{
39+
PWLAN_AVAILABLE_NETWORK pWlanNetwork = &this->lstWlanNetworks->Network[dwIndex];
40+
41+
if (pWlanNetwork->dot11BssType == dot11_BSS_type_independent)
42+
setAdHoc.insert(dwIndex);
43+
}
44+
45+
DWORD CWlanWizard::TryFindConnected(DWORD dwIndex)
46+
{
47+
PWLAN_AVAILABLE_NETWORK pWlanNetwork = &this->lstWlanNetworks->Network[dwIndex];
48+
49+
if ((pWlanNetwork->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) == WLAN_AVAILABLE_NETWORK_CONNECTED)
50+
return dwIndex;
51+
52+
return MAXDWORD;
53+
}
1154

1255
LRESULT CWlanWizard::OnScanNetworks(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
1356
{
@@ -95,68 +138,99 @@ LRESULT CWlanWizard::OnScanNetworks(WORD wNotifyCode, WORD wID, HWND hWndCtl, BO
95138

96139
m_SidebarButtonAS.EnableWindow();
97140
m_SidebarButtonSN.EnableWindow();
98-
99-
/*
100-
* WIP: Single pass sorting of discovered networks.
101-
* TODO: Restore ad-hoc network positioning in the end of the list.
102-
*/
141+
103142
if (this->lstWlanNetworks->dwNumberOfItems > 0)
104143
{
105-
/* Add discovered networks to listbox and sort networks by signal level */
106-
std::unordered_set<std::wstring_view> ucAPsWithProfiles;
107-
WLAN_SIGNAL_QUALITY ulPrevSignalQuality = 0, ulWorstSignalQuality = 100;
108-
109-
for (;
110-
this->lstWlanNetworks->dwIndex <= this->lstWlanNetworks->dwNumberOfItems - 1;
111-
++this->lstWlanNetworks->dwIndex)
144+
auto vecIndexesBySignalQuality = std::vector<DWORD>(this->lstWlanNetworks->dwNumberOfItems);
145+
DWORD dwConnectedTo = MAXDWORD;
146+
std::set<DWORD> setDiscoveredAdHocIndexes;
147+
std::set<DWORD> setAPsWithProfiles;
148+
std::iota(vecIndexesBySignalQuality.begin(), vecIndexesBySignalQuality.end(), 0);
149+
150+
/* Sort networks by signal level */
151+
std::sort(vecIndexesBySignalQuality.begin(), vecIndexesBySignalQuality.end(), [&](auto left, auto right)
152+
{
153+
TryInsertToAdHoc(setDiscoveredAdHocIndexes, left);
154+
TryInsertToAdHoc(setDiscoveredAdHocIndexes, right);
155+
156+
/* Try to determine if we are connected currently to anything.
157+
* Once found, these two steps are skipped. */
158+
if (dwConnectedTo == MAXDWORD)
159+
dwConnectedTo = TryFindConnected(left);
160+
161+
if (dwConnectedTo == MAXDWORD)
162+
dwConnectedTo = TryFindConnected(right);
163+
164+
/* Count network as known if it fully matches SSID with profile name */
165+
TryInsertToKnown(setAPsWithProfiles, left);
166+
TryInsertToKnown(setAPsWithProfiles, right);
167+
168+
return this->lstWlanNetworks->Network[left].wlanSignalQuality > this->lstWlanNetworks->Network[right].wlanSignalQuality;
169+
});
170+
171+
/* Remove networks that do not have profile name exactly matching SSID */
172+
for (const auto& dwKnownAPIdx : setAPsWithProfiles)
112173
{
113-
WLAN_AVAILABLE_NETWORK wlanNetwork = this->lstWlanNetworks->Network[this->lstWlanNetworks->dwIndex];
114-
std::wstring_view wsvSSID;
115-
int iInsertAt = -1;
174+
PWLAN_AVAILABLE_NETWORK wlanNetWithProfile = &this->lstWlanNetworks->Network[dwKnownAPIdx];
175+
176+
vecIndexesBySignalQuality.erase(std::remove_if(vecIndexesBySignalQuality.begin(), vecIndexesBySignalQuality.end(), [&](const DWORD& dwAP)
177+
{
178+
if (dwKnownAPIdx == dwAP)
179+
return false;
116180

117-
// Convert SSID from UTF-8 to UTF-16
118-
int iSSIDLengthWide = MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<LPCSTR>(wlanNetwork.dot11Ssid.ucSSID), wlanNetwork.dot11Ssid.uSSIDLength, NULL, 0);
181+
bool bProfileNameIsSSID = ATL::CStringW(wlanNetWithProfile->strProfileName) == APNameToUnicode(&this->lstWlanNetworks->Network[dwAP].dot11Ssid);
182+
bool bHasProfile = (this->lstWlanNetworks->Network[dwAP].dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE) != 0;
183+
184+
return bProfileNameIsSSID && !bHasProfile;
185+
}), vecIndexesBySignalQuality.end());
186+
}
187+
188+
DPRINT("Discovered %lu access points (%u are known)\n", this->lstWlanNetworks->dwNumberOfItems, setAPsWithProfiles.size());
189+
190+
/* Shift all ad hoc networks to end */
191+
for (const auto& dwAdHocIdx : setDiscoveredAdHocIndexes)
192+
{
193+
auto iter = std::find(vecIndexesBySignalQuality.begin(), vecIndexesBySignalQuality.end(), dwAdHocIdx);
119194

120-
ATL::CStringW cswSSID = ATL::CStringW(L"", iSSIDLengthWide);
121-
MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<LPCSTR>(wlanNetwork.dot11Ssid.ucSSID), wlanNetwork.dot11Ssid.uSSIDLength, cswSSID.GetBuffer(), iSSIDLengthWide);
122-
wsvSSID = std::wstring_view(cswSSID.GetBuffer());
195+
if (iter != vecIndexesBySignalQuality.end())
196+
{
197+
auto idx = iter - vecIndexesBySignalQuality.begin();
198+
std::rotate(vecIndexesBySignalQuality.begin() + idx, vecIndexesBySignalQuality.begin() + idx + 1, vecIndexesBySignalQuality.end());
199+
}
200+
}
123201

124-
// TODO: filter access points by profile
125-
if (ucAPsWithProfiles.find(wsvSSID) != ucAPsWithProfiles.end())
126-
continue;
202+
/* Finally, move currently connected network to beginning */
203+
if (dwConnectedTo != MAXDWORD)
204+
{
205+
auto connectedIdx = std::find(vecIndexesBySignalQuality.begin(), vecIndexesBySignalQuality.end(), dwConnectedTo) - vecIndexesBySignalQuality.begin();
127206

128-
/* This allows discarding duplicated entries that with APs we had already connected earlier */
129-
if (wlanNetwork.dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE)
130-
ucAPsWithProfiles.emplace(wsvSSID);
207+
if (connectedIdx > 0)
208+
{
209+
auto iter = vecIndexesBySignalQuality.begin();
210+
std::rotate(iter, iter + connectedIdx, iter + connectedIdx + 1);
211+
}
212+
}
131213

132-
/* Sort by descending signal order */
133-
if (this->lstWlanNetworks->dwIndex == 0 || wlanNetwork.wlanSignalQuality > ulPrevSignalQuality)
134-
iInsertAt = 0;
135-
else if (wlanNetwork.wlanSignalQuality < ulPrevSignalQuality)
136-
iInsertAt = 1;
214+
for (const auto& dwNetwork : vecIndexesBySignalQuality)
215+
{
216+
WLAN_AVAILABLE_NETWORK wlanNetwork = this->lstWlanNetworks->Network[dwNetwork];
217+
ATL::CStringW cswSSID = APNameToUnicode(&wlanNetwork.dot11Ssid);
137218

138219
if (cswSSID.IsEmpty())
139220
cswSSID.LoadStringW(IDS_WLANWIZ_HIDDEN_NETWORK);
140221

141222
LRESULT iItemIdx = m_ListboxWLAN.SendMessageW(LB_INSERTSTRING,
142-
iInsertAt,
223+
-1,
143224
reinterpret_cast<LPARAM>(cswSSID.GetBuffer()));
144225

145226
m_ListboxWLAN.SendMessageW(LB_SETITEMDATA,
146227
iItemIdx,
147-
static_cast<LPARAM>(this->lstWlanNetworks->dwIndex));
148-
149-
ulPrevSignalQuality = wlanNetwork.wlanSignalQuality;
150-
151-
if (ulPrevSignalQuality < ulWorstSignalQuality)
152-
ulWorstSignalQuality = ulPrevSignalQuality;
228+
static_cast<LPARAM>(dwNetwork));
153229
}
154230
}
155231

156232
/* Show discovered networks */
157-
RECT rc;
158233
m_ListboxWLAN.EnableWindow();
159-
m_ListboxWLAN.GetClientRect(&rc);
160234
m_ListboxWLAN.Invalidate();
161235
m_ListboxWLAN.SetFocus();
162236

0 commit comments

Comments
 (0)