diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-28 20:20:17 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-28 20:20:17 -0500 |
| commit | 2edfae46cc600079cb705e78f885df1fac269ce2 (patch) | |
| tree | ee7d2370ffc570c69842bbfcfa392fdd8cacf23f /src | |
| parent | fbfdd7b1171e692a663bf221075abfe0e0ef0ab9 (diff) | |
Strip Windows-only blocks from env*.cpp/.h
These files were ported from upstream MO2 with the Windows code wrapped
in #ifdef _WIN32 and Linux equivalents in the #else branch. The Windows
branches never compile on this fork — drop them so the source matches
what's actually built.
- envwindows.cpp/.h: kept Linux uname()/os-release implementation; the
WindowsInfo::Version/Release fields drop their DWORD/uint32_t fork.
- envshell.cpp: deleted entirely (Linux body was empty — header
declares no-op stubs inline).
- envshell.h: drop Win32 ShellMenu declarations, keep Linux stubs.
- envmetrics.cpp: kept QScreen-based Linux Display/Metrics implementation.
- envshortcut.cpp: kept Linux .desktop shortcut writer + PE icon
extractor, drop Win32 IShellLink path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/src/envmetrics.cpp | 493 | ||||
| -rw-r--r-- | src/src/envshell.cpp | 610 | ||||
| -rw-r--r-- | src/src/envshell.h | 157 | ||||
| -rw-r--r-- | src/src/envshortcut.cpp | 359 | ||||
| -rw-r--r-- | src/src/envwindows.cpp | 442 | ||||
| -rw-r--r-- | src/src/envwindows.h | 19 |
6 files changed, 295 insertions, 1785 deletions
diff --git a/src/src/envmetrics.cpp b/src/src/envmetrics.cpp index 828848d..5eb623c 100644 --- a/src/src/envmetrics.cpp +++ b/src/src/envmetrics.cpp @@ -1,379 +1,114 @@ -#include "envmetrics.h"
-
-#ifdef _WIN32
-
-#include "env.h"
-#include <QScreen>
-#include <Windows.h>
-#include <log.h>
-#include <shellscalingapi.h>
-#include <utility.h>
-
-namespace env
-{
-
-using namespace MOBase;
-
-// fallback for windows 7
-//
-int getDesktopDpi()
-{
- // desktop DC
- DesktopDCPtr dc(GetDC(0));
-
- if (!dc) {
- const auto e = GetLastError();
- log::error("can't get desktop DC, {}", formatSystemMessage(e));
- return 0;
- }
-
- return GetDeviceCaps(dc.get(), LOGPIXELSX);
-}
-
-// finds a monitor by device name; there's no real good way to do that except
-// by enumerating all the monitors and checking their name
-//
-HMONITOR findMonitor(const QString& name)
-{
- // passed to the enumeration callback
- struct Data
- {
- QString name;
- HMONITOR hm;
- };
-
- Data data = {name, 0};
-
- // callback
- auto callback = [](HMONITOR hm, HDC, RECT*, LPARAM lp) {
- auto& data = *reinterpret_cast<Data*>(lp);
-
- MONITORINFOEX mi = {};
- mi.cbSize = sizeof(mi);
-
- // monitor info will include the name
- if (!GetMonitorInfoW(hm, &mi)) {
- const auto e = GetLastError();
- log::error("GetMonitorInfo() failed for '{}', {}", data.name,
- formatSystemMessage(e));
-
- // error for this monitor, but continue
- return TRUE;
- }
-
- if (QString::fromWCharArray(mi.szDevice) == data.name) {
- // found, stop
- data.hm = hm;
- return FALSE;
- }
-
- // not found, continue to the next monitor
- return TRUE;
- };
-
- // for each monitor
- EnumDisplayMonitors(0, nullptr, callback, reinterpret_cast<LPARAM>(&data));
-
- return data.hm;
-}
-
-// returns the dpi for the given monitor; for systems that do not support
-// per-monitor dpi (such as windows 7), this is the desktop dpi
-//
-int getDpi(const QString& monitorDevice)
-{
- using GetDpiForMonitorFunction =
- HRESULT WINAPI(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
-
- static LibraryPtr shcore;
- static GetDpiForMonitorFunction* GetDpiForMonitor = nullptr;
- static bool checked = false;
-
- if (!checked) {
- // try to find GetDpiForMonitor() from shcored.dll
-
- shcore.reset(LoadLibraryW(L"Shcore.dll"));
-
- if (shcore) {
- // windows 8.1+ only
- GetDpiForMonitor = reinterpret_cast<GetDpiForMonitorFunction*>(
- GetProcAddress(shcore.get(), "GetDpiForMonitor"));
- }
-
- checked = true;
- }
-
- if (!GetDpiForMonitor) {
- // get the desktop dpi instead
- return getDesktopDpi();
- }
-
- // there's no way to get an HMONITOR from a device name, so all monitors
- // will have to be enumerated and their name checked
- HMONITOR hm = findMonitor(monitorDevice);
- if (!hm) {
- log::error("can't get dpi for monitor '{}', not found", monitorDevice);
- return 0;
- }
-
- UINT dpiX = 0, dpiY = 0;
- const auto r = GetDpiForMonitor(hm, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
-
- if (FAILED(r)) {
- log::error("GetDpiForMonitor() failed for '{}', {}", monitorDevice,
- formatSystemMessage(r));
-
- return 0;
- }
-
- // dpiX and dpiY are always identical, as per the documentation
- return dpiX;
-}
-
-Display::Display(QString adapter, QString monitorDevice, bool primary)
- : m_adapter(std::move(adapter)), m_monitorDevice(std::move(monitorDevice)),
- m_primary(primary), m_resX(0), m_resY(0), m_dpi(0), m_refreshRate(0)
-{
- getSettings();
- m_dpi = getDpi(m_monitorDevice);
-}
-
-const QString& Display::adapter() const
-{
- return m_adapter;
-}
-
-const QString& Display::monitorDevice() const
-{
- return m_monitorDevice;
-}
-
-bool Display::primary()
-{
- return m_primary;
-}
-
-int Display::resX() const
-{
- return m_resX;
-}
-
-int Display::resY() const
-{
- return m_resY;
-}
-
-int Display::dpi()
-{
- return m_dpi;
-}
-
-int Display::refreshRate() const
-{
- return m_refreshRate;
-}
-
-QString Display::toString() const
-{
- return QString("%1*%2 %3hz dpi=%4 on %5%6")
- .arg(m_resX)
- .arg(m_resY)
- .arg(m_refreshRate)
- .arg(m_dpi)
- .arg(m_adapter)
- .arg(m_primary ? " (primary)" : "");
-}
-
-void Display::getSettings()
-{
- DEVMODEW dm = {};
- dm.dmSize = sizeof(dm);
-
- const auto wsDevice = m_monitorDevice.toStdWString();
-
- if (!EnumDisplaySettingsW(wsDevice.c_str(), ENUM_CURRENT_SETTINGS, &dm)) {
- log::error("EnumDisplaySettings() failed for '{}'", m_monitorDevice);
- return;
- }
-
- // all these fields should be available
-
- if (dm.dmFields & DM_DISPLAYFREQUENCY) {
- m_refreshRate = dm.dmDisplayFrequency;
- }
-
- if (dm.dmFields & DM_PELSWIDTH) {
- m_resX = dm.dmPelsWidth;
- }
-
- if (dm.dmFields & DM_PELSHEIGHT) {
- m_resY = dm.dmPelsHeight;
- }
-}
-
-Metrics::Metrics()
-{
- getDisplays();
-}
-
-const std::vector<Display>& Metrics::displays() const
-{
- return m_displays;
-}
-
-QRect Metrics::desktopGeometry() const
-{
- QRect r;
-
- for (auto* s : QGuiApplication::screens()) {
- r = r.united(s->geometry());
- }
-
- return r;
-}
-
-void Metrics::getDisplays()
-{
- // don't bother if it goes over 100
- for (int i = 0; i < 100; ++i) {
- DISPLAY_DEVICEW device = {};
- device.cb = sizeof(device);
-
- if (!EnumDisplayDevicesW(nullptr, i, &device, 0)) {
- // no more
- break;
- }
-
- // EnumDisplayDevices() seems to be returning a lot of devices that are
- // not actually monitors, but those don't have the
- // DISPLAY_DEVICE_ATTACHED_TO_DESKTOP bit set
- if ((device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == 0) {
- continue;
- }
-
- m_displays.emplace_back(QString::fromWCharArray(device.DeviceString),
- QString::fromWCharArray(device.DeviceName),
- (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE));
- }
-}
-
-} // namespace env
-
-#else // Linux
-
-#include <QGuiApplication>
-#include <QRect>
-#include <QScreen>
-
-namespace env
-{
-
-Display::Display(QString adapter, QString monitorDevice, bool primary)
- : m_adapter(std::move(adapter)), m_monitorDevice(std::move(monitorDevice)),
- m_primary(primary), m_resX(0), m_resY(0), m_dpi(0), m_refreshRate(0)
-{
- getSettings();
-}
-
-const QString& Display::adapter() const
-{
- return m_adapter;
-}
-
-const QString& Display::monitorDevice() const
-{
- return m_monitorDevice;
-}
-
-bool Display::primary()
-{
- return m_primary;
-}
-
-int Display::resX() const
-{
- return m_resX;
-}
-
-int Display::resY() const
-{
- return m_resY;
-}
-
-int Display::dpi()
-{
- return m_dpi;
-}
-
-int Display::refreshRate() const
-{
- return m_refreshRate;
-}
-
-QString Display::toString() const
-{
- return QString("%1*%2 %3hz dpi=%4 on %5%6")
- .arg(m_resX)
- .arg(m_resY)
- .arg(m_refreshRate)
- .arg(m_dpi)
- .arg(m_adapter)
- .arg(m_primary ? " (primary)" : "");
-}
-
-void Display::getSettings()
-{
- // Use QScreen to get display settings on Linux
- const auto screens = QGuiApplication::screens();
- for (auto* screen : screens) {
- if (screen->name() == m_monitorDevice) {
- const auto geo = screen->geometry();
- m_resX = geo.width();
- m_resY = geo.height();
- m_refreshRate = qRound(screen->refreshRate());
- m_dpi = qRound(screen->logicalDotsPerInch());
- return;
- }
- }
-
- // Fallback: if monitor name didn't match, use primary screen
- if (auto* primary = QGuiApplication::primaryScreen()) {
- const auto geo = primary->geometry();
- m_resX = geo.width();
- m_resY = geo.height();
- m_refreshRate = qRound(primary->refreshRate());
- m_dpi = qRound(primary->logicalDotsPerInch());
- }
-}
-
-Metrics::Metrics()
-{
- getDisplays();
-}
-
-const std::vector<Display>& Metrics::displays() const
-{
- return m_displays;
-}
-
-QRect Metrics::desktopGeometry() const
-{
- if (auto* primary = QGuiApplication::primaryScreen()) {
- return primary->virtualGeometry();
- }
- return QRect();
-}
-
-void Metrics::getDisplays()
-{
- const auto screens = QGuiApplication::screens();
- for (auto* screen : screens) {
- const bool isPrimary = (screen == QGuiApplication::primaryScreen());
- m_displays.emplace_back(screen->manufacturer() + " " + screen->model(),
- screen->name(), isPrimary);
- }
-}
-
-} // namespace env
-
-#endif // _WIN32
+#include "envmetrics.h" + +#include <QGuiApplication> +#include <QRect> +#include <QScreen> + +namespace env +{ + +Display::Display(QString adapter, QString monitorDevice, bool primary) + : m_adapter(std::move(adapter)), m_monitorDevice(std::move(monitorDevice)), + m_primary(primary), m_resX(0), m_resY(0), m_dpi(0), m_refreshRate(0) +{ + getSettings(); +} + +const QString& Display::adapter() const +{ + return m_adapter; +} + +const QString& Display::monitorDevice() const +{ + return m_monitorDevice; +} + +bool Display::primary() +{ + return m_primary; +} + +int Display::resX() const +{ + return m_resX; +} + +int Display::resY() const +{ + return m_resY; +} + +int Display::dpi() +{ + return m_dpi; +} + +int Display::refreshRate() const +{ + return m_refreshRate; +} + +QString Display::toString() const +{ + return QString("%1*%2 %3hz dpi=%4 on %5%6") + .arg(m_resX) + .arg(m_resY) + .arg(m_refreshRate) + .arg(m_dpi) + .arg(m_adapter) + .arg(m_primary ? " (primary)" : ""); +} + +void Display::getSettings() +{ + const auto screens = QGuiApplication::screens(); + for (auto* screen : screens) { + if (screen->name() == m_monitorDevice) { + const auto geo = screen->geometry(); + m_resX = geo.width(); + m_resY = geo.height(); + m_refreshRate = qRound(screen->refreshRate()); + m_dpi = qRound(screen->logicalDotsPerInch()); + return; + } + } + + if (auto* primary = QGuiApplication::primaryScreen()) { + const auto geo = primary->geometry(); + m_resX = geo.width(); + m_resY = geo.height(); + m_refreshRate = qRound(primary->refreshRate()); + m_dpi = qRound(primary->logicalDotsPerInch()); + } +} + +Metrics::Metrics() +{ + getDisplays(); +} + +const std::vector<Display>& Metrics::displays() const +{ + return m_displays; +} + +QRect Metrics::desktopGeometry() const +{ + if (auto* primary = QGuiApplication::primaryScreen()) { + return primary->virtualGeometry(); + } + return QRect(); +} + +void Metrics::getDisplays() +{ + const auto screens = QGuiApplication::screens(); + for (auto* screen : screens) { + const bool isPrimary = (screen == QGuiApplication::primaryScreen()); + m_displays.emplace_back(screen->manufacturer() + " " + screen->model(), + screen->name(), isPrimary); + } +} + +} // namespace env diff --git a/src/src/envshell.cpp b/src/src/envshell.cpp deleted file mode 100644 index f8e1ec9..0000000 --- a/src/src/envshell.cpp +++ /dev/null @@ -1,610 +0,0 @@ -#ifdef _WIN32
-
-#include <format>
-
-#include <log.h>
-#include <utility.h>
-#include <windowsx.h>
-
-#include "envshell.h"
-
-namespace env
-{
-
-using namespace MOBase;
-
-const int QCM_FIRST = 1;
-const int QCM_LAST = 0x7ff;
-
-class MenuFailed : public std::runtime_error
-{
-public:
- MenuFailed(HRESULT r, const std::string& what)
- : runtime_error(
- std::format("{}, {}", what,
- QString::fromStdWString(formatSystemMessage(r)).toStdString()))
- {}
-};
-
-class DummyMenu
-{
-public:
- DummyMenu(QString s) : m_what(s) {}
-
- const QString& what() const { return m_what; }
-
-private:
- QString m_what;
-};
-
-struct IdlsFreer
-{
- const std::vector<LPCITEMIDLIST>& v;
-
- IdlsFreer(const std::vector<LPCITEMIDLIST>& v) : v(v) {}
-
- ~IdlsFreer()
- {
- for (auto&& idl : v) {
- ::CoTaskMemFree(const_cast<LPITEMIDLIST>(idl));
- }
- }
-};
-
-class WndProcFilter : public QAbstractNativeEventFilter
-{
-public:
- using function_type =
- std::function<bool(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out)>;
-
- WndProcFilter(function_type f) : m_f(std::move(f)) {}
-
- bool nativeEventFilter(const QByteArray& eventType, void* message,
- qintptr* result) override
- {
- MSG* msg = (MSG*)message;
- if (!msg) {
- return false;
- }
-
- LRESULT lr = 0;
-
- const bool r = m_f(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lr);
-
- if (result) {
- *result = lr;
- }
-
- return r;
- }
-
-private:
- function_type m_f;
-};
-
-HWND getHWND(QMainWindow* mw)
-{
- if (mw) {
- return (HWND)mw->winId();
- } else {
- return 0;
- }
-}
-
-// adapted from
-// https://devblogs.microsoft.com/oldnewthing/20040928-00/?p=37723
-//
-HRESULT IContextMenu_GetCommandString(IContextMenu* pcm, UINT_PTR idCmd, UINT uFlags,
- UINT* pwReserved, LPWSTR pszName, UINT cchMax)
-{
- // Callers are expected to be using Unicode.
- if (!(uFlags & GCS_UNICODE)) {
- return E_INVALIDARG;
- }
-
- if (cchMax <= 1) {
- return E_FAIL;
- }
-
- cchMax--;
-
- pszName[0] = L'\0';
-
- HRESULT hr = pcm->GetCommandString(idCmd, uFlags, pwReserved, (LPSTR)pszName, cchMax);
-
- if (SUCCEEDED(hr) && pszName[0] == L'\0') {
- hr = E_NOTIMPL;
- }
-
- if (FAILED(hr)) {
- LPSTR pszAnsi = (LPSTR)LocalAlloc(LMEM_FIXED, (cchMax + 1) * sizeof(CHAR));
-
- if (pszAnsi) {
- pszAnsi[0] = '\0';
-
- hr = pcm->GetCommandString(idCmd, uFlags & ~GCS_UNICODE, pwReserved, pszAnsi,
- cchMax);
-
- if (SUCCEEDED(hr) && pszAnsi[0] == '\0') {
- hr = E_NOTIMPL;
- }
-
- if (SUCCEEDED(hr)) {
- if (MultiByteToWideChar(CP_ACP, 0, pszAnsi, -1, pszName, cchMax) == 0) {
- hr = E_FAIL;
- }
- }
-
- LocalFree(pszAnsi);
-
- } else {
- hr = E_OUTOFMEMORY;
- }
- }
-
- return hr;
-}
-
-ShellMenu::ShellMenu(QMainWindow* mw) : m_mw(mw) {}
-
-void ShellMenu::addFile(QFileInfo fi)
-{
- m_files.emplace_back(std::move(fi));
-}
-
-int ShellMenu::fileCount() const
-{
- return static_cast<int>(m_files.size());
-}
-
-void ShellMenu::exec(const QPoint& pos)
-{
- HMENU menu = getMenu();
- if (!menu) {
- return;
- }
-
- try {
- const auto hwnd = getHWND(m_mw);
-
- auto filter = std::make_unique<WndProcFilter>(
- [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) {
- return wndProc(h, m, wp, lp, out);
- });
-
- QCoreApplication::instance()->installNativeEventFilter(filter.get());
-
- const int cmd =
- TrackPopupMenuEx(menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr);
-
- if (m_mw) {
- if (auto* sb = m_mw->statusBar()) {
- sb->clearMessage();
- }
- }
-
- if (cmd <= 0) {
- return;
- }
-
- invoke(pos, cmd - QCM_FIRST);
- } catch (MenuFailed& e) {
- if (m_files.size() == 1) {
- log::error("can't exec shell menu for '{}': {}",
- QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what());
- } else {
- log::error("can't exec shell menu for {} files: {}", m_files.size(), e.what());
- }
- }
-}
-
-HMENU ShellMenu::getMenu()
-{
- if (!m_menu) {
- create();
- }
-
- return m_menu.get();
-}
-
-bool ShellMenu::wndProc(HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out)
-{
- if (m == WM_MENUSELECT) {
- HANDLE_WM_MENUSELECT(h, wp, lp, onMenuSelect);
- return true;
- }
-
- if (m_cm3) {
- const auto r = m_cm3->HandleMenuMsg2(m, wp, lp, out);
-
- if (SUCCEEDED(r)) {
- return true;
- }
- }
-
- if (m_cm2) {
- const auto r = m_cm2->HandleMenuMsg(m, wp, lp);
-
- if (SUCCEEDED(r)) {
- if (out) {
- *out = 0;
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-void ShellMenu::onMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup,
- UINT flags)
-{
- if (m_cm && item >= QCM_FIRST && item <= QCM_LAST) {
- WCHAR szBuf[MAX_PATH];
-
- const auto r = IContextMenu_GetCommandString(m_cm.get(), item - QCM_FIRST,
- GCS_HELPTEXTW, NULL, szBuf, MAX_PATH);
-
- if (FAILED(r)) {
- lstrcpynW(szBuf, L"No help available.", MAX_PATH);
- }
-
- if (m_mw) {
- if (auto* sb = m_mw->statusBar()) {
- sb->showMessage(QString::fromWCharArray(szBuf));
- }
- }
- }
-}
-
-void ShellMenu::create()
-{
- if (m_files.empty()) {
- log::warn("showShellMenu(): no files given");
- return;
- }
-
- try {
- auto idls = createIdls(m_files);
-
- if (idls.empty()) {
- log::error("no idls, can't create context menu");
- return;
- }
-
- IdlsFreer freer(idls);
-
- auto array = createItemArray(idls);
-
- createContextMenu(array.get());
- createPopupMenu(m_cm.get());
- } catch (DummyMenu& dm) {
- m_menu = createDummyMenu(dm.what());
- } catch (MenuFailed& e) {
- if (m_files.size() == 1) {
- log::error("can't create shell menu for '{}': {}",
- QDir::toNativeSeparators(m_files[0].absoluteFilePath()), e.what());
- } else {
- log::error("can't create shell menu for {} files: {}", m_files.size(), e.what());
- }
-
- m_menu = createDummyMenu(QObject::tr("No menu available"));
- }
-}
-
-HMenuPtr ShellMenu::createDummyMenu(const QString& what)
-{
- try {
- HMENU menu = CreatePopupMenu();
- if (!menu) {
- const auto e = GetLastError();
- throw MenuFailed(e, "CreatePopupMenu failed");
- }
-
- if (!AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, what.toStdWString().c_str())) {
- const auto e = GetLastError();
- throw MenuFailed(e, "AppendMenuW failed");
- }
-
- return HMenuPtr(menu);
- } catch (MenuFailed& e) {
- log::error("{}", what);
- log::error("additionally, creating the dummy menu failed: {}", e.what());
-
- return {};
- }
-}
-
-std::vector<LPCITEMIDLIST> ShellMenu::createIdls(const std::vector<QFileInfo>& files)
-{
- std::vector<LPCITEMIDLIST> idls;
- std::optional<QDir> parent;
-
- for (auto&& f : files) {
- const auto path = QDir::toNativeSeparators(f.absoluteFilePath()).toStdWString();
-
- if (!parent) {
- parent = f.absoluteDir();
- } else {
- if (*parent != f.absoluteDir()) {
- throw DummyMenu(QObject::tr("Selected files must be in the same directory"));
- }
- }
-
- auto item = createShellItem(path);
- auto pidlist = getPersistIDList(item.get());
- auto absIdl = getIDList(pidlist.get());
-
- idls.push_back(absIdl.release());
- }
-
- return idls;
-}
-
-COMPtr<IShellItemArray> ShellMenu::createItemArray(std::vector<LPCITEMIDLIST>& idls)
-{
- IShellItemArray* array = nullptr;
- auto r = SHCreateShellItemArrayFromIDLists(static_cast<UINT>(idls.size()), &idls[0],
- &array);
-
- if (FAILED(r)) {
- throw MenuFailed(r, "SHCreateShellItemArrayFromIDLists failed");
- }
-
- return COMPtr<IShellItemArray>(array);
-}
-
-void ShellMenu::createContextMenu(IShellItemArray* array)
-{
- IContextMenu* cm = nullptr;
-
- auto r =
- array->BindToHandler(nullptr, BHID_SFUIObject, IID_IContextMenu, (void**)&cm);
-
- if (FAILED(r)) {
- throw MenuFailed(r, "BindToHandler failed");
- }
-
- m_cm.reset(cm);
-
- {
- IContextMenu2* cm2 = nullptr;
- if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu2, (void**)&cm2))) {
- m_cm2.reset(cm2);
- }
- }
-
- {
- IContextMenu3* cm3 = nullptr;
- if (SUCCEEDED(m_cm->QueryInterface(IID_IContextMenu3, (void**)&cm3))) {
- m_cm3.reset(cm3);
- }
- }
-}
-
-void ShellMenu::createPopupMenu(IContextMenu* cm)
-{
- HMENU hmenu = CreatePopupMenu();
- if (!hmenu) {
- const auto e = GetLastError();
- throw MenuFailed(e, "CreatePopupMenu failed");
- }
-
- const auto r = cm->QueryContextMenu(hmenu, 0, QCM_FIRST, QCM_LAST, CMF_EXTENDEDVERBS);
-
- if (FAILED(r)) {
- throw MenuFailed(r, "QueryContextMenu failed");
- }
-
- m_menu.reset(hmenu);
-}
-
-COMPtr<IShellItem> ShellMenu::createShellItem(const std::wstring& path)
-{
- IShellItem* item = nullptr;
-
- auto r =
- SHCreateItemFromParsingName(path.c_str(), nullptr, IID_IShellItem, (void**)&item);
-
- if (FAILED(r)) {
- throw MenuFailed(r, "SHCreateItemFromParsingName failed");
- }
-
- return COMPtr<IShellItem>(item);
-}
-
-COMPtr<IPersistIDList> ShellMenu::getPersistIDList(IShellItem* item)
-{
- IPersistIDList* idl = nullptr;
- auto r = item->QueryInterface(IID_IPersistIDList, (void**)&idl);
-
- if (FAILED(r)) {
- throw MenuFailed(r, "QueryInterface IID_IPersistIDList failed");
- }
-
- return COMPtr<IPersistIDList>(idl);
-}
-
-CoTaskMemPtr<LPITEMIDLIST> ShellMenu::getIDList(IPersistIDList* pidlist)
-{
- LPITEMIDLIST absIdl = nullptr;
- auto r = pidlist->GetIDList(&absIdl);
-
- if (FAILED(r)) {
- throw MenuFailed(r, "GetIDList failed");
- }
-
- return CoTaskMemPtr<LPITEMIDLIST>(absIdl);
-}
-
-void ShellMenu::invoke(const QPoint& p, int cmd)
-{
- const auto hwnd = getHWND(m_mw);
-
- CMINVOKECOMMANDINFOEX info = {};
-
- info.cbSize = sizeof(info);
- info.fMask = CMIC_MASK_UNICODE | CMIC_MASK_PTINVOKE;
- info.hwnd = hwnd;
- info.lpVerb = MAKEINTRESOURCEA(cmd);
- info.lpVerbW = MAKEINTRESOURCEW(cmd);
- info.nShow = SW_SHOWNORMAL;
- info.ptInvoke = {p.x(), p.y()};
-
- const auto m = QApplication::queryKeyboardModifiers();
-
- if (m & Qt::ShiftModifier) {
- info.fMask |= CMIC_MASK_SHIFT_DOWN;
- }
-
- if (m & Qt::ControlModifier) {
- info.fMask |= CMIC_MASK_CONTROL_DOWN;
- }
-
- const auto r = m_cm->InvokeCommand((CMINVOKECOMMANDINFO*)&info);
-
- if (FAILED(r)) {
- throw MenuFailed(r, std::format("InvokeCommand failed, verb={}", cmd));
- }
-}
-
-ShellMenuCollection::ShellMenuCollection(QMainWindow* mw) : m_mw(mw), m_active(nullptr)
-{}
-
-void ShellMenuCollection::addDetails(QString s)
-{
- m_details.emplace_back(std::move(s));
-}
-
-void ShellMenuCollection::add(QString name, ShellMenu m)
-{
- m_menus.push_back({name, std::move(m)});
-}
-
-void ShellMenuCollection::exec(const QPoint& pos)
-{
- HMENU menu = ::CreatePopupMenu();
- if (!menu) {
- const auto e = GetLastError();
-
- log::error("CreatePopupMenu for merged menus failed, {}", formatSystemMessage(e));
-
- return;
- }
-
- if (!m_details.empty()) {
- for (auto&& d : m_details) {
- const auto s = d.toStdWString();
- const auto r = AppendMenuW(menu, MF_STRING | MF_DISABLED, 0, s.c_str());
-
- if (!r) {
- const auto e = GetLastError();
- log::error("AppendMenuW failed for details '{}', {}", d,
- formatSystemMessage(e));
- }
- }
-
- const auto r = AppendMenuW(menu, MF_SEPARATOR, 0, nullptr);
- if (!r) {
- const auto e = GetLastError();
- log::error("AppendMenuW failed for separator, {}", formatSystemMessage(e));
- }
- }
-
- for (auto&& m : m_menus) {
- auto hmenu = m.menu.getMenu();
- if (!hmenu) {
- continue;
- }
-
- const auto r =
- AppendMenuW(menu, MF_POPUP | MF_STRING, reinterpret_cast<UINT_PTR>(hmenu),
- m.name.toStdWString().c_str());
-
- if (!r) {
- const auto e = GetLastError();
-
- log::error("AppendMenuW failed for merged menu {}, {}", m.name,
- formatSystemMessage(e));
-
- continue;
- }
- }
-
- auto hwnd = getHWND(m_mw);
-
- auto filter = std::make_unique<WndProcFilter>(
- [&](HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out) {
- return wndProc(h, m, wp, lp, out);
- });
-
- QCoreApplication::instance()->installNativeEventFilter(filter.get());
-
- const int cmd =
- TrackPopupMenuEx(menu, TPM_RETURNCMD, pos.x(), pos.y(), hwnd, nullptr);
-
- if (m_mw) {
- if (auto* sb = m_mw->statusBar()) {
- sb->clearMessage();
- }
- }
-
- if (cmd <= 0) {
- return;
- }
-
- if (!m_active) {
- log::debug("SMC: command {} selected without active submenu", cmd);
- return;
- }
-
- const auto realCmd = cmd - QCM_FIRST;
-
- log::debug("SMC: invoking {} on {}", realCmd, m_active->name);
- m_active->menu.invoke(pos, realCmd);
-}
-
-bool ShellMenuCollection::wndProc(HWND h, UINT m, WPARAM wp, LPARAM lp, LRESULT* out)
-{
- if (m == WM_MENUSELECT) {
- auto* oldActive = m_active;
- m_active = nullptr;
-
- HANDLE_WM_MENUSELECT(h, wp, lp, onMenuSelect);
-
- if (!m_active && oldActive) {
- m_active = oldActive;
- } else if (m_active && m_active == oldActive) {
- return true;
- } else if (m_active && m_active != oldActive) {
- log::debug("SMC: switching to {}", m_active->name);
- }
- }
-
- if (!m_active) {
- return false;
- }
-
- return m_active->menu.wndProc(h, m, wp, lp, out);
-}
-
-void ShellMenuCollection::onMenuSelect(HWND hwnd, HMENU hmenu, int item,
- HMENU hmenuPopup, UINT flags)
-{
- for (auto&& m : m_menus) {
- if (m.menu.getMenu() == hmenuPopup) {
- m_active = &m;
- break;
- }
- }
-}
-
-} // namespace env
-
-#else // Linux
-
-// The header (envshell.h) provides stub class declarations for Linux.
-// No additional implementation is needed since the stubs are inline in the header.
-
-#endif // _WIN32
diff --git a/src/src/envshell.h b/src/src/envshell.h index a390f3a..c672949 100644 --- a/src/src/envshell.h +++ b/src/src/envshell.h @@ -1,115 +1,42 @@ -#ifndef ENV_SHELL_H
-#define ENV_SHELL_H
-
-#include "env.h"
-#include <QFileInfo>
-#include <QPoint>
-
-namespace env
-{
-
-#ifdef _WIN32
-
-class ShellMenu
-{
-public:
- ShellMenu(QMainWindow* mw);
-
- // noncopyable
- ShellMenu(const ShellMenu&) = delete;
- ShellMenu& operator=(const ShellMenu&) = delete;
- ShellMenu(ShellMenu&&) = default;
- ShellMenu& operator=(ShellMenu&&) = default;
-
- void addFile(QFileInfo fi);
- int fileCount() const;
-
- void exec(const QPoint& pos);
- HMENU getMenu();
- bool wndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out);
- void invoke(const QPoint& p, int cmd);
-
-private:
- QMainWindow* m_mw;
- std::vector<QFileInfo> m_files;
- COMPtr<IContextMenu> m_cm;
- COMPtr<IContextMenu2> m_cm2;
- COMPtr<IContextMenu3> m_cm3;
- HMenuPtr m_menu;
-
- void create();
-
- std::vector<LPCITEMIDLIST> createIdls(const std::vector<QFileInfo>& files);
- COMPtr<IShellItemArray> createItemArray(std::vector<LPCITEMIDLIST>& idls);
-
- void createContextMenu(IShellItemArray* array);
- void createPopupMenu(IContextMenu* cm);
-
- COMPtr<IShellItem> createShellItem(const std::wstring& path);
- COMPtr<IPersistIDList> getPersistIDList(IShellItem* item);
- CoTaskMemPtr<LPITEMIDLIST> getIDList(IPersistIDList* pidlist);
- HMenuPtr createDummyMenu(const QString& what);
-
- void onMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags);
-};
-
-class ShellMenuCollection
-{
-public:
- ShellMenuCollection(QMainWindow* mw);
-
- void addDetails(QString s);
- void add(QString name, ShellMenu m);
-
- void exec(const QPoint& pos);
-
-private:
- struct MenuInfo
- {
- QString name;
- ShellMenu menu;
- };
-
- QMainWindow* m_mw;
- std::vector<QString> m_details;
- std::vector<MenuInfo> m_menus;
- MenuInfo* m_active;
-
- bool wndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp, LRESULT* out);
-
- void onMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags);
-};
-
-#else // Linux
-
-// Stub implementations for Linux - shell context menus are Windows-only
-class ShellMenu
-{
-public:
- ShellMenu(QMainWindow*) {}
-
- ShellMenu(const ShellMenu&) = delete;
- ShellMenu& operator=(const ShellMenu&) = delete;
- ShellMenu(ShellMenu&&) = default;
- ShellMenu& operator=(ShellMenu&&) = default;
-
- void addFile(QFileInfo) {}
- int fileCount() const { return 0; }
- void exec(const QPoint&) {}
-};
-
-class ShellMenuCollection
-{
-public:
- ShellMenuCollection(QMainWindow*) {}
-
- void addDetails(QString) {}
- void add(QString, ShellMenu) {}
- void exec(const QPoint&) {}
-};
-
-#endif // _WIN32
-
-} // namespace env
-
-#endif // ENV_SHELL_H
+#ifndef ENV_SHELL_H +#define ENV_SHELL_H + +#include "env.h" +#include <QFileInfo> +#include <QMainWindow> +#include <QPoint> +#include <QString> + +namespace env +{ + +// Shell context menus are Windows-only — these stubs let the rest of the +// codebase compile and call into them as no-ops on Linux. +class ShellMenu +{ +public: + ShellMenu(QMainWindow*) {} + + ShellMenu(const ShellMenu&) = delete; + ShellMenu& operator=(const ShellMenu&) = delete; + ShellMenu(ShellMenu&&) = default; + ShellMenu& operator=(ShellMenu&&) = default; + + void addFile(QFileInfo) {} + int fileCount() const { return 0; } + void exec(const QPoint&) {} +}; + +class ShellMenuCollection +{ +public: + ShellMenuCollection(QMainWindow*) {} + + void addDetails(QString) {} + void add(QString, ShellMenu) {} + void exec(const QPoint&) {} +}; + +} // namespace env + +#endif // ENV_SHELL_H diff --git a/src/src/envshortcut.cpp b/src/src/envshortcut.cpp index 5b6ff8e..1a36cf4 100644 --- a/src/src/envshortcut.cpp +++ b/src/src/envshortcut.cpp @@ -1,358 +1,5 @@ -#include "envshortcut.h"
-
-#ifdef _WIN32
-
-#include "env.h"
-#include "executableslist.h"
-#include "filesystemutilities.h"
-#include "instancemanager.h"
-#include <log.h>
-#include <utility.h>
-
-namespace env
-{
-
-using namespace MOBase;
-
-class ShellLinkException
-{
-public:
- ShellLinkException(QString s) : m_what(std::move(s)) {}
-
- const QString& what() const { return m_what; }
-
-private:
- QString m_what;
-};
-
-// just a wrapper around IShellLink operations that throws ShellLinkException
-// on errors
-//
-class ShellLinkWrapper
-{
-public:
- ShellLinkWrapper()
- {
- m_link = createShellLink();
- m_file = createPersistFile();
- }
-
- void setPath(const QString& s)
- {
- if (s.isEmpty()) {
- throw ShellLinkException("path cannot be empty");
- }
-
- const auto r = m_link->SetPath(s.toStdWString().c_str());
- throwOnFail(r, QString("failed to set target path '%1'").arg(s));
- }
-
- void setArguments(const QString& s)
- {
- const auto r = m_link->SetArguments(s.toStdWString().c_str());
- throwOnFail(r, QString("failed to set arguments '%1'").arg(s));
- }
-
- void setDescription(const QString& s)
- {
- if (s.isEmpty()) {
- return;
- }
-
- const auto r = m_link->SetDescription(s.toStdWString().c_str());
- throwOnFail(r, QString("failed to set description '%1'").arg(s));
- }
-
- void setIcon(const QString& file, int i)
- {
- if (file.isEmpty()) {
- return;
- }
-
- const auto r = m_link->SetIconLocation(file.toStdWString().c_str(), i);
- throwOnFail(r, QString("failed to set icon '%1' @ %2").arg(file).arg(i));
- }
-
- void setWorkingDirectory(const QString& s)
- {
- if (s.isEmpty()) {
- return;
- }
-
- const auto r = m_link->SetWorkingDirectory(s.toStdWString().c_str());
- throwOnFail(r, QString("failed to set working directory '%1'").arg(s));
- }
-
- void save(const QString& path)
- {
- const auto r = m_file->Save(path.toStdWString().c_str(), TRUE);
- throwOnFail(r, QString("failed to save link '%1'").arg(path));
- }
-
-private:
- COMPtr<IShellLink> m_link;
- COMPtr<IPersistFile> m_file;
-
- void throwOnFail(HRESULT r, const QString& s)
- {
- if (FAILED(r)) {
- throw ShellLinkException(QString("%1, %2").arg(s).arg(formatSystemMessage(r)));
- }
- }
-
- COMPtr<IShellLink> createShellLink()
- {
- void* link = nullptr;
-
- const auto r = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
- IID_IShellLink, &link);
-
- throwOnFail(r, "failed to create IShellLink instance");
-
- if (!link) {
- throw ShellLinkException("creating IShellLink worked, pointer is null");
- }
-
- return COMPtr<IShellLink>(static_cast<IShellLink*>(link));
- }
-
- COMPtr<IPersistFile> createPersistFile()
- {
- void* file = nullptr;
-
- const auto r = m_link->QueryInterface(IID_IPersistFile, &file);
- throwOnFail(r, "failed to get IPersistFile interface");
-
- if (!file) {
- throw ShellLinkException("querying IPersistFile worked, pointer is null");
- }
-
- return COMPtr<IPersistFile>(static_cast<IPersistFile*>(file));
- }
-};
-
-Shortcut::Shortcut() : m_iconIndex(0) {}
-
-Shortcut::Shortcut(const Executable& exe) : Shortcut()
-{
- const auto i = *InstanceManager::singleton().currentInstance();
-
- m_name = MOBase::sanitizeFileName(exe.title());
- m_target = QFileInfo(qApp->applicationFilePath()).absoluteFilePath();
-
- m_arguments = QString("\"moshortcut://%1:%2\"")
- .arg(i.isPortable() ? "" : i.displayName())
- .arg(exe.title());
-
- m_description = QString("Run %1 with ModOrganizer").arg(exe.title());
-
- if (exe.usesOwnIcon()) {
- m_icon = exe.binaryInfo().absoluteFilePath();
- }
-
- m_workingDirectory = qApp->applicationDirPath();
-}
-
-Shortcut& Shortcut::name(const QString& s)
-{
- m_name = s;
- return *this;
-}
-
-Shortcut& Shortcut::target(const QString& s)
-{
- m_target = s;
- return *this;
-}
-
-Shortcut& Shortcut::arguments(const QString& s)
-{
- m_arguments = s;
- return *this;
-}
-
-Shortcut& Shortcut::description(const QString& s)
-{
- m_description = s;
- return *this;
-}
-
-Shortcut& Shortcut::icon(const QString& s, int index)
-{
- m_icon = s;
- m_iconIndex = index;
- return *this;
-}
-
-Shortcut& Shortcut::workingDirectory(const QString& s)
-{
- m_workingDirectory = s;
- return *this;
-}
-
-bool Shortcut::exists(Locations loc) const
-{
- const auto path = shortcutPath(loc);
- if (path.isEmpty()) {
- return false;
- }
-
- return QFileInfo(path).exists();
-}
-
-bool Shortcut::toggle(Locations loc)
-{
- if (exists(loc)) {
- return remove(loc);
- } else {
- return add(loc);
- }
-}
-
-bool Shortcut::add(Locations loc)
-{
- log::debug("adding shortcut to {}:\n"
- " . name: '{}'\n"
- " . target: '{}'\n"
- " . arguments: '{}'\n"
- " . description: '{}'\n"
- " . icon: '{}' @ {}\n"
- " . working directory: '{}'",
- toString(loc), m_name, m_target, m_arguments, m_description, m_icon,
- m_iconIndex, m_workingDirectory);
-
- if (m_target.isEmpty()) {
- log::error("shortcut: target is empty");
- return false;
- }
-
- const auto path = shortcutPath(loc);
- if (path.isEmpty()) {
- return false;
- }
-
- log::debug("shorcut file will be saved at '{}'", path);
-
- try {
- ShellLinkWrapper link;
-
- link.setPath(m_target);
- link.setArguments(m_arguments);
- link.setDescription(m_description);
- link.setIcon(m_icon, m_iconIndex);
- link.setWorkingDirectory(m_workingDirectory);
-
- link.save(path);
-
- return true;
- } catch (ShellLinkException& e) {
- log::error("{}\nshortcut file was not saved", e.what());
- }
-
- return false;
-}
-
-bool Shortcut::remove(Locations loc)
-{
- log::debug("removing shortcut for '{}' from {}", m_name, toString(loc));
-
- const auto path = shortcutPath(loc);
- if (path.isEmpty()) {
- return false;
- }
-
- log::debug("path to shortcut file is '{}'", path);
-
- if (!QFile::exists(path)) {
- log::error("can't remove shortcut '{}', file not found", path);
- return false;
- }
-
- if (!MOBase::shellDelete({path})) {
- const auto e = ::GetLastError();
-
- log::error("failed to remove shortcut '{}', {}", path, formatSystemMessage(e));
-
- return false;
- }
-
- return true;
-}
-
-QString Shortcut::shortcutPath(Locations loc) const
-{
- const auto dir = shortcutDirectory(loc);
- if (dir.isEmpty()) {
- return {};
- }
-
- const auto file = shortcutFilename();
- if (file.isEmpty()) {
- return {};
- }
-
- return dir + QDir::separator() + file;
-}
-
-QString Shortcut::shortcutDirectory(Locations loc) const
-{
- QString dir;
-
- try {
- switch (loc) {
- case Desktop:
- dir = MOBase::getDesktopDirectory();
- break;
-
- case StartMenu:
- dir = MOBase::getStartMenuDirectory();
- break;
-
- case None:
- default:
- log::error("shortcut: bad location {}", loc);
- break;
- }
- } catch (std::exception&) {
- }
-
- return QDir::toNativeSeparators(dir);
-}
-
-QString Shortcut::shortcutFilename() const
-{
- if (m_name.isEmpty()) {
- log::error("shortcut name is empty");
- return {};
- }
-
- return m_name + ".lnk";
-}
-
-QString toString(Shortcut::Locations loc)
-{
- switch (loc) {
- case Shortcut::None:
- return "none";
-
- case Shortcut::Desktop:
- return "desktop";
-
- case Shortcut::StartMenu:
- return "start menu";
-
- case Shortcut::ApplicationMenu:
- return "application menu";
-
- default:
- return QString("? (%1)").arg(static_cast<int>(loc));
- }
-}
-
-} // namespace env
-
-#else // Linux
-
+#include "envshortcut.h" + #include <QBuffer>
#include <QDir>
#include <QFile>
@@ -921,5 +568,3 @@ QString toString(Shortcut::Locations loc) }
} // namespace env
-
-#endif // _WIN32
diff --git a/src/src/envwindows.cpp b/src/src/envwindows.cpp index 24f98cf..e235032 100644 --- a/src/src/envwindows.cpp +++ b/src/src/envwindows.cpp @@ -1,305 +1,137 @@ -#include "envwindows.h"
-#include "env.h"
-#include "envmodule.h"
-#include <log.h>
-#include <utility.h>
-
-#ifndef _WIN32
-#include <sys/utsname.h>
-#include <unistd.h>
-#include <fstream>
-#include <string>
-#endif
-
-namespace env
-{
-
-using namespace MOBase;
-
-#ifdef _WIN32
-
-WindowsInfo::WindowsInfo()
-{
- // loading ntdll.dll, the functions will be found with GetProcAddress()
- LibraryPtr ntdll(LoadLibraryW(L"ntdll.dll"));
-
- if (!ntdll) {
- log::error("failed to load ntdll.dll while getting version");
- return;
- } else {
- m_reported = getReportedVersion(ntdll.get());
- m_real = getRealVersion(ntdll.get());
- }
-
- m_release = getRelease();
- m_elevated = getElevated();
-}
-
-WindowsInfo::Version WindowsInfo::getReportedVersion(HINSTANCE ntdll) const
-{
- using RtlGetVersionType = NTSTATUS(NTAPI)(PRTL_OSVERSIONINFOW);
-
- auto* RtlGetVersion =
- reinterpret_cast<RtlGetVersionType*>(GetProcAddress(ntdll, "RtlGetVersion"));
-
- if (!RtlGetVersion) {
- log::error("RtlGetVersion() not found in ntdll.dll");
- return {};
- }
-
- OSVERSIONINFOEX vi = {};
- vi.dwOSVersionInfoSize = sizeof(vi);
-
- RtlGetVersion((RTL_OSVERSIONINFOW*)&vi);
-
- return {vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber};
-}
-
-WindowsInfo::Version WindowsInfo::getRealVersion(HINSTANCE ntdll) const
-{
- using RtlGetNtVersionNumbersType = void(NTAPI)(DWORD*, DWORD*, DWORD*);
-
- auto* RtlGetNtVersionNumbers = reinterpret_cast<RtlGetNtVersionNumbersType*>(
- GetProcAddress(ntdll, "RtlGetNtVersionNumbers"));
-
- if (!RtlGetNtVersionNumbers) {
- log::error("RtlGetNtVersionNumbers not found in ntdll.dll");
- return {};
- }
-
- DWORD major = 0, minor = 0, build = 0;
- RtlGetNtVersionNumbers(&major, &minor, &build);
-
- // for whatever reason, the build number has 0xf0000000 set
- build = 0x0fffffff & build;
-
- return {major, minor, build};
-}
-
-WindowsInfo::Release WindowsInfo::getRelease() const
-{
- QSettings settings(
- R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion)",
- QSettings::NativeFormat);
-
- Release r;
-
- r.buildLab = settings.value("BuildLabEx", "").toString();
- if (r.buildLab.isEmpty()) {
- r.buildLab = settings.value("BuildLab", "").toString();
- if (r.buildLab.isEmpty()) {
- r.buildLab = settings.value("BuildBranch", "").toString();
- }
- }
-
- r.ID = settings.value("DisplayVersion", "").toString();
- if (r.ID.isEmpty()) {
- r.ID = settings.value("ReleaseId", "").toString();
- }
-
- r.UBR = settings.value("UBR", 0).toUInt();
-
- return r;
-}
-
-std::optional<bool> WindowsInfo::getElevated() const
-{
- HandlePtr token;
-
- {
- HANDLE rawToken = 0;
-
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
- const auto e = GetLastError();
-
- log::error("while trying to check if process is elevated, "
- "OpenProcessToken() failed: {}",
- formatSystemMessage(e));
-
- return {};
- }
-
- token.reset(rawToken);
- }
-
- TOKEN_ELEVATION e = {};
- DWORD size = sizeof(TOKEN_ELEVATION);
-
- if (!GetTokenInformation(token.get(), TokenElevation, &e, sizeof(e), &size)) {
- const auto e = GetLastError();
-
- log::error("while trying to check if process is elevated, "
- "GetTokenInformation() failed: {}",
- formatSystemMessage(e));
-
- return {};
- }
-
- return (e.TokenIsElevated != 0);
-}
-
-#else // Linux
-
-WindowsInfo::WindowsInfo()
-{
- m_reported = getKernelVersion();
- m_real = m_reported;
- m_release = getRelease();
- m_elevated = getElevated();
-}
-
-WindowsInfo::Version WindowsInfo::getKernelVersion() const
-{
- struct utsname uts;
- if (uname(&uts) != 0) {
- log::error("uname() failed");
- return {};
- }
-
- Version v;
-
- // Parse kernel version string like "6.18.9-2-cachyos"
- QString kver = QString::fromUtf8(uts.release);
- QStringList parts = kver.split('.');
-
- if (parts.size() >= 1) v.major = parts[0].toUInt();
- if (parts.size() >= 2) v.minor = parts[1].toUInt();
- if (parts.size() >= 3) {
- // Build may contain suffix like "9-2-cachyos", take numeric prefix
- QString buildStr = parts[2];
- int dashPos = buildStr.indexOf('-');
- if (dashPos >= 0) {
- buildStr = buildStr.left(dashPos);
- }
- v.build = buildStr.toUInt();
- }
-
- return v;
-}
-
-WindowsInfo::Release WindowsInfo::getRelease() const
-{
- Release r;
-
- // Parse /etc/os-release
- std::ifstream osRelease("/etc/os-release");
- if (osRelease.is_open()) {
- std::string line;
- while (std::getline(osRelease, line)) {
- // Lines are KEY=VALUE or KEY="VALUE"
- auto eqPos = line.find('=');
- if (eqPos == std::string::npos) continue;
-
- std::string key = line.substr(0, eqPos);
- std::string val = line.substr(eqPos + 1);
-
- // Strip quotes
- if (val.size() >= 2 && val.front() == '"' && val.back() == '"') {
- val = val.substr(1, val.size() - 2);
- }
-
- if (key == "PRETTY_NAME") {
- r.buildLab = QString::fromStdString(val);
- } else if (key == "VERSION_ID") {
- r.ID = QString::fromStdString(val);
- }
- }
- }
-
- return r;
-}
-
-std::optional<bool> WindowsInfo::getElevated() const
-{
- return (geteuid() == 0);
-}
-
-#endif // _WIN32
-
-bool WindowsInfo::compatibilityMode() const
-{
-#ifdef _WIN32
- if (m_real == Version()) {
- // don't know the real version, can't guess compatibility mode
- return false;
- }
-
- return (m_real != m_reported);
-#else
- // compatibility mode doesn't apply on Linux
- return false;
-#endif
-}
-
-const WindowsInfo::Version& WindowsInfo::reportedVersion() const
-{
- return m_reported;
-}
-
-const WindowsInfo::Version& WindowsInfo::realVersion() const
-{
- return m_real;
-}
-
-const WindowsInfo::Release& WindowsInfo::release() const
-{
- return m_release;
-}
-
-std::optional<bool> WindowsInfo::isElevated() const
-{
- return m_elevated;
-}
-
-QString WindowsInfo::toString() const
-{
- QStringList sl;
-
- const QString reported = m_reported.toString();
- const QString real = m_real.toString();
-
- // version
- sl.push_back("version " + reported);
-
- // real version if different
- if (compatibilityMode()) {
- sl.push_back("real version " + real);
- }
-
-#ifdef _WIN32
- // build.UBR, such as 17763.557
- if (m_release.UBR != 0) {
- DWORD build = 0;
-
- if (compatibilityMode()) {
- build = m_real.build;
- } else {
- build = m_reported.build;
- }
-
- sl.push_back(QString("%1.%2").arg(build).arg(m_release.UBR));
- }
-#endif
-
- // release ID
- if (!m_release.ID.isEmpty()) {
- sl.push_back("release " + m_release.ID);
- }
-
- // buildlab string / distro name
- if (!m_release.buildLab.isEmpty()) {
- sl.push_back(m_release.buildLab);
- }
-
- // elevated
- QString elevated = "?";
- if (m_elevated.has_value()) {
- elevated = (*m_elevated ? "yes" : "no");
- }
-
- sl.push_back("elevated: " + elevated);
-
- return sl.join(", ");
-}
-
-} // namespace env
+#include "envwindows.h" +#include "env.h" +#include "envmodule.h" +#include <log.h> +#include <utility.h> + +#include <sys/utsname.h> +#include <unistd.h> +#include <fstream> +#include <string> + +namespace env +{ + +using namespace MOBase; + +WindowsInfo::WindowsInfo() +{ + m_reported = getKernelVersion(); + m_real = m_reported; + m_release = getRelease(); + m_elevated = getElevated(); +} + +WindowsInfo::Version WindowsInfo::getKernelVersion() const +{ + struct utsname uts; + if (uname(&uts) != 0) { + log::error("uname() failed"); + return {}; + } + + Version v; + + // Parse kernel version like "6.18.9-2-cachyos". + QString kver = QString::fromUtf8(uts.release); + QStringList parts = kver.split('.'); + + if (parts.size() >= 1) + v.major = parts[0].toUInt(); + if (parts.size() >= 2) + v.minor = parts[1].toUInt(); + if (parts.size() >= 3) { + QString buildStr = parts[2]; + int dashPos = buildStr.indexOf('-'); + if (dashPos >= 0) { + buildStr = buildStr.left(dashPos); + } + v.build = buildStr.toUInt(); + } + + return v; +} + +WindowsInfo::Release WindowsInfo::getRelease() const +{ + Release r; + + std::ifstream osRelease("/etc/os-release"); + if (osRelease.is_open()) { + std::string line; + while (std::getline(osRelease, line)) { + auto eqPos = line.find('='); + if (eqPos == std::string::npos) + continue; + + std::string key = line.substr(0, eqPos); + std::string val = line.substr(eqPos + 1); + + if (val.size() >= 2 && val.front() == '"' && val.back() == '"') { + val = val.substr(1, val.size() - 2); + } + + if (key == "PRETTY_NAME") { + r.buildLab = QString::fromStdString(val); + } else if (key == "VERSION_ID") { + r.ID = QString::fromStdString(val); + } + } + } + + return r; +} + +std::optional<bool> WindowsInfo::getElevated() const +{ + return (geteuid() == 0); +} + +bool WindowsInfo::compatibilityMode() const +{ + return false; +} + +const WindowsInfo::Version& WindowsInfo::reportedVersion() const +{ + return m_reported; +} + +const WindowsInfo::Version& WindowsInfo::realVersion() const +{ + return m_real; +} + +const WindowsInfo::Release& WindowsInfo::release() const +{ + return m_release; +} + +std::optional<bool> WindowsInfo::isElevated() const +{ + return m_elevated; +} + +QString WindowsInfo::toString() const +{ + QStringList sl; + + sl.push_back("version " + m_reported.toString()); + + if (!m_release.ID.isEmpty()) { + sl.push_back("release " + m_release.ID); + } + if (!m_release.buildLab.isEmpty()) { + sl.push_back(m_release.buildLab); + } + + QString elevated = "?"; + if (m_elevated.has_value()) { + elevated = (*m_elevated ? "yes" : "no"); + } + sl.push_back("elevated: " + elevated); + + return sl.join(", "); +} + +} // namespace env diff --git a/src/src/envwindows.h b/src/src/envwindows.h index 938bf3f..70d8d2a 100644 --- a/src/src/envwindows.h +++ b/src/src/envwindows.h @@ -14,11 +14,7 @@ class WindowsInfo public:
struct Version
{
-#ifdef _WIN32
- DWORD major = 0, minor = 0, build = 0;
-#else
uint32_t major = 0, minor = 0, build = 0;
-#endif
QString toString() const
{
@@ -43,11 +39,7 @@ public: QString ID;
// some sub-build number, may be empty
-#ifdef _WIN32
- DWORD UBR;
-#else
uint32_t UBR;
-#endif
Release() : UBR(0) {}
};
@@ -83,19 +75,8 @@ private: Release m_release;
std::optional<bool> m_elevated;
-#ifdef _WIN32
- // uses RtlGetVersion() to get the version number as reported by Windows
- //
- Version getReportedVersion(HINSTANCE ntdll) const;
-
- // uses RtlGetNtVersionNumbers() to get the real version number
- //
- Version getRealVersion(HINSTANCE ntdll) const;
-#else
// uses uname() to get the kernel version
- //
Version getKernelVersion() const;
-#endif
// gets various information from the registry (Windows) or /etc/os-release (Linux)
//
|
