From c3624f84902e2271e40816bf07cc7f652cd3f909 Mon Sep 17 00:00:00 2001 From: mjk Date: Fri, 19 Mar 2021 21:19:39 +0000 Subject: [PATCH] handle exe paths longer than 259 chars --- .../windows-notification/api/src/win32.cpp | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/plugins/windows-notification/api/src/win32.cpp b/plugins/windows-notification/api/src/win32.cpp index 42bc45b0..a5fcf0ef 100644 --- a/plugins/windows-notification/api/src/win32.cpp +++ b/plugins/windows-notification/api/src/win32.cpp @@ -11,16 +11,48 @@ win32_error::win32_error() noexcept constexpr auto noncharacter = L'\uFFFF'; +template +static std::wstring GetStringOfGuessableLength(const Oracle &take_a_guess) +{ + constexpr auto grow = [](const std::size_t s) { return s + s/2; }; + static_assert( + grow(InitialGuess) != InitialGuess, "imminent infinite loop"); + + std::wstring buf(InitialGuess, noncharacter); + auto maybe_len = take_a_guess(buf.data(), static_cast(buf.size())); + + if (not maybe_len) do + { + constexpr auto dw_max = std::size_t{std::numeric_limits::max()}; + if (buf.size() == dw_max) + throw std::runtime_error{"wat, string too long for DWORD?"}; + buf.resize(std::min(grow(buf.size()), dw_max)); + maybe_len = take_a_guess(buf.data(), static_cast(buf.size())); + } + while (not maybe_len); + + buf.resize(*maybe_len); + return buf; +} + std::wstring GetExePath() { - std::wstring exePath(MAX_PATH, 0); - auto charWritten = GetModuleFileName(nullptr, exePath.data(), exePath.size()); - if (charWritten > 0) + const auto try_get_exe_path = []( + const auto buf, const auto bufsize) -> std::optional { - exePath.resize(charWritten); - return exePath; - } - throw win32_error{}; + constexpr HMODULE exe_module = nullptr; + ::SetLastError(0); // just in case + const auto res = ::GetModuleFileNameW(exe_module, buf, bufsize); + if (const auto e = ::GetLastError(); + e == ERROR_INSUFFICIENT_BUFFER or res == bufsize) + return {}; + else if (not e) + return res; + else + throw win32_error{e}; + }; + + return GetStringOfGuessableLength(try_get_exe_path); } std::wstring GetEnv(const wchar_t *const variable_name)