Apply clang-format across the whole tree
Run clang-format (the repo's .clang-format: LLVM base, 120 cols, tabs, Allman functions) over every source file so the tree is formatter-clean. Whitespace only -- no behavior change; full x64 + x86 suites pass. Also set SortIncludes: false in .clang-format. Windows include order is load-bearing (windows.h must precede tlhelp32.h / mmreg.h / xinput.h / dinput.h; winsock2.h must precede windows.h), and the default alphabetical sort reorders tlhelp32.h ahead of windows.h -- a build break. Leaving order alone keeps the manual, correct grouping.
This commit is contained in:
@@ -25,8 +25,7 @@
|
||||
#include "coop/shared_memory.hpp"
|
||||
#include "coop/tool_paths.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
// coop_hook.dll ships in the deployable bin/<config>/ root; this probe runs from
|
||||
// bin/<config>/tools/, so resolve next-to-self first, then one level up.
|
||||
@@ -47,9 +46,8 @@ bool inject_via_helper(unsigned long pid, const std::wstring& dll_path)
|
||||
{
|
||||
const std::wstring helper = sibling_of(dll_path, L"coop_inject_x86.exe");
|
||||
const std::wstring x86_dll = sibling_of(dll_path, L"coop_hook_x86.dll");
|
||||
if (GetFileAttributesW(helper.c_str()) == INVALID_FILE_ATTRIBUTES ||
|
||||
GetFileAttributesW(x86_dll.c_str()) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (GetFileAttributesW(helper.c_str()) == INVALID_FILE_ATTRIBUTES
|
||||
|| GetFileAttributesW(x86_dll.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||
std::printf("ERROR: x86 helper/dll missing next to the probe.\n");
|
||||
return false;
|
||||
}
|
||||
@@ -58,8 +56,7 @@ bool inject_via_helper(unsigned long pid, const std::wstring& dll_path)
|
||||
STARTUPINFOW si{};
|
||||
si.cb = sizeof(si);
|
||||
PROCESS_INFORMATION pi{};
|
||||
if (!CreateProcessW(helper.c_str(), cmd.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi))
|
||||
{
|
||||
if (!CreateProcessW(helper.c_str(), cmd.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
|
||||
std::printf("ERROR: CreateProcess(coop_inject_x86) failed (%lu).\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
@@ -68,8 +65,7 @@ bool inject_via_helper(unsigned long pid, const std::wstring& dll_path)
|
||||
GetExitCodeProcess(pi.hProcess, &code);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
if (code != 0)
|
||||
{
|
||||
if (code != 0) {
|
||||
std::printf("ERROR: coop_inject_x86 reported failure (exit %lu).\n", code);
|
||||
return false;
|
||||
}
|
||||
@@ -78,37 +74,32 @@ bool inject_via_helper(unsigned long pid, const std::wstring& dll_path)
|
||||
|
||||
bool inject(unsigned long pid, const std::wstring& dll_path)
|
||||
{
|
||||
if (GetFileAttributesW(dll_path.c_str()) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (GetFileAttributesW(dll_path.c_str()) == INVALID_FILE_ATTRIBUTES) {
|
||||
std::printf("ERROR: coop_hook.dll not found at the probe's directory.\n");
|
||||
return false;
|
||||
}
|
||||
const DWORD access = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE | PROCESS_VM_READ;
|
||||
const DWORD access =
|
||||
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ;
|
||||
HANDLE process = OpenProcess(access, FALSE, pid);
|
||||
if (process == nullptr)
|
||||
{
|
||||
if (process == nullptr) {
|
||||
std::printf("ERROR: OpenProcess(%lu) failed (%lu). Run as administrator?\n", pid, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 32-bit target -> delegate to the x86 helper (a 64-bit process can't inject it).
|
||||
USHORT proc_machine = IMAGE_FILE_MACHINE_UNKNOWN, native_machine = IMAGE_FILE_MACHINE_UNKNOWN;
|
||||
if (IsWow64Process2(process, &proc_machine, &native_machine) && proc_machine != IMAGE_FILE_MACHINE_UNKNOWN)
|
||||
{
|
||||
if (IsWow64Process2(process, &proc_machine, &native_machine) && proc_machine != IMAGE_FILE_MACHINE_UNKNOWN) {
|
||||
CloseHandle(process);
|
||||
return inject_via_helper(pid, dll_path);
|
||||
}
|
||||
const SIZE_T bytes = (dll_path.size() + 1) * sizeof(wchar_t);
|
||||
void* remote = VirtualAllocEx(process, nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
bool ok = false;
|
||||
if (remote != nullptr && WriteProcessMemory(process, remote, dll_path.c_str(), bytes, nullptr))
|
||||
{
|
||||
auto load_library = reinterpret_cast<LPTHREAD_START_ROUTINE>(
|
||||
GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW"));
|
||||
if (remote != nullptr && WriteProcessMemory(process, remote, dll_path.c_str(), bytes, nullptr)) {
|
||||
auto load_library =
|
||||
reinterpret_cast<LPTHREAD_START_ROUTINE>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW"));
|
||||
HANDLE thread = CreateRemoteThread(process, nullptr, 0, load_library, remote, 0, nullptr);
|
||||
if (thread != nullptr)
|
||||
{
|
||||
if (thread != nullptr) {
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
DWORD exit_code = 0;
|
||||
GetExitCodeThread(thread, &exit_code);
|
||||
@@ -116,13 +107,11 @@ bool inject(unsigned long pid, const std::wstring& dll_path)
|
||||
ok = (exit_code != 0);
|
||||
}
|
||||
}
|
||||
if (remote != nullptr)
|
||||
{
|
||||
if (remote != nullptr) {
|
||||
VirtualFreeEx(process, remote, 0, MEM_RELEASE);
|
||||
}
|
||||
CloseHandle(process);
|
||||
if (!ok)
|
||||
{
|
||||
if (!ok) {
|
||||
std::printf("ERROR: injection failed (%lu).\n", GetLastError());
|
||||
}
|
||||
return ok;
|
||||
@@ -132,8 +121,7 @@ bool inject(unsigned long pid, const std::wstring& dll_path)
|
||||
|
||||
int wmain(int argc, wchar_t** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::printf("usage: coop_audio_probe <pid> [seconds] [ring_delay_ms]\n"
|
||||
" ring_delay_ms: how long after injecting to create the audio ring\n"
|
||||
" (default 1500 = reproduces the real app, which creates the ring\n"
|
||||
@@ -144,16 +132,14 @@ int wmain(int argc, wchar_t** argv)
|
||||
const int seconds = (argc >= 3) ? std::max(1, _wtoi(argv[2])) : 20;
|
||||
const int ring_delay_ms = (argc >= 4) ? std::max(0, _wtoi(argv[3])) : 1500;
|
||||
const bool audio_enabled = (argc >= 5) ? _wtoi(argv[4]) != 0 : true; // arg5=0 tests unhooking audio
|
||||
if (pid == 0)
|
||||
{
|
||||
if (pid == 0) {
|
||||
std::printf("ERROR: invalid pid.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1) Input SharedBlock (the hook's worker exits if it can't connect to this).
|
||||
coop::SharedMemory ipc;
|
||||
if (!ipc.create(coop::shared_memory_name(pid), sizeof(coop::SharedBlock)))
|
||||
{
|
||||
if (!ipc.create(coop::shared_memory_name(pid), sizeof(coop::SharedBlock))) {
|
||||
std::printf("ERROR: create input mapping failed (%lu).\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
@@ -161,8 +147,7 @@ int wmain(int argc, wchar_t** argv)
|
||||
block->version = coop::kProtocolVersion;
|
||||
block->pad_count = 0;
|
||||
block->sequence.store(0, std::memory_order_relaxed);
|
||||
if (!audio_enabled)
|
||||
{
|
||||
if (!audio_enabled) {
|
||||
// Request the hook NOT install the audio subsystem (control-channel test).
|
||||
block->control.subsystem_disabled[coop::HookSubsys_Audio].store(1, std::memory_order_release);
|
||||
std::printf("Audio subsystem requested OFF (control channel test).\n");
|
||||
@@ -173,8 +158,7 @@ int wmain(int argc, wchar_t** argv)
|
||||
coop::SharedMemory log_shm;
|
||||
coop::LogRing* log_ring = nullptr;
|
||||
std::uint64_t log_cursor = 0;
|
||||
if (log_shm.create(coop::log_ring_name(pid), coop::log_ring_total_size(coop::kLogCapacity)))
|
||||
{
|
||||
if (log_shm.create(coop::log_ring_name(pid), coop::log_ring_total_size(coop::kLogCapacity))) {
|
||||
log_ring = log_shm.as<coop::LogRing>();
|
||||
coop::log_ring_init(*log_ring, coop::kLogCapacity);
|
||||
}
|
||||
@@ -182,13 +166,11 @@ int wmain(int argc, wchar_t** argv)
|
||||
// Enable the hook's file trace (%TEMP%\coop_hook.log) for this debug session.
|
||||
{
|
||||
wchar_t dir[MAX_PATH] = {};
|
||||
if (GetTempPathW(MAX_PATH, dir) != 0)
|
||||
{
|
||||
if (GetTempPathW(MAX_PATH, dir) != 0) {
|
||||
const std::wstring sentinel = std::wstring(dir) + L"coop_hook.log.on";
|
||||
HANDLE h = CreateFileW(sentinel.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
HANDLE h = CreateFileW(sentinel.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (h != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(h);
|
||||
}
|
||||
}
|
||||
@@ -201,9 +183,7 @@ int wmain(int argc, wchar_t** argv)
|
||||
coop::SharedMemory ring_shm;
|
||||
coop::AudioRingHeader* ring = nullptr;
|
||||
auto create_ring = [&]() -> bool {
|
||||
if (!ring_shm.create(coop::audio_ring_name(pid),
|
||||
coop::audio_ring_total_size(coop::kAudioRingCapacity)))
|
||||
{
|
||||
if (!ring_shm.create(coop::audio_ring_name(pid), coop::audio_ring_total_size(coop::kAudioRingCapacity))) {
|
||||
std::printf("ERROR: create audio ring mapping failed (%lu).\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
@@ -213,24 +193,20 @@ int wmain(int argc, wchar_t** argv)
|
||||
return true;
|
||||
};
|
||||
|
||||
if (ring_delay_ms == 0 && !create_ring())
|
||||
{
|
||||
if (ring_delay_ms == 0 && !create_ring()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Inject.
|
||||
std::printf("Injecting coop_hook.dll into pid %lu ...\n", pid);
|
||||
if (!inject(pid, dll_path_next_to_self()))
|
||||
{
|
||||
if (!inject(pid, dll_path_next_to_self())) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ring_delay_ms > 0)
|
||||
{
|
||||
if (ring_delay_ms > 0) {
|
||||
std::printf("Injected. Creating audio ring %d ms later (app-ordering)...\n", ring_delay_ms);
|
||||
Sleep(static_cast<DWORD>(ring_delay_ms));
|
||||
if (!create_ring())
|
||||
{
|
||||
if (!create_ring()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -241,15 +217,13 @@ int wmain(int argc, wchar_t** argv)
|
||||
const coop::HookStatus& status = block->status;
|
||||
std::uint64_t prev_frames[coop::kMaxAudioStreams] = {};
|
||||
std::vector<std::uint8_t> drain(coop::kAudioRingCapacity);
|
||||
for (int t = 0; t < seconds * 2; ++t)
|
||||
{
|
||||
for (int t = 0; t < seconds * 2; ++t) {
|
||||
Sleep(500);
|
||||
|
||||
// If audio started disabled, re-enable it at the midpoint to demonstrate
|
||||
// runtime hooking ("hook with a button press"): the worker should install
|
||||
// the audio hooks and capture should start within a tick or two.
|
||||
if (!audio_enabled && t == seconds)
|
||||
{
|
||||
if (!audio_enabled && t == seconds) {
|
||||
block->control.subsystem_disabled[coop::HookSubsys_Audio].store(0, std::memory_order_release);
|
||||
std::printf(">>> re-enabling audio subsystem at runtime <<<\n");
|
||||
}
|
||||
@@ -257,26 +231,19 @@ int wmain(int argc, wchar_t** argv)
|
||||
// Consume everything available and find the peak sample magnitude.
|
||||
double peak = 0.0;
|
||||
std::uint32_t got = 0;
|
||||
while ((got = coop::audio_ring_pop(*ring, drain.data(), static_cast<std::uint32_t>(drain.size()))) > 0)
|
||||
{
|
||||
if (ring->format_tag == 3 /*IEEE_FLOAT*/ && ring->bits == 32)
|
||||
{
|
||||
while ((got = coop::audio_ring_pop(*ring, drain.data(), static_cast<std::uint32_t>(drain.size()))) > 0) {
|
||||
if (ring->format_tag == 3 /*IEEE_FLOAT*/ && ring->bits == 32) {
|
||||
const auto* f = reinterpret_cast<const float*>(drain.data());
|
||||
for (std::uint32_t i = 0; i < got / 4; ++i)
|
||||
{
|
||||
for (std::uint32_t i = 0; i < got / 4; ++i) {
|
||||
peak = std::max(peak, static_cast<double>(std::abs(f[i])));
|
||||
}
|
||||
}
|
||||
else if (ring->bits == 16)
|
||||
{
|
||||
} else if (ring->bits == 16) {
|
||||
const auto* s = reinterpret_cast<const std::int16_t*>(drain.data());
|
||||
for (std::uint32_t i = 0; i < got / 2; ++i)
|
||||
{
|
||||
for (std::uint32_t i = 0; i < got / 2; ++i) {
|
||||
peak = std::max(peak, std::abs(s[i]) / 32768.0);
|
||||
}
|
||||
}
|
||||
if (got < drain.size())
|
||||
{
|
||||
if (got < drain.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -291,35 +258,30 @@ int wmain(int argc, wchar_t** argv)
|
||||
|
||||
std::printf("[%4.1fs] hb=%u streams=%u peak=%.4f ring{fmt=%d %uHz/%uch/%ubit produced=%llu "
|
||||
"overruns=%llu} video{present=%llu gen=%u %ux%u}\n",
|
||||
(t + 1) * 0.5, heartbeat, streams, peak, fmt_ready ? 1 : 0, ring->sample_rate,
|
||||
ring->channels, ring->bits, static_cast<unsigned long long>(produced),
|
||||
static_cast<unsigned long long>(overruns), static_cast<unsigned long long>(vpresent),
|
||||
vgen, block->video.width, block->video.height);
|
||||
for (std::uint32_t i = 0; i < coop::kMaxAudioStreams && i < streams; ++i)
|
||||
{
|
||||
(t + 1) * 0.5, heartbeat, streams, peak, fmt_ready ? 1 : 0, ring->sample_rate, ring->channels,
|
||||
ring->bits, static_cast<unsigned long long>(produced), static_cast<unsigned long long>(overruns),
|
||||
static_cast<unsigned long long>(vpresent), vgen, block->video.width, block->video.height);
|
||||
for (std::uint32_t i = 0; i < coop::kMaxAudioStreams && i < streams; ++i) {
|
||||
const coop::AudioStreamInfo& s = status.audio_streams[i];
|
||||
const bool live = s.frames_rendered > prev_frames[i];
|
||||
prev_frames[i] = s.frames_rendered;
|
||||
std::printf(" stream %u %s %uHz/%uch/%ubit tag=%u frames=%llu %s\n", i,
|
||||
s.is_primary ? "PRIMARY" : "extra ", s.sample_rate, s.channels, s.bits,
|
||||
s.format_tag, static_cast<unsigned long long>(s.frames_rendered),
|
||||
live ? "<live>" : "");
|
||||
s.is_primary ? "PRIMARY" : "extra ", s.sample_rate, s.channels, s.bits, s.format_tag,
|
||||
static_cast<unsigned long long>(s.frames_rendered), live ? "<live>" : "");
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the hook registry so the installed-hooks list can be verified headless.
|
||||
static const char* kSubsys[] = {"Input", "Focus", "Audio", "Video", "MKB"};
|
||||
std::printf("\nInstalled hooks (%u):\n", status.hook_entry_count);
|
||||
for (std::uint32_t i = 0; i < status.hook_entry_count && i < coop::kMaxHookEntries; ++i)
|
||||
{
|
||||
for (std::uint32_t i = 0; i < status.hook_entry_count && i < coop::kMaxHookEntries; ++i) {
|
||||
const coop::HookEntry& e = status.hook_entries[i];
|
||||
std::printf(" [%-5s] %-34s %s calls=%llu\n", e.subsystem < 5 ? kSubsys[e.subsystem] : "?", e.name,
|
||||
e.installed ? "ON " : "off", static_cast<unsigned long long>(e.calls));
|
||||
}
|
||||
|
||||
// Drain the IPC log ring to verify the hook streams its logs to the host.
|
||||
if (log_ring != nullptr)
|
||||
{
|
||||
if (log_ring != nullptr) {
|
||||
std::printf("\nHook log (streamed over IPC):\n");
|
||||
coop::log_ring_drain(*log_ring, log_cursor,
|
||||
[](const coop::LogRecord& rec) { std::printf(" %s\n", rec.text); });
|
||||
|
||||
Reference in New Issue
Block a user