mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-07 20:28:10 +00:00
200 lines
6.1 KiB
C++
200 lines
6.1 KiB
C++
#include <Utils/StringHelper.h>
|
|
#include <Utils/WinHelper.h>
|
|
#include <Main/LiteLoader.h>
|
|
#include <Utils/DbgHelper.h>
|
|
#include <LoggerAPI.h>
|
|
#include <I18nAPI.h>
|
|
#include <Psapi.h>
|
|
#include <string>
|
|
#include <Main/Config.h>
|
|
|
|
using namespace std;
|
|
|
|
string GetLastErrorMessage(DWORD error_message_id) {
|
|
if (error_message_id == 0)
|
|
return "";
|
|
|
|
LPWSTR message_buffer = nullptr;
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
nullptr, error_message_id, MAKELANGID(0x09, SUBLANG_DEFAULT), (LPWSTR)&message_buffer, 0, nullptr);
|
|
string res = wstr2str(wstring(message_buffer));
|
|
LocalFree(message_buffer);
|
|
return res;
|
|
}
|
|
|
|
string GetLastErrorMessage() {
|
|
DWORD error_message_id = ::GetLastError();
|
|
if (error_message_id == 0)
|
|
return "";
|
|
|
|
LPWSTR message_buffer = nullptr;
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
nullptr, error_message_id, MAKELANGID(0x09, SUBLANG_DEFAULT), (LPWSTR)&message_buffer, 0, nullptr);
|
|
string res = wstr2str(wstring(message_buffer));
|
|
LocalFree(message_buffer);
|
|
return res;
|
|
}
|
|
|
|
// Tool
|
|
wchar_t* str2cwstr(const string& str) {
|
|
auto len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
|
|
auto* buffer = new wchar_t[len + 1];
|
|
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, buffer, len + 1);
|
|
buffer[len] = L'\0';
|
|
return buffer;
|
|
}
|
|
|
|
#define READ_BUFFER_SIZE 4096
|
|
|
|
bool NewProcess(const std::string& process, std::function<void(int, std::string)> callback, int timeLimit) {
|
|
SECURITY_ATTRIBUTES sa;
|
|
HANDLE hRead, hWrite;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = nullptr;
|
|
sa.bInheritHandle = TRUE;
|
|
|
|
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
|
|
return false;
|
|
STARTUPINFOW si = {0};
|
|
PROCESS_INFORMATION pi;
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
GetStartupInfoW(&si);
|
|
si.hStdOutput = si.hStdError = hWrite;
|
|
si.dwFlags = STARTF_USESTDHANDLES;
|
|
|
|
auto wCmd = str2cwstr(process);
|
|
if (!CreateProcessW(nullptr, wCmd, nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi)) {
|
|
delete[] wCmd;
|
|
return false;
|
|
}
|
|
CloseHandle(hWrite);
|
|
CloseHandle(pi.hThread);
|
|
|
|
std::thread([hRead{hRead}, hProcess{pi.hProcess},
|
|
callback{std::move(callback)}, timeLimit{timeLimit}, wCmd{wCmd}]() {
|
|
if (!LL::isDebugMode())
|
|
_set_se_translator(seh_exception::TranslateSEHtoCE);
|
|
if (timeLimit == -1)
|
|
WaitForSingleObject(hProcess, INFINITE);
|
|
else {
|
|
WaitForSingleObject(hProcess, timeLimit);
|
|
TerminateProcess(hProcess, -1);
|
|
}
|
|
char buffer[READ_BUFFER_SIZE];
|
|
string strOutput;
|
|
DWORD bytesRead, exitCode;
|
|
|
|
delete[] wCmd;
|
|
GetExitCodeProcess(hProcess, &exitCode);
|
|
while (true) {
|
|
ZeroMemory(buffer, READ_BUFFER_SIZE);
|
|
if (!ReadFile(hRead, buffer, READ_BUFFER_SIZE, &bytesRead, nullptr))
|
|
break;
|
|
strOutput.append(buffer, bytesRead);
|
|
}
|
|
CloseHandle(hRead);
|
|
CloseHandle(hProcess);
|
|
|
|
try {
|
|
if (callback)
|
|
callback((int)exitCode, strOutput);
|
|
} catch (const seh_exception& e) {
|
|
logger.error("SEH Uncaught Exception Detected!\n{}", TextEncoding::toUTF8(e.what()));
|
|
logger.error("In NewProcess callback");
|
|
PrintCurrentStackTraceback();
|
|
} catch (...) {
|
|
logger.error("NewProcess Callback Failed!");
|
|
logger.error("Uncaught Exception Detected!");
|
|
PrintCurrentStackTraceback();
|
|
}
|
|
}).detach();
|
|
|
|
return true;
|
|
}
|
|
|
|
std::pair<int, string> NewProcessSync(const std::string& process, int timeLimit, bool noReadOutput) {
|
|
SECURITY_ATTRIBUTES sa;
|
|
HANDLE hRead, hWrite;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = nullptr;
|
|
sa.bInheritHandle = TRUE;
|
|
|
|
if (!CreatePipe(&hRead, &hWrite, &sa, 0))
|
|
return {-1, ""};
|
|
STARTUPINFOW si = {0};
|
|
PROCESS_INFORMATION pi;
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
GetStartupInfoW(&si);
|
|
si.hStdOutput = si.hStdError = hWrite;
|
|
si.dwFlags = STARTF_USESTDHANDLES;
|
|
|
|
auto wCmd = str2cwstr(process);
|
|
if (!CreateProcessW(nullptr, wCmd, nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi)) {
|
|
delete[] wCmd;
|
|
return {-1, ""};
|
|
}
|
|
CloseHandle(hWrite);
|
|
CloseHandle(pi.hThread);
|
|
|
|
if (timeLimit == -1)
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
else {
|
|
WaitForSingleObject(pi.hProcess, timeLimit);
|
|
TerminateProcess(pi.hProcess, -1);
|
|
}
|
|
char buffer[READ_BUFFER_SIZE];
|
|
string strOutput;
|
|
DWORD bytesRead, exitCode;
|
|
|
|
delete[] wCmd;
|
|
GetExitCodeProcess(pi.hProcess, &exitCode);
|
|
if (!noReadOutput) {
|
|
while (true) {
|
|
ZeroMemory(buffer, READ_BUFFER_SIZE);
|
|
if (!ReadFile(hRead, buffer, READ_BUFFER_SIZE, &bytesRead, nullptr))
|
|
break;
|
|
strOutput.append(buffer, bytesRead);
|
|
}
|
|
}
|
|
CloseHandle(hRead);
|
|
CloseHandle(pi.hProcess);
|
|
return {exitCode, strOutput};
|
|
}
|
|
|
|
string GetModulePath(HMODULE handle) {
|
|
wchar_t buf[MAX_PATH] = {0};
|
|
GetModuleFileNameEx(GetCurrentProcess(), handle, buf, MAX_PATH);
|
|
return wstr2str(std::wstring(buf));
|
|
}
|
|
|
|
string GetModuleName(HMODULE handle) {
|
|
wchar_t buf[MAX_PATH] = {0};
|
|
GetModuleFileNameEx(GetCurrentProcess(), handle, buf, MAX_PATH);
|
|
return UTF82String(std::filesystem::path(buf).filename().u8string());
|
|
}
|
|
|
|
std::string GetSystemLocaleName() {
|
|
wchar_t buf[256] = {0};
|
|
auto lcid = GetSystemDefaultLCID();
|
|
GetSystemDefaultLocaleName(buf, lcid);
|
|
auto str = wstr2str(buf);
|
|
std::replace(str.begin(), str.end(), '-', '_');
|
|
return str;
|
|
}
|
|
|
|
inline bool isWine() {
|
|
HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
|
|
auto pwine_get_version = GetProcAddress(ntdll, "wine_get_version");
|
|
if (pwine_get_version)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool IsWineEnvironment() {
|
|
static bool result = isWine();
|
|
return result;
|
|
}
|