Browse Source

Error message when wlanapi.dll is missing
Code improvements due to @lukasmatena code review.

David Kocik 1 year ago
parent
commit
e0e1afd640
3 changed files with 214 additions and 169 deletions
  1. 16 0
      src/slic3r/GUI/WifiConfigDialog.cpp
  2. 166 167
      src/slic3r/Utils/WifiScanner.cpp
  3. 32 2
      src/slic3r/Utils/WifiScanner.hpp

+ 16 - 0
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();

+ 166 - 167
src/slic3r/Utils/WifiScanner.cpp

@@ -8,7 +8,6 @@
 
 #ifdef _WIN32
 #include <windows.h>
-#include <wlanapi.h>
 #include <objbase.h>
 #include <wtypes.h>
 
@@ -42,170 +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)
-{
-    HINSTANCE hWlanApi = LoadLibrary(L"wlanapi.dll");
-    if (hWlanApi == NULL)
-        return;
-    Slic3r::ScopeGuard guard([&hWlanApi] { FreeLibrary(hWlanApi); });
-    
-    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         = reinterpret_cast<WlanOpenHandleFunc>(GetProcAddress(hWlanApi, "WlanOpenHandle"));
-    WlanEnumInterfacesFunc wlanEnumInterfacesFunc = reinterpret_cast<WlanEnumInterfacesFunc>(GetProcAddress(hWlanApi, "WlanEnumInterfaces"));
-    WlanQueryInterfaceFunc wlanQueryInterfaceFunc = reinterpret_cast<WlanQueryInterfaceFunc>(GetProcAddress(hWlanApi, "WlanQueryInterface"));
-    WlanFreeMemoryFunc wlanFreeMemoryFunc         = reinterpret_cast<WlanFreeMemoryFunc>(GetProcAddress(hWlanApi, "WlanFreeMemory"));
-    WlanGetProfileFunc wlanGetProfileFunc         = reinterpret_cast<WlanGetProfileFunc>(GetProcAddress(hWlanApi, "WlanGetProfile"));
-    WlanGetProfileListFunc wlanGetProfileListFunc = reinterpret_cast<WlanGetProfileListFunc>(GetProcAddress(hWlanApi, "WlanGetProfileList"));
-    WlanGetAvailableNetworkListFunc wlanGetAvailableNetworkListFunc = reinterpret_cast<WlanGetAvailableNetworkListFunc>(GetProcAddress(hWlanApi, "WlanGetAvailableNetworkList"));
-    WlanCloseHandleFunc wlanCloseHandleFunc       = reinterpret_cast<WlanCloseHandleFunc>(GetProcAddress(hWlanApi, "WlanCloseHandle"));
-
-    if (! wlanOpenHandleFunc || ! wlanEnumInterfacesFunc || ! wlanQueryInterfaceFunc || ! wlanFreeMemoryFunc
-     || ! wlanGetProfileFunc || ! wlanGetProfileListFunc || ! wlanGetAvailableNetworkListFunc || ! wlanCloseHandleFunc)
-        return;
-
-
-    HANDLE handle;
-    DWORD supported_version = 0;
-    DWORD client_version = 2;
-    PWLAN_INTERFACE_INFO_LIST interface_list = NULL;
-
-    
-    if (wlanOpenHandleFunc(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS)
-        return;
-
-    if (wlanEnumInterfacesFunc(handle, NULL, &interface_list) != ERROR_SUCCESS) {
-        // Touhle cestou funkce vrati bez toho, aby zavolala WlanCloseHandleFunc.
-        // I tady by stalo za uvahu pouziti ScopeGuard, ktery podobnou chybu vylouci
-        // a kod bude exception-safe (coz je tady asi jedno, ale obecne to jedno neni).
-        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);
-    wlanCloseHandleFunc(handle, NULL);
-}
 #elif __APPLE__
 void get_connected_ssid(std::string& connected_ssid)
 {
@@ -426,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<WlanOpenHandleFunc>(GetProcAddress(m_wlanapi_handle, "WlanOpenHandle"));
+    wlanEnumInterfacesFunc = reinterpret_cast<WlanEnumInterfacesFunc>(GetProcAddress(m_wlanapi_handle, "WlanEnumInterfaces"));
+    wlanQueryInterfaceFunc = reinterpret_cast<WlanQueryInterfaceFunc>(GetProcAddress(m_wlanapi_handle, "WlanQueryInterface"));
+    wlanFreeMemoryFunc = reinterpret_cast<WlanFreeMemoryFunc>(GetProcAddress(m_wlanapi_handle, "WlanFreeMemory"));
+    wlanGetProfileFunc = reinterpret_cast<WlanGetProfileFunc>(GetProcAddress(m_wlanapi_handle, "WlanGetProfile"));
+    wlanGetProfileListFunc = reinterpret_cast<WlanGetProfileListFunc>(GetProcAddress(m_wlanapi_handle, "WlanGetProfileList"));
+    wlanGetAvailableNetworkListFunc = reinterpret_cast<WlanGetAvailableNetworkListFunc>(GetProcAddress(m_wlanapi_handle, "WlanGetAvailableNetworkList"));
+    wlanCloseHandleFunc = reinterpret_cast<WlanCloseHandleFunc>(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);
@@ -490,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

+ 32 - 2
src/slic3r/Utils/WifiScanner.hpp

@@ -6,9 +6,13 @@
 #include <string>
 #include <wx/string.h>
 
+#ifdef _WIN32
+#include <wlanapi.h>
+#endif //_WIN32
+
 namespace Slic3r {
 
-typedef std::map<wxString, std::string> WifiSsidPskMap;
+using  WifiSsidPskMap = std::map<wxString, std::string>;
 
 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<std::string>& ssids);
     std::string get_psk_mac(const std::string& ssid);
     std::string get_current_ssid_mac();