DT
14 квітня 2025 р. 15:38

Qt 6.8 MinGW - управление подключением WiFi из программы

C++, MinGW, windows, WiFi

Всем привет!
На Qt 6.8 MinGW пытаюсь сделать управление подключением WiFi из программы. Пока делаю поддержку Windows, но так же хочу в дальнейшем внедрить и поддержку Linux/MacOS.

Для управления пробрасываю команды в netsh и разбираю результат.
Пока загвоздка в разных локализациях системы, из-за чего или некорректно отображаются названия на русском языке (одни ??????????????), либо ничего не выдается из-за того, что не удается разобрать результат. Хотел бы библиотеку унифицировать.

Есть идеи?

Пока выглядит следующим образом:

wifimanager.h

  1. #ifndef WIFIMANAGER_H
  2. #define WIFIMANAGER_H
  3.  
  4. #include <QtNetwork/QtNetwork>
  5. #include <QtCore>
  6. #include <QtGui>
  7. #include <QtWidgets>
  8. #include <list>
  9.  
  10.  
  11. /**
  12. * Open - открытая сеть без шифрования
  13. * Shared - устаревший режим WEP с общей аутентификацией
  14. * WPA-Personal - WPA с использованием PSK (Pre-Shared Key)
  15. * WPA-Enterprise - WPA с использованием RADIUS-сервера для аутентификации
  16. * WPA2-Personal - WPA2 с PSK (наиболее распространенный сейчас режим)
  17. * WPA2-Enterprise - WPA2 с RADIUS-сервером
  18. * WPA3-Personal - современный WPA3 с PSK
  19. * WPA3-Enterprise - WPA3 с RADIUS-сервером
  20. */
  21. typedef enum {
  22. AUTH_TYPE_UNKNOWN = 0,
  23. AUTH_TYPE_OPEN,
  24. AUTH_TYPE_SHARED,
  25. AUTH_TYPE_WPA_PERSONAL,
  26. AUTH_TYPE_WPA_ENTERPRISE,
  27. AUTH_TYPE_WPA2_PERSONAL,
  28. AUTH_TYPE_WPA2_ENTERPRISE,
  29. AUTH_TYPE_WPA3_PERSONAL,
  30. AUTH_TYPE_WPA3_ENTERPRISE,
  31. AUTH_TYPE_MAX
  32. } auth_type_t;
  33.  
  34. typedef enum {
  35. WIFI_BAND_UNKNOWN = 0,
  36. WIFI_BAND_2_4_GHZ,
  37. WIFI_BAND_5_GHZ,
  38. WIFI_BAND_MAX
  39. } wifi_band_t;
  40.  
  41. typedef enum {
  42. WIFI_STATE_DISCONNECTED = 0,
  43. WIFI_STATE_CONNECTED
  44. } wifi_state_t;
  45.  
  46. typedef enum {
  47. INTERFACE_TYPE_PRIMARY = 0,
  48. INTERFACE_TYPE_SECONDARY
  49. } interface_type_t;
  50.  
  51. /**
  52. * Name : Беспроводная сеть
  53. * Description : Intel(R) Wireless-AC 9560 160MHz
  54. * GUID : 082bf832-bae3-4933-a678-16e21e1dfb75
  55. * Physical address : 5c:87:9c:94:c2:76
  56. * Interface type : Primary
  57. * State : connected
  58. * SSID : tp-link
  59. * AP BSSID : 78:8c:b5:b7:27:a6
  60. * Band : 5 GHz
  61. * Channel : 48
  62. * Network type : Infrastructure
  63. * Radio type : 802.11ac
  64. * Authentication : WPA2-Personal
  65. * Cipher : CCMP
  66. * Connection mode : Profile
  67. * Receive rate (Mbps) : 780
  68. * Transmit rate (Mbps) : 780
  69. * Signal : 87%
  70. * Profile : tp-link
  71. */
  72. typedef struct {
  73. QString interfaceName;
  74. QString interfaceDesc;
  75. QString interfaceMAC;
  76. interface_type_t interfaceType;
  77. wifi_state_t wifiConnected;
  78. auth_type_t authType;
  79. int signal;
  80. QString currentProfileUsed;
  81. QString wifiSSIDConnected;
  82. wifi_band_t currentBand;
  83. } interface_desc_t;
  84.  
  85. typedef struct {
  86. QString wifiSSID;
  87. QString wifiBSSID;
  88. int signal;
  89. wifi_band_t band;
  90. } wifi_network_t;
  91.  
  92. inline QString wifiBandToStr(wifi_band_t band) {
  93. switch (band) {
  94. case WIFI_BAND_2_4_GHZ:
  95. return "2.4 GHz";
  96. case WIFI_BAND_5_GHZ:
  97. return "5 GHz";
  98. default:
  99. return "Unknown";
  100. }
  101. }
  102.  
  103. class WiFiManager
  104. {
  105. public:
  106. WiFiManager();
  107. ~WiFiManager();
  108. QList<wifi_network_t> scanNetworks(interface_desc_t wifi_interface);
  109. QList<wifi_network_t> getLastScannedNetworks() { return wifiNetworks; }
  110. interface_desc_t getLastScannedWifiInterface() { return wifiScannedInterface; }
  111.  
  112. QList<interface_desc_t> getWifiInterfaces();
  113. QList<interface_desc_t> getLastCheckedWifiInterfaces() { return interfacesDescriptions; }
  114.  
  115. private:
  116. QList<interface_desc_t> interfacesDescriptions;
  117. QList<wifi_network_t> wifiNetworks;
  118. interface_desc_t wifiScannedInterface;
  119.  
  120. QString tempFolderPath;
  121. };
  122.  
  123. #endif // WIFIMANAGER_H
  124.  

wifimanager.cpp

  1. #include "wifimanager.h"
  2.  
  3.  
  4. WiFiManager::WiFiManager() {
  5.  
  6. }
  7.  
  8. WiFiManager::~WiFiManager() {
  9. interfacesDescriptions.clear();
  10. }
  11.  
  12. QList<interface_desc_t> WiFiManager::getWifiInterfaces() {
  13. QProcess process;
  14.  
  15. qDebug() << "WiFi interfaces getting...";
  16.  
  17. // Выполняем команду netsh
  18. QString cmd = QString("cmd /U /C chcp 437 > nul && netsh wlan show interfaces");
  19. // process.start("netsh", QStringList() << "wlan" << "show" << "interfaces");
  20. process.startCommand(cmd);
  21. process.waitForFinished();
  22.  
  23. QString output = QString::fromLocal8Bit(process.readAllStandardOutput());
  24. QStringList lines = output.split("\n");
  25.  
  26. interface_desc_t currentInterface;
  27. bool parsingInterface = false;
  28.  
  29. // Регулярные выражения для разбора
  30. QRegularExpression nameRe("^Name\\s*:\\s*(.+)$");
  31. QRegularExpression descRe("^Description\\s*:\\s*(.+)$");
  32. QRegularExpression macRe("^Physical address\\s*:\\s*([0-9a-fA-F:]+)$");
  33. QRegularExpression typeRe("^Interface type\\s*:\\s*(.+)$");
  34. QRegularExpression stateRe("^State\\s*:\\s*(.+)$");
  35. QRegularExpression ssidRe("^SSID\\s*:\\s*(.+)$");
  36. QRegularExpression bandRe("^Band\\s*:\\s*(.+)$");
  37. QRegularExpression authRe("^Authentication\\s*:\\s*(.+)$");
  38. QRegularExpression signalRe("^Signal\\s*:\\s*(\\d+)%$");
  39. QRegularExpression profileRe("^Profile\\s*:\\s*(.+)$");
  40.  
  41. for (const QString& line : lines) {
  42. QString trimmedLine = line.trimmed();
  43. qDebug() << "Line to be parsed: " << line << ", trimmed: " << trimmedLine;
  44. if (trimmedLine.isEmpty()) {
  45. if (parsingInterface && currentInterface.interfaceName.length() > 0) {
  46. qDebug() << "Interface name to be added: " + currentInterface.interfaceName;
  47. interfacesDescriptions.append(currentInterface);
  48. parsingInterface = false;
  49. }
  50. continue;
  51. }
  52.  
  53.  
  54. QRegularExpressionMatch match;
  55.  
  56. if (!parsingInterface) {
  57. currentInterface = interface_desc_t();
  58. currentInterface.currentBand = WIFI_BAND_UNKNOWN;
  59. currentInterface.signal = 0;
  60. currentInterface.authType = AUTH_TYPE_UNKNOWN;
  61. parsingInterface = true;
  62. qDebug() << "Starting new interface parsing";
  63. }
  64.  
  65. // Парсинг полей
  66. if ((match = nameRe.match(trimmedLine)).hasMatch()) {
  67. currentInterface.interfaceName = match.captured(1);
  68. qDebug() << "Interface name parsed: " << currentInterface.interfaceName;
  69. // parsingInterface = true;
  70. // continue;
  71. }
  72. else if ((match = descRe.match(trimmedLine)).hasMatch()) {
  73. currentInterface.interfaceDesc = match.captured(1);
  74. qDebug() << "Interface desc parsed: " << currentInterface.interfaceDesc;
  75. // parsingInterface = true;
  76. // continue;
  77. }
  78. else if ((match = macRe.match(trimmedLine)).hasMatch()) {
  79. currentInterface.interfaceMAC = match.captured(1);
  80. qDebug() << "Interface MAC parsed: " << currentInterface.interfaceMAC;
  81. // parsingInterface = true;
  82. // continue;
  83. }
  84. else if ((match = typeRe.match(trimmedLine)).hasMatch()) {
  85. qDebug() << "interface type parsed: " << match.captured(1);
  86. currentInterface.interfaceType = match.captured(1) == "Primary" ?
  87. INTERFACE_TYPE_PRIMARY : INTERFACE_TYPE_SECONDARY;
  88. // parsingInterface = true;
  89. // continue;
  90. }
  91. else if ((match = stateRe.match(trimmedLine)).hasMatch()) {
  92. qDebug() << "state parsed: " << match.captured(1);
  93. currentInterface.wifiConnected = match.captured(1) == "connected" ?
  94. WIFI_STATE_CONNECTED : WIFI_STATE_DISCONNECTED;
  95. // parsingInterface = true;
  96. // continue;
  97. }
  98. else if ((match = ssidRe.match(trimmedLine)).hasMatch()) {
  99. qDebug() << "current SSID parsed: " << match.captured(1);
  100. currentInterface.wifiSSIDConnected = match.captured(1);
  101. // parsingInterface = true;
  102. // continue;
  103. }
  104. else if ((match = bandRe.match(trimmedLine)).hasMatch()) {
  105. QString band = match.captured(1);
  106. qDebug() << "band parsed: " << band;
  107. if (band == "2.4 GHz") {
  108. currentInterface.currentBand = WIFI_BAND_2_4_GHZ;
  109. } else if (band == "5 GHz") {
  110. currentInterface.currentBand = WIFI_BAND_5_GHZ;
  111. } else {
  112. currentInterface.currentBand = WIFI_BAND_UNKNOWN;
  113. }
  114. // parsingInterface = true;
  115. // continue;
  116. }
  117. else if ((match = authRe.match(trimmedLine)).hasMatch()) {
  118. QString auth = match.captured(1);
  119. qDebug() << "auth type parsed: " << auth;
  120. if (auth == "Open") currentInterface.authType = AUTH_TYPE_OPEN;
  121. else if (auth == "Shared") currentInterface.authType = AUTH_TYPE_SHARED;
  122. else if (auth == "WPA-Personal") currentInterface.authType = AUTH_TYPE_WPA_PERSONAL;
  123. else if (auth == "WPA-Enterprise") currentInterface.authType = AUTH_TYPE_WPA_ENTERPRISE;
  124. else if (auth == "WPA2-Personal") currentInterface.authType = AUTH_TYPE_WPA2_PERSONAL;
  125. else if (auth == "WPA2-Enterprise") currentInterface.authType = AUTH_TYPE_WPA2_ENTERPRISE;
  126. else if (auth == "WPA3-Personal") currentInterface.authType = AUTH_TYPE_WPA3_PERSONAL;
  127. else if (auth == "WPA3-Enterprise") currentInterface.authType = AUTH_TYPE_WPA3_ENTERPRISE;
  128. else currentInterface.authType = AUTH_TYPE_UNKNOWN;
  129.  
  130. // parsingInterface = true;
  131. // continue;
  132. }
  133. else if ((match = signalRe.match(trimmedLine)).hasMatch()) {
  134. qDebug() << "current signal parsed: " << match.captured(1);
  135. currentInterface.signal = match.captured(1).toInt();
  136. // parsingInterface = true;
  137. // continue;
  138. }
  139. else if ((match = profileRe.match(trimmedLine)).hasMatch()) {
  140. qDebug() << "profile used parsed: " << match.captured(1);
  141. currentInterface.currentProfileUsed = match.captured(1);
  142. // parsingInterface = true;
  143. // continue;
  144. }
  145.  
  146.  
  147. }
  148.  
  149. // Добавляем последний интерфейс, если он есть
  150. if (parsingInterface && currentInterface.interfaceName.length() > 0) {
  151. qDebug() << "Last interface name to be added: " + currentInterface.interfaceName;
  152. interfacesDescriptions.append(currentInterface);
  153. parsingInterface = false;
  154. }
  155.  
  156. return interfacesDescriptions;
  157. }
  158.  
  159. QList<wifi_network_t> WiFiManager::scanNetworks(interface_desc_t wifi_interface) {
  160. QProcess process;
  161.  
  162. wifiScannedInterface = wifi_interface;
  163.  
  164. wifiNetworks.clear();
  165.  
  166. // process.start("netsh", {"wlan", "show", "networks", "mode=bssid"});
  167. QString cmd = QString("cmd /U /C chcp 437 > nul && netsh wlan show networks mode=bssid interface=\"%1\"").arg(wifiScannedInterface.interfaceName);
  168. process.startCommand(cmd);
  169. process.waitForFinished();
  170.  
  171. QString output = process.readAllStandardOutput();
  172. QTextStream stream(&output);
  173.  
  174. // Регулярные выражения для парсинга
  175. QRegularExpression ssidRegex("\\bSSID\\b (\\d+)( +):((.+)|\\n)");
  176. QRegularExpression bssidRegex("( +)\\bBSSID\\b (\\d+)( +): (.+)");
  177. QRegularExpression signalRegex("( +)\\bSignal\\b( +): (\\d+)(%)");
  178. QRegularExpression bandRegex("( +)\\bBand\\b( +): (.+)");
  179.  
  180. bool parsingNetwork = false;
  181. wifi_network_t currentNetwork;
  182.  
  183. while (!stream.atEnd()) {
  184. QString line = stream.readLine();
  185.  
  186. // Ищем начало новой сети
  187. QRegularExpressionMatch ssidMatch = ssidRegex.match(line);
  188. if (ssidMatch.hasMatch()) {
  189. QString ssid_to_check = ssidMatch.captured(3);
  190. currentNetwork.wifiSSID = ssid_to_check;
  191. qDebug() << "Got SSID: " << currentNetwork.wifiSSID;
  192. parsingNetwork = true;
  193. continue;
  194. }
  195.  
  196. // Ищем BSSID
  197. QRegularExpressionMatch bssidMatch = bssidRegex.match(line);
  198. if (bssidMatch.hasMatch()) {
  199. currentNetwork.wifiBSSID = bssidMatch.captured(4);
  200. qDebug() << "Got BSSID: " << currentNetwork.wifiBSSID;
  201. parsingNetwork = true;
  202. continue;
  203. }
  204.  
  205. // Ищем уровень сигнала
  206. QRegularExpressionMatch signalMatch = signalRegex.match(line);
  207. if (signalMatch.hasMatch()) {
  208. qDebug() << "Got signal: " << signalMatch.captured(3);
  209. currentNetwork.signal = signalMatch.captured(3).toInt();
  210. parsingNetwork = true;
  211. continue;
  212. }
  213.  
  214. // Ищем полосу частот
  215. QRegularExpressionMatch bandMatch = bandRegex.match(line);
  216. if (bandMatch.hasMatch()) {
  217. QString bandStr = bandMatch.captured(3);
  218. qDebug() << "Got band: " << bandStr;
  219. if (bandStr == "2.4 GHz")
  220. currentNetwork.band = WIFI_BAND_2_4_GHZ;
  221. else if (bandStr == "5 GHz")
  222. currentNetwork.band = WIFI_BAND_5_GHZ;
  223. else
  224. currentNetwork.band = WIFI_BAND_UNKNOWN;
  225.  
  226. // parsingNetwork = true;
  227. // Добавляем сеть в список
  228. if (parsingNetwork) {
  229. currentNetwork.wifiSSID = currentNetwork.wifiSSID.trimmed();
  230.  
  231. qDebug() << "WiFi SSID found: " << currentNetwork.wifiSSID << " (" + currentNetwork.wifiBSSID + ")";
  232. // Excluding empty wifi ssids
  233. if (!currentNetwork.wifiSSID.isNull())
  234. if (currentNetwork.wifiSSID.length() > 0)
  235. wifiNetworks.append(currentNetwork);
  236.  
  237. parsingNetwork = false;
  238. }
  239. continue;
  240. }
  241.  
  242. }
  243.  
  244. return wifiNetworks;
  245. }
  246.  
1

Вам це подобається? Поділіться в соціальних мережах!

0

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
  • Останні коментарі
  • Evgenii Legotckoi
    16 квітня 2025 р. 17:08
    Благодарю за отзыв. И вам желаю всяческих успехов!
  • IscanderChe
    12 квітня 2025 р. 17:12
    Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
  • AK
    01 квітня 2025 р. 11:41
    Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
  • Evgenii Legotckoi
    09 березня 2025 р. 21:02
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    09 березня 2025 р. 16:14
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…