Check previously-ignored injection / capture / rumble return values
- injector bitness gate: IsWow64Process2 failure was treated as "native", which would send the x64 DLL into a 32-bit target. Fall back to the legacy IsWow64Process before giving up to permissive. - injector helper exit: GetExitCodeProcess's BOOL was ignored; on a failed query surface GetLastError instead of a misleading exit code. - window_capture: CreateShaderResourceView's HRESULT was ignored, and width_/ height_ were committed even on failure, so the (latest_ == nullptr) recreate guard never retried -- a silently black mirror until the next resize. Only commit the dims on success; otherwise drop latest_ so the next frame retries. - xinput rumble: make the best-effort XInputSetState ignore explicit (a disconnected pad re-syncs on the next refresh; the result isn't actionable). The GetClientRect/ClientToScreen reads in mkb_forward are left as-is: a failure there is a single self-correcting frame (the mapping is rejected and reused next frame), so checking them adds no actionable behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -113,12 +113,6 @@ default** and covers anything the hooked path doesn't.
|
|||||||
From an in-depth review pass. Each item is fixed test-first (a failing test, then the fix) and lands
|
From an in-depth review pass. Each item is fixed test-first (a failing test, then the fix) and lands
|
||||||
as its own commit; "verify" items are confirmed real before any change, and dropped if not.
|
as its own commit; "verify" items are confirmed real before any change, and dropped if not.
|
||||||
|
|
||||||
Robustness (verify, then fix if real):
|
|
||||||
- **Permissive injector bitness gate** — `IsWow64Process2` failure is treated as 64-bit; fall back to
|
|
||||||
`IsWow64Process` instead of mis-injecting.
|
|
||||||
- **Ignored HRESULT/BOOL returns** — `CreateShaderResourceView`, `GetClientRect`/`ClientToScreen`,
|
|
||||||
`XInputSetState`, `GetExitCodeProcess`: check and surface/handle.
|
|
||||||
|
|
||||||
Cross-process / ABI:
|
Cross-process / ABI:
|
||||||
- **Tie `kProtocolVersion` to the layout** — `static_assert` `sizeof(SharedBlock)` + the full offset
|
- **Tie `kProtocolVersion` to the layout** — `static_assert` `sizeof(SharedBlock)` + the full offset
|
||||||
set, and make `hook_selftest`'s `dump_layout` assert instead of only printing.
|
set, and make `hook_selftest`'s `dump_layout` assert instead of only printing.
|
||||||
|
|||||||
@@ -188,10 +188,19 @@ void WindowCapture::draw_latest(FrameRenderer& renderer, ID3D11DeviceContext* ct
|
|||||||
dst.MiscFlags = 0;
|
dst.MiscFlags = 0;
|
||||||
if (SUCCEEDED(device_->CreateTexture2D(&dst, nullptr, latest_.GetAddressOf())))
|
if (SUCCEEDED(device_->CreateTexture2D(&dst, nullptr, latest_.GetAddressOf())))
|
||||||
{
|
{
|
||||||
device_->CreateShaderResourceView(latest_.Get(), nullptr, latest_srv_.GetAddressOf());
|
if (SUCCEEDED(device_->CreateShaderResourceView(latest_.Get(), nullptr,
|
||||||
|
latest_srv_.GetAddressOf())))
|
||||||
|
{
|
||||||
width_ = desc.Width;
|
width_ = desc.Width;
|
||||||
height_ = desc.Height;
|
height_ = desc.Height;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Drop the texture so the (latest_ == nullptr) guard retries next frame instead
|
||||||
|
// of leaving a null SRV (a silently black mirror) until the next resize.
|
||||||
|
latest_.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (latest_ != nullptr)
|
if (latest_ != nullptr)
|
||||||
|
|||||||
@@ -50,7 +50,15 @@ bool is_wow64_process(HANDLE process)
|
|||||||
{
|
{
|
||||||
return process_machine != IMAGE_FILE_MACHINE_UNKNOWN;
|
return process_machine != IMAGE_FILE_MACHINE_UNKNOWN;
|
||||||
}
|
}
|
||||||
return false; // be permissive if the query is unavailable
|
// IsWow64Process2 failed -- fall back to the legacy query rather than guessing "native", since
|
||||||
|
// guessing wrong sends the x64 DLL into a 32-bit target (which can't load it). Only if BOTH
|
||||||
|
// queries fail do we fall back to permissive.
|
||||||
|
BOOL wow64 = FALSE;
|
||||||
|
if (IsWow64Process(process, &wow64))
|
||||||
|
{
|
||||||
|
return wow64 != FALSE;
|
||||||
|
}
|
||||||
|
return false; // both queries failed; best-effort assume native
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the trailing file name of `path` with `name` (same directory).
|
// Replace the trailing file name of `path` with `name` (same directory).
|
||||||
@@ -86,12 +94,13 @@ InjectResult inject_via_helper(unsigned long pid, const std::wstring& dll_path)
|
|||||||
}
|
}
|
||||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
DWORD exit_code = 1;
|
DWORD exit_code = 1;
|
||||||
GetExitCodeProcess(pi.hProcess, &exit_code);
|
const BOOL got = GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||||
|
const DWORD err = got ? exit_code : GetLastError(); // on a failed query, surface the OS error
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
if (exit_code != 0)
|
if (!got || exit_code != 0)
|
||||||
{
|
{
|
||||||
return InjectResult{InjectStatus::HelperFailed, exit_code};
|
return InjectResult{InjectStatus::HelperFailed, err};
|
||||||
}
|
}
|
||||||
return InjectResult{InjectStatus::Ok, 0};
|
return InjectResult{InjectStatus::Ok, 0};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ void XInputSource::set_rumble(int slot, std::uint16_t left, std::uint16_t right)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
XINPUT_VIBRATION v{left, right};
|
XINPUT_VIBRATION v{left, right};
|
||||||
XInputSetState(static_cast<DWORD>(slot), &v);
|
// Best-effort: if the device just disconnected this returns ERROR_DEVICE_NOT_CONNECTED, but rumble
|
||||||
|
// is fire-and-forget (the next connected-pad refresh re-syncs state), so the result isn't acted on.
|
||||||
|
(void)XInputSetState(static_cast<DWORD>(slot), &v);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace coop
|
} // namespace coop
|
||||||
|
|||||||
Reference in New Issue
Block a user