diff --git a/UE4SS/proxy_generator/main.cpp b/UE4SS/proxy_generator/main.cpp index 7bc9ce4db..9ccdae2e1 100644 --- a/UE4SS/proxy_generator/main.cpp +++ b/UE4SS/proxy_generator/main.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include using namespace RC; namespace fs = std::filesystem; @@ -51,7 +51,7 @@ std::vector DumpExports(const fs::path& dll_path) if (export_directory == nullptr) { - auto err_msg = to_string(Win32Error(GetLastError())); + auto err_msg = to_string(SysError(GetLastError())); cerr << std::format("Failed to get export directory, reason: {}", err_msg) << '\n'; return {}; } diff --git a/UE4SS/src/CrashDumper.cpp b/UE4SS/src/CrashDumper.cpp index 0ab3a4b19..c7b7bf86a 100644 --- a/UE4SS/src/CrashDumper.cpp +++ b/UE4SS/src/CrashDumper.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace fs = std::filesystem; @@ -33,7 +33,7 @@ namespace RC if (file == INVALID_HANDLE_VALUE) { - const StringType message = fmt::format(STR("Failed to create crashdump file, reason: {}"), Win32Error(GetLastError()).c_str()); + const StringType message = fmt::format(STR("Failed to create crashdump file, reason: {}"), SysError(GetLastError()).c_str()); MessageBoxW(NULL, FromCharTypePtr(message.c_str()), L"Fatal Error!", MB_OK); return EXCEPTION_CONTINUE_SEARCH; } @@ -55,7 +55,7 @@ namespace RC if (!ok) { - const StringType message = fmt::format(STR("Failed to write crashdump file, reason: {}"), Win32Error(GetLastError()).c_str()); + const StringType message = fmt::format(STR("Failed to write crashdump file, reason: {}"), SysError(GetLastError()).c_str()); MessageBoxW(NULL, FromCharTypePtr(message.c_str()), L"Fatal Error!", MB_OK); return EXCEPTION_CONTINUE_SEARCH; } diff --git a/UE4SS/src/Mod/CppMod.cpp b/UE4SS/src/Mod/CppMod.cpp index 31daef1b8..c1a4c99a0 100644 --- a/UE4SS/src/Mod/CppMod.cpp +++ b/UE4SS/src/Mod/CppMod.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ namespace RC if (!m_main_dll_module) { Output::send(STR("Failed to load dll <{}> for mod {}, error: {}\n"), - ensure_str(dll_path), m_mod_name, Win32Error(GetLastError()).c_str()); + ensure_str(dll_path), m_mod_name, SysError(GetLastError()).c_str()); set_installable(false); return; } diff --git a/deps/first/File/src/FileType/WinFile.cpp b/deps/first/File/src/FileType/WinFile.cpp index 92092b71d..c64fbedf1 100644 --- a/deps/first/File/src/FileType/WinFile.cpp +++ b/deps/first/File/src/FileType/WinFile.cpp @@ -7,7 +7,7 @@ #define NOMINMAX #include #include -#include +#include #ifdef TEXT #undef TEXT #endif @@ -34,7 +34,7 @@ namespace RC::File if (DeleteFileW(file_path_and_name.wstring().c_str()) == 0) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::delete_file] Was unable to delete file, error: {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } } else @@ -42,7 +42,7 @@ namespace RC::File if (DeleteFileA(file_path_and_name.string().c_str()) == 0) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::delete_file] Was unable to delete file, error: {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } } } @@ -104,7 +104,7 @@ namespace RC::File if (!WriteFile(file.get_file(), data, num_bytes_to_write, &bytes_written, nullptr)) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::write_to_file] Tried writing to file but was unable to complete operation. error: {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } } @@ -296,7 +296,7 @@ namespace RC::File if (res == 0) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::get_serialized_item] Tried deserializing file but was unable to complete operation. error: {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } cache_file.close(); @@ -344,7 +344,7 @@ namespace RC::File { if (UnmapViewOfFile(m_memory_map) == 0) { - THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::close_file] Was unable to unmap file, error: {}", to_string(Win32Error(GetLastError())).c_str())) + THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::close_file] Was unable to unmap file, error: {}", to_string(SysError(GetLastError())).c_str())) } else { @@ -356,7 +356,7 @@ namespace RC::File { if (CloseHandle(m_map_handle) == 0) { - THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::close_file] Was unable to close map handle, {}", to_string(Win32Error(GetLastError())).c_str())) + THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::close_file] Was unable to close map handle, {}", to_string(SysError(GetLastError())).c_str())) } else { @@ -371,7 +371,7 @@ namespace RC::File if (CloseHandle(m_file) == 0) { - THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::close_file] Was unable to close file, {}", to_string(Win32Error(GetLastError())).c_str())) + THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::close_file] Was unable to close file, {}", to_string(SysError(GetLastError())).c_str())) } else { @@ -391,7 +391,7 @@ namespace RC::File if (string_size == 0) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::write_string_to_file] Tried writing string to file but string_size was 0. {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } std::string string_converted_to_utf8(string_size, 0); @@ -406,7 +406,7 @@ namespace RC::File { THROW_INTERNAL_FILE_ERROR( fmt::format("[WinFile::write_string_to_file] Tried writing string to file but could not convert to utf-8. {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } write_to_file(*this, string_converted_to_utf8.c_str(), string_size); @@ -417,13 +417,13 @@ namespace RC::File BY_HANDLE_FILE_INFORMATION file_info{}; if (GetFileInformationByHandle(m_file, &file_info) == 0) { - THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::is_same_as] Tried retrieving file information by handle. {}", to_string(Win32Error(GetLastError())).c_str())) + THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::is_same_as] Tried retrieving file information by handle. {}", to_string(SysError(GetLastError())).c_str())) } BY_HANDLE_FILE_INFORMATION other_file_info{}; if (GetFileInformationByHandle(other_file.get_file(), &other_file_info) == 0) { - THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::is_same_as] Tried retrieving file information by handle. {}", to_string(Win32Error(GetLastError())).c_str())) + THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::is_same_as] Tried retrieving file information by handle. {}", to_string(SysError(GetLastError())).c_str())) } if (file_info.dwVolumeSerialNumber != other_file_info.dwVolumeSerialNumber) @@ -523,14 +523,14 @@ namespace RC::File if (!m_map_handle) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::memory_map] Tried to memory map file but 'CreateFileMapping' returned {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } m_memory_map = static_cast(MapViewOfFile(m_map_handle, mapping_desired_access, 0, 0, 0)); if (!m_memory_map) { THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::memory_map] Tried to memory map file but 'MapViewOfFile' returned {}", - to_string(Win32Error(GetLastError())).c_str())) + to_string(SysError(GetLastError())).c_str())) } MEMORY_BASIC_INFORMATION buffer{}; @@ -613,7 +613,7 @@ namespace RC::File std::string_view open_type = open_properties.open_for == OpenFor::Writing || open_properties.open_for == OpenFor::Appending ? "writing" : "reading"; THROW_INTERNAL_FILE_ERROR(fmt::format("[WinFile::open_file] Tried opening file for {} but encountered an error. Path & File: {} | error: {}\n", - open_type, file_name_and_path.string(), to_string(Win32Error(GetLastError())).c_str())) + open_type, file_name_and_path.string(), to_string(SysError(GetLastError())).c_str())) } file.m_file_path_and_name = file_name_and_path; diff --git a/deps/first/Helpers/include/Helpers/SysError.hpp b/deps/first/Helpers/include/Helpers/SysError.hpp new file mode 100644 index 000000000..fd3349748 --- /dev/null +++ b/deps/first/Helpers/include/Helpers/SysError.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include + +namespace RC +{ + inline const std::error_category& default_error_category() noexcept + { +#ifdef _WIN32 + return std::system_category(); +#else + return std::generic_category(); +#endif + } + +#ifdef _WIN32 + using PlatformResultCode = HRESULT; +#else + using PlatformResultCode = int; +#endif +} + +namespace RC +{ + /** + * Wrapper for error messages from system error code to be used as a string object + */ + class SysError + { + public: + /** + * Constructor for error code + * @param error_code : a system error code + * @param category : the error category (std::system_category() for OS specific codes or std::generic_category() for POSIX codes) + */ + explicit SysError(int error_code, const std::error_category& category = default_error_category()); + /** + * Constructor for error code + * @param error_code : a system error code + * @param category : the error category (std::system_category() for OS specific codes or std::generic_category() for POSIX codes) + */ + explicit SysError(unsigned long error_code, const std::error_category& category = default_error_category()); + /** + * Assign an error code and update the object with the corresponding error message + * @param error_code : a system error code + */ + auto assign(unsigned long error_code) -> void; +#ifdef _WIN32 + /** + * Constructor for COM HRESULT codes -- only works for FACILITY_WIN32 + * @param hresult : a COM operation result code + */ + explicit SysError(HRESULT hresult); + + /** + * Assign an error code and update the object with the corresponding error message + * @param hresult : a COM operation result code + */ + auto assign(HRESULT hresult) -> void; +#endif + /** + * Returns a pointer to an array that contains a null-terminated sequence of characters representing the current value of the string object + * @return a pointer to the c-string representation of the string object's value + */ + [[nodiscard]] auto c_str() const noexcept -> const CharType* { return m_error_text.c_str(); } + /** + * Returns the name of the error category + * @return the name of the error category + */ + [[nodiscard]] auto category() const -> StringType; + /** + * Explicit cast operator to const CharType* + */ + explicit operator const CharType*() const noexcept { return c_str(); } // must be explicit, or it will cause an ambiguous call to overloaded function error when passed to RC::to_string + /** + * Implicit cast operator to const StringType& so that the wrapper can be passed to RC::to_string, for instance + */ + operator const StringType&() const noexcept { return m_error_text; } + private: + /** + * Formats the error message corresponding to the specified error code. + * @param error_code : a system error code or COM error code + * @return a string containing the formatted message, if successful + */ + [[nodiscard]] auto format_error(int error_code) const -> StringType; + /** + * The error category (std::system_category() for OS specific codes or std::generic_category() for POSIX codes) + */ + const std::error_category* m_error_category = nullptr; + /** + * The string object backing the wrapper + */ + StringType m_error_text; + }; +} diff --git a/deps/first/Helpers/include/Helpers/Win32Error.hpp b/deps/first/Helpers/include/Helpers/Win32Error.hpp deleted file mode 100644 index 3637c5e19..000000000 --- a/deps/first/Helpers/include/Helpers/Win32Error.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#ifdef _WIN32 - -namespace RC -{ - /** - * Wrapper for WinAPI error code to be used as a string object - */ - class Win32Error - { - public: - /** - * Constructor for error codes coming from GetLastError() - * @param errorCode : a WinAPI error code - */ - explicit Win32Error(DWORD errorCode); - /** - * Constructor for COM HRESULT codes -- only works for FACILITY_WIN32 - * @param hResult : a COM operation result code - */ - explicit Win32Error(HRESULT hResult); - - /** - * Assign an error code and update the object with the corresponding error message - * @param errorCode : a WinAPI error code from GetLastError() - * @param dwLanguageId : the language identifier for the requested message passed to FormatMessage - */ - auto assign(DWORD errorCode, DWORD dwLanguageId) -> void; - /** - * Assign an error code and update the object with the corresponding error message - * @param hResult : a COM operation result code - * @param dwLanguageId : the language identifier for the requested message passed to FormatMessage - */ - auto assign(HRESULT hResult, DWORD dwLanguageId) -> void; - /** - * Returns a pointer to an array that contains a null-terminated sequence of characters representing the current value of the string object - * @return a pointer to the c-string representation of the string object's value - */ - [[nodiscard]] auto c_str() const -> const CharType* { return m_ErrorText.c_str(); } - /** - * Explicit cast operator to const CharType* - */ - explicit operator const CharType*() const { return c_str(); } // must be explicit, or it will cause an ambiguous call to overloaded function error when passed to RC::to_string - /** - * Implicit cast operator to const StringType& so that the wrapper can be passed to RC::to_string, for instance - */ - operator const StringType&() const { return m_ErrorText; } - private: - /** - * Formats the error message corresponding to the specified error code. - * The allocation is handled by FormatMessage itself and the resulting pointer must be freed by calling LocalFree. - * @param errorCode : a WinAPI or COM error code - * @param dwLanguageId : the language identifier for the requested message passed to FormatMessage - * @return a buffer containing the formatted message if successful; nullptr otherwise - */ - static auto format_error(DWORD errorCode, DWORD dwLanguageId) -> CharType*; - /** - * The string object backing the wrapper - */ - StringType m_ErrorText; - }; -} - - -#endif diff --git a/deps/first/Helpers/src/SysError.cpp b/deps/first/Helpers/src/SysError.cpp new file mode 100644 index 000000000..922eba05b --- /dev/null +++ b/deps/first/Helpers/src/SysError.cpp @@ -0,0 +1,72 @@ +#ifdef _WIN32 + #include +#endif + +#include +#include +#include +#include + +#include + +#include "Helpers/SysError.hpp" +#include "Helpers/String.hpp" + +namespace RC +{ + SysError::SysError(const int error_code, const std::error_category &category) + : m_error_category(&category) + { + assign(static_cast(error_code)); + } + + SysError::SysError(const unsigned long error_code, const std::error_category& category) + : m_error_category(&category) + { + assign(error_code); + } + + auto SysError::assign(unsigned long error_code) -> void + { + m_error_text.assign(std::format(L"[0x{:x}] {}", error_code, format_error(static_cast(error_code)))); + } + +#ifdef _WIN32 + SysError::SysError(const HRESULT hresult): m_error_category(&std::system_category()) + { + assign(hresult); + } + + auto SysError::assign(HRESULT hresult) -> void + { + if (HRESULT_FACILITY(hresult) == FACILITY_WIN32) + { + assign(static_cast(hresult)); + } + else + { + // this error code will most likely be formatted to an unrelated error message, inform the caller + m_error_text.assign(std::format(L"Failed to format the error message: HRESULT 0x{:x} is not a WIN32 error code", hresult)); + } + } +#endif + + auto SysError::category() const -> StringType + { + return to_wstring(m_error_category->name()); + } + + auto SysError::format_error(const int error_code) const -> StringType + { + const std::error_category& error_category = *m_error_category; + const std::error_code ec(error_code, error_category); + // remove new line(s) and tabs + auto result = std::regex_replace(to_wstring(std::system_error(ec).what()), std::wregex(STR("(\t|\r?\n)")), STR(" ")); + // right trim + result.erase(std::ranges::find_if(std::ranges::reverse_view(result), [](const CharType c) -> bool { + return !std::isspace(c, std::locale::classic()); + }).base(), result.end()); + + return result; + } +} diff --git a/deps/first/Helpers/src/Win32Error.cpp b/deps/first/Helpers/src/Win32Error.cpp deleted file mode 100644 index e0fa6fa32..000000000 --- a/deps/first/Helpers/src/Win32Error.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifdef _WIN32 -#include -#include - -#include - -#include "Helpers/Win32Error.hpp" - -namespace RC -{ - Win32Error::Win32Error(DWORD errorCode) - { - static constexpr auto dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); - - assign(errorCode, dwLanguageId); - } - - Win32Error::Win32Error(HRESULT hResult) - { - static constexpr auto dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); - - assign(hResult, dwLanguageId); - } - - auto Win32Error::assign(DWORD errorCode, DWORD dwLanguageId) -> void - { - if (auto pErrorText = format_error(errorCode, dwLanguageId); pErrorText != nullptr) - { - m_ErrorText = std::format(L"[0x{:x}] {}", errorCode, pErrorText); - LocalFree(pErrorText); - } - else - { - // the call to FormatMessage failed, but we can attempt to find out why - const auto formatErrorCode = GetLastError(); - - if (auto pFormatErrorText = format_error(formatErrorCode, dwLanguageId); pFormatErrorText != nullptr) - { - // we couldn't format the message for the initial error code, but we can inform the caller as to why - m_ErrorText = std::format(L"Failed to format the error message for code 0x{:x}: error {}\n", errorCode, pFormatErrorText); - LocalFree(pFormatErrorText); - } - else - { - // probably unlikely that the second call to FormatMessage fails, however fall back to the error code should it happen - m_ErrorText = std::format(L"Failed to format the error message for code 0x{:x}: error code 0x{:x}\n", errorCode, formatErrorCode); - } - } - } - - auto Win32Error::assign(HRESULT hResult, DWORD dwLanguageId) -> void - { - if (HRESULT_FACILITY(hResult) == FACILITY_WIN32) - { - assign(static_cast(hResult), dwLanguageId); - } - else - { - // this error code will most likely be formatted to an unrelated error message, inform the caller - m_ErrorText = std::format(L"Failed to format the error message: HRESULT 0x{:x} is not a WIN32 error code\n", hResult); - } - } - - auto Win32Error::format_error(DWORD errorCode, DWORD dwLanguageId) -> CharType* - { - // see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage#parameters - DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM // search the system message-table resource(s) for the requested message - | FORMAT_MESSAGE_ALLOCATE_BUFFER // allocates the buffer, use LocalFree to free the result - | FORMAT_MESSAGE_IGNORE_INSERTS // formatting placeholders are ignored (we pass nullptr for the Arguments parameter) - | FORMAT_MESSAGE_MAX_WIDTH_MASK; // ignore regular line breaks in the message definition text - LPVOID pBuffer = nullptr; - // format the system message corresponding to the error code - return FormatMessage(dwFlags, nullptr, errorCode, dwLanguageId, reinterpret_cast(&pBuffer), 0, nullptr) == 0 - ? nullptr : static_cast(pBuffer); - } -} - -#endif diff --git a/deps/first/Unreal b/deps/first/Unreal index e52c72f4b..7f540d36b 160000 --- a/deps/first/Unreal +++ b/deps/first/Unreal @@ -1 +1 @@ -Subproject commit e52c72f4b2f1fd42a16a44248c6da495b5984054 +Subproject commit 7f540d36b442fb2b2985f6b72518c00e2c2d7e45