Update to spice2x-25-10-07 (pre-apply)
> broken commit
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
#include "build/defs.h"
|
||||
#include "deferlog.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace deferredlogs {
|
||||
|
||||
const std::initializer_list<std::string> SUPERSTEP_SOUND_ERROR_MESSAGE = {
|
||||
"audio initialization error was previously detected during boot!",
|
||||
" this crash is most likely related to audio init failure",
|
||||
" * check if the default audio device has changed",
|
||||
" * fix your audio device settings (e.g., sample rate)",
|
||||
" * double check your spice audio options and patches"
|
||||
};
|
||||
|
||||
std::mutex deferred_errors_mutex;
|
||||
std::vector<std::vector<std::string>> deferred_errors;
|
||||
|
||||
void defer_error_messages(std::initializer_list<std::string> messages) {
|
||||
std::lock_guard<std::mutex> lock(deferred_errors_mutex);
|
||||
deferred_errors.emplace_back(messages);
|
||||
}
|
||||
|
||||
void dump_to_logger(bool is_crash) {
|
||||
static std::once_flag printed;
|
||||
std::call_once(printed, [is_crash]() {
|
||||
|
||||
// move to a local vector under lock first
|
||||
// this is to avoid holding a lock while emitting to the logger, which may deadlock
|
||||
// due to recursive calls (e.g., via log hooks used for failure detection which then
|
||||
// again calls into defer_error_messages), and std::mutex cannot be acquired recursively
|
||||
std::vector<std::vector<std::string>> errors;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(deferred_errors_mutex);
|
||||
if (deferred_errors.empty() && !is_crash) {
|
||||
return;
|
||||
}
|
||||
errors = std::move(deferred_errors);
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
msg += "\n\n";
|
||||
msg += "/-------------------------- spice2x auto-troubleshooter -----------------------\\\n";
|
||||
msg += "\n";
|
||||
msg += " spice2x version: " + to_string(VERSION_STRING_CFG) + "\n";
|
||||
msg += "\n";
|
||||
|
||||
if (is_crash) {
|
||||
msg += " the game has crashed\n";
|
||||
msg += " share this entire log file with someone for troubleshooting (log.txt)\n";
|
||||
msg += " spice will also attempt to create a minidump (minidump.dmp)\n";
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
for (auto messages : errors) {
|
||||
for (auto message : messages) {
|
||||
msg += " " + message + "\n";
|
||||
}
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
msg += " unsure what to do next?\n";
|
||||
msg += " * update to the latest version:\n";
|
||||
msg += " https://github.com/spice2x/spice2x.github.io/releases/latest\n";
|
||||
msg += " * check the FAQ:\n";
|
||||
msg += " https://github.com/spice2x/spice2x.github.io/wiki/Known-issues\n";
|
||||
msg += "\n";
|
||||
msg += "\\------------------------- spice2x auto-troubleshooter ------------------------/\n";
|
||||
|
||||
log_warning("troubleshooter", "{}", msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace deferredlogs {
|
||||
|
||||
// some shared error messages
|
||||
extern const std::initializer_list<std::string> SUPERSTEP_SOUND_ERROR_MESSAGE;
|
||||
|
||||
void defer_error_messages(std::initializer_list<std::string> messages);
|
||||
void dump_to_logger(bool is_crash=false);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
#include <set>
|
||||
#include "logging.h"
|
||||
#include "libutils.h"
|
||||
#include "scope_guard.h"
|
||||
#include "dependencies.h"
|
||||
|
||||
using loader_hint = std::tuple<std::string, std::string, std::string>;
|
||||
|
||||
namespace {
|
||||
// list of commonly missing dependencies and tips on where to get them
|
||||
std::vector<loader_hint> hints = {
|
||||
{
|
||||
"msvcr100.dll",
|
||||
"Visual Studio 2010 (VC++ 10.0) SP1 Redistributable",
|
||||
"Download and install VisualCppRedist_AIO_x86_x64.exe from https://github.com/abbodi1406/vcredist/releases/latest",
|
||||
},
|
||||
{
|
||||
"d3dx9_43.dll",
|
||||
"DirectX End-User Runtimes",
|
||||
"Download and install from https://www.microsoft.com/en-us/download/details.aspx?id=35"
|
||||
},
|
||||
{
|
||||
"nvEncodeAPI64.dll",
|
||||
"NVIDIA Graphics Driver",
|
||||
"For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.",
|
||||
},
|
||||
{
|
||||
"nvcuda.dll",
|
||||
"NVIDIA Graphics Driver",
|
||||
"For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.",
|
||||
},
|
||||
{
|
||||
"nvcuvid.dll",
|
||||
"NVIDIA Graphics Driver",
|
||||
"For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.",
|
||||
},
|
||||
{
|
||||
"cpusbxpkm.dll",
|
||||
"LovePlus Printer DLL",
|
||||
"Copy the stub file from the spice2x release .zip.",
|
||||
},
|
||||
};
|
||||
|
||||
std::set<std::wstring> failed = {};
|
||||
|
||||
auto read_imports(const std::filesystem::path& path) -> std::vector<std::filesystem::path> {
|
||||
auto result = std::vector<std::filesystem::path> {};
|
||||
auto const file = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto const file_ = scope_guard { [file] { CloseHandle(file); } };
|
||||
auto const mapping = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
|
||||
if (!mapping) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto const mapping_ = scope_guard { [mapping] { CloseHandle(mapping); } };
|
||||
auto const view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
|
||||
if (!view) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto const view_ = scope_guard { [view] { UnmapViewOfFile(view); } };
|
||||
auto const dos = static_cast<PIMAGE_DOS_HEADER>(view);
|
||||
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto const base = static_cast<std::uint8_t*>(view);
|
||||
auto const nt = reinterpret_cast<PIMAGE_NT_HEADERS>(base + dos->e_lfanew);
|
||||
|
||||
if (nt->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto const imports = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
|
||||
if (imports.VirtualAddress == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto desc = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(base + libutils::rva2offset(nt, imports.VirtualAddress));
|
||||
|
||||
while (desc->Name != 0) {
|
||||
auto const filename = reinterpret_cast<char*>(base + libutils::rva2offset(nt, desc->Name));
|
||||
auto entry_path = path.parent_path().append(filename);
|
||||
|
||||
// try to use library in the same directory if one exists
|
||||
// otherwise, assume system library and use filename only
|
||||
if (!std::filesystem::exists(entry_path)) {
|
||||
entry_path = filename;
|
||||
}
|
||||
|
||||
result.emplace_back(entry_path);
|
||||
desc++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace dependencies {
|
||||
auto walk(const std::filesystem::path& path, const std::string& prefix) -> bool {
|
||||
// try to load the library -- skip walking if it loads successfully
|
||||
if (auto const module = LoadLibraryW(path.c_str())) {
|
||||
FreeLibrary(module);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto const error = GetLastError();
|
||||
auto const filename = path.filename().string();
|
||||
|
||||
log_misc("dependencies", "{}{}", prefix + (prefix.empty() ? "": "|-- "), filename);
|
||||
|
||||
if (failed.contains(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
failed.insert(path);
|
||||
|
||||
auto const dependencies = read_imports(path);
|
||||
auto const next_prefix = prefix + (prefix.empty() ? " ": "| ");
|
||||
|
||||
if (!dependencies.empty()) {
|
||||
for (auto const& item : dependencies) {
|
||||
walk(item, next_prefix);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto const& [dll, name, hint] : hints) {
|
||||
if (_stricmp(dll.c_str(), filename.c_str()) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
log_warning("dependencies", "{}|-- [!] {}", next_prefix, name.c_str());
|
||||
log_warning("dependencies", "{}|-- {}", next_prefix, hint.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
log_warning("dependencies", "{}|-- [!] The library could not be loaded. ({})", next_prefix, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
namespace dependencies {
|
||||
auto walk(const std::filesystem::path& path, const std::string& prefix = "") -> bool;
|
||||
}
|
||||
@@ -106,8 +106,10 @@ bool detour::inline_restore(void *address, char *data) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "OCDFAInspection"
|
||||
#endif
|
||||
|
||||
static void *pe_offset(void *ptr, size_t offset) {
|
||||
if (offset == 0) {
|
||||
@@ -282,7 +284,9 @@ void **detour::iat_find_proc(const char *iid_name, void *proc, HMODULE module) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
void *detour::iat_try(const char *function, void *new_func, HMODULE module, const char *iid_name) {
|
||||
|
||||
|
||||
@@ -14,11 +14,13 @@ namespace execexe {
|
||||
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
||||
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
||||
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
||||
static uint64_t (*execexe_PreLoadLibraries)(const char *) = nullptr;
|
||||
|
||||
static std::wstring plugins_dir;
|
||||
static acioemu::ACIOHandle *acio = nullptr;
|
||||
static std::wstring port_name;
|
||||
static bool port_opened = false;
|
||||
static std::function<void()> deferred_function = nullptr;
|
||||
|
||||
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
@@ -62,6 +64,24 @@ namespace execexe {
|
||||
return execexe_CloseHandle(hObject);
|
||||
}
|
||||
|
||||
static uint64_t execexe_PreLoadLibraries_hook(const char *libs) {
|
||||
static bool init = false;
|
||||
|
||||
uint64_t result = execexe_PreLoadLibraries(libs);
|
||||
if (init) {
|
||||
return result;
|
||||
}
|
||||
|
||||
init = true;
|
||||
log_info("execexe", "execexe_PreLoadLibraries hook hit");
|
||||
|
||||
if (deferred_function) {
|
||||
deferred_function();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HMODULE init() {
|
||||
execexe_module = libutils::load_library("execexe.dll");
|
||||
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
||||
@@ -70,6 +90,7 @@ namespace execexe {
|
||||
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
||||
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
||||
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
||||
execexe_PreLoadLibraries = libutils::get_proc<decltype(execexe_PreLoadLibraries)>(execexe_module, MAKEINTRESOURCE(48));
|
||||
|
||||
auto module_path = libutils::module_file_name(nullptr);
|
||||
module_path = module_path.replace_extension("");
|
||||
@@ -79,6 +100,15 @@ namespace execexe {
|
||||
return execexe_module;
|
||||
}
|
||||
|
||||
void init_deferred(std::function<void()> init_func) {
|
||||
if (deferred_function) {
|
||||
log_fatal("execexe", "deferred init function is already set");
|
||||
}
|
||||
deferred_function = std::move(init_func);
|
||||
detour::trampoline("execexe.dll", MAKEINTRESOURCE(48),
|
||||
execexe_PreLoadLibraries_hook, &execexe_PreLoadLibraries);
|
||||
}
|
||||
|
||||
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
||||
static bool init = false;
|
||||
if (init)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <windows.h>
|
||||
#include "acioemu/handle.h"
|
||||
|
||||
namespace execexe {
|
||||
HMODULE init();
|
||||
void init_deferred(std::function<void()> init_func);
|
||||
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle);
|
||||
HMODULE load_library(const char *module_name, bool fatal = true);
|
||||
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal = true);
|
||||
|
||||
+25
-13
@@ -8,6 +8,7 @@
|
||||
#include "utils.h"
|
||||
#include "peb.h"
|
||||
#include "util/fileutils.h"
|
||||
#include "util/dependencies.h"
|
||||
|
||||
std::filesystem::path libutils::module_file_name(HMODULE module) {
|
||||
std::wstring buf;
|
||||
@@ -29,19 +30,17 @@ std::filesystem::path libutils::module_file_name(HMODULE module) {
|
||||
|
||||
static inline void load_library_fail(const std::string &file_name, bool fatal) {
|
||||
std::string info_str { fmt::format(
|
||||
"\n\nPlease check if {} exists and the permissions are fine.\n"
|
||||
"\n"
|
||||
"* If the problem still persists, try installing things on this list:\n"
|
||||
" https://github.com/spice2x/spice2x.github.io/wiki/DLL-Dependencies \n"
|
||||
"\n"
|
||||
"* Still have problems after installing from above and rebooting PC?\n"
|
||||
" Avoid manually specifying DLL path (-exec) and module directory (-modules); let spice2x auto-detect unless you have a good reason not to\n"
|
||||
" Ensure you do NOT have multiple copies of the game DLLs (e.g., in contents and in contents\\modules)\n"
|
||||
" Certain games require specific NVIDIA DLLs when running with AMD/Intel GPUs (hint: look inside stub directory for DLLs)\n"
|
||||
"\n"
|
||||
"* (For advanced users) if none of the above helps, find the missing dependency using:\n"
|
||||
" https://github.com/lucasg/Dependencies (recommended for most) \n"
|
||||
" http://www.dependencywalker.com/ (for old OS) \n"
|
||||
"DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:\n"
|
||||
" 1. Confirm if the file ({}) exists on the disk and check the file permissions.\n"
|
||||
" 2. Follow this link and install DLL prerequisites on this list:\n"
|
||||
" https://github.com/spice2x/spice2x.github.io/wiki/DLL-Dependencies \n"
|
||||
" 3. Still have problems after installing from above and rebooting PC?\n"
|
||||
" a. Avoid manually specifying DLL path (-exec) and module directory (-modules); let spice2x auto-detect unless you have a good reason not to\n"
|
||||
" b. Ensure you do NOT have multiple copies of the game DLLs (e.g., in contents and in contents\\modules)\n"
|
||||
" c. Certain games require specific NVIDIA DLLs when running with AMD/Intel GPUs (hint: look inside stub directory for DLLs)\n"
|
||||
" 4. (For advanced users) if none of the above helps, find the missing dependency using:\n"
|
||||
" a. https://github.com/lucasg/Dependencies (recommended for most) \n"
|
||||
" b. http://www.dependencywalker.com/ (for old OS) \n"
|
||||
, file_name) };
|
||||
if (fatal) {
|
||||
log_fatal("libutils", "{}", info_str);
|
||||
@@ -67,6 +66,7 @@ HMODULE libutils::load_library(const std::filesystem::path &path, bool fatal) {
|
||||
|
||||
if (!module) {
|
||||
log_warning("libutils", "'{}' couldn't be loaded: {}", path.string(), get_last_error_string());
|
||||
dependencies::walk(path);
|
||||
load_library_fail(path.filename().string(), fatal);
|
||||
}
|
||||
|
||||
@@ -355,4 +355,16 @@ void libutils::check_duplicate_dlls() {
|
||||
(MODULE_PATH / filename).string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void libutils::warn_if_dll_exists(const std::string &file_name) {
|
||||
if (fileutils::file_exists(MODULE_PATH / file_name)) {
|
||||
log_info("libutils", "found user-supplied {} in modules directory", file_name);
|
||||
return;
|
||||
}
|
||||
const auto &spice_bin_path = libutils::module_file_name(nullptr).parent_path();
|
||||
if (fileutils::file_exists(spice_bin_path / file_name)) {
|
||||
log_info("libutils", "found user-supplied {} next to spice executable path", file_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ namespace libutils {
|
||||
}
|
||||
|
||||
void check_duplicate_dlls();
|
||||
void warn_if_dll_exists(const std::string &file_name);
|
||||
|
||||
// get module handle helpers
|
||||
HMODULE get_module(const char *module_name);
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ std::string peb::entry_name(const LDR_DATA_TABLE_ENTRY* entry) {
|
||||
}
|
||||
|
||||
const PEB* peb::peb_get() {
|
||||
#ifdef SPICE64
|
||||
#ifdef _WIN64
|
||||
return reinterpret_cast<const PEB *>(__readgsqword(0x60));
|
||||
#else
|
||||
return reinterpret_cast<const PEB *>(__readfsdword(0x30));
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
class scope_guard {
|
||||
private:
|
||||
std::function<void()> f;
|
||||
public:
|
||||
explicit scope_guard(std::function<void()>&& f) : f(std::move(f)) {}
|
||||
~scope_guard() {
|
||||
f();
|
||||
}
|
||||
|
||||
scope_guard(const scope_guard&) = delete;
|
||||
scope_guard& operator=(const scope_guard&) = delete;
|
||||
|
||||
scope_guard(scope_guard&&) = delete;
|
||||
scope_guard& operator=(scope_guard&&) = delete;
|
||||
};
|
||||
+26
-7
@@ -215,23 +215,42 @@ namespace sysutils {
|
||||
}
|
||||
std::string prefix("device");
|
||||
if (is_monitor) {
|
||||
prefix = " adapter";
|
||||
prefix = " adapter";
|
||||
}
|
||||
log_misc("gpuinfo", "{} {} device name : {}", prefix.c_str(), index, adapter->DeviceName);
|
||||
log_misc("gpuinfo", "{} {} device string : {}", prefix.c_str(), index, adapter->DeviceString);
|
||||
log_dbug("gpuinfo", "{} {} flags : 0x{:x}", prefix.c_str(), index, adapter->StateFlags);
|
||||
|
||||
if (!is_monitor) {
|
||||
DEVMODEA devmode = {};
|
||||
devmode.dmSize = sizeof(devmode);
|
||||
if (EnumDisplaySettingsA(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &devmode)) {
|
||||
log_misc(
|
||||
"gpuinfo",
|
||||
"{} {} resolution : {}px * {}px @ {}Hz",
|
||||
prefix.c_str(),
|
||||
index,
|
||||
devmode.dmPelsWidth, devmode.dmPelsHeight,
|
||||
devmode.dmDisplayFrequency);
|
||||
} else {
|
||||
log_misc("gpuinfo", "EnumDisplaySettingsA failed");
|
||||
}
|
||||
}
|
||||
log_misc("gpuinfo", "{} {} name : {}", prefix.c_str(), index, adapter->DeviceName);
|
||||
log_misc("gpuinfo", "{} {} string : {}", prefix.c_str(), index, adapter->DeviceString);
|
||||
log_dbug("gpuinfo", "{} {} flags : 0x{:x}", prefix.c_str(), index, adapter->StateFlags);
|
||||
}
|
||||
|
||||
void print_gpus() {
|
||||
DWORD device_index = 0;
|
||||
DISPLAY_DEVICEA device;
|
||||
DISPLAY_DEVICEA device = {};
|
||||
device.cb = sizeof(device);
|
||||
log_misc("smbios", "dumping GPU/monitor information...");
|
||||
log_misc(
|
||||
"gpuinfo",
|
||||
"dumping GPU/monitor information... "
|
||||
"(note: these are current values **before** launching the game)");
|
||||
while (EnumDisplayDevicesA(nullptr, device_index, &device, 0)) {
|
||||
print_adapter(device_index, &device, false);
|
||||
|
||||
DWORD monitor_index = 0;
|
||||
DISPLAY_DEVICEA monitor;
|
||||
DISPLAY_DEVICEA monitor = {};
|
||||
monitor.cb = sizeof(monitor);
|
||||
while (EnumDisplayDevicesA((PCHAR)device.DeviceName, monitor_index, &monitor, 0)) {
|
||||
print_adapter(monitor_index, &monitor, true);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tapeledutils {
|
||||
|
||||
@@ -20,6 +22,15 @@ namespace tapeledutils {
|
||||
float b;
|
||||
} rgb_float3_t;
|
||||
|
||||
struct tape_led {
|
||||
std::vector<rgb_float3_t> data;
|
||||
int index_r, index_g, index_b; // Averaged RGB light output indexes
|
||||
std::string lightName;
|
||||
|
||||
tape_led(size_t data_size, int index_r, int index_g, int index_b, std::string lightName)
|
||||
: data(std::vector<rgb_float3_t>(data_size)), index_r(index_r), index_g(index_g), index_b(index_b), lightName(std::move(lightName)) {}
|
||||
};
|
||||
|
||||
bool is_enabled();
|
||||
rgb_float3_t pick_color_from_led_tape(uint8_t *data, size_t data_size);
|
||||
size_t get_led_index_using_avg_algo(size_t data_size);
|
||||
|
||||
+31
-2
@@ -227,6 +227,7 @@ static inline std::vector<HWND> find_windows_beginning_with(const std::string &t
|
||||
return windows;
|
||||
}
|
||||
|
||||
// exists for compat only; prefer to use FindProcessWindowBeginsWith instead
|
||||
static inline HWND FindWindowBeginsWith(std::string title) {
|
||||
|
||||
// get all windows
|
||||
@@ -248,6 +249,28 @@ static inline HWND FindWindowBeginsWith(std::string title) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline HWND FindProcessWindowBeginsWith(const std::string &title) {
|
||||
// try foreground window first
|
||||
HWND fg_win = GetForegroundWindow();
|
||||
if (string_begins_with(get_window_title(fg_win), title)) {
|
||||
DWORD fg_pid;
|
||||
GetWindowThreadProcessId(fg_win, &fg_pid);
|
||||
if (fg_pid == GetCurrentProcessId()) {
|
||||
return fg_win;
|
||||
}
|
||||
}
|
||||
|
||||
// try different windows
|
||||
for (const auto window : find_windows_beginning_with(title)) {
|
||||
DWORD fg_pid;
|
||||
GetWindowThreadProcessId(window, &fg_pid);
|
||||
if (fg_pid == GetCurrentProcessId()) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline std::string get_last_error_string() {
|
||||
|
||||
// get error
|
||||
@@ -260,7 +283,8 @@ static inline std::string get_last_error_string() {
|
||||
LPSTR messageBuffer = nullptr;
|
||||
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
nullptr,
|
||||
error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
@@ -269,7 +293,12 @@ static inline std::string get_last_error_string() {
|
||||
nullptr);
|
||||
|
||||
// return as string
|
||||
std::string message(messageBuffer, size);
|
||||
std::string message;
|
||||
if (size == 0) {
|
||||
message = fmt::format("(Win32 error {})", error);
|
||||
} else {
|
||||
message = fmt::format("{}(Win32 error {})", messageBuffer, error);
|
||||
}
|
||||
LocalFree(messageBuffer);
|
||||
|
||||
return message;
|
||||
|
||||
Reference in New Issue
Block a user