diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-06-29 15:26:04 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2019-06-29 15:26:04 -0400 |
| commit | eab0ec298b81138c4c602259ebf930f583113b95 (patch) | |
| tree | 2ed827f459a6d462ef32f6fb4ca28153f124ed5d /src | |
| parent | 38b9c7c060aeee46d463930e313683e6e5bc0675 (diff) | |
refactored preloadSsl() into preloadDll()
removed old HGID check
moved formatSystemMessage() to uibase
added Environment class, lists loaded modules, logged at startup
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 70 | ||||
| -rw-r--r-- | src/settings.cpp | 31 | ||||
| -rw-r--r-- | src/shared/util.cpp | 327 | ||||
| -rw-r--r-- | src/shared/util.h | 50 |
4 files changed, 418 insertions, 60 deletions
diff --git a/src/main.cpp b/src/main.cpp index 6f304944..e1a6b853 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -411,27 +411,39 @@ void setupPath() ::SetEnvironmentVariableW(L"PATH", newPath.c_str()); } -static void preloadSsl() +void preloadDll(const QString& filename) { - QString appPath = QDir::toNativeSeparators(QCoreApplication::applicationDirPath()); - if (GetModuleHandleA("libeay32.dll")) - qWarning("libeay32.dll already loaded?!"); - else { - QString libeay32 = appPath + "\\libeay32.dll"; - if (!QFile::exists(libeay32)) - qWarning("libeay32.dll not found: %s", qUtf8Printable(libeay32)); - else if (!LoadLibraryW(libeay32.toStdWString().c_str())) - qWarning("failed to load: %s, %d", qUtf8Printable(libeay32), GetLastError()); + qDebug().nospace() << "preloading " << filename; + + if (!GetModuleHandleW(filename.toStdWString().c_str())) { + // already loaded, this can happen when "restarting" MO by switching + // instances, for example + return; } - if (GetModuleHandleA("ssleay32.dll")) - qWarning("ssleay32.dll already loaded?!"); - else { - QString ssleay32 = appPath + "\\ssleay32.dll"; - if (!QFile::exists(ssleay32)) - qWarning("ssleay32.dll not found: %s", qUtf8Printable(ssleay32)); - else if (!LoadLibraryW(ssleay32.toStdWString().c_str())) - qWarning("failed to load: %s, %d", qUtf8Printable(ssleay32), GetLastError()); + + const auto appPath = QDir::toNativeSeparators( + QCoreApplication::applicationDirPath()); + + const auto dllPath = appPath + "\\" + filename; + + if (!QFile::exists(dllPath)) { + qWarning().nospace() << dllPath << "not found"; + return; } + + if (!LoadLibraryW(dllPath.toStdWString().c_str())) { + const auto e = GetLastError(); + + qWarning().nospace() + << "failed to load " << dllPath << ": " + << formatSystemMessage(e); + } +} + +void preloadSsl() +{ + preloadDll("libeay32.dll"); + preloadDll("ssleay32.dll"); } static QString getVersionDisplayString() @@ -443,15 +455,9 @@ int runApplication(MOApplication &application, SingleInstance &instance, const QString &splashPath) { - qDebug("Starting Mod Organizer version %s revision %s", qUtf8Printable(getVersionDisplayString()), -#if defined(HGID) - HGID -#elif defined(GITID) - GITID -#else - "unknown" -#endif - ); + qDebug().nospace() + << "Starting Mod Organizer version " + << getVersionDisplayString() << " revision " << GITID; #if !defined(QT_NO_SSL) preloadSsl(); @@ -460,6 +466,16 @@ int runApplication(MOApplication &application, SingleInstance &instance, qDebug("non-ssl build"); #endif + { + Environment env; + + for (const auto& m : env.loadedModules()) { + qInfo().nospace().noquote() << " . " << m.toString(); + } + + return 0; + } + QString dataPath = application.property("dataPath").toString(); qDebug("data path: %s", qUtf8Printable(dataPath)); diff --git a/src/settings.cpp b/src/settings.cpp index b45912d4..59d3369a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -82,37 +82,6 @@ private: }; -QString formatSystemMessage(DWORD id) -{ - wchar_t* message = nullptr; - - const auto ret = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - id, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast<LPWSTR>(&message), - 0, NULL); - - QString s; - const QString idString = QString("0x%1").arg(id, 0, 16); - - if (ret == 0 || !message) { - s = idString; - } else { - s = QString("%1 (%2)") - .arg(QString::fromStdWString(message).trimmed()) - .arg(idString); - } - - LocalFree(message); - - return s; -} - - Settings *Settings::s_Instance = nullptr; diff --git a/src/shared/util.cpp b/src/shared/util.cpp index ed7c434e..16b373db 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "util.h"
#include "windows_error.h"
#include "error_report.h"
+#include <utility.h>
#include <sstream>
#include <locale>
@@ -29,6 +30,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <boost/scoped_array.hpp>
#include <QApplication>
+using MOBase::formatSystemMessage;
+
namespace MOShared {
@@ -253,4 +256,328 @@ MOBase::VersionInfo createVersionInfo() }
+struct HandleCloser
+{
+ using pointer = HANDLE;
+ void operator()(HANDLE h)
+ {
+ if (h != INVALID_HANDLE_VALUE) {
+ ::CloseHandle(h);
+ }
+ }
+};
+
+
+Environment::Environment()
+{
+ getLoadedModules();
+}
+
+const std::vector<Environment::Module>& Environment::loadedModules()
+{
+ return m_modules;
+}
+
+void Environment::getLoadedModules()
+{
+ std::unique_ptr<HANDLE, HandleCloser> snapshot(CreateToolhelp32Snapshot(
+ TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, GetCurrentProcessId()));
+
+ if (snapshot.get() == INVALID_HANDLE_VALUE)
+ {
+ const auto e = GetLastError();
+
+ qCritical().nospace()
+ << "CreateToolhelp32Snapshot() failed, "
+ << formatSystemMessage(e);
+
+ return;
+ }
+
+ // Set the size of the structure before using it.
+ MODULEENTRY32 me = {};
+ me.dwSize = sizeof(me);
+
+ // Retrieve information about the first module,
+ // and exit if unsuccessful
+ if (!Module32First(snapshot.get(), &me))
+ {
+ const auto e = GetLastError();
+
+ qCritical().nospace()
+ << "Module32First() failed, " << formatSystemMessage(e);
+
+ return;
+ }
+
+ // Now walk the module list of the process,
+ // and display information about each module
+ qInfo() << "modules loaded in process:";
+
+ for (;;)
+ {
+ const auto path = QString::fromWCharArray(me.szExePath);
+
+ m_modules.push_back(Module(path, me.modBaseSize));
+
+ if (!Module32Next(snapshot.get(), &me)) {
+ const auto e = GetLastError();
+
+ if (e != ERROR_NO_MORE_FILES) {
+ qCritical() << "Module32Next() failed, " << formatSystemMessage(e);
+ }
+
+ break;
+ }
+ }
+}
+
+
+Environment::Module::Module(QString path, std::size_t fileSize)
+ : m_path(std::move(path)), m_fileSize(fileSize)
+{
+ const auto fi = getFileInfo();
+
+ m_version = getVersion(fi.ffi);
+ m_timestamp = getTimestamp(fi.ffi);
+ m_versionString = fi.fileDescription;
+}
+
+const QString& Environment::Module::path() const
+{
+ return m_path;
+}
+
+std::size_t Environment::Module::fileSize() const
+{
+ return m_fileSize;
+}
+
+const QString& Environment::Module::version() const
+{
+ return m_version;
+}
+
+const QString& Environment::Module::versionString() const
+{
+ return m_versionString;
+}
+
+QString Environment::Module::timestampString() const
+{
+ if (!m_timestamp.isValid()) {
+ return "(no timestamp)";
+ }
+
+ return m_timestamp.toString(Qt::DateFormat::ISODate);
+}
+
+QString Environment::Module::toString() const
+{
+ QStringList sl;
+
+ sl.push_back(m_path);
+ sl.push_back(QString("%1 B").arg(m_fileSize));
+
+ if (m_version.isEmpty() && m_versionString.isEmpty()) {
+ sl.push_back("(no version)");
+ } else {
+ if (!m_version.isEmpty()) {
+ sl.push_back(m_version);
+ }
+
+ if (m_versionString != m_version) {
+ sl.push_back(versionString());
+ }
+ }
+
+ if (m_timestamp.isValid()) {
+ sl.push_back(m_timestamp.toString(Qt::DateFormat::ISODate));
+ } else {
+ sl.push_back("(no timestamp)");
+ }
+
+ return sl.join(", ");
+}
+
+Environment::Module::FileInfo Environment::Module::getFileInfo() const
+{
+ const auto wspath = m_path.toStdWString();
+
+ DWORD dummy = 0;
+ const DWORD size = GetFileVersionInfoSizeW(wspath.c_str(), &dummy);
+
+ if (size == 0) {
+ const auto e = GetLastError();
+
+ if (e == ERROR_RESOURCE_TYPE_NOT_FOUND) {
+ // not an error, no version information built into that module
+ return {};
+ }
+
+ qCritical().nospace().noquote()
+ << "GetFileVersionInfoSizeW() failed on '" << m_path << "', "
+ << formatSystemMessage(e);
+
+ return {};
+ }
+
+ auto buffer = std::make_unique<std::byte[]>(size);
+
+ if (!GetFileVersionInfoW(wspath.c_str(), 0, size, buffer.get())) {
+ const auto e = GetLastError();
+
+ qCritical().nospace().noquote()
+ << "GetFileVersionInfoW() failed on '" << m_path << "', "
+ << formatSystemMessage(e);
+
+ return {};
+ }
+
+
+ FileInfo fi;
+ fi.ffi = getFixedFileInfo(buffer.get());
+ fi.fileDescription = getFileDescription(buffer.get());
+
+ return fi;
+}
+
+VS_FIXEDFILEINFO Environment::Module::getFixedFileInfo(std::byte* buffer) const
+{
+ void* valuePointer = nullptr;
+ unsigned int valueSize = 0;
+
+ const auto ret = VerQueryValueW(buffer, L"\\", &valuePointer, &valueSize);
+
+ if (!ret || !valuePointer || valueSize == 0) {
+ // not an error, no fixed file info
+ return {};
+ }
+
+ const auto* fi = reinterpret_cast<VS_FIXEDFILEINFO*>(valuePointer);
+
+ if (fi->dwSignature != 0xfeef04bd) {
+ qCritical().nospace().noquote()
+ << "bad file info signature 0x" << hex << fi->dwSignature << " for "
+ << "'" << m_path << "'";
+
+ return {};
+ }
+
+ return *fi;
+}
+
+QString Environment::Module::getFileDescription(std::byte* buffer) const
+{
+ struct LANGANDCODEPAGE
+ {
+ WORD wLanguage;
+ WORD wCodePage;
+ };
+
+ void* valuePointer = nullptr;
+ unsigned int valueSize = 0;
+
+ auto ret = VerQueryValueW(
+ buffer, L"\\VarFileInfo\\Translation", &valuePointer, &valueSize);
+
+ if (!ret || !valuePointer || valueSize == 0) {
+ qCritical().nospace().noquote()
+ << "VerQueryValueW() for translations failed on '" << m_path << "'";
+
+ return {};
+ }
+
+ const auto count = valueSize / sizeof(LANGANDCODEPAGE);
+ if (count == 0) {
+ return {};
+ }
+
+ const auto* lcp = reinterpret_cast<LANGANDCODEPAGE*>(valuePointer);
+
+ const auto subBlock = QString("\\StringFileInfo\\%1%2\\FileVersion")
+ .arg(lcp->wLanguage, 4, 16, QChar('0'))
+ .arg(lcp->wCodePage, 4, 16, QChar('0'));
+
+ ret = VerQueryValueW(
+ buffer, subBlock.toStdWString().c_str(), &valuePointer, &valueSize);
+
+ if (!ret || !valuePointer || valueSize == 0) {
+ // not an error, no file version
+ return {};
+ }
+
+ // valueSize includes the null terminator
+ return QString::fromWCharArray(
+ reinterpret_cast<wchar_t*>(valuePointer), valueSize - 1);
+}
+
+QString Environment::Module::getVersion(const VS_FIXEDFILEINFO& fi) const
+{
+ if (fi.dwSignature == 0) {
+ return {};
+ }
+
+ const DWORD major = (fi.dwFileVersionMS >> 16 ) & 0xffff;
+ const DWORD minor = (fi.dwFileVersionMS >> 0 ) & 0xffff;
+ const DWORD maintenance = (fi.dwFileVersionLS >> 16 ) & 0xffff;
+ const DWORD build = (fi.dwFileVersionLS >> 0 ) & 0xffff;
+
+ if (major == 0 && minor == 0 && maintenance == 0 && build == 0) {
+ return {};
+ }
+
+ return QString("%1.%2.%3.%4")
+ .arg(major).arg(minor).arg(maintenance).arg(build);
+}
+
+QDateTime Environment::Module::getTimestamp(const VS_FIXEDFILEINFO& fi) const
+{
+ FILETIME ft = {};
+
+ if (fi.dwSignature == 0 || (fi.dwFileDateMS == 0 && fi.dwFileDateLS == 0)) {
+ std::unique_ptr<HANDLE, HandleCloser> h(CreateFileW(
+ m_path.toStdWString().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0));
+
+ if (h.get() == INVALID_HANDLE_VALUE) {
+ const auto e = GetLastError();
+
+ qCritical()
+ << "can't open file '" << m_path << "' for timestamp, "
+ << formatSystemMessage(e);
+
+ return {};
+ }
+
+ if (!GetFileTime(h.get(), &ft, nullptr, nullptr)) {
+ const auto e = GetLastError();
+ qCritical()
+ << "can't get file time for '" << m_path << "', "
+ << formatSystemMessage(e);
+
+ return {};
+ }
+ } else {
+ ft.dwHighDateTime = fi.dwFileDateMS;
+ ft.dwLowDateTime = fi.dwFileDateLS;
+ }
+
+
+ SYSTEMTIME utc = {};
+ if (!FileTimeToSystemTime(&ft, &utc)) {
+ qCritical()
+ << "FileTimeToSystemTime() failed on timestamp "
+ << "high=0x" << hex << ft.dwHighDateTime << " "
+ << "low=0x" << hex << ft.dwLowDateTime << " for "
+ << "'" << m_path << "'";
+
+ return {};
+ }
+
+ return QDateTime(
+ QDate(utc.wYear, utc.wMonth, utc.wDay),
+ QTime(utc.wHour, utc.wMinute, utc.wSecond, utc.wMilliseconds));
+}
+
} // namespace MOShared
diff --git a/src/shared/util.h b/src/shared/util.h index 1fdfb089..5d88481c 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -46,8 +46,54 @@ std::wstring ToLower(const std::wstring &text); bool CaseInsensitiveEqual(const std::wstring &lhs, const std::wstring &rhs);
-VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName);
-std::wstring GetFileVersionString(const std::wstring &fileName);
+class Environment
+{
+public:
+ class Module
+ {
+ public:
+ explicit Module(QString path, std::size_t fileSize);
+
+ const QString& path() const;
+ std::size_t fileSize() const;
+ const QString& version() const;
+ const QString& versionString() const;
+ QString timestampString() const;
+
+ QString toString() const;
+
+ private:
+ struct FileInfo
+ {
+ VS_FIXEDFILEINFO ffi;
+ QString fileDescription;
+ };
+
+ QString m_path;
+ std::size_t m_fileSize;
+ QString m_version;
+ QDateTime m_timestamp;
+ QString m_versionString;
+
+ FileInfo getFileInfo() const;
+
+ QString getVersion(const VS_FIXEDFILEINFO& fi) const;
+ QDateTime getTimestamp(const VS_FIXEDFILEINFO& fi) const;
+
+ VS_FIXEDFILEINFO getFixedFileInfo(std::byte* buffer) const;
+ QString getFileDescription(std::byte* buffer) const;
+ };
+
+ Environment();
+
+ const std::vector<Module>& loadedModules();
+
+private:
+ std::vector<Module> m_modules;
+
+ void getLoadedModules();
+};
+
MOBase::VersionInfo createVersionInfo();
} // namespace MOShared
|
