diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 7c8032810..133b771c8 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -18,6 +18,10 @@ #include #include #include + +#include +#include +#include #else // unix, linux & OSX includes #include @@ -80,7 +84,7 @@ std::vector RemovableDriveManager::search_for_removable_drives() cons namespace { - +#if 0 // From https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview typedef struct _STRING_DESCRIPTOR_NODE { @@ -581,6 +585,57 @@ void eject_alt(std::string path, wxEvtHandler* callback_evt_handler, DriveData d if (callback_evt_handler) wxPostEvent(callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(drive_data), true))); } +#endif // 0 + +// C++ equivavalent of PowerShell script: +// $driveEject = New - Object - comObject Shell.Application +// $driveEject.Namespace(17).ParseName("E:").InvokeVerb("Eject") +// from https://superuser.com/a/1750403 +bool eject_inner(const std::string& path) +{ + std::wstring wpath = boost::nowide::widen(path); + CoInitialize(nullptr); + CComPtr pShellDisp; + HRESULT hr = pShellDisp.CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER); + if (!SUCCEEDED(hr)) { + BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to get Shell pointer has failed.", path); + CoUninitialize(); + return false; + } + CComPtr pFolder; + VARIANT vtDrives; + VariantInit(&vtDrives); + vtDrives.vt = VT_I4; + vtDrives.lVal = ssfDRIVES; + hr = pShellDisp->NameSpace(vtDrives, &pFolder); + if (!SUCCEEDED(hr)) { + BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to create Namespace has failed.", path); + CoUninitialize(); + return false; + } + CComPtr pItem; + hr = pFolder->ParseName(static_cast(const_cast(wpath.c_str())), &pItem); + if (!SUCCEEDED(hr)) { + BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to Parse name has failed.", path); + CoUninitialize(); + return false; + } + VARIANT vtEject; + VariantInit(&vtEject); + vtEject.vt = VT_BSTR; + vtEject.bstrVal = SysAllocString(L"Eject"); + hr = pItem->InvokeVerb(vtEject); + if (!SUCCEEDED(hr)) { + BOOST_LOG_TRIVIAL(error) << GUI::format("Ejecting of %1% has failed: Attempt to Invoke Verb has failed.", path); + VariantClear(&vtEject); + CoUninitialize(); + return false; + } + BOOST_LOG_TRIVIAL(debug) << "Ejecting via InvokeVerb has succeeded."; + VariantClear(&vtEject); + CoUninitialize(); + return true; +} } // namespace // Called from UI therefore it blocks the UI thread. @@ -597,27 +652,19 @@ void RemovableDriveManager::eject_drive() BOOST_LOG_TRIVIAL(info) << "Ejecting started"; std::scoped_lock lock(m_drives_mutex); auto it_drive_data = this->find_last_save_path_drive_data(); -#if 1 if (it_drive_data != m_current_drives.end()) { - if (!eject_inner(m_last_save_path)) { + if (eject_inner(m_last_save_path)) { // success BOOST_LOG_TRIVIAL(info) << "Ejecting has succeeded."; assert(m_callback_evt_handler); if (m_callback_evt_handler) wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(*it_drive_data), true))); } else { - if (m_eject_thread.joinable()) - m_eject_thread.join(); - m_eject_thread = boost::thread(eject_alt, m_last_save_path, m_callback_evt_handler, std::move(*it_drive_data)); - // failed to eject - // this should not happen, throwing exception might be the way here - /* BOOST_LOG_TRIVIAL(error) << "Ejecting has failed."; assert(m_callback_evt_handler); if (m_callback_evt_handler) wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair(*it_drive_data, false))); - */ } } else { // drive not found in m_current_drives @@ -626,47 +673,6 @@ void RemovableDriveManager::eject_drive() if (m_callback_evt_handler) wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair({"",""}, false))); } -#endif -#if 0 - // Implementation used until 2.5.x version - // Some usb drives does not eject properly (still visible in file explorer). Some even does not write all content and eject. - if (it_drive_data != m_current_drives.end()) { - // get handle to device - std::string mpath = "\\\\.\\" + m_last_save_path; - mpath = mpath.substr(0, mpath.size() - 1); - HANDLE handle = CreateFileW(boost::nowide::widen(mpath).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - if (handle == INVALID_HANDLE_VALUE) { - BOOST_LOG_TRIVIAL(error) << "Ejecting " << mpath << " failed (handle == INVALID_HANDLE_VALUE): " << GetLastError(); - assert(m_callback_evt_handler); - if (m_callback_evt_handler) - wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair(*it_drive_data, false))); - return; - } - DWORD deviceControlRetVal(0); - //these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger. - //sd cards does trigger WM_DEVICECHANGE messege, usb drives dont - BOOL e1 = DeviceIoControl(handle, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); - BOOST_LOG_TRIVIAL(error) << "FSCTL_LOCK_VOLUME " << e1 << " ; " << deviceControlRetVal << " ; " << GetLastError(); - BOOL e2 = DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); - BOOST_LOG_TRIVIAL(error) << "FSCTL_DISMOUNT_VOLUME " << e2 << " ; " << deviceControlRetVal << " ; " << GetLastError(); - // some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here with FALSE as third parameter, which should set PreventMediaRemoval - BOOL error = DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, nullptr, 0, nullptr, 0, &deviceControlRetVal, nullptr); - if (error == 0) { - CloseHandle(handle); - BOOST_LOG_TRIVIAL(error) << "Ejecting " << mpath << " failed (IOCTL_STORAGE_EJECT_MEDIA)" << deviceControlRetVal << " " << GetLastError(); - assert(m_callback_evt_handler); - if (m_callback_evt_handler) - wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair(*it_drive_data, false))); - return; - } - CloseHandle(handle); - BOOST_LOG_TRIVIAL(info) << "Ejecting finished"; - assert(m_callback_evt_handler); - if (m_callback_evt_handler) - wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair< DriveData, bool >(std::move(*it_drive_data), true))); - m_current_drives.erase(it_drive_data); - } -#endif // 0 } std::string RemovableDriveManager::get_removable_drive_path(const std::string &path) diff --git a/src/slic3r/GUI/RemovableDriveManager.hpp b/src/slic3r/GUI/RemovableDriveManager.hpp index 264066c32..4ea25ea63 100644 --- a/src/slic3r/GUI/RemovableDriveManager.hpp +++ b/src/slic3r/GUI/RemovableDriveManager.hpp @@ -106,12 +106,6 @@ private: #endif /* _WIN32 */ #endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS -#ifdef _WIN32 - // Another worker thread, used only to perform alt_eject method (external SD cards only). - // Does not share data with m_thread - boost::thread m_eject_thread; -#endif /* _WIN32 */ - // Called from update() to enumerate removable drives. std::vector search_for_removable_drives() const;