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
88#include " main.h"
99
10+ #include < algorithm>
11+ #include < numeric>
12+ #include < set>
1013#include < string>
11- #include < unordered_set >
14+ #include < vector >
1215
1316LRESULT CWlanWizard::OnScanNetworks (WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
1417{
@@ -88,23 +91,57 @@ LRESULT CWlanWizard::OnScanNetworks(WORD wNotifyCode, WORD wID, HWND hWndCtl, BO
8891 m_SidebarButtonAS.EnableWindow ();
8992 m_SidebarButtonSN.EnableWindow ();
9093
91- /*
92- * WIP: Single pass sorting of discovered networks.
93- * TODO: Restore ad-hoc network positioning in the end of the list.
94- */
94+ DPRINT (" Discovered %lu access points\n " , this ->lstWlanNetworks ->dwNumberOfItems );
95+
9596 if (this ->lstWlanNetworks ->dwNumberOfItems > 0 )
9697 {
97- /* Add discovered networks to listbox and sort networks by signal level */
98- std::unordered_set<std::wstring_view> ucAPsWithProfiles;
99- WLAN_SIGNAL_QUALITY ulPrevSignalQuality = 0 , ulWorstSignalQuality = 100 ;
100-
101- for (;
102- this ->lstWlanNetworks ->dwIndex <= this ->lstWlanNetworks ->dwNumberOfItems - 1 ;
103- ++this ->lstWlanNetworks ->dwIndex )
98+ auto vecIndexesBySignalQuality = std::vector<DWORD>(this ->lstWlanNetworks ->dwNumberOfItems );
99+ DWORD dwConnectedTo = MAXDWORD;
100+ std::set<DWORD> setDiscoveredAdHocIndexes;
101+ std::iota (vecIndexesBySignalQuality.begin (), vecIndexesBySignalQuality.end (), 0 );
102+
103+ /* Sort networks by signal level */
104+ std::sort (vecIndexesBySignalQuality.begin (), vecIndexesBySignalQuality.end (), [&](DWORD left, DWORD right)
105+ {
106+ WLAN_AVAILABLE_NETWORK wlanLeft = this ->lstWlanNetworks ->Network [left];
107+ WLAN_AVAILABLE_NETWORK wlanRight = this ->lstWlanNetworks ->Network [right];
108+
109+ if (wlanLeft.dot11BssType == dot11_BSS_type_independent)
110+ setDiscoveredAdHocIndexes.insert (left);
111+
112+ if (wlanLeft.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
113+ dwConnectedTo = left;
114+
115+ return wlanLeft.wlanSignalQuality > wlanRight.wlanSignalQuality ;
116+ });
117+
118+ /* Shift all ad hoc networks to end */
119+ if (setDiscoveredAdHocIndexes.size () > 0 )
104120 {
105- WLAN_AVAILABLE_NETWORK wlanNetwork = this ->lstWlanNetworks ->Network [this ->lstWlanNetworks ->dwIndex ];
121+ for (const auto & dwAdHocIdx : setDiscoveredAdHocIndexes)
122+ {
123+ auto iter = std::find (vecIndexesBySignalQuality.begin (), vecIndexesBySignalQuality.end (), dwAdHocIdx);
124+
125+ if (iter != vecIndexesBySignalQuality.end ())
126+ {
127+ auto idx = iter - vecIndexesBySignalQuality.begin ();
128+ std::rotate (vecIndexesBySignalQuality.begin () + idx, vecIndexesBySignalQuality.begin () + idx + 1 , vecIndexesBySignalQuality.end ());
129+ }
130+ }
131+ }
132+
133+ /* Finally, move currently connected network to beginning */
134+ if (dwConnectedTo != MAXDWORD)
135+ {
136+ auto connectedIdx = std::find (vecIndexesBySignalQuality.begin (), vecIndexesBySignalQuality.end (), dwConnectedTo) - vecIndexesBySignalQuality.begin ();
137+ std::rotate (vecIndexesBySignalQuality.begin () + connectedIdx, vecIndexesBySignalQuality.begin () + connectedIdx + 1 , vecIndexesBySignalQuality.end ());
138+ }
139+
140+ /* TODO: remove networks that do not have a saved profile matching the SSID */
141+ for (const auto & dwNetwork : vecIndexesBySignalQuality)
142+ {
143+ WLAN_AVAILABLE_NETWORK wlanNetwork = this ->lstWlanNetworks ->Network [dwNetwork];
106144 std::wstring_view wsvSSID;
107- int iInsertAt = -1 ;
108145
109146 // Convert SSID from UTF-8 to UTF-16
110147 int iSSIDLengthWide = MultiByteToWideChar (CP_UTF8, 0 , reinterpret_cast <LPCSTR>(wlanNetwork.dot11Ssid .ucSSID ), wlanNetwork.dot11Ssid .uSSIDLength , NULL , 0 );
@@ -113,35 +150,16 @@ LRESULT CWlanWizard::OnScanNetworks(WORD wNotifyCode, WORD wID, HWND hWndCtl, BO
113150 MultiByteToWideChar (CP_UTF8, 0 , reinterpret_cast <LPCSTR>(wlanNetwork.dot11Ssid .ucSSID ), wlanNetwork.dot11Ssid .uSSIDLength , cswSSID.GetBuffer (), iSSIDLengthWide);
114151 wsvSSID = std::wstring_view (cswSSID.GetBuffer ());
115152
116- // TODO: filter access points by profile
117- if (ucAPsWithProfiles.find (wsvSSID) != ucAPsWithProfiles.end ())
118- continue ;
119-
120- /* This allows discarding duplicated entries that with APs we had already connected earlier */
121- if (wlanNetwork.dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE)
122- ucAPsWithProfiles.emplace (wsvSSID);
123-
124- /* Sort by descending signal order */
125- if (this ->lstWlanNetworks ->dwIndex == 0 || wlanNetwork.wlanSignalQuality > ulPrevSignalQuality)
126- iInsertAt = 0 ;
127- else if (wlanNetwork.wlanSignalQuality < ulPrevSignalQuality)
128- iInsertAt = 1 ;
129-
130153 if (cswSSID.IsEmpty ())
131154 cswSSID.LoadStringW (IDS_WLANWIZ_HIDDEN_NETWORK);
132155
133156 LRESULT iItemIdx = m_ListboxWLAN.SendMessageW (LB_INSERTSTRING,
134- iInsertAt ,
157+ - 1 ,
135158 reinterpret_cast <LPARAM>(cswSSID.GetBuffer ()));
136159
137160 m_ListboxWLAN.SendMessageW (LB_SETITEMDATA,
138161 iItemIdx,
139- static_cast <LPARAM>(this ->lstWlanNetworks ->dwIndex ));
140-
141- ulPrevSignalQuality = wlanNetwork.wlanSignalQuality ;
142-
143- if (ulPrevSignalQuality < ulWorstSignalQuality)
144- ulWorstSignalQuality = ulPrevSignalQuality;
162+ static_cast <LPARAM>(dwNetwork));
145163 }
146164 }
147165
0 commit comments