From edab423c1622452b2ad65680f8e4f087592a1589 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 10 May 2023 14:59:31 -0400 Subject: [PATCH 1/6] add red process type & docs --- include/RED4ext/RedProcess.hpp | 73 ++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 include/RED4ext/RedProcess.hpp diff --git a/include/RED4ext/RedProcess.hpp b/include/RED4ext/RedProcess.hpp new file mode 100644 index 000000000..7a6dccf9e --- /dev/null +++ b/include/RED4ext/RedProcess.hpp @@ -0,0 +1,73 @@ +#include + +namespace RED4ext::red +{ + +struct Process +{ + struct FixedWString + { + uint32_t length; + uint32_t maxLength; + const wchar_t* str; + }; + + enum class ExecutionFlags : unsigned char + { + // unsets CREATE_NO_WINDOW + ShouldCreateWindow = 0x1, + // sets CREATE_BREAKAWAY_FROM_JOB | CREATE_SUSPENDED in Process Creation Flags + BreakawayAndSuspend = 0x2, + // unsets bInheritHandles + NoInheritHandles = 0x4 + }; + + DEFINE_ENUM_FLAG_OPERATORS(ExecutionFlags); + + enum class ReadFlags : unsigned char { + Unk1 = 0x1, + WriteToFile = 0x2, + GetCString = 0x4 + }; + + DEFINE_ENUM_FLAG_OPERATORS(ReadFlags); + + static constexpr uint32_t defaultTimeout = 60000; + + // creates the read & write pipes, and handle information + /// @pattern 48 89 5C 24 08 57 48 83 EC 40 33 C0 C7 44 24 20 18 00 00 00 48 8D 91 08 20 00 00 48 89 81 00 20 + Process(); + + /// @pattern 40 53 48 83 EC 20 48 8B D9 48 8B 89 08 20 00 00 FF 15 42 70 4B 00 48 8B 8B 00 20 00 00 48 83 C4 + bool __fastcall CloseHandles(); + + // assigns to this->errorCode, but also returns + /// @pattern 40 53 48 83 EC 20 48 8D 99 28 20 00 00 48 8B 89 10 20 00 00 48 8B D3 FF 15 C3 6F 4B 00 8B 03 48 + int32_t __fastcall GetExitCode(); + + /// @pattern 40 55 56 57 41 56 B8 68 20 00 00 E8 00 52 E7 FF 48 2B E0 49 8B E9 49 8B F0 8B FA 4C 8B F1 F6 C2 + void __fastcall ReadFromPipe(ReadFlags aFlags, CString* aFilename, CString* aStdOut); + + // converts aWorkingDirectory to a FixedWString + /// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8 + bool __fastcall Execute(CString* aCommand, FixedWString* aArgs, CString* aWorkingDirectory, ExecutionFlags aFlags); + + /// @pattern 48 89 5C 24 10 48 89 74 24 18 55 57 41 54 41 56 41 57 48 8D 6C 24 B0 48 81 EC 50 01 00 00 0F 57 + bool __fastcall Execute(CString* aCommand, FixedWString* aArgs, FixedWString* aWorkingDirectory, ExecutionFlags aFlags); + + /// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 52 6D 4B 00 85 C0 + bool __fastcall Terminate(uint32_t aExitCode, bool closeHandles); + + /// @pattern 48 83 EC 48 48 8B 89 10 20 00 00 FF 15 F7 6B 4B 00 85 C0 74 4A 3D 02 01 00 00 74 3C FF 15 BE 6A + bool __fastcall WaitUntilCompleted(uint32_t aTimeoutMS); + + wchar_t command[0x1000]; // 0000 + PHANDLE readPipe; // 2000 + PHANDLE writePipe; // 2008 + HANDLE handle; // 2010 + HANDLE hThread; // 2018 + uint64_t unk2; // 2020 + int32_t errorCode; // 2028 +}; + +} // RED4ext namespace \ No newline at end of file From b3b496a507ab076494850b4d6b7193e176a687ec Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 10 May 2023 15:31:17 -0400 Subject: [PATCH 2/6] clean-up args, compiling with red4ext --- include/RED4ext/RedProcess.hpp | 35 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/include/RED4ext/RedProcess.hpp b/include/RED4ext/RedProcess.hpp index 7a6dccf9e..1f01dc877 100644 --- a/include/RED4ext/RedProcess.hpp +++ b/include/RED4ext/RedProcess.hpp @@ -22,44 +22,46 @@ struct Process NoInheritHandles = 0x4 }; - DEFINE_ENUM_FLAG_OPERATORS(ExecutionFlags); - - enum class ReadFlags : unsigned char { + enum class ReadFlags : unsigned char + { + // open & read regardless of other options Unk1 = 0x1, + // opens file from name provided and writes output WriteToFile = 0x2, + // writes output to CString GetCString = 0x4 }; - DEFINE_ENUM_FLAG_OPERATORS(ReadFlags); + static const constexpr uint32_t defaultTimeout = 60000; - static constexpr uint32_t defaultTimeout = 60000; - // creates the read & write pipes, and handle information /// @pattern 48 89 5C 24 08 57 48 83 EC 40 33 C0 C7 44 24 20 18 00 00 00 48 8D 91 08 20 00 00 48 89 81 00 20 Process(); /// @pattern 40 53 48 83 EC 20 48 8B D9 48 8B 89 08 20 00 00 FF 15 42 70 4B 00 48 8B 8B 00 20 00 00 48 83 C4 - bool __fastcall CloseHandles(); + bool RED4EXT_CALL CloseHandles(); // assigns to this->errorCode, but also returns /// @pattern 40 53 48 83 EC 20 48 8D 99 28 20 00 00 48 8B 89 10 20 00 00 48 8B D3 FF 15 C3 6F 4B 00 8B 03 48 - int32_t __fastcall GetExitCode(); + DWORD RED4EXT_CALL GetExitCode(); /// @pattern 40 55 56 57 41 56 B8 68 20 00 00 E8 00 52 E7 FF 48 2B E0 49 8B E9 49 8B F0 8B FA 4C 8B F1 F6 C2 - void __fastcall ReadFromPipe(ReadFlags aFlags, CString* aFilename, CString* aStdOut); + void RED4EXT_CALL ReadFromPipe(const ReadFlags aFlags, const CString& aFilename, CString& aStdOut); // converts aWorkingDirectory to a FixedWString /// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8 - bool __fastcall Execute(CString* aCommand, FixedWString* aArgs, CString* aWorkingDirectory, ExecutionFlags aFlags); + bool RED4EXT_CALL ExecuteWithCString(const CString& aCommand, FixedWString& aArgs, const CString& aWorkingDirectory, + const ExecutionFlags aFlags); /// @pattern 48 89 5C 24 10 48 89 74 24 18 55 57 41 54 41 56 41 57 48 8D 6C 24 B0 48 81 EC 50 01 00 00 0F 57 - bool __fastcall Execute(CString* aCommand, FixedWString* aArgs, FixedWString* aWorkingDirectory, ExecutionFlags aFlags); + bool RED4EXT_CALL Execute(const CString& aCommand, FixedWString& aArgs, const FixedWString& aWorkingDirectory, + const ExecutionFlags aFlags); /// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 52 6D 4B 00 85 C0 - bool __fastcall Terminate(uint32_t aExitCode, bool closeHandles); + bool RED4EXT_CALL Terminate(const uint32_t aExitCode, const bool closeHandles); /// @pattern 48 83 EC 48 48 8B 89 10 20 00 00 FF 15 F7 6B 4B 00 85 C0 74 4A 3D 02 01 00 00 74 3C FF 15 BE 6A - bool __fastcall WaitUntilCompleted(uint32_t aTimeoutMS); + bool RED4EXT_CALL WaitUntilCompleted(const uint32_t aTimeoutMS) const; wchar_t command[0x1000]; // 0000 PHANDLE readPipe; // 2000 @@ -67,7 +69,10 @@ struct Process HANDLE handle; // 2010 HANDLE hThread; // 2018 uint64_t unk2; // 2020 - int32_t errorCode; // 2028 + DWORD errorCode; // 2028 }; -} // RED4ext namespace \ No newline at end of file +DEFINE_ENUM_FLAG_OPERATORS(Process::ExecutionFlags); +DEFINE_ENUM_FLAG_OPERATORS(Process::ReadFlags); + +} // namespace RED4ext::red \ No newline at end of file From 7e0123843bfbb3f9af8d99b291b1f4f69bad71d3 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 10 May 2023 16:02:37 -0400 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Octavian Dima <3403191+WopsS@users.noreply.github.com> --- include/RED4ext/RedProcess.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/RED4ext/RedProcess.hpp b/include/RED4ext/RedProcess.hpp index 1f01dc877..8df95a3c4 100644 --- a/include/RED4ext/RedProcess.hpp +++ b/include/RED4ext/RedProcess.hpp @@ -1,8 +1,7 @@ #include -namespace RED4ext::red +namespace RED4ext { - struct Process { struct FixedWString @@ -12,7 +11,7 @@ struct Process const wchar_t* str; }; - enum class ExecutionFlags : unsigned char + enum class ExecutionFlags : std::uint8_t { // unsets CREATE_NO_WINDOW ShouldCreateWindow = 0x1, @@ -22,7 +21,7 @@ struct Process NoInheritHandles = 0x4 }; - enum class ReadFlags : unsigned char + enum class ReadFlags : std::uint8_t { // open & read regardless of other options Unk1 = 0x1, @@ -32,7 +31,7 @@ struct Process GetCString = 0x4 }; - static const constexpr uint32_t defaultTimeout = 60000; + static constexpr uint32_t DefaultTimeout = 60000; // creates the read & write pipes, and handle information /// @pattern 48 89 5C 24 08 57 48 83 EC 40 33 C0 C7 44 24 20 18 00 00 00 48 8D 91 08 20 00 00 48 89 81 00 20 @@ -58,7 +57,7 @@ struct Process const ExecutionFlags aFlags); /// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 52 6D 4B 00 85 C0 - bool RED4EXT_CALL Terminate(const uint32_t aExitCode, const bool closeHandles); + bool RED4EXT_CALL Terminate(const uint32_t aExitCode, const bool aCloseHandles); /// @pattern 48 83 EC 48 48 8B 89 10 20 00 00 FF 15 F7 6B 4B 00 85 C0 74 4A 3D 02 01 00 00 74 3C FF 15 BE 6A bool RED4EXT_CALL WaitUntilCompleted(const uint32_t aTimeoutMS) const; @@ -74,5 +73,4 @@ struct Process DEFINE_ENUM_FLAG_OPERATORS(Process::ExecutionFlags); DEFINE_ENUM_FLAG_OPERATORS(Process::ReadFlags); - } // namespace RED4ext::red \ No newline at end of file From fd1882d1927ad5f86a76a7243f7f2abbb66229c0 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 10 May 2023 22:18:52 -0400 Subject: [PATCH 4/6] apply changes from review, add definitions (still zoltan-based) --- include/RED4ext/Process-inl.hpp | 60 ++++++++++++++++ include/RED4ext/Process.hpp | 118 ++++++++++++++++++++++++++++++++ include/RED4ext/RedProcess.hpp | 76 -------------------- 3 files changed, 178 insertions(+), 76 deletions(-) create mode 100644 include/RED4ext/Process-inl.hpp create mode 100644 include/RED4ext/Process.hpp delete mode 100644 include/RED4ext/RedProcess.hpp diff --git a/include/RED4ext/Process-inl.hpp b/include/RED4ext/Process-inl.hpp new file mode 100644 index 000000000..661170517 --- /dev/null +++ b/include/RED4ext/Process-inl.hpp @@ -0,0 +1,60 @@ +#pragma once + +#ifdef RED4EXT_STATIC_LIB +#include +#endif +#include + +// This file has been generated by zoltan (https://github.com/jac3km4/zoltan) + +#define Process_CloseHandles_Addr 0x2C23B30 +#define Process_Execute_Addr 0x2C23D70 +#define Process_Execute_0_Addr 0x2C23DD0 +#define Process_GetExitCode_Addr 0x2C23B60 +#define Process_Process_Addr 0x2C23AA0 +#define Process_ReadFromPipe_Addr 0x2C23B90 +#define Process_Terminate_Addr 0x2C24040 +#define Process_WaitUntilCompleted_Addr 0x2C240B0 + +inline bool RED4ext::Process::CloseHandles() { + using Process_CloseHandles_t = bool (*)(RED4ext::Process*); + RED4ext::RelocFunc call(Process_CloseHandles_Addr); + return call(this); +} + +inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, const RED4ext::CString& a3, const RED4ext::Process::ExecutionFlags a4) { + using Process_Execute_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, const RED4ext::CString&, const RED4ext::Process::ExecutionFlags); + RED4ext::RelocFunc call(Process_Execute_Addr); + return call(this, a1, a2, a3, a4); +} + +inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, const RED4ext::Process::FixedWString& a3, const RED4ext::Process::ExecutionFlags a4) { + using Process_Execute_0_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, const RED4ext::Process::FixedWString&, const RED4ext::Process::ExecutionFlags); + RED4ext::RelocFunc call(Process_Execute_0_Addr); + return call(this, a1, a2, a3, a4); +} + +inline uint64_t RED4ext::Process::GetExitCode() { + using Process_GetExitCode_t = uint64_t (*)(RED4ext::Process*); + RED4ext::RelocFunc call(Process_GetExitCode_Addr); + return call(this); +} + +inline void RED4ext::Process::ReadFromPipe(const RED4ext::Process::ReadFlags a1, const RED4ext::CString& a2, RED4ext::CString& a3) { + using Process_ReadFromPipe_t = void (*)(RED4ext::Process*, const RED4ext::Process::ReadFlags, const RED4ext::CString&, RED4ext::CString&); + RED4ext::RelocFunc call(Process_ReadFromPipe_Addr); + return call(this, a1, a2, a3); +} + +inline bool RED4ext::Process::Terminate(const uint32_t a1, const bool a2) { + using Process_Terminate_t = bool (*)(RED4ext::Process*, const uint32_t, const bool); + RED4ext::RelocFunc call(Process_Terminate_Addr); + return call(this, a1, a2); +} + +inline bool RED4ext::Process::WaitUntilCompleted(const uint32_t a1) const { + using Process_WaitUntilCompleted_t = bool (*)(RED4ext::Process*, const uint32_t); + RED4ext::RelocFunc call(Process_WaitUntilCompleted_Addr); + return call(this, a1); +} + diff --git a/include/RED4ext/Process.hpp b/include/RED4ext/Process.hpp new file mode 100644 index 000000000..ca05da4a4 --- /dev/null +++ b/include/RED4ext/Process.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include + +namespace RED4ext +{ +struct Process +{ + static constexpr uint32_t DefaultTimeout = 60000; + + struct FixedWString + { + uint32_t length; + uint32_t maxLength; + const wchar_t* str; + }; + + enum class ExecutionFlags : std::uint8_t + { + // unsets CREATE_NO_WINDOW + ShouldCreateWindow = 0x1, + // sets CREATE_BREAKAWAY_FROM_JOB | CREATE_SUSPENDED in Process Creation Flags + BreakawayAndSuspend = 0x2, + // unsets bInheritHandles + NoInheritHandles = 0x4 + }; + + enum class ReadFlags : std::uint8_t + { + // open & read regardless of other options + Unk1 = 0x1, + // opens file from name provided and writes output + WriteToFile = 0x2, + // writes output to CString + GetCString = 0x4 + }; + + /** + * @brief creates the read & write pipes, and handle information + * + * @param[in] aHandle The plugin's handle. + * @param[in] aPath The path to be added to the redscript compilation - can be a folder or a .reds file + * + * @return Returns true if the path was added is attached, false otherwise. + * + * @pattern 48 89 5C 24 08 57 48 83 EC 40 33 C0 C7 44 24 20 18 00 00 00 48 8D 91 08 20 00 00 48 89 81 00 20 + */ + Process(); + + /// @pattern 40 53 48 83 EC 20 48 8B D9 48 8B 89 08 20 00 00 FF 15 ? ? 4B 00 48 8B 8B 00 20 00 00 48 83 C4 + bool CloseHandles(); + + /** + * @brief Assigns the process's error code to this->errorCode + * + * @return Returns the error code + * + * @pattern 40 53 48 83 EC 20 48 8D 99 28 20 00 00 48 8B 89 10 20 00 00 48 8B D3 FF 15 ? ? 4B 00 8B 03 48 + */ + DWORD GetExitCode(); + + /// @pattern 40 55 56 57 41 56 B8 68 20 00 00 E8 ? ? E7 FF 48 2B E0 49 8B E9 49 8B F0 8B FA 4C 8B F1 F6 C2 + void ReadFromPipe(const ReadFlags aFlags, const CString& aFilename, CString& aStdOut); + + /** + * @brief Converts aWorkingDirectory to a FixedWString and calls Execute + * + * @param[in] aCommand The location of the executable + * @param[in] aArgs Arguments passed to the command + * @param[in] aWorkingDirectory The directory to execute the process from + * @param[in] aFlags Flags that alter the execution + * + * @return True if the process was started successfully + * + * @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8 + */ + bool Execute(const CString& aCommand, FixedWString& aArgs, const CString& aWorkingDirectory, + const ExecutionFlags aFlags); + + /** + * @brief Begins the proccess + * + * @param[in] aCommand The location of the executable + * @param[in] aArgs Arguments passed to the command + * @param[in] aWorkingDirectory The directory to execute the process from + * @param[in] aFlags Flags that alter the execution + * + * @return True if the process was started successfully + * + * @pattern 48 89 5C 24 10 48 89 74 24 18 55 57 41 54 41 56 41 57 48 8D 6C 24 B0 48 81 EC 50 01 00 00 0F 57 + */ + bool Execute(const CString& aCommand, FixedWString& aArgs, const FixedWString& aWorkingDirectory, + const ExecutionFlags aFlags); + + /// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 ? ? 4B 00 85 C0 + bool Terminate(const uint32_t aExitCode, const bool aCloseHandles); + + /// @pattern 48 83 EC 48 48 8B 89 10 20 00 00 FF 15 ? ? 4B 00 85 C0 74 4A 3D 02 01 00 00 74 3C FF 15 ? ? + bool WaitUntilCompleted(const uint32_t aTimeoutMS) const; + + wchar_t command[0x1000]; // 0000 + PHANDLE readPipe; // 2000 + PHANDLE writePipe; // 2008 + HANDLE handle; // 2010 + HANDLE hThread; // 2018 + uint64_t unk2; // 2020 + DWORD errorCode; // 2028 +}; + +// DEFINE_ENUM_FLAG_OPERATORS(Process::ExecutionFlags); +// DEFINE_ENUM_FLAG_OPERATORS(Process::ReadFlags); +} // namespace RED4ext + +#ifdef RED4EXT_HEADER_ONLY +#include +#endif \ No newline at end of file diff --git a/include/RED4ext/RedProcess.hpp b/include/RED4ext/RedProcess.hpp deleted file mode 100644 index 8df95a3c4..000000000 --- a/include/RED4ext/RedProcess.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -namespace RED4ext -{ -struct Process -{ - struct FixedWString - { - uint32_t length; - uint32_t maxLength; - const wchar_t* str; - }; - - enum class ExecutionFlags : std::uint8_t - { - // unsets CREATE_NO_WINDOW - ShouldCreateWindow = 0x1, - // sets CREATE_BREAKAWAY_FROM_JOB | CREATE_SUSPENDED in Process Creation Flags - BreakawayAndSuspend = 0x2, - // unsets bInheritHandles - NoInheritHandles = 0x4 - }; - - enum class ReadFlags : std::uint8_t - { - // open & read regardless of other options - Unk1 = 0x1, - // opens file from name provided and writes output - WriteToFile = 0x2, - // writes output to CString - GetCString = 0x4 - }; - - static constexpr uint32_t DefaultTimeout = 60000; - - // creates the read & write pipes, and handle information - /// @pattern 48 89 5C 24 08 57 48 83 EC 40 33 C0 C7 44 24 20 18 00 00 00 48 8D 91 08 20 00 00 48 89 81 00 20 - Process(); - - /// @pattern 40 53 48 83 EC 20 48 8B D9 48 8B 89 08 20 00 00 FF 15 42 70 4B 00 48 8B 8B 00 20 00 00 48 83 C4 - bool RED4EXT_CALL CloseHandles(); - - // assigns to this->errorCode, but also returns - /// @pattern 40 53 48 83 EC 20 48 8D 99 28 20 00 00 48 8B 89 10 20 00 00 48 8B D3 FF 15 C3 6F 4B 00 8B 03 48 - DWORD RED4EXT_CALL GetExitCode(); - - /// @pattern 40 55 56 57 41 56 B8 68 20 00 00 E8 00 52 E7 FF 48 2B E0 49 8B E9 49 8B F0 8B FA 4C 8B F1 F6 C2 - void RED4EXT_CALL ReadFromPipe(const ReadFlags aFlags, const CString& aFilename, CString& aStdOut); - - // converts aWorkingDirectory to a FixedWString - /// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8 - bool RED4EXT_CALL ExecuteWithCString(const CString& aCommand, FixedWString& aArgs, const CString& aWorkingDirectory, - const ExecutionFlags aFlags); - - /// @pattern 48 89 5C 24 10 48 89 74 24 18 55 57 41 54 41 56 41 57 48 8D 6C 24 B0 48 81 EC 50 01 00 00 0F 57 - bool RED4EXT_CALL Execute(const CString& aCommand, FixedWString& aArgs, const FixedWString& aWorkingDirectory, - const ExecutionFlags aFlags); - - /// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 52 6D 4B 00 85 C0 - bool RED4EXT_CALL Terminate(const uint32_t aExitCode, const bool aCloseHandles); - - /// @pattern 48 83 EC 48 48 8B 89 10 20 00 00 FF 15 F7 6B 4B 00 85 C0 74 4A 3D 02 01 00 00 74 3C FF 15 BE 6A - bool RED4EXT_CALL WaitUntilCompleted(const uint32_t aTimeoutMS) const; - - wchar_t command[0x1000]; // 0000 - PHANDLE readPipe; // 2000 - PHANDLE writePipe; // 2008 - HANDLE handle; // 2010 - HANDLE hThread; // 2018 - uint64_t unk2; // 2020 - DWORD errorCode; // 2028 -}; - -DEFINE_ENUM_FLAG_OPERATORS(Process::ExecutionFlags); -DEFINE_ENUM_FLAG_OPERATORS(Process::ReadFlags); -} // namespace RED4ext::red \ No newline at end of file From a4c529d34ea63f32398db8903e0d3a5217a86a8c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 10 May 2023 22:22:05 -0400 Subject: [PATCH 5/6] make clang happy --- include/RED4ext/Process-inl.hpp | 35 ++++++++++++++++++++++----------- include/RED4ext/Process.hpp | 4 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/include/RED4ext/Process-inl.hpp b/include/RED4ext/Process-inl.hpp index 661170517..5acc64924 100644 --- a/include/RED4ext/Process-inl.hpp +++ b/include/RED4ext/Process-inl.hpp @@ -16,45 +16,58 @@ #define Process_Terminate_Addr 0x2C24040 #define Process_WaitUntilCompleted_Addr 0x2C240B0 -inline bool RED4ext::Process::CloseHandles() { +inline bool RED4ext::Process::CloseHandles() +{ using Process_CloseHandles_t = bool (*)(RED4ext::Process*); RED4ext::RelocFunc call(Process_CloseHandles_Addr); return call(this); } -inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, const RED4ext::CString& a3, const RED4ext::Process::ExecutionFlags a4) { - using Process_Execute_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, const RED4ext::CString&, const RED4ext::Process::ExecutionFlags); +inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, + const RED4ext::CString& a3, const RED4ext::Process::ExecutionFlags a4) +{ + using Process_Execute_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, + const RED4ext::CString&, const RED4ext::Process::ExecutionFlags); RED4ext::RelocFunc call(Process_Execute_Addr); return call(this, a1, a2, a3, a4); } -inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, const RED4ext::Process::FixedWString& a3, const RED4ext::Process::ExecutionFlags a4) { - using Process_Execute_0_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, const RED4ext::Process::FixedWString&, const RED4ext::Process::ExecutionFlags); +inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, + const RED4ext::Process::FixedWString& a3, + const RED4ext::Process::ExecutionFlags a4) +{ + using Process_Execute_0_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, + const RED4ext::Process::FixedWString&, const RED4ext::Process::ExecutionFlags); RED4ext::RelocFunc call(Process_Execute_0_Addr); return call(this, a1, a2, a3, a4); } -inline uint64_t RED4ext::Process::GetExitCode() { +inline uint64_t RED4ext::Process::GetExitCode() +{ using Process_GetExitCode_t = uint64_t (*)(RED4ext::Process*); RED4ext::RelocFunc call(Process_GetExitCode_Addr); return call(this); } -inline void RED4ext::Process::ReadFromPipe(const RED4ext::Process::ReadFlags a1, const RED4ext::CString& a2, RED4ext::CString& a3) { - using Process_ReadFromPipe_t = void (*)(RED4ext::Process*, const RED4ext::Process::ReadFlags, const RED4ext::CString&, RED4ext::CString&); +inline void RED4ext::Process::ReadFromPipe(const RED4ext::Process::ReadFlags a1, const RED4ext::CString& a2, + RED4ext::CString& a3) +{ + using Process_ReadFromPipe_t = + void (*)(RED4ext::Process*, const RED4ext::Process::ReadFlags, const RED4ext::CString&, RED4ext::CString&); RED4ext::RelocFunc call(Process_ReadFromPipe_Addr); return call(this, a1, a2, a3); } -inline bool RED4ext::Process::Terminate(const uint32_t a1, const bool a2) { +inline bool RED4ext::Process::Terminate(const uint32_t a1, const bool a2) +{ using Process_Terminate_t = bool (*)(RED4ext::Process*, const uint32_t, const bool); RED4ext::RelocFunc call(Process_Terminate_Addr); return call(this, a1, a2); } -inline bool RED4ext::Process::WaitUntilCompleted(const uint32_t a1) const { +inline bool RED4ext::Process::WaitUntilCompleted(const uint32_t a1) const +{ using Process_WaitUntilCompleted_t = bool (*)(RED4ext::Process*, const uint32_t); RED4ext::RelocFunc call(Process_WaitUntilCompleted_Addr); return call(this, a1); } - diff --git a/include/RED4ext/Process.hpp b/include/RED4ext/Process.hpp index ca05da4a4..ddf795775 100644 --- a/include/RED4ext/Process.hpp +++ b/include/RED4ext/Process.hpp @@ -1,8 +1,8 @@ #pragma once -#include -#include #include +#include +#include namespace RED4ext { From 5f23ce0c8ca411416df23a7a37c45fe34b95e845 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Thu, 11 May 2023 13:05:11 -0400 Subject: [PATCH 6/6] break-out wstring to its own file --- include/RED4ext/CWideString.hpp | 182 ++++++++++++++++++++++++++++++++ include/RED4ext/Process-inl.hpp | 16 +-- include/RED4ext/Process.hpp | 15 +-- 3 files changed, 195 insertions(+), 18 deletions(-) create mode 100644 include/RED4ext/CWideString.hpp diff --git a/include/RED4ext/CWideString.hpp b/include/RED4ext/CWideString.hpp new file mode 100644 index 000000000..7c594c6cc --- /dev/null +++ b/include/RED4ext/CWideString.hpp @@ -0,0 +1,182 @@ +#pragma once + +#include +#include + +namespace RED4ext +{ +struct CString; +struct CWideString +{ + /// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 33 F6 48 8B FA 48 89 31 48 8B D9 48 89 71 08 48 85 + CWideString(const char* aStr) + { + int length; + + this->length = 0; + this->capacity = 0; + this->wstr = 0i64; + if (aStr) + { + length = -1i64; + do + ++length; + while (aStr[length]); + this->length = length; + if (length) + { + Reserve(length); + int length = this->length; + for (int i = 0; i < this->length; length = this->length) + { + int64_t v7 = i++; + this->wstr[v7] = aStr[v7]; + } + this->wstr[length] = 0; + } + } + } + + /// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 33 F6 48 8B FA 48 89 31 48 8B D9 48 89 71 08 48 85 + CWideString(const wchar_t *aWstr) + { + uint32_t strLength; // eax + + this->length = 0; + this->capacity = 0; + this->wstr = 0i64; + if ( aWstr ) + { + strLength = wcslen(aWstr); + this->length = strLength; + if ( strLength ) + { + Reserve(strLength); + memmove(this->wstr, aWstr, 2i64 * this->length); + this->wstr[this->length] = 0; + } + } + } + + /// @pattern 48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 30 8B 02 48 8B F9 48 8B 72 08 89 44 24 20 8B 42 04 89 + CWideString(CWideString& aWStr); + + /// @pattern 8B 02 89 01 8B 42 04 89 41 04 48 8B 42 08 48 89 41 08 33 C0 48 89 02 48 89 42 08 48 8B C1 C3 + CWideString(CWideString&& aCwstr) + { + this->length = aCwstr.length; + this->capacity = aCwstr.capacity; + this->wstr = aCwstr.wstr; + aCwstr.length = 0; + aCwstr.capacity = 0; + aCwstr.wstr = nullptr; + } + + /// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 33 F6 48 8B FA 8B 12 48 8B D9 89 11 89 71 04 48 89 + CWideString(CWideString* a2) + { + uint32_t length; + length = a2->length; + this->length = 0; + this->capacity = 0; + this->wstr = 0i64; + if (length) + { + Reserve(length); + memmove(this->wstr, a2->wstr, 2i64 * a2->length); + this->wstr[this->length] = 0; + } + } + + /// @pattern 48 89 5C 24 08 57 48 83 EC 20 33 FF 48 8B D9 48 89 39 48 89 79 08 85 D2 74 0C E8 41 03 00 00 48 + CWideString(uint32_t aCapacity) + { + this->length = 0; + this->capacity = 0; + this->wstr = 0i64; + if (aCapacity) + { + Reserve(aCapacity); + *this->wstr = 0; + } + } + + /// @pattern 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 56 48 83 EC 20 45 33 F6 41 8B F0 4C 89 31 48 8B + CWideString(const wchar_t* aWstr, uint32_t aLength) + { + int64_t length; + wchar_t* wstr; + + length = aLength; + this->length = 0i64; + this->capacity = 0i64; + this->wstr = 0i64; + if (aWstr && aLength) + { + Reserve(aLength); + memmove(this->wstr, aWstr, 2 * length); + wstr = this->wstr; + this->length = length; + wstr[length] = 0; + } + } + + /// @pattern 48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B 79 08 48 8B F1 48 8D 4C 24 30 E8 E0 6B 5F FD + ~CWideString(); + + /// @pattern 48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 57 48 83 EC 30 48 8B F1 8B EA 48 8D 4C 24 40 E8 3D + void Reserve(uint32_t aCapacity); + + /// @pattern 33 D2 89 11 39 51 04 76 07 48 8B 41 08 66 89 10 C3 + void Clear() + { + this->length = 0; + if (this->capacity) + *this->wstr = 0; + } + + /// @pattern 48 8B 41 08 C3 + const wchar_t* c_str() const noexcept + { + return wstr; + } + + /// @pattern 8B 01 C3 + uint32_t Length() const noexcept + { + return length; + } + + /// @pattern 48 89 5C 24 10 56 48 83 EC 20 41 8B F0 48 8B C1 4D 85 C9 75 11 45 85 C0 0F 95 C0 48 8B 5C 24 38 + int8_t FindMaybe(int start_i, int end_i, const wchar_t *needle, int needle_start, int needle_end) const; + + /// @pattern 48 89 5C 24 08 57 48 83 EC 20 8B 02 48 8B D9 8B 49 04 48 8B FA 85 C0 74 62 3B C8 72 15 48 8B 52 + RED4ext::CWideString * CopyFrom(const RED4ext::CWideString *a2); + + /// @pattern 40 55 57 48 83 EC 48 8B EA 48 8B F9 39 51 04 0F 83 F4 00 00 00 48 89 5C 24 68 48 89 74 24 70 4C + void Resize(uint32_t aLength); + + /// @pattern 48 8B 41 08 8B D2 48 8D 04 50 C3 + wchar_t * GetWideChar(unsigned int index) + { + return &wstr[index]; + } + + /// @pattern 40 53 48 81 EC 40 04 00 00 48 8B D9 48 8B CA E8 EC 83 5C FD 48 8B C8 48 8D 54 24 40 41 B8 00 04 + static CString* GetCString(CString* aStr, const CWideString* aWStr); + + [[nodiscard]] const wchar_t* begin() const + { + return c_str(); + } + + [[nodiscard]] const wchar_t* end() const + { + return c_str() + Length(); + } + + uint32_t length; // 00 + uint32_t capacity; // 04 + wchar_t* wstr; // 08 +}; +} // namespace RED4ext \ No newline at end of file diff --git a/include/RED4ext/Process-inl.hpp b/include/RED4ext/Process-inl.hpp index 5acc64924..fa1184d3a 100644 --- a/include/RED4ext/Process-inl.hpp +++ b/include/RED4ext/Process-inl.hpp @@ -23,28 +23,28 @@ inline bool RED4ext::Process::CloseHandles() return call(this); } -inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, +inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::CWideString& a2, const RED4ext::CString& a3, const RED4ext::Process::ExecutionFlags a4) { - using Process_Execute_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, + using Process_Execute_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::CWideString&, const RED4ext::CString&, const RED4ext::Process::ExecutionFlags); RED4ext::RelocFunc call(Process_Execute_Addr); return call(this, a1, a2, a3, a4); } -inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::Process::FixedWString& a2, - const RED4ext::Process::FixedWString& a3, +inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::CWideString& a2, + const RED4ext::CWideString& a3, const RED4ext::Process::ExecutionFlags a4) { - using Process_Execute_0_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::Process::FixedWString&, - const RED4ext::Process::FixedWString&, const RED4ext::Process::ExecutionFlags); + using Process_Execute_0_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::CWideString&, + const RED4ext::CWideString&, const RED4ext::Process::ExecutionFlags); RED4ext::RelocFunc call(Process_Execute_0_Addr); return call(this, a1, a2, a3, a4); } -inline uint64_t RED4ext::Process::GetExitCode() +inline uint32_t RED4ext::Process::GetExitCode() { - using Process_GetExitCode_t = uint64_t (*)(RED4ext::Process*); + using Process_GetExitCode_t = uint32_t (*)(RED4ext::Process*); RED4ext::RelocFunc call(Process_GetExitCode_Addr); return call(this); } diff --git a/include/RED4ext/Process.hpp b/include/RED4ext/Process.hpp index ddf795775..0e5b47aa8 100644 --- a/include/RED4ext/Process.hpp +++ b/include/RED4ext/Process.hpp @@ -1,8 +1,10 @@ #pragma once #include +#include #include #include +#include namespace RED4ext { @@ -10,13 +12,6 @@ struct Process { static constexpr uint32_t DefaultTimeout = 60000; - struct FixedWString - { - uint32_t length; - uint32_t maxLength; - const wchar_t* str; - }; - enum class ExecutionFlags : std::uint8_t { // unsets CREATE_NO_WINDOW @@ -65,7 +60,7 @@ struct Process void ReadFromPipe(const ReadFlags aFlags, const CString& aFilename, CString& aStdOut); /** - * @brief Converts aWorkingDirectory to a FixedWString and calls Execute + * @brief Converts aWorkingDirectory to a CWideString and calls Execute * * @param[in] aCommand The location of the executable * @param[in] aArgs Arguments passed to the command @@ -76,7 +71,7 @@ struct Process * * @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8 */ - bool Execute(const CString& aCommand, FixedWString& aArgs, const CString& aWorkingDirectory, + bool Execute(const CString& aCommand, CWideString& aArgs, const CString& aWorkingDirectory, const ExecutionFlags aFlags); /** @@ -91,7 +86,7 @@ struct Process * * @pattern 48 89 5C 24 10 48 89 74 24 18 55 57 41 54 41 56 41 57 48 8D 6C 24 B0 48 81 EC 50 01 00 00 0F 57 */ - bool Execute(const CString& aCommand, FixedWString& aArgs, const FixedWString& aWorkingDirectory, + bool Execute(const CString& aCommand, CWideString& aArgs, const CWideString& aWorkingDirectory, const ExecutionFlags aFlags); /// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 ? ? 4B 00 85 C0