diff --git a/src/slic3r/GUI/WifiConfigDialog.cpp b/src/slic3r/GUI/WifiConfigDialog.cpp index e5be758be5..9e535337fc 100644 --- a/src/slic3r/GUI/WifiConfigDialog.cpp +++ b/src/slic3r/GUI/WifiConfigDialog.cpp @@ -29,6 +29,19 @@ WifiConfigDialog::WifiConfigDialog(wxWindow* parent, std::string& file_path, Rem , out_file_path(file_path) , m_removable_manager(removable_manager) { + // Propagation of error in wifi scanner construtor + if (!m_wifi_scanner->is_init()) { + // TRN Error dialog of configuration -> wifi configuration file + wxString msg = format_wxstr(L"%1%\n\n%2%", _L("Failed to scan wireless networks. Please fill SSID manually."), +#ifdef _WIN32 + // TRN Windows specific second line of error dialog of configuration -> wifi configuration file + _L("Library wlanapi.dll was not loaded.") +#else + "" +#endif // _WIN32 + ); + show_error(this, msg); + } wxPanel* panel = new wxPanel(this); wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); panel->SetSizer(vsizer); @@ -188,6 +201,9 @@ void WifiConfigDialog::on_rescan_networks(wxCommandEvent& e) void WifiConfigDialog::rescan_networks(bool select) { assert(m_ssid_combo && m_wifi_scanner); + // Do not do anything if scanner is in faulty state (which should has been propageted in constructor call) + if (!m_wifi_scanner->is_init()) + return; m_wifi_scanner->scan(); std::string current = m_wifi_scanner->get_current_ssid(); const auto& map = m_wifi_scanner->get_map(); diff --git a/src/slic3r/Utils/WifiScanner.cpp b/src/slic3r/Utils/WifiScanner.cpp index aa4c8f4e9f..390a6b2e04 100644 --- a/src/slic3r/Utils/WifiScanner.cpp +++ b/src/slic3r/Utils/WifiScanner.cpp @@ -8,13 +8,11 @@ #ifdef _WIN32 #include -#include #include #include -// Need to link with Wlanapi.lib and Ole32.lib -#pragma comment(lib, "wlanapi.lib") -#pragma comment(lib, "ole32.lib") +#include "libslic3r//Utils.hpp" + #elif __APPLE_ #include "WifiScannerMac.h" #endif @@ -43,138 +41,6 @@ bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& t return false; // Element not found in this subtree } - -// Fill SSID map. Implementation from Raspberry Pi imager and Win32 Api examples. -// https://github.com/raspberrypi/rpi-imager/blob/qml/src/windows/winwlancredentials.cpp -// https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist -void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid) -{ - HANDLE handle; - DWORD supported_version = 0; - DWORD client_version = 2; - PWLAN_INTERFACE_INFO_LIST interface_list = NULL; - - - if (WlanOpenHandle(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS) - return; - - if (WlanEnumInterfaces(handle, NULL, &interface_list) != ERROR_SUCCESS) - return; - - for (DWORD i = 0; i < interface_list->dwNumberOfItems; i++) - { - if (interface_list->InterfaceInfo[i].isState == wlan_interface_state_connected) - { - PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL; - DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES); - WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid; - - if (WlanQueryInterface(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, - wlan_intf_opcode_current_connection, NULL, - &connectInfoSize, (PVOID*)&pConnectInfo, &opCode) == ERROR_SUCCESS && pConnectInfo && pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength) - { - connected_ssid = std::string((const char*)pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID, - pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength); - } - - WlanFreeMemory(pConnectInfo); - } - - PWLAN_PROFILE_INFO_LIST profile_list = NULL; - PWLAN_INTERFACE_INFO interface_info_entry = NULL; - PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; - WCHAR guid[39] = { 0 }; - - // Get all available networks. - interface_info_entry = (WLAN_INTERFACE_INFO*)&interface_list->InterfaceInfo[i]; - int iRet = StringFromGUID2(interface_info_entry->InterfaceGuid, (LPOLESTR)&guid, - sizeof(guid) / sizeof(*guid)); - - if (WlanGetAvailableNetworkList(handle, - &interface_info_entry->InterfaceGuid, - 0, - NULL, - &available_network_list) - != ERROR_SUCCESS) - { - continue; - } - - for (unsigned int j = 0; j < available_network_list->dwNumberOfItems; j++) - { - PWLAN_AVAILABLE_NETWORK available_network_entry = NULL; - wxString ssid; - - // Store SSID into the map. - available_network_entry = - (WLAN_AVAILABLE_NETWORK*)&available_network_list->Network[j]; - - if (available_network_entry->dot11Ssid.uSSIDLength != 0) - ssid = wxString(available_network_entry->dot11Ssid.ucSSID, - available_network_entry->dot11Ssid.uSSIDLength); - - if (ssid.empty()) - continue; - - if (wifi_map.find(ssid) != wifi_map.end()) - continue; - - wifi_map[ssid] = std::string(); - - if (WlanGetProfileList(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, - NULL, &profile_list) != ERROR_SUCCESS) - { - continue; - } - // enmurate all stored profiles, take password from matching one. - for (DWORD k = 0; k < profile_list->dwNumberOfItems; k++) - { - DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY; - DWORD access = 0; - DWORD ret = 0; - LPWSTR xmlstr = NULL; - wxString s(profile_list->ProfileInfo[k].strProfileName); - - BOOST_LOG_TRIVIAL(debug) << "Enumerating wlan profiles, SSID found:" << s << " looking for:" << ssid; - - if (s != ssid) - continue; - - if ((ret = WlanGetProfile(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName, - NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr) - { - wxString xml(xmlstr); - boost::property_tree::ptree pt; - std::stringstream ss(boost::nowide::narrow(xml)); - boost::property_tree::read_xml(ss, pt); - std::string password; - std::string psk_protected; - - BOOST_LOG_TRIVIAL(debug) << "XML wlan profile:" << xml; - - // break if password is not readable - // TODO: what if there is other line "protected" in the XML? - if (ptree_get_value(pt, "protected", psk_protected) && psk_protected != "false") - break; - - if (ptree_get_value(pt, "keyMaterial", password)) - wifi_map[ssid] = password; - - WlanFreeMemory(xmlstr); - break; - } - } - - if (profile_list) { - WlanFreeMemory(profile_list); - } - } - } - - if (interface_list) - WlanFreeMemory(interface_list); - WlanCloseHandle(handle, NULL); -} #elif __APPLE__ void get_connected_ssid(std::string& connected_ssid) { @@ -395,11 +261,39 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map) namespace Slic3r { WifiScanner::WifiScanner() -{} +{ +#ifdef _WIN32 + m_wlanapi_handle = LoadLibrary(L"wlanapi.dll"); + if (m_wlanapi_handle == NULL) + return; + + wlanOpenHandleFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanOpenHandle")); + wlanEnumInterfacesFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanEnumInterfaces")); + wlanQueryInterfaceFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanQueryInterface")); + wlanFreeMemoryFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanFreeMemory")); + wlanGetProfileFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanGetProfile")); + wlanGetProfileListFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanGetProfileList")); + wlanGetAvailableNetworkListFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanGetAvailableNetworkList")); + wlanCloseHandleFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanCloseHandle")); + + if (!wlanOpenHandleFunc || !wlanEnumInterfacesFunc || !wlanQueryInterfaceFunc || !wlanFreeMemoryFunc + || !wlanGetProfileFunc || !wlanGetProfileListFunc || !wlanGetAvailableNetworkListFunc || !wlanCloseHandleFunc) + return; +#endif // _WIN32 + m_init = true; +} WifiScanner::~WifiScanner() -{} +{ +#ifdef _WIN32 + if (m_wlanapi_handle) + FreeLibrary(m_wlanapi_handle); +#endif // _WIN32 + +} void WifiScanner::scan() { + if (!m_init) + return; m_map.clear(); #ifdef _WIN32 fill_wifi_map(m_map, m_current_ssid); @@ -459,4 +353,140 @@ std::string WifiScanner::get_psk(const std::string& ssid) } return {}; } + +#ifdef _WIN32 +// Fill SSID map. Implementation from Raspberry Pi imager and Win32 Api examples. +// https://github.com/raspberrypi/rpi-imager/blob/qml/src/windows/winwlancredentials.cpp +// https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist +void WifiScanner::fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid) +{ + HANDLE handle; + DWORD supported_version = 0; + DWORD client_version = 2; + PWLAN_INTERFACE_INFO_LIST interface_list = NULL; + + if (!m_init) + return; + + if (wlanOpenHandleFunc(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS) + return; + + Slic3r::ScopeGuard guard([this, &handle] { wlanCloseHandleFunc(handle, NULL); }); + + if (wlanEnumInterfacesFunc(handle, NULL, &interface_list) != ERROR_SUCCESS) + return; + + for (DWORD i = 0; i < interface_list->dwNumberOfItems; i++) + { + if (interface_list->InterfaceInfo[i].isState == wlan_interface_state_connected) + { + PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL; + DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES); + WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid; + + if (wlanQueryInterfaceFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, + wlan_intf_opcode_current_connection, NULL, + &connectInfoSize, (PVOID*)&pConnectInfo, &opCode) == ERROR_SUCCESS && pConnectInfo && pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength) + { + connected_ssid = std::string((const char*)pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID, + pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength); + wlanFreeMemoryFunc(pConnectInfo); + } + } + + PWLAN_PROFILE_INFO_LIST profile_list = NULL; + PWLAN_INTERFACE_INFO interface_info_entry = NULL; + PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; + WCHAR guid[39] = { 0 }; + + // Get all available networks. + interface_info_entry = (WLAN_INTERFACE_INFO*)&interface_list->InterfaceInfo[i]; + int iRet = StringFromGUID2(interface_info_entry->InterfaceGuid, (LPOLESTR)&guid, + sizeof(guid) / sizeof(*guid)); + + if (wlanGetAvailableNetworkListFunc(handle, + &interface_info_entry->InterfaceGuid, + 0, + NULL, + &available_network_list) + != ERROR_SUCCESS) + { + continue; + } + + for (unsigned int j = 0; j < available_network_list->dwNumberOfItems; j++) + { + PWLAN_AVAILABLE_NETWORK available_network_entry = NULL; + wxString ssid; + + // Store SSID into the map. + available_network_entry = + (WLAN_AVAILABLE_NETWORK*)&available_network_list->Network[j]; + + if (available_network_entry->dot11Ssid.uSSIDLength != 0) + ssid = wxString(available_network_entry->dot11Ssid.ucSSID, + available_network_entry->dot11Ssid.uSSIDLength); + + if (ssid.empty()) + continue; + + if (wifi_map.find(ssid) != wifi_map.end()) + continue; + + wifi_map[ssid] = std::string(); + + if (wlanGetProfileListFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, + NULL, &profile_list) != ERROR_SUCCESS) + { + continue; + } + // enmurate all stored profiles, take password from matching one. + for (DWORD k = 0; k < profile_list->dwNumberOfItems; k++) + { + DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY; + DWORD access = 0; + DWORD ret = 0; + LPWSTR xmlstr = NULL; + wxString s(profile_list->ProfileInfo[k].strProfileName); + + BOOST_LOG_TRIVIAL(debug) << "Enumerating wlan profiles, SSID found:" << s << " looking for:" << ssid; + + if (s != ssid) + continue; + + if ((ret = wlanGetProfileFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName, + NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr) + { + wxString xml(xmlstr); + boost::property_tree::ptree pt; + std::stringstream ss(boost::nowide::narrow(xml)); + boost::property_tree::read_xml(ss, pt); + std::string password; + std::string psk_protected; + + BOOST_LOG_TRIVIAL(debug) << "XML wlan profile:" << xml; + + // break if password is not readable + // TODO: what if there is other line "protected" in the XML? + if (ptree_get_value(pt, "protected", psk_protected) && psk_protected != "false") + break; + + if (ptree_get_value(pt, "keyMaterial", password)) + wifi_map[ssid] = password; + + wlanFreeMemoryFunc(xmlstr); + break; + } + } + + if (profile_list) { + wlanFreeMemoryFunc(profile_list); + } + } + } + + if (interface_list) + wlanFreeMemoryFunc(interface_list); +} +#endif // _WIN32 } // Slic3r \ No newline at end of file diff --git a/src/slic3r/Utils/WifiScanner.hpp b/src/slic3r/Utils/WifiScanner.hpp index 96befa5e65..0223e2d8dc 100644 --- a/src/slic3r/Utils/WifiScanner.hpp +++ b/src/slic3r/Utils/WifiScanner.hpp @@ -6,9 +6,13 @@ #include #include +#ifdef _WIN32 +#include +#endif //_WIN32 + namespace Slic3r { -typedef std::map WifiSsidPskMap; +using WifiSsidPskMap = std::map; class WifiScanner { @@ -16,6 +20,8 @@ public: WifiScanner(); ~WifiScanner(); + bool is_init() const { return m_init; } + const WifiSsidPskMap& get_map() const { return m_map; } // returns psk for given ssid // used on APPLE where each psk query requires user to give their password @@ -27,7 +33,31 @@ public: private: WifiSsidPskMap m_map; std::string m_current_ssid; -#if __APPLE__ + + bool m_init { false }; + +#ifdef _WIN32 + void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid); + HINSTANCE m_wlanapi_handle; + // Functions of wlanapi used by fill_wifi_map + using WlanOpenHandleFunc = DWORD(WINAPI*)(DWORD, PVOID, PDWORD, PHANDLE); + using WlanEnumInterfacesFunc = DWORD(WINAPI*)(HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST*); + using WlanQueryInterfaceFunc = DWORD(WINAPI*)(HANDLE, const GUID*, WLAN_INTF_OPCODE, PVOID, PDWORD, PVOID*, PWLAN_OPCODE_VALUE_TYPE); + using WlanFreeMemoryFunc = VOID(WINAPI*)(PVOID); + using WlanGetProfileFunc = DWORD(WINAPI*)(HANDLE, const GUID*, LPCWSTR, PVOID, LPWSTR*, DWORD*, DWORD*); + using WlanGetProfileListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, PVOID, PWLAN_PROFILE_INFO_LIST*); + using WlanGetAvailableNetworkListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, DWORD, PVOID, PWLAN_AVAILABLE_NETWORK_LIST*); + using WlanCloseHandleFunc = DWORD(WINAPI*)(HANDLE, PVOID); + + WlanOpenHandleFunc wlanOpenHandleFunc; + WlanEnumInterfacesFunc wlanEnumInterfacesFunc; + WlanQueryInterfaceFunc wlanQueryInterfaceFunc; + WlanFreeMemoryFunc wlanFreeMemoryFunc; + WlanGetProfileFunc wlanGetProfileFunc; + WlanGetProfileListFunc wlanGetProfileListFunc; + WlanGetAvailableNetworkListFunc wlanGetAvailableNetworkListFunc; + WlanCloseHandleFunc wlanCloseHandleFunc; +#elif __APPLE__ void get_ssids_mac(std::vector& ssids); std::string get_psk_mac(const std::string& ssid); std::string get_current_ssid_mac();