From 7276a79cefe00f3e82fec8760ec876aa8a276df0 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 28 Sep 2019 15:46:26 +0800 Subject: [PATCH 1/4] Call Windows API directly We already bumped the OS requirement to Windows 7 and those functions can be called directly without the need to load them first. --- src/app/application.cpp | 13 +++---------- src/app/qtlocalpeer/qtlocalpeer.cpp | 11 +++-------- src/base/bittorrent/session.cpp | 16 ++++------------ src/base/utils/misc.cpp | 10 +++------- winconf.pri | 4 ++-- 5 files changed, 15 insertions(+), 39 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index f065cb72e..3c122bf86 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -685,11 +685,8 @@ void Application::cleanup() m_window->hide(); #ifdef Q_OS_WIN - typedef BOOL (WINAPI *PSHUTDOWNBRCREATE)(HWND, LPCWSTR); - const auto shutdownBRCreate = Utils::Misc::loadWinAPI("User32.dll", "ShutdownBlockReasonCreate"); - // Only available on Vista+ - if (shutdownBRCreate) - shutdownBRCreate((HWND)m_window->effectiveWinId(), tr("Saving torrent progress...").toStdWString().c_str()); + ::ShutdownBlockReasonCreate(reinterpret_cast(m_window->effectiveWinId()) + , tr("Saving torrent progress...").toStdWString().c_str()); #endif // Q_OS_WIN // Do manual cleanup in MainWindow to force widgets @@ -728,11 +725,7 @@ void Application::cleanup() #ifndef DISABLE_GUI if (m_window) { #ifdef Q_OS_WIN - using PSHUTDOWNBRDESTROY = BOOL (WINAPI *)(HWND); - const auto shutdownBRDestroy = Utils::Misc::loadWinAPI("User32.dll", "ShutdownBlockReasonDestroy"); - // Only available on Vista+ - if (shutdownBRDestroy) - shutdownBRDestroy(reinterpret_cast(m_window->effectiveWinId())); + ::ShutdownBlockReasonDestroy(reinterpret_cast(m_window->effectiveWinId())); #endif // Q_OS_WIN delete m_window; UIThemeManager::freeInstance(); diff --git a/src/app/qtlocalpeer/qtlocalpeer.cpp b/src/app/qtlocalpeer/qtlocalpeer.cpp index a8517a77a..71843de4f 100644 --- a/src/app/qtlocalpeer/qtlocalpeer.cpp +++ b/src/app/qtlocalpeer/qtlocalpeer.cpp @@ -116,14 +116,9 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + QLatin1Char('-') + QString::number(idNum, 16); #if defined(Q_OS_WIN) - using PPROCESSIDTOSESSIONID = BOOL (WINAPI *)(DWORD, DWORD *); - const auto processIdToSessionId = Utils::Misc::loadWinAPI("kernel32.dll", "ProcessIdToSessionId"); - - if (processIdToSessionId) { - DWORD sessionId = 0; - processIdToSessionId(GetCurrentProcessId(), &sessionId); - socketName += (QLatin1Char('-') + QString::number(sessionId, 16)); - } + DWORD sessionId = 0; + ::ProcessIdToSessionId(GetCurrentProcessId(), &sessionId); + socketName += (QLatin1Char('-') + QString::number(sessionId, 16)); #else socketName += (QLatin1Char('-') + QString::number(::getuid(), 16)); #endif diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 7e246fd54..707d2ef8f 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -4531,23 +4531,15 @@ namespace QString convertIfaceNameToGuid(const QString &name) { // Under Windows XP or on Qt version <= 5.5 'name' will be a GUID already. - QUuid uuid(name); + const QUuid uuid(name); if (!uuid.isNull()) return uuid.toString().toUpper(); // Libtorrent expects the GUID in uppercase - using PCONVERTIFACENAMETOLUID = NETIO_STATUS (WINAPI *)(const WCHAR *, PNET_LUID); - const auto ConvertIfaceNameToLuid = Utils::Misc::loadWinAPI("Iphlpapi.dll", "ConvertInterfaceNameToLuidW"); - if (!ConvertIfaceNameToLuid) return {}; - - using PCONVERTIFACELUIDTOGUID = NETIO_STATUS (WINAPI *)(const NET_LUID *, GUID *); - const auto ConvertIfaceLuidToGuid = Utils::Misc::loadWinAPI("Iphlpapi.dll", "ConvertInterfaceLuidToGuid"); - if (!ConvertIfaceLuidToGuid) return {}; - - NET_LUID luid; - const LONG res = ConvertIfaceNameToLuid(name.toStdWString().c_str(), &luid); + NET_LUID luid {}; + const LONG res = ::ConvertInterfaceNameToLuidW(name.toStdWString().c_str(), &luid); if (res == 0) { GUID guid; - if (ConvertIfaceLuidToGuid(&luid, &guid) == 0) + if (::ConvertInterfaceLuidToGuid(&luid, &guid) == 0) return QUuid(guid).toString().toUpper(); } diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index 1e3a08082..a8e4386bc 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -30,6 +30,7 @@ #ifdef Q_OS_WIN #include +#include #include #else #include @@ -117,16 +118,11 @@ void Utils::Misc::shutdownComputer(const ShutdownDialogAction &action) if (GetLastError() != ERROR_SUCCESS) return; - using PSETSUSPENDSTATE = BOOLEAN (WINAPI *)(BOOLEAN, BOOLEAN, BOOLEAN); - const auto setSuspendState = Utils::Misc::loadWinAPI("PowrProf.dll", "SetSuspendState"); - if (action == ShutdownDialogAction::Suspend) { - if (setSuspendState) - setSuspendState(false, false, false); + ::SetSuspendState(false, false, false); } else if (action == ShutdownDialogAction::Hibernate) { - if (setSuspendState) - setSuspendState(true, false, false); + ::SetSuspendState(true, false, false); } else { const QString msg = QCoreApplication::translate("misc", "qBittorrent will shutdown the computer now because all downloads are complete."); diff --git a/winconf.pri b/winconf.pri index b69b964a6..b4fbdaef3 100644 --- a/winconf.pri +++ b/winconf.pri @@ -34,7 +34,7 @@ win32-g++* { RC_FILE = qbittorrent_mingw.rc - LIBS += libadvapi32 libshell32 libuser32 libole32 libwsock32 libws2_32 + LIBS += libadvapi32 libiphlpapi libole32 libpowrprof libshell32 libuser32 libwsock32 libws2_32 } else:win32-msvc* { CONFIG -= embed_manifest_exe @@ -42,7 +42,7 @@ else:win32-msvc* { RC_FILE = qbittorrent.rc - LIBS += advapi32.lib shell32.lib crypt32.lib User32.lib ole32.lib + LIBS += advapi32.lib crypt32.lib Iphlpapi.lib ole32.lib PowrProf.lib shell32.lib User32.lib } # See an example build configuration in "conf.pri.windows" From 7f453a80d3c222ca5897cbda8a7dc1fb8dce108f Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 28 Sep 2019 16:49:36 +0800 Subject: [PATCH 2/4] Revise SessionSettingsEnums wrapper This simplify the wrapper to become a namespace. --- src/base/bittorrent/session.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 43b070dc9..7324ea812 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -95,18 +95,19 @@ namespace BitTorrent class TrackerEntry; struct CreateTorrentParams; - class SessionSettingsEnums + // Using `Q_ENUM_NS()` without a wrapper namespace in our case is not advised + // since `Q_NAMESPACE` cannot be used when the same namespace resides at different files. + // https://www.kdab.com/new-qt-5-8-meta-object-support-namespaces/#comment-143779 + namespace SessionSettingsEnums { - Q_GADGET + Q_NAMESPACE - public: - // TODO: remove `SessionSettingsEnums` wrapper when we can use `Q_ENUM_NS` directly (QT >= 5.8 only) enum class ChokingAlgorithm : int { FixedSlots = 0, RateBased = 1 }; - Q_ENUM(ChokingAlgorithm) + Q_ENUM_NS(ChokingAlgorithm) enum class SeedChokingAlgorithm : int { @@ -114,14 +115,14 @@ namespace BitTorrent FastestUpload = 1, AntiLeech = 2 }; - Q_ENUM(SeedChokingAlgorithm) + Q_ENUM_NS(SeedChokingAlgorithm) enum class MixedModeAlgorithm : int { TCP = 0, Proportional = 1 }; - Q_ENUM(MixedModeAlgorithm) + Q_ENUM_NS(MixedModeAlgorithm) enum class BTProtocol : int { @@ -129,12 +130,9 @@ namespace BitTorrent TCP = 1, UTP = 2 }; - Q_ENUM(BTProtocol) - }; - using ChokingAlgorithm = SessionSettingsEnums::ChokingAlgorithm; - using SeedChokingAlgorithm = SessionSettingsEnums::SeedChokingAlgorithm; - using MixedModeAlgorithm = SessionSettingsEnums::MixedModeAlgorithm; - using BTProtocol = SessionSettingsEnums::BTProtocol; + Q_ENUM_NS(BTProtocol) + } + using namespace SessionSettingsEnums; struct SessionMetricIndices { From d76adff81dd26b4bc9b99e8f269df7908d14c5b1 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 29 Sep 2019 09:47:06 +0800 Subject: [PATCH 3/4] Change Session::deleteTorrent() first parameter to take InfoHash type --- src/base/bittorrent/session.cpp | 2 +- src/base/bittorrent/session.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 707d2ef8f..7e3866031 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -1625,7 +1625,7 @@ void Session::banIP(const QString &ip) // Delete a torrent from the session, given its hash // and from the disk, if the corresponding deleteOption is chosen -bool Session::deleteTorrent(const QString &hash, const DeleteOption deleteOption) +bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOption) { TorrentHandle *const torrent = m_torrents.take(hash); if (!torrent) return false; diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 7324ea812..1dfbbfa42 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -407,7 +407,7 @@ namespace BitTorrent bool isKnownTorrent(const InfoHash &hash) const; bool addTorrent(const QString &source, const AddTorrentParams ¶ms = AddTorrentParams()); bool addTorrent(const TorrentInfo &torrentInfo, const AddTorrentParams ¶ms = AddTorrentParams()); - bool deleteTorrent(const QString &hash, DeleteOption deleteOption = Torrent); + bool deleteTorrent(const InfoHash &hash, DeleteOption deleteOption = Torrent); bool loadMetadata(const MagnetUri &magnetUri); bool cancelLoadMetadata(const InfoHash &hash); From 36056ad5af7c8dca051d629e8efbbcefab72abbb Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 29 Sep 2019 10:12:56 +0800 Subject: [PATCH 4/4] Avoid redundant lookups --- src/base/bittorrent/session.cpp | 48 +++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 7e3866031..e2029a1ce 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -1680,9 +1680,10 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio bool Session::cancelLoadMetadata(const InfoHash &hash) { - if (!m_loadedMetadata.contains(hash)) return false; + const auto loadedMetadataIter = m_loadedMetadata.find(hash); + if (loadedMetadataIter == m_loadedMetadata.end()) return false; - m_loadedMetadata.remove(hash); + m_loadedMetadata.erase(loadedMetadataIter); const lt::torrent_handle torrent = m_nativeSession->find_torrent(hash); if (!torrent.is_valid()) return false; @@ -4008,14 +4009,17 @@ void Session::handleTorrentRemovedAlert(const lt::torrent_removed_alert *p) { const InfoHash infoHash {p->info_hash}; - if (m_loadedMetadata.contains(infoHash)) - emit metadataLoaded(m_loadedMetadata.take(infoHash)); + const auto loadedMetadataIter = m_loadedMetadata.find(infoHash); + if (loadedMetadataIter != m_loadedMetadata.end()) { + emit metadataLoaded(*loadedMetadataIter); + m_loadedMetadata.erase(loadedMetadataIter); + } - if (m_removingTorrents.contains(infoHash)) { - const RemovingTorrentData tmpRemovingTorrentData = m_removingTorrents[infoHash]; - if (tmpRemovingTorrentData.deleteOption == Torrent) { - LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(tmpRemovingTorrentData.name)); - m_removingTorrents.remove(infoHash); + const auto removingTorrentDataIter = m_removingTorrents.find(infoHash); + if (removingTorrentDataIter != m_removingTorrents.end()) { + if (removingTorrentDataIter->deleteOption == Torrent) { + LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name)); + m_removingTorrents.erase(removingTorrentDataIter); } } } @@ -4023,44 +4027,48 @@ void Session::handleTorrentRemovedAlert(const lt::torrent_removed_alert *p) void Session::handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p) { const InfoHash infoHash {p->info_hash}; + const auto removingTorrentDataIter = m_removingTorrents.find(infoHash); - if (!m_removingTorrents.contains(infoHash)) + if (removingTorrentDataIter == m_removingTorrents.end()) return; - const RemovingTorrentData tmpRemovingTorrentData = m_removingTorrents.take(infoHash); - Utils::Fs::smartRemoveEmptyFolderTree(tmpRemovingTorrentData.savePathToRemove); - LogMsg(tr("'%1' was removed from the transfer list and hard disk.", "'xxx.avi' was removed...").arg(tmpRemovingTorrentData.name)); + Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->savePathToRemove); + LogMsg(tr("'%1' was removed from the transfer list and hard disk.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name)); + m_removingTorrents.erase(removingTorrentDataIter); } void Session::handleTorrentDeleteFailedAlert(const lt::torrent_delete_failed_alert *p) { const InfoHash infoHash {p->info_hash}; + const auto removingTorrentDataIter = m_removingTorrents.find(infoHash); - if (!m_removingTorrents.contains(infoHash)) + if (removingTorrentDataIter == m_removingTorrents.end()) return; - const RemovingTorrentData tmpRemovingTorrentData = m_removingTorrents.take(infoHash); + // libtorrent won't delete the directory if it contains files not listed in the torrent, // so we remove the directory ourselves - Utils::Fs::smartRemoveEmptyFolderTree(tmpRemovingTorrentData.savePathToRemove); + Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->savePathToRemove); if (p->error) { LogMsg(tr("'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2", "'xxx.avi' was removed...") - .arg(tmpRemovingTorrentData.name, QString::fromLocal8Bit(p->error.message().c_str())) + .arg(removingTorrentDataIter->name, QString::fromLocal8Bit(p->error.message().c_str())) , Log::WARNING); } else { - LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(tmpRemovingTorrentData.name)); + LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name)); } + m_removingTorrents.erase(removingTorrentDataIter); } void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p) { const InfoHash hash {p->handle.info_hash()}; + const auto loadedMetadataIter = m_loadedMetadata.find(hash); - if (m_loadedMetadata.contains(hash)) { + if (loadedMetadataIter != m_loadedMetadata.end()) { --m_extraLimit; adjustLimits(); - m_loadedMetadata[hash] = TorrentInfo(p->handle.torrent_file()); + *loadedMetadataIter = TorrentInfo(p->handle.torrent_file()); m_nativeSession->remove_torrent(p->handle, lt::session::delete_files); } }