chore: CRLF to LF

This commit is contained in:
smpn2
2022-12-16 23:18:35 +09:00
parent b7a60638a4
commit 6c914266d9
725 changed files with 131020 additions and 131020 deletions
+87 -87
View File
@@ -1,87 +1,87 @@
#include "audio.h"
#include <vector>
#include <windows.h>
#include <initguid.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include "hooks/audio/backends/mmdevice/device_enumerator.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/memutils.h"
#include "audio_private.h"
#ifdef _MSC_VER
DEFINE_GUID(CLSID_MMDeviceEnumerator,
0xBCDE0395, 0xE52F, 0x467C,
0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
#endif
// function pointers
static decltype(CoCreateInstance) *CoCreateInstance_orig = nullptr;
namespace hooks::audio {
// public globals
bool ENABLED = true;
bool USE_DUMMY = false;
WAVEFORMATEXTENSIBLE FORMAT {};
std::optional<Backend> BACKEND = std::nullopt;
size_t ASIO_DRIVER_ID = 0;
// private globals
IAudioClient *CLIENT = nullptr;
std::mutex INITIALIZE_LOCK;
}
static HRESULT STDAPICALLTYPE CoCreateInstance_hook(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID *ppv)
{
// call original
HRESULT ret = CoCreateInstance_orig(rclsid, pUnkOuter, dwClsContext, riid, ppv);
if (FAILED(ret)) {
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
log_warning("audio", "CoCreateInstance failed, hr={}", FMT_HRESULT(ret));
}
return ret;
}
// check if this is the audio device enumerator
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
// wrap object
auto mmde = reinterpret_cast<IMMDeviceEnumerator **>(ppv);
*mmde = new WrappedIMMDeviceEnumerator(*mmde);
}
// return original result
return ret;
}
namespace hooks::audio {
void init() {
if (!ENABLED) {
return;
}
log_info("audio", "initializing");
// general hooks
CoCreateInstance_orig = detour::iat_try("CoCreateInstance", CoCreateInstance_hook);
}
void stop() {
if (CLIENT) {
CLIENT->Stop();
CLIENT->Release();
CLIENT = nullptr;
}
}
}
#include "audio.h"
#include <vector>
#include <windows.h>
#include <initguid.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include "hooks/audio/backends/mmdevice/device_enumerator.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/memutils.h"
#include "audio_private.h"
#ifdef _MSC_VER
DEFINE_GUID(CLSID_MMDeviceEnumerator,
0xBCDE0395, 0xE52F, 0x467C,
0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
#endif
// function pointers
static decltype(CoCreateInstance) *CoCreateInstance_orig = nullptr;
namespace hooks::audio {
// public globals
bool ENABLED = true;
bool USE_DUMMY = false;
WAVEFORMATEXTENSIBLE FORMAT {};
std::optional<Backend> BACKEND = std::nullopt;
size_t ASIO_DRIVER_ID = 0;
// private globals
IAudioClient *CLIENT = nullptr;
std::mutex INITIALIZE_LOCK;
}
static HRESULT STDAPICALLTYPE CoCreateInstance_hook(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID *ppv)
{
// call original
HRESULT ret = CoCreateInstance_orig(rclsid, pUnkOuter, dwClsContext, riid, ppv);
if (FAILED(ret)) {
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
log_warning("audio", "CoCreateInstance failed, hr={}", FMT_HRESULT(ret));
}
return ret;
}
// check if this is the audio device enumerator
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
// wrap object
auto mmde = reinterpret_cast<IMMDeviceEnumerator **>(ppv);
*mmde = new WrappedIMMDeviceEnumerator(*mmde);
}
// return original result
return ret;
}
namespace hooks::audio {
void init() {
if (!ENABLED) {
return;
}
log_info("audio", "initializing");
// general hooks
CoCreateInstance_orig = detour::iat_try("CoCreateInstance", CoCreateInstance_hook);
}
void stop() {
if (CLIENT) {
CLIENT->Stop();
CLIENT->Release();
CLIENT = nullptr;
}
}
}
+34 -34
View File
@@ -1,34 +1,34 @@
#pragma once
#include <optional>
#include <windows.h>
#include <mmreg.h>
#include <ks.h>
#include <ksmedia.h>
namespace hooks::audio {
enum class Backend {
Asio,
WaveOut,
};
extern bool ENABLED;
extern bool USE_DUMMY;
extern WAVEFORMATEXTENSIBLE FORMAT;
extern std::optional<Backend> BACKEND;
extern size_t ASIO_DRIVER_ID;
void init();
void stop();
inline std::optional<Backend> name_to_backend(const char *value) {
if (_stricmp(value, "asio") == 0) {
return Backend::Asio;
} else if (_stricmp(value, "waveout") == 0) {
return Backend::WaveOut;
}
return std::nullopt;
}
}
#pragma once
#include <optional>
#include <windows.h>
#include <mmreg.h>
#include <ks.h>
#include <ksmedia.h>
namespace hooks::audio {
enum class Backend {
Asio,
WaveOut,
};
extern bool ENABLED;
extern bool USE_DUMMY;
extern WAVEFORMATEXTENSIBLE FORMAT;
extern std::optional<Backend> BACKEND;
extern size_t ASIO_DRIVER_ID;
void init();
void stop();
inline std::optional<Backend> name_to_backend(const char *value) {
if (_stricmp(value, "asio") == 0) {
return Backend::Asio;
} else if (_stricmp(value, "waveout") == 0) {
return Backend::WaveOut;
}
return std::nullopt;
}
}
+14 -14
View File
@@ -1,14 +1,14 @@
#pragma once
#include <mutex>
#include <windows.h>
#include <audioclient.h>
constexpr bool AUDIO_LOG_HRESULT = true;
namespace hooks::audio {
extern IAudioClient *CLIENT;
extern std::mutex INITIALIZE_LOCK;
}
#pragma once
#include <mutex>
#include <windows.h>
#include <audioclient.h>
constexpr bool AUDIO_LOG_HRESULT = true;
namespace hooks::audio {
extern IAudioClient *CLIENT;
extern std::mutex INITIALIZE_LOCK;
}
+123 -123
View File
@@ -1,123 +1,123 @@
#include "device.h"
#include <mutex>
#include <audioclient.h>
#include "hooks/audio/audio_private.h"
#include "hooks/audio/backends/wasapi/audio_client.h"
#define PRINT_FAILED_RESULT(name, ret) \
do { \
if (AUDIO_LOG_HRESULT) { \
log_warning("audio::mmdevice", "{} failed, hr={}", name, FMT_HRESULT(ret)); \
} \
} while (0)
#define CHECK_RESULT(x) \
do { \
HRESULT __ret = (x); \
if (FAILED(__ret)) { \
PRINT_FAILED_RESULT(__FUNCTION__, __ret); \
} \
return __ret; \
} while (0)
#ifdef _MSC_VER
DEFINE_GUID(IID_IMMDevice,
0xd666063f, 0x1587, 0x4e43,
0x81, 0xf1, 0xb9, 0x48, 0xe8, 0x07, 0x36, 0x3f);
#endif
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_WrappedIMMDevice ||
riid == IID_IMMDevice)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIMMDevice::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIMMDevice::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IMMDevice
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::Activate(
REFIID iid,
DWORD dwClsCtx,
PROPVARIANT *pActivationParams,
void **ppInterface)
{
log_misc("audio::mmdevice", "WrappedIMMDevice::Activate");
// call original
HRESULT ret = pReal->Activate(iid, dwClsCtx, pActivationParams, ppInterface);
// check for failure
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IMMDevice::Activate", ret);
return ret;
}
if (iid == IID_IAudioClient) {
// prevent initialization recursion when using some ASIO backends that proxy to DirectSound, WASAPI, or WDM
// like ASIO4All or FlexASIO
if (!hooks::audio::INITIALIZE_LOCK.try_lock()) {
log_warning("audio::mmdevice", "ignoring wrap request while backend is initializing, possible recursion");
return ret;
}
std::lock_guard initialize_guard(hooks::audio::INITIALIZE_LOCK, std::adopt_lock);
auto client = reinterpret_cast<IAudioClient *>(*ppInterface);
// release old audio client if initialized
if (hooks::audio::CLIENT) {
hooks::audio::CLIENT->Release();
}
/*
ret = wrap_audio_client(pReal, dwClsCtx, pActivationParams, &client);
if (FAILED(ret)) {
return ret;
}
*/
client = wrap_audio_client(client);
*ppInterface = client;
// persist the audio client
hooks::audio::CLIENT = client;
hooks::audio::CLIENT->AddRef();
}
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::OpenPropertyStore(DWORD stgmAccess, IPropertyStore **ppProperties) {
CHECK_RESULT(pReal->OpenPropertyStore(stgmAccess, ppProperties));
}
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::GetId(LPWSTR *ppstrId) {
CHECK_RESULT(pReal->GetId(ppstrId));
}
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::GetState(DWORD *pdwState) {
CHECK_RESULT(pReal->GetState(pdwState));
}
#include "device.h"
#include <mutex>
#include <audioclient.h>
#include "hooks/audio/audio_private.h"
#include "hooks/audio/backends/wasapi/audio_client.h"
#define PRINT_FAILED_RESULT(name, ret) \
do { \
if (AUDIO_LOG_HRESULT) { \
log_warning("audio::mmdevice", "{} failed, hr={}", name, FMT_HRESULT(ret)); \
} \
} while (0)
#define CHECK_RESULT(x) \
do { \
HRESULT __ret = (x); \
if (FAILED(__ret)) { \
PRINT_FAILED_RESULT(__FUNCTION__, __ret); \
} \
return __ret; \
} while (0)
#ifdef _MSC_VER
DEFINE_GUID(IID_IMMDevice,
0xd666063f, 0x1587, 0x4e43,
0x81, 0xf1, 0xb9, 0x48, 0xe8, 0x07, 0x36, 0x3f);
#endif
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_WrappedIMMDevice ||
riid == IID_IMMDevice)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIMMDevice::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIMMDevice::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IMMDevice
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::Activate(
REFIID iid,
DWORD dwClsCtx,
PROPVARIANT *pActivationParams,
void **ppInterface)
{
log_misc("audio::mmdevice", "WrappedIMMDevice::Activate");
// call original
HRESULT ret = pReal->Activate(iid, dwClsCtx, pActivationParams, ppInterface);
// check for failure
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IMMDevice::Activate", ret);
return ret;
}
if (iid == IID_IAudioClient) {
// prevent initialization recursion when using some ASIO backends that proxy to DirectSound, WASAPI, or WDM
// like ASIO4All or FlexASIO
if (!hooks::audio::INITIALIZE_LOCK.try_lock()) {
log_warning("audio::mmdevice", "ignoring wrap request while backend is initializing, possible recursion");
return ret;
}
std::lock_guard initialize_guard(hooks::audio::INITIALIZE_LOCK, std::adopt_lock);
auto client = reinterpret_cast<IAudioClient *>(*ppInterface);
// release old audio client if initialized
if (hooks::audio::CLIENT) {
hooks::audio::CLIENT->Release();
}
/*
ret = wrap_audio_client(pReal, dwClsCtx, pActivationParams, &client);
if (FAILED(ret)) {
return ret;
}
*/
client = wrap_audio_client(client);
*ppInterface = client;
// persist the audio client
hooks::audio::CLIENT = client;
hooks::audio::CLIENT->AddRef();
}
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::OpenPropertyStore(DWORD stgmAccess, IPropertyStore **ppProperties) {
CHECK_RESULT(pReal->OpenPropertyStore(stgmAccess, ppProperties));
}
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::GetId(LPWSTR *ppstrId) {
CHECK_RESULT(pReal->GetId(ppstrId));
}
HRESULT STDMETHODCALLTYPE WrappedIMMDevice::GetState(DWORD *pdwState) {
CHECK_RESULT(pReal->GetState(pdwState));
}
+36 -36
View File
@@ -1,36 +1,36 @@
#pragma once
#include <initguid.h>
#include <mmdeviceapi.h>
#include "util/logging.h"
// {7CC2A363-D96F-4BE2-B6CF-2A44AADA424B}
static const GUID IID_WrappedIMMDevice = {
0x7cc2a363, 0xd96f, 0x4be2, { 0xb6, 0xcf, 0x2a, 0x44, 0xaa, 0xda, 0x42, 0x4b }
};
struct WrappedIMMDevice : IMMDevice {
explicit WrappedIMMDevice(IMMDevice *orig) : pReal(orig) {
}
WrappedIMMDevice(const WrappedIMMDevice &) = delete;
WrappedIMMDevice &operator=(const WrappedIMMDevice &) = delete;
virtual ~WrappedIMMDevice() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IMMDevice
HRESULT STDMETHODCALLTYPE Activate(REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface) override;
HRESULT STDMETHODCALLTYPE OpenPropertyStore(DWORD stgmAccess, IPropertyStore **ppProperties) override;
HRESULT STDMETHODCALLTYPE GetId(LPWSTR *ppstrId) override;
HRESULT STDMETHODCALLTYPE GetState(DWORD *pdwState) override;
#pragma endregion
IMMDevice *const pReal;
};
#pragma once
#include <initguid.h>
#include <mmdeviceapi.h>
#include "util/logging.h"
// {7CC2A363-D96F-4BE2-B6CF-2A44AADA424B}
static const GUID IID_WrappedIMMDevice = {
0x7cc2a363, 0xd96f, 0x4be2, { 0xb6, 0xcf, 0x2a, 0x44, 0xaa, 0xda, 0x42, 0x4b }
};
struct WrappedIMMDevice : IMMDevice {
explicit WrappedIMMDevice(IMMDevice *orig) : pReal(orig) {
}
WrappedIMMDevice(const WrappedIMMDevice &) = delete;
WrappedIMMDevice &operator=(const WrappedIMMDevice &) = delete;
virtual ~WrappedIMMDevice() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IMMDevice
HRESULT STDMETHODCALLTYPE Activate(REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface) override;
HRESULT STDMETHODCALLTYPE OpenPropertyStore(DWORD stgmAccess, IPropertyStore **ppProperties) override;
HRESULT STDMETHODCALLTYPE GetId(LPWSTR *ppstrId) override;
HRESULT STDMETHODCALLTYPE GetState(DWORD *pdwState) override;
#pragma endregion
IMMDevice *const pReal;
};
@@ -1,85 +1,85 @@
#include "device_enumerator.h"
#include "util/logging.h"
#include "device.h"
#ifdef _MSC_VER
DEFINE_GUID(IID_IMMDeviceEnumerator,
0xa95664d2, 0x9614, 0x4f35,
0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6);
#endif
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IMMDeviceEnumerator) {
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::EnumAudioEndpoints(
EDataFlow dataFlow,
DWORD dwStateMask,
IMMDeviceCollection **ppDevices)
{
return pReal->EnumAudioEndpoints(dataFlow, dwStateMask, ppDevices);
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDefaultAudioEndpoint(
EDataFlow dataFlow,
ERole role,
IMMDevice **ppEndpoint)
{
// call orignal
HRESULT ret = this->pReal->GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint);
// check for failure
if (FAILED(ret)) {
log_warning("audio", "IMMDeviceEnumerator::GetDefaultAudioEndpoint failed, hr={}", FMT_HRESULT(ret));
return ret;
}
// wrap interface
*ppEndpoint = new WrappedIMMDevice(*ppEndpoint);
// return original result
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDevice(
LPCWSTR pwstrId,
IMMDevice **ppDevice)
{
return pReal->GetDevice(pwstrId, ppDevice);
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::RegisterEndpointNotificationCallback(
IMMNotificationClient *pClient)
{
return pReal->RegisterEndpointNotificationCallback(pClient);
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::UnregisterEndpointNotificationCallback(
IMMNotificationClient *pClient)
{
return pReal->UnregisterEndpointNotificationCallback(pClient);
}
#include "device_enumerator.h"
#include "util/logging.h"
#include "device.h"
#ifdef _MSC_VER
DEFINE_GUID(IID_IMMDeviceEnumerator,
0xa95664d2, 0x9614, 0x4f35,
0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6);
#endif
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IMMDeviceEnumerator) {
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::EnumAudioEndpoints(
EDataFlow dataFlow,
DWORD dwStateMask,
IMMDeviceCollection **ppDevices)
{
return pReal->EnumAudioEndpoints(dataFlow, dwStateMask, ppDevices);
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDefaultAudioEndpoint(
EDataFlow dataFlow,
ERole role,
IMMDevice **ppEndpoint)
{
// call orignal
HRESULT ret = this->pReal->GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint);
// check for failure
if (FAILED(ret)) {
log_warning("audio", "IMMDeviceEnumerator::GetDefaultAudioEndpoint failed, hr={}", FMT_HRESULT(ret));
return ret;
}
// wrap interface
*ppEndpoint = new WrappedIMMDevice(*ppEndpoint);
// return original result
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::GetDevice(
LPCWSTR pwstrId,
IMMDevice **ppDevice)
{
return pReal->GetDevice(pwstrId, ppDevice);
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::RegisterEndpointNotificationCallback(
IMMNotificationClient *pClient)
{
return pReal->RegisterEndpointNotificationCallback(pClient);
}
HRESULT STDMETHODCALLTYPE WrappedIMMDeviceEnumerator::UnregisterEndpointNotificationCallback(
IMMNotificationClient *pClient)
{
return pReal->UnregisterEndpointNotificationCallback(pClient);
}
@@ -1,33 +1,33 @@
#pragma once
#include <initguid.h>
#include <mmdeviceapi.h>
#include "util/logging.h"
struct WrappedIMMDeviceEnumerator : IMMDeviceEnumerator {
explicit WrappedIMMDeviceEnumerator(IMMDeviceEnumerator *orig) : pReal(orig) {
}
WrappedIMMDeviceEnumerator(const WrappedIMMDeviceEnumerator &) = delete;
WrappedIMMDeviceEnumerator &operator=(const WrappedIMMDeviceEnumerator &) = delete;
virtual ~WrappedIMMDeviceEnumerator() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IMMDeviceEnumerator
virtual HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection **ppDevices) override;
virtual HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(IMMNotificationClient *pClient) override;
virtual HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(IMMNotificationClient *pClient) override;
#pragma endregion
private:
IMMDeviceEnumerator *const pReal;
};
#pragma once
#include <initguid.h>
#include <mmdeviceapi.h>
#include "util/logging.h"
struct WrappedIMMDeviceEnumerator : IMMDeviceEnumerator {
explicit WrappedIMMDeviceEnumerator(IMMDeviceEnumerator *orig) : pReal(orig) {
}
WrappedIMMDeviceEnumerator(const WrappedIMMDeviceEnumerator &) = delete;
WrappedIMMDeviceEnumerator &operator=(const WrappedIMMDeviceEnumerator &) = delete;
virtual ~WrappedIMMDeviceEnumerator() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IMMDeviceEnumerator
virtual HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection **ppDevices) override;
virtual HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(IMMNotificationClient *pClient) override;
virtual HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(IMMNotificationClient *pClient) override;
#pragma endregion
private:
IMMDeviceEnumerator *const pReal;
};
+484 -484
View File
@@ -1,484 +1,484 @@
#include "audio_client.h"
#include <ks.h>
#include <ksmedia.h>
#include "avs/game.h"
#include "hooks/audio/audio.h"
#include "hooks/audio/util.h"
#include "hooks/audio/backends/wasapi/util.h"
#include "hooks/audio/implementations/asio.h"
#include "hooks/audio/implementations/wave_out.h"
//#include "util/co_task_mem_ptr.h"
#include "defs.h"
#include "dummy_audio_client.h"
#include "wasapi_private.h"
#if 0
#define WRAP_DEBUG log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("audio::wasapi", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#if 1
#define WRAP_VERBOSE log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#else
#define WRAP_VERBOSE do {} while (0)
#endif
const char CLASS_NAME[] = "WrappedIAudioClient";
static void fix_rec_format(WAVEFORMATEX *pFormat) {
log_misc("audio::wasapi", "changing format to 2ch 16-bit");
pFormat->nChannels = 2;
pFormat->wBitsPerSample = 16;
pFormat->nBlockAlign = pFormat->nChannels * (pFormat->wBitsPerSample / 8);
pFormat->nAvgBytesPerSec = pFormat->nSamplesPerSec * pFormat->nBlockAlign;
}
// TODO(felix): is it appropriate to automatically switch to shared mode? should we do a
// `MessageBox` to notify the user?
/*
static bool check_for_exclusive_access(IAudioClient *client) {
static bool checked_once = false;
static bool previous_check_result = false;
CoTaskMemPtr<WAVEFORMATEX> mix_format;
REFERENCE_TIME requested_duration = 0;
if (checked_once) {
return previous_check_result;
}
if (audio::BACKEND.has_value()) {
return false;
}
// scope function so it has access to the local static variables
auto set_result = [](bool result) {
checked_once = true;
previous_check_result = result;
return result;
};
HRESULT ret = client->GetMixFormat(mix_format.ppv());
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IAudioClient::GetMixFormat", ret);
return set_result(false);
}
log_info("audio::wasapi", "Mix Format:");
print_format(mix_format.data());
ret = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, mix_format.data(), nullptr);
if (ret == AUDCLNT_E_UNSUPPORTED_FORMAT) {
auto mix_format_ex = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.data());
log_warning("audio::wasapi", "device does not natively support the mix format, converting to PCM");
if (mix_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
IsEqualGUID(GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, mix_format_ex->SubFormat))
{
mix_format_ex->Format.wBitsPerSample = 16;
mix_format_ex->Format.nBlockAlign = mix_format_ex->Format.nChannels * (mix_format_ex->Format.wBitsPerSample / 8);
mix_format_ex->Format.nAvgBytesPerSec = mix_format_ex->Format.nSamplesPerSec * mix_format_ex->Format.nBlockAlign;
mix_format_ex->Samples.wValidBitsPerSample = 16;
mix_format_ex->SubFormat = GUID_KSDATAFORMAT_SUBTYPE_PCM;
} else if (mix_format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
mix_format->wBitsPerSample = 16;
mix_format->nBlockAlign = mix_format->nChannels * (mix_format->wBitsPerSample / 8);
mix_format->nAvgBytesPerSec = mix_format->nSamplesPerSec * mix_format->nBlockAlign;
mix_format->wFormatTag = WAVE_FORMAT_PCM;
} else {
log_warning("audio::wasapi", "mix format is not a floating point format");
return set_result(false);
}
ret = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, mix_format.data(), nullptr);
if (FAILED(ret)) {
log_warning("audio::wasapi", "mix format is not supported");
return set_result(false);
}
}
ret = client->GetDevicePeriod(nullptr, &requested_duration);
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IAudioClient::GetDevicePeriod", ret);
return false;
}
ret = client->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
requested_duration,
requested_duration,
mix_format.data(),
nullptr);
if (ret == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED || SUCCEEDED(ret)) {
log_info("audio::wasapi", "exclusive mode is available, disabling backend");
return set_result(true);
} else {
log_warning("audio::wasapi", "exclusive mode is not available, enabling backend, hr={}", FMT_HRESULT(ret));
}
return set_result(false);
}
HRESULT wrap_audio_client(
IMMDevice *device,
DWORD cls_ctx,
PROPVARIANT *activation_params,
IAudioClient **audio_client)
{
auto exclusive_available = check_for_exclusive_access(*audio_client);
(*audio_client)->Stop();
(*audio_client)->Reset();
(*audio_client)->Release();
*audio_client = nullptr;
SAFE_CALL("IMMDevice", "Activate", device->Activate(
IID_IAudioClient,
cls_ctx,
activation_params,
reinterpret_cast<void **>(audio_client)));
*/
IAudioClient *wrap_audio_client(IAudioClient *audio_client) {
AudioBackend *backend = nullptr;
bool requires_dummy = false;
if (hooks::audio::BACKEND.has_value()) {
switch (hooks::audio::BACKEND.value()) {
case hooks::audio::Backend::Asio:
backend = new AsioBackend();
requires_dummy = true;
break;
case hooks::audio::Backend::WaveOut:
backend = new WaveOutBackend();
break;
default:
break;
}
}
//} else if (!exclusive_available) {
// backend = new WaveOutBackend();
//}
IAudioClient *new_client;
if (hooks::audio::USE_DUMMY || requires_dummy) {
// release the old context since it is not used by the dummy context
audio_client->Release();
new_client = new DummyIAudioClient(backend);
} else {
new_client = new WrappedIAudioClient(audio_client, backend);
}
return new_client;
}
// IUnknown
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_WrappedIAudioClient ||
riid == IID_IAudioClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIAudioClient::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIAudioClient::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioClient
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Initialize(
AUDCLNT_SHAREMODE ShareMode,
DWORD StreamFlags,
REFERENCE_TIME hnsBufferDuration,
REFERENCE_TIME hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid)
{
WRAP_DEBUG;
if (!pFormat) {
return E_POINTER;
}
// check if format needs to be fixed
if (pFormat->nChannels > 2 && avs::game::is_model("REC")) {
fix_rec_format(const_cast<WAVEFORMATEX *>(pFormat));
}
// verbose output
log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
log_info("audio::wasapi", "... ShareMode : {}", share_mode_str(ShareMode));
log_info("audio::wasapi", "... StreamFlags : {}", stream_flags_str(StreamFlags));
log_info("audio::wasapi", "... hnsBufferDuration : {}", hnsBufferDuration);
log_info("audio::wasapi", "... hnsPeriodicity : {}", hnsPeriodicity);
print_format(pFormat);
if (this->backend) {
SAFE_CALL("AudioBackend", "on_initialize", this->backend->on_initialize(
&ShareMode,
&StreamFlags,
&hnsBufferDuration,
&hnsPeriodicity,
pFormat,
AudioSessionGuid));
log_info("audio::wasapi", "AudioBackend::on_initialize call finished");
log_info("audio::wasapi", "... ShareMode : {}", share_mode_str(ShareMode));
log_info("audio::wasapi", "... StreamFlags : {}", stream_flags_str(StreamFlags));
log_info("audio::wasapi", "... hnsBufferDuration : {}", hnsBufferDuration);
log_info("audio::wasapi", "... hnsPeriodicity : {}", hnsPeriodicity);
print_format(pFormat);
}
// check for exclusive mode
if (ShareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
this->exclusive_mode = true;
this->frame_size = pFormat->nChannels * (pFormat->wBitsPerSample / 8);
}
// call next
HRESULT ret = pReal->Initialize(
ShareMode,
StreamFlags,
hnsBufferDuration,
hnsPeriodicity,
pFormat,
AudioSessionGuid);
// check for failure
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IAudioClient", "Initialize", ret);
return ret;
}
log_info("audio::wasapi", "IAudioClient::Initialize success, hr={}", FMT_HRESULT(ret));
/*
if (ShareMode == AUDCLNT_SHAREMODE_SHARED) {
IAudioClockAdjustment *clock = nullptr;
SAFE_CALL("IAudioClient", "GetService", pReal->GetService(
IID_IAudioClockAdjustment,
reinterpret_cast<void **>(&clock)));
SAFE_CALL("IAudioClockAdjustment", "SetSampleRate", clock->SetSampleRate(
static_cast<float>(pFormat->nSamplesPerSec)));
}
*/
copy_wave_format(&hooks::audio::FORMAT, pFormat);
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetBufferSize(UINT32 *pNumBufferFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetBufferSize");
});
if (this->backend) {
uint32_t buffer_frames = 0;
SAFE_CALL("AudioBackend", "on_get_buffer_size", this->backend->on_get_buffer_size(&buffer_frames));
if (buffer_frames > 0) {
*pNumBufferFrames = buffer_frames;
return S_OK;
}
}
CHECK_RESULT(pReal->GetBufferSize(pNumBufferFrames));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetStreamLatency(REFERENCE_TIME *phnsLatency) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetStreamLatency");
});
if (this->backend) {
REFERENCE_TIME latency = 0;
SAFE_CALL("AudioBackend", "on_get_stream_latency", this->backend->on_get_stream_latency(
&latency));
if (latency > 0) {
*phnsLatency = latency;
return S_OK;
}
}
CHECK_RESULT(pReal->GetStreamLatency(phnsLatency));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetCurrentPadding(UINT32 *pNumPaddingFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetCurrentPadding");
});
if (pNumPaddingFrames && this->backend) {
std::optional<uint32_t> padding_frames;
SAFE_CALL("AudioBackend", "on_get_current_padding",this->backend->on_get_current_padding(
padding_frames));
if (padding_frames.has_value()) {
*pNumPaddingFrames = padding_frames.value();
return S_OK;
}
}
CHECK_RESULT(pReal->GetCurrentPadding(pNumPaddingFrames));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::IsFormatSupported(
AUDCLNT_SHAREMODE ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch)
{
WRAP_VERBOSE;
if (!pFormat) {
return E_POINTER;
}
// check if format needs to be fixed
if (avs::game::is_model("REC") && pFormat->nChannels > 2) {
fix_rec_format(const_cast<WAVEFORMATEX *>(pFormat));
}
if (this->backend) {
HRESULT ret = this->backend->on_is_format_supported(&ShareMode, pFormat, ppClosestMatch);
if (SUCCEEDED(ret)) {
return ret;
}
// return errors other than unsupported format
if (ret != AUDCLNT_E_UNSUPPORTED_FORMAT) {
SAFE_CALL("AudioBackend", "on_is_format_supported", ret);
}
}
CHECK_RESULT(pReal->IsFormatSupported(ShareMode, pFormat, ppClosestMatch));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetMixFormat(WAVEFORMATEX **ppDeviceFormat) {
WRAP_VERBOSE;
if (!ppDeviceFormat) {
return E_POINTER;
}
if (this->backend) {
HRESULT ret = this->backend->on_get_mix_format(ppDeviceFormat);
if (SUCCEEDED(ret)) {
return ret;
}
// return errors other than E_NOTIMPL
if (ret != E_NOTIMPL) {
SAFE_CALL("AudioBackend", "on_get_mix_format", ret);
}
}
CHECK_RESULT(pReal->GetMixFormat(ppDeviceFormat));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetDevicePeriod(
REFERENCE_TIME *phnsDefaultDevicePeriod,
REFERENCE_TIME *phnsMinimumDevicePeriod)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetDevicePeriod");
});
HRESULT ret = pReal->GetDevicePeriod(phnsDefaultDevicePeriod, phnsMinimumDevicePeriod);
if (SUCCEEDED(ret) && this->backend) {
SAFE_CALL("AudioBackend", "on_get_device_period", this->backend->on_get_device_period(
phnsDefaultDevicePeriod,
phnsMinimumDevicePeriod));
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Start() {
WRAP_VERBOSE;
HRESULT ret = pReal->Start();
if (SUCCEEDED(ret) && this->backend) {
SAFE_CALL("AudioBackend", "on_start", this->backend->on_start());
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Stop() {
WRAP_VERBOSE;
HRESULT ret = pReal->Stop();
if (SUCCEEDED(ret) && this->backend) {
SAFE_CALL("AudioBackend", "on_stop", this->backend->on_stop());
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Reset() {
WRAP_VERBOSE;
CHECK_RESULT(pReal->Reset());
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::SetEventHandle(HANDLE eventHandle) {
WRAP_VERBOSE;
if (this->backend) {
SAFE_CALL("AudioBackend", "on_set_event_handle", this->backend->on_set_event_handle(&eventHandle));
}
CHECK_RESULT(pReal->SetEventHandle(eventHandle));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetService(REFIID riid, void **ppv) {
WRAP_DEBUG_FMT("WrappedIAudioClient::GetService({})", guid2s(riid));
HRESULT ret = pReal->GetService(riid, ppv);
if (SUCCEEDED(ret) && ppv && *ppv && riid == IID_IAudioRenderClient) {
auto render_client = reinterpret_cast<IAudioRenderClient *>(*ppv);
*ppv = new WrappedIAudioRenderClient(this, render_client);
}
return ret;
}
#include "audio_client.h"
#include <ks.h>
#include <ksmedia.h>
#include "avs/game.h"
#include "hooks/audio/audio.h"
#include "hooks/audio/util.h"
#include "hooks/audio/backends/wasapi/util.h"
#include "hooks/audio/implementations/asio.h"
#include "hooks/audio/implementations/wave_out.h"
//#include "util/co_task_mem_ptr.h"
#include "defs.h"
#include "dummy_audio_client.h"
#include "wasapi_private.h"
#if 0
#define WRAP_DEBUG log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("audio::wasapi", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#if 1
#define WRAP_VERBOSE log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#else
#define WRAP_VERBOSE do {} while (0)
#endif
const char CLASS_NAME[] = "WrappedIAudioClient";
static void fix_rec_format(WAVEFORMATEX *pFormat) {
log_misc("audio::wasapi", "changing format to 2ch 16-bit");
pFormat->nChannels = 2;
pFormat->wBitsPerSample = 16;
pFormat->nBlockAlign = pFormat->nChannels * (pFormat->wBitsPerSample / 8);
pFormat->nAvgBytesPerSec = pFormat->nSamplesPerSec * pFormat->nBlockAlign;
}
// TODO(felix): is it appropriate to automatically switch to shared mode? should we do a
// `MessageBox` to notify the user?
/*
static bool check_for_exclusive_access(IAudioClient *client) {
static bool checked_once = false;
static bool previous_check_result = false;
CoTaskMemPtr<WAVEFORMATEX> mix_format;
REFERENCE_TIME requested_duration = 0;
if (checked_once) {
return previous_check_result;
}
if (audio::BACKEND.has_value()) {
return false;
}
// scope function so it has access to the local static variables
auto set_result = [](bool result) {
checked_once = true;
previous_check_result = result;
return result;
};
HRESULT ret = client->GetMixFormat(mix_format.ppv());
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IAudioClient::GetMixFormat", ret);
return set_result(false);
}
log_info("audio::wasapi", "Mix Format:");
print_format(mix_format.data());
ret = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, mix_format.data(), nullptr);
if (ret == AUDCLNT_E_UNSUPPORTED_FORMAT) {
auto mix_format_ex = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.data());
log_warning("audio::wasapi", "device does not natively support the mix format, converting to PCM");
if (mix_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
IsEqualGUID(GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, mix_format_ex->SubFormat))
{
mix_format_ex->Format.wBitsPerSample = 16;
mix_format_ex->Format.nBlockAlign = mix_format_ex->Format.nChannels * (mix_format_ex->Format.wBitsPerSample / 8);
mix_format_ex->Format.nAvgBytesPerSec = mix_format_ex->Format.nSamplesPerSec * mix_format_ex->Format.nBlockAlign;
mix_format_ex->Samples.wValidBitsPerSample = 16;
mix_format_ex->SubFormat = GUID_KSDATAFORMAT_SUBTYPE_PCM;
} else if (mix_format->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
mix_format->wBitsPerSample = 16;
mix_format->nBlockAlign = mix_format->nChannels * (mix_format->wBitsPerSample / 8);
mix_format->nAvgBytesPerSec = mix_format->nSamplesPerSec * mix_format->nBlockAlign;
mix_format->wFormatTag = WAVE_FORMAT_PCM;
} else {
log_warning("audio::wasapi", "mix format is not a floating point format");
return set_result(false);
}
ret = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, mix_format.data(), nullptr);
if (FAILED(ret)) {
log_warning("audio::wasapi", "mix format is not supported");
return set_result(false);
}
}
ret = client->GetDevicePeriod(nullptr, &requested_duration);
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IAudioClient::GetDevicePeriod", ret);
return false;
}
ret = client->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
requested_duration,
requested_duration,
mix_format.data(),
nullptr);
if (ret == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED || SUCCEEDED(ret)) {
log_info("audio::wasapi", "exclusive mode is available, disabling backend");
return set_result(true);
} else {
log_warning("audio::wasapi", "exclusive mode is not available, enabling backend, hr={}", FMT_HRESULT(ret));
}
return set_result(false);
}
HRESULT wrap_audio_client(
IMMDevice *device,
DWORD cls_ctx,
PROPVARIANT *activation_params,
IAudioClient **audio_client)
{
auto exclusive_available = check_for_exclusive_access(*audio_client);
(*audio_client)->Stop();
(*audio_client)->Reset();
(*audio_client)->Release();
*audio_client = nullptr;
SAFE_CALL("IMMDevice", "Activate", device->Activate(
IID_IAudioClient,
cls_ctx,
activation_params,
reinterpret_cast<void **>(audio_client)));
*/
IAudioClient *wrap_audio_client(IAudioClient *audio_client) {
AudioBackend *backend = nullptr;
bool requires_dummy = false;
if (hooks::audio::BACKEND.has_value()) {
switch (hooks::audio::BACKEND.value()) {
case hooks::audio::Backend::Asio:
backend = new AsioBackend();
requires_dummy = true;
break;
case hooks::audio::Backend::WaveOut:
backend = new WaveOutBackend();
break;
default:
break;
}
}
//} else if (!exclusive_available) {
// backend = new WaveOutBackend();
//}
IAudioClient *new_client;
if (hooks::audio::USE_DUMMY || requires_dummy) {
// release the old context since it is not used by the dummy context
audio_client->Release();
new_client = new DummyIAudioClient(backend);
} else {
new_client = new WrappedIAudioClient(audio_client, backend);
}
return new_client;
}
// IUnknown
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_WrappedIAudioClient ||
riid == IID_IAudioClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIAudioClient::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIAudioClient::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioClient
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Initialize(
AUDCLNT_SHAREMODE ShareMode,
DWORD StreamFlags,
REFERENCE_TIME hnsBufferDuration,
REFERENCE_TIME hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid)
{
WRAP_DEBUG;
if (!pFormat) {
return E_POINTER;
}
// check if format needs to be fixed
if (pFormat->nChannels > 2 && avs::game::is_model("REC")) {
fix_rec_format(const_cast<WAVEFORMATEX *>(pFormat));
}
// verbose output
log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
log_info("audio::wasapi", "... ShareMode : {}", share_mode_str(ShareMode));
log_info("audio::wasapi", "... StreamFlags : {}", stream_flags_str(StreamFlags));
log_info("audio::wasapi", "... hnsBufferDuration : {}", hnsBufferDuration);
log_info("audio::wasapi", "... hnsPeriodicity : {}", hnsPeriodicity);
print_format(pFormat);
if (this->backend) {
SAFE_CALL("AudioBackend", "on_initialize", this->backend->on_initialize(
&ShareMode,
&StreamFlags,
&hnsBufferDuration,
&hnsPeriodicity,
pFormat,
AudioSessionGuid));
log_info("audio::wasapi", "AudioBackend::on_initialize call finished");
log_info("audio::wasapi", "... ShareMode : {}", share_mode_str(ShareMode));
log_info("audio::wasapi", "... StreamFlags : {}", stream_flags_str(StreamFlags));
log_info("audio::wasapi", "... hnsBufferDuration : {}", hnsBufferDuration);
log_info("audio::wasapi", "... hnsPeriodicity : {}", hnsPeriodicity);
print_format(pFormat);
}
// check for exclusive mode
if (ShareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
this->exclusive_mode = true;
this->frame_size = pFormat->nChannels * (pFormat->wBitsPerSample / 8);
}
// call next
HRESULT ret = pReal->Initialize(
ShareMode,
StreamFlags,
hnsBufferDuration,
hnsPeriodicity,
pFormat,
AudioSessionGuid);
// check for failure
if (FAILED(ret)) {
PRINT_FAILED_RESULT("IAudioClient", "Initialize", ret);
return ret;
}
log_info("audio::wasapi", "IAudioClient::Initialize success, hr={}", FMT_HRESULT(ret));
/*
if (ShareMode == AUDCLNT_SHAREMODE_SHARED) {
IAudioClockAdjustment *clock = nullptr;
SAFE_CALL("IAudioClient", "GetService", pReal->GetService(
IID_IAudioClockAdjustment,
reinterpret_cast<void **>(&clock)));
SAFE_CALL("IAudioClockAdjustment", "SetSampleRate", clock->SetSampleRate(
static_cast<float>(pFormat->nSamplesPerSec)));
}
*/
copy_wave_format(&hooks::audio::FORMAT, pFormat);
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetBufferSize(UINT32 *pNumBufferFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetBufferSize");
});
if (this->backend) {
uint32_t buffer_frames = 0;
SAFE_CALL("AudioBackend", "on_get_buffer_size", this->backend->on_get_buffer_size(&buffer_frames));
if (buffer_frames > 0) {
*pNumBufferFrames = buffer_frames;
return S_OK;
}
}
CHECK_RESULT(pReal->GetBufferSize(pNumBufferFrames));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetStreamLatency(REFERENCE_TIME *phnsLatency) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetStreamLatency");
});
if (this->backend) {
REFERENCE_TIME latency = 0;
SAFE_CALL("AudioBackend", "on_get_stream_latency", this->backend->on_get_stream_latency(
&latency));
if (latency > 0) {
*phnsLatency = latency;
return S_OK;
}
}
CHECK_RESULT(pReal->GetStreamLatency(phnsLatency));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetCurrentPadding(UINT32 *pNumPaddingFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetCurrentPadding");
});
if (pNumPaddingFrames && this->backend) {
std::optional<uint32_t> padding_frames;
SAFE_CALL("AudioBackend", "on_get_current_padding",this->backend->on_get_current_padding(
padding_frames));
if (padding_frames.has_value()) {
*pNumPaddingFrames = padding_frames.value();
return S_OK;
}
}
CHECK_RESULT(pReal->GetCurrentPadding(pNumPaddingFrames));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::IsFormatSupported(
AUDCLNT_SHAREMODE ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch)
{
WRAP_VERBOSE;
if (!pFormat) {
return E_POINTER;
}
// check if format needs to be fixed
if (avs::game::is_model("REC") && pFormat->nChannels > 2) {
fix_rec_format(const_cast<WAVEFORMATEX *>(pFormat));
}
if (this->backend) {
HRESULT ret = this->backend->on_is_format_supported(&ShareMode, pFormat, ppClosestMatch);
if (SUCCEEDED(ret)) {
return ret;
}
// return errors other than unsupported format
if (ret != AUDCLNT_E_UNSUPPORTED_FORMAT) {
SAFE_CALL("AudioBackend", "on_is_format_supported", ret);
}
}
CHECK_RESULT(pReal->IsFormatSupported(ShareMode, pFormat, ppClosestMatch));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetMixFormat(WAVEFORMATEX **ppDeviceFormat) {
WRAP_VERBOSE;
if (!ppDeviceFormat) {
return E_POINTER;
}
if (this->backend) {
HRESULT ret = this->backend->on_get_mix_format(ppDeviceFormat);
if (SUCCEEDED(ret)) {
return ret;
}
// return errors other than E_NOTIMPL
if (ret != E_NOTIMPL) {
SAFE_CALL("AudioBackend", "on_get_mix_format", ret);
}
}
CHECK_RESULT(pReal->GetMixFormat(ppDeviceFormat));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetDevicePeriod(
REFERENCE_TIME *phnsDefaultDevicePeriod,
REFERENCE_TIME *phnsMinimumDevicePeriod)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioClient::GetDevicePeriod");
});
HRESULT ret = pReal->GetDevicePeriod(phnsDefaultDevicePeriod, phnsMinimumDevicePeriod);
if (SUCCEEDED(ret) && this->backend) {
SAFE_CALL("AudioBackend", "on_get_device_period", this->backend->on_get_device_period(
phnsDefaultDevicePeriod,
phnsMinimumDevicePeriod));
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Start() {
WRAP_VERBOSE;
HRESULT ret = pReal->Start();
if (SUCCEEDED(ret) && this->backend) {
SAFE_CALL("AudioBackend", "on_start", this->backend->on_start());
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Stop() {
WRAP_VERBOSE;
HRESULT ret = pReal->Stop();
if (SUCCEEDED(ret) && this->backend) {
SAFE_CALL("AudioBackend", "on_stop", this->backend->on_stop());
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::Reset() {
WRAP_VERBOSE;
CHECK_RESULT(pReal->Reset());
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::SetEventHandle(HANDLE eventHandle) {
WRAP_VERBOSE;
if (this->backend) {
SAFE_CALL("AudioBackend", "on_set_event_handle", this->backend->on_set_event_handle(&eventHandle));
}
CHECK_RESULT(pReal->SetEventHandle(eventHandle));
}
HRESULT STDMETHODCALLTYPE WrappedIAudioClient::GetService(REFIID riid, void **ppv) {
WRAP_DEBUG_FMT("WrappedIAudioClient::GetService({})", guid2s(riid));
HRESULT ret = pReal->GetService(riid, ppv);
if (SUCCEEDED(ret) && ppv && *ppv && riid == IID_IAudioRenderClient) {
auto render_client = reinterpret_cast<IAudioRenderClient *>(*ppv);
*ppv = new WrappedIAudioRenderClient(this, render_client);
}
return ret;
}
+55 -55
View File
@@ -1,55 +1,55 @@
#pragma once
#include <initguid.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include "hooks/audio/implementations/backend.h"
#include "hooks/audio/audio_private.h"
#include "util/logging.h"
#include "audio_render_client.h"
// {1FBC8530-AF3E-4128-B418-115DE72F76B6}
static const GUID IID_WrappedIAudioClient = {
0x1fbc8530, 0xaf3e, 0x4128, { 0xb4, 0x18, 0x11, 0x5d, 0xe7, 0x2f, 0x76, 0xb6 }
};
IAudioClient *wrap_audio_client(IAudioClient *client);
struct WrappedIAudioClient : IAudioClient {
explicit WrappedIAudioClient(IAudioClient *orig, AudioBackend *backend) : pReal(orig), backend(backend) {
}
WrappedIAudioClient(const WrappedIAudioClient &) = delete;
WrappedIAudioClient &operator=(const WrappedIAudioClient &) = delete;
virtual ~WrappedIAudioClient() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE Initialize(AUDCLNT_SHAREMODE ShareMode, DWORD StreamFlags, REFERENCE_TIME hnsBufferDuration, REFERENCE_TIME hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) override;
HRESULT STDMETHODCALLTYPE GetBufferSize(UINT32 *pNumBufferFrames) override;
HRESULT STDMETHODCALLTYPE GetStreamLatency(REFERENCE_TIME *phnsLatency) override;
HRESULT STDMETHODCALLTYPE GetCurrentPadding(UINT32 *pNumPaddingFrames) override;
HRESULT STDMETHODCALLTYPE IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) override;
HRESULT STDMETHODCALLTYPE GetMixFormat(WAVEFORMATEX **ppDeviceFormat) override;
HRESULT STDMETHODCALLTYPE GetDevicePeriod(REFERENCE_TIME *phnsDefaultDevicePeriod, REFERENCE_TIME *phnsMinimumDevicePeriod) override;
HRESULT STDMETHODCALLTYPE Start() override;
HRESULT STDMETHODCALLTYPE Stop() override;
HRESULT STDMETHODCALLTYPE Reset() override;
HRESULT STDMETHODCALLTYPE SetEventHandle(HANDLE eventHandle) override;
HRESULT STDMETHODCALLTYPE GetService(REFIID riid, void **ppv) override;
#pragma endregion
IAudioClient *const pReal;
AudioBackend *const backend;
bool exclusive_mode = false;
int frame_size = 0;
};
#pragma once
#include <initguid.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include "hooks/audio/implementations/backend.h"
#include "hooks/audio/audio_private.h"
#include "util/logging.h"
#include "audio_render_client.h"
// {1FBC8530-AF3E-4128-B418-115DE72F76B6}
static const GUID IID_WrappedIAudioClient = {
0x1fbc8530, 0xaf3e, 0x4128, { 0xb4, 0x18, 0x11, 0x5d, 0xe7, 0x2f, 0x76, 0xb6 }
};
IAudioClient *wrap_audio_client(IAudioClient *client);
struct WrappedIAudioClient : IAudioClient {
explicit WrappedIAudioClient(IAudioClient *orig, AudioBackend *backend) : pReal(orig), backend(backend) {
}
WrappedIAudioClient(const WrappedIAudioClient &) = delete;
WrappedIAudioClient &operator=(const WrappedIAudioClient &) = delete;
virtual ~WrappedIAudioClient() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE Initialize(AUDCLNT_SHAREMODE ShareMode, DWORD StreamFlags, REFERENCE_TIME hnsBufferDuration, REFERENCE_TIME hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) override;
HRESULT STDMETHODCALLTYPE GetBufferSize(UINT32 *pNumBufferFrames) override;
HRESULT STDMETHODCALLTYPE GetStreamLatency(REFERENCE_TIME *phnsLatency) override;
HRESULT STDMETHODCALLTYPE GetCurrentPadding(UINT32 *pNumPaddingFrames) override;
HRESULT STDMETHODCALLTYPE IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) override;
HRESULT STDMETHODCALLTYPE GetMixFormat(WAVEFORMATEX **ppDeviceFormat) override;
HRESULT STDMETHODCALLTYPE GetDevicePeriod(REFERENCE_TIME *phnsDefaultDevicePeriod, REFERENCE_TIME *phnsMinimumDevicePeriod) override;
HRESULT STDMETHODCALLTYPE Start() override;
HRESULT STDMETHODCALLTYPE Stop() override;
HRESULT STDMETHODCALLTYPE Reset() override;
HRESULT STDMETHODCALLTYPE SetEventHandle(HANDLE eventHandle) override;
HRESULT STDMETHODCALLTYPE GetService(REFIID riid, void **ppv) override;
#pragma endregion
IAudioClient *const pReal;
AudioBackend *const backend;
bool exclusive_mode = false;
int frame_size = 0;
};
@@ -1,88 +1,88 @@
#include "audio_render_client.h"
#include "audio_client.h"
#include "wasapi_private.h"
const char CLASS_NAME[] = "WrappedIAudioRenderClient";
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_WrappedIAudioRenderClient ||
riid == IID_IAudioRenderClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIAudioRenderClient::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIAudioRenderClient::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioRenderClient
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioRenderClient::GetBuffer");
});
if (this->client->backend) {
SAFE_CALL("AudioBackend", "on_get_buffer", this->client->backend->on_get_buffer(
NumFramesRequested,
ppData));
return S_OK;
}
// call original
HRESULT ret = pReal->GetBuffer(NumFramesRequested, ppData);
// store buffer reference
if (SUCCEEDED(ret)) {
this->audio_buffer = *ppData;
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioRenderClient::ReleaseBuffer");
});
if (this->client->backend) {
SAFE_CALL("AudioBackend", "on_release_buffer", this->client->backend->on_release_buffer(
NumFramesWritten,
dwFlags));
return S_OK;
}
// fix for audio pop effect
if (this->buffers_to_mute > 0 && this->client->frame_size > 0) {
// zero out = mute
memset(this->audio_buffer, 0, NumFramesWritten * this->client->frame_size);
this->buffers_to_mute--;
}
CHECK_RESULT(pReal->ReleaseBuffer(NumFramesWritten, dwFlags));
}
#include "audio_render_client.h"
#include "audio_client.h"
#include "wasapi_private.h"
const char CLASS_NAME[] = "WrappedIAudioRenderClient";
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_WrappedIAudioRenderClient ||
riid == IID_IAudioRenderClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIAudioRenderClient::AddRef() {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIAudioRenderClient::Release() {
// get reference count of underlying interface
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioRenderClient
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioRenderClient::GetBuffer");
});
if (this->client->backend) {
SAFE_CALL("AudioBackend", "on_get_buffer", this->client->backend->on_get_buffer(
NumFramesRequested,
ppData));
return S_OK;
}
// call original
HRESULT ret = pReal->GetBuffer(NumFramesRequested, ppData);
// store buffer reference
if (SUCCEEDED(ret)) {
this->audio_buffer = *ppData;
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE WrappedIAudioRenderClient::ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "WrappedIAudioRenderClient::ReleaseBuffer");
});
if (this->client->backend) {
SAFE_CALL("AudioBackend", "on_release_buffer", this->client->backend->on_release_buffer(
NumFramesWritten,
dwFlags));
return S_OK;
}
// fix for audio pop effect
if (this->buffers_to_mute > 0 && this->client->frame_size > 0) {
// zero out = mute
memset(this->audio_buffer, 0, NumFramesWritten * this->client->frame_size);
this->buffers_to_mute--;
}
CHECK_RESULT(pReal->ReleaseBuffer(NumFramesWritten, dwFlags));
}
@@ -1,38 +1,38 @@
#pragma once
#include <initguid.h>
#include <audioclient.h>
struct WrappedIAudioClient;
// {1CB6ABEE-1181-4FF7-8449-1CA18C2109E3}
static const GUID IID_WrappedIAudioRenderClient = {
0x1cb6abee, 0x1181, 0x4ff7, { 0x84, 0x49, 0x1c, 0xa1, 0x8c, 0x21, 0x09, 0xe3 }
};
struct WrappedIAudioRenderClient : IAudioRenderClient {
explicit WrappedIAudioRenderClient(WrappedIAudioClient *client, IAudioRenderClient *orig) : pReal(orig), client(client) {
}
WrappedIAudioRenderClient(const WrappedIAudioRenderClient &) = delete;
WrappedIAudioRenderClient &operator=(const WrappedIAudioRenderClient &) = delete;
virtual ~WrappedIAudioRenderClient() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) override;
HRESULT STDMETHODCALLTYPE ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) override;
#pragma endregion
IAudioRenderClient *const pReal;
WrappedIAudioClient *const client;
int buffers_to_mute = 16;
BYTE *audio_buffer = nullptr;
};
#pragma once
#include <initguid.h>
#include <audioclient.h>
struct WrappedIAudioClient;
// {1CB6ABEE-1181-4FF7-8449-1CA18C2109E3}
static const GUID IID_WrappedIAudioRenderClient = {
0x1cb6abee, 0x1181, 0x4ff7, { 0x84, 0x49, 0x1c, 0xa1, 0x8c, 0x21, 0x09, 0xe3 }
};
struct WrappedIAudioRenderClient : IAudioRenderClient {
explicit WrappedIAudioRenderClient(WrappedIAudioClient *client, IAudioRenderClient *orig) : pReal(orig), client(client) {
}
WrappedIAudioRenderClient(const WrappedIAudioRenderClient &) = delete;
WrappedIAudioRenderClient &operator=(const WrappedIAudioRenderClient &) = delete;
virtual ~WrappedIAudioRenderClient() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) override;
HRESULT STDMETHODCALLTYPE ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) override;
#pragma endregion
IAudioRenderClient *const pReal;
WrappedIAudioClient *const client;
int buffers_to_mute = 16;
BYTE *audio_buffer = nullptr;
};
+51 -51
View File
@@ -1,51 +1,51 @@
#pragma once
#include <initguid.h>
// missing from MinGW
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#endif
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
// defined starting with Windows 10, version 1803
// https://docs.microsoft.com/en-us/windows/win32/coreaudio/audclnt-streamflags-xxx-constants
#ifndef AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE
#define AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE 0x01000000
#endif
DEFINE_GUID(GUID_KSDATAFORMAT_SUBTYPE_PCM,
0x00000001, 0x0000, 0x0010,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
0x00000003, 0x0000, 0x0010,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
#ifdef _MSC_VER
DEFINE_GUID(IID_IAudioClient,
0x1cb9ad4c, 0xdbfa, 0x4c32,
0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2);
DEFINE_GUID(IID_IAudioClock,
0xcd63314f, 0x3fba, 0x4a1b,
0x81, 0x2c, 0xef, 0x96, 0x35, 0x87, 0x28, 0xe7);
DEFINE_GUID(IID_IAudioClock2,
0x6f49ff73, 0x6727, 0x49ac,
0xa0, 0x08, 0xd9, 0x8c, 0xf5, 0xe7, 0x00, 0x48);
DEFINE_GUID(IID_IAudioClockAdjustment,
0xf6e4c0a0, 0x46d9, 0x4fb8,
0xbe, 0x21, 0x57, 0xa3, 0xef, 0x2b, 0x62, 0x6c);
DEFINE_GUID(IID_IAudioRenderClient,
0xf294acfc, 0x3146, 0x4483,
0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2);
DEFINE_GUID(IID_IAudioSessionControl,
0xf4b1a599, 0x7266, 0x4319,
0xa8, 0xca, 0xe7, 0x0a, 0xcb, 0x11, 0xe8, 0xcd);
#endif
#pragma once
#include <initguid.h>
// missing from MinGW
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#endif
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
// defined starting with Windows 10, version 1803
// https://docs.microsoft.com/en-us/windows/win32/coreaudio/audclnt-streamflags-xxx-constants
#ifndef AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE
#define AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE 0x01000000
#endif
DEFINE_GUID(GUID_KSDATAFORMAT_SUBTYPE_PCM,
0x00000001, 0x0000, 0x0010,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
0x00000003, 0x0000, 0x0010,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
#ifdef _MSC_VER
DEFINE_GUID(IID_IAudioClient,
0x1cb9ad4c, 0xdbfa, 0x4c32,
0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2);
DEFINE_GUID(IID_IAudioClock,
0xcd63314f, 0x3fba, 0x4a1b,
0x81, 0x2c, 0xef, 0x96, 0x35, 0x87, 0x28, 0xe7);
DEFINE_GUID(IID_IAudioClock2,
0x6f49ff73, 0x6727, 0x49ac,
0xa0, 0x08, 0xd9, 0x8c, 0xf5, 0xe7, 0x00, 0x48);
DEFINE_GUID(IID_IAudioClockAdjustment,
0xf6e4c0a0, 0x46d9, 0x4fb8,
0xbe, 0x21, 0x57, 0xa3, 0xef, 0x2b, 0x62, 0x6c);
DEFINE_GUID(IID_IAudioRenderClient,
0xf294acfc, 0x3146, 0x4483,
0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2);
DEFINE_GUID(IID_IAudioSessionControl,
0xf4b1a599, 0x7266, 0x4319,
0xa8, 0xca, 0xe7, 0x0a, 0xcb, 0x11, 0xe8, 0xcd);
#endif
+216 -216
View File
@@ -1,216 +1,216 @@
#include "dummy_audio_client.h"
#include "hooks/audio/audio.h"
#include "hooks/audio/util.h"
#include "defs.h"
#include "dummy_audio_clock.h"
#include "dummy_audio_render_client.h"
#include "dummy_audio_session_control.h"
#include "util.h"
#include "wasapi_private.h"
#if 0
#define WRAP_DEBUG log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("audio::wasapi", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#if 1
#define WRAP_VERBOSE log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#else
#define WRAP_VERBOSE do {} while (0)
#endif
const char CLASS_NAME[] = "DummyIAudioClient";
// IUnknown
HRESULT STDMETHODCALLTYPE DummyIAudioClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioClient ||
riid == IID_IAudioClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioClient::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioClient::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioClient
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Initialize(
AUDCLNT_SHAREMODE ShareMode,
DWORD StreamFlags,
REFERENCE_TIME hnsBufferDuration,
REFERENCE_TIME hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid)
{
WRAP_DEBUG;
if (!pFormat) {
return E_POINTER;
}
// verbose output
log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
log_info("audio::wasapi", "... ShareMode : {}", share_mode_str(ShareMode));
log_info("audio::wasapi", "... StreamFlags : {}", stream_flags_str(StreamFlags));
log_info("audio::wasapi", "... hnsBufferDuration : {}", hnsBufferDuration);
log_info("audio::wasapi", "... hnsPeriodicity : {}", hnsPeriodicity);
print_format(pFormat);
CHECK_RESULT(this->backend->on_initialize(
&ShareMode,
&StreamFlags,
&hnsBufferDuration,
&hnsPeriodicity,
pFormat,
AudioSessionGuid));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetBufferSize(UINT32 *pNumBufferFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetBufferSize");
});
CHECK_RESULT(this->backend->on_get_buffer_size(pNumBufferFrames));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetStreamLatency(REFERENCE_TIME *phnsLatency) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetStreamLatency");
});
CHECK_RESULT(this->backend->on_get_stream_latency(phnsLatency));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetCurrentPadding(UINT32 *pNumPaddingFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetCurrentPadding");
});
if (!pNumPaddingFrames) {
return E_POINTER;
}
std::optional<uint32_t> padding_frames;
HRESULT ret = this->backend->on_get_current_padding(padding_frames);
if (SUCCEEDED(ret)) {
*pNumPaddingFrames = padding_frames.value_or(0);
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::IsFormatSupported(
AUDCLNT_SHAREMODE ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch)
{
WRAP_VERBOSE;
if (!pFormat) {
return E_POINTER;
}
CHECK_RESULT(this->backend->on_is_format_supported(&ShareMode, pFormat, ppClosestMatch));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetMixFormat(WAVEFORMATEX **ppDeviceFormat) {
WRAP_VERBOSE;
if (!ppDeviceFormat) {
return E_POINTER;
}
CHECK_RESULT(this->backend->on_get_mix_format(ppDeviceFormat));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetDevicePeriod(
REFERENCE_TIME *phnsDefaultDevicePeriod,
REFERENCE_TIME *phnsMinimumDevicePeriod)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetDevicePeriod");
});
CHECK_RESULT(this->backend->on_get_device_period(
phnsDefaultDevicePeriod,
phnsMinimumDevicePeriod));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Start() {
WRAP_VERBOSE;
HRESULT ret = this->backend->on_start();
if (SUCCEEDED(ret)) {
for (auto &handler : this->session_notification_handlers) {
handler->OnStateChanged(AudioSessionStateActive);
}
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Stop() {
WRAP_VERBOSE;
HRESULT ret = this->backend->on_stop();
if (SUCCEEDED(ret)) {
for (auto &handler : this->session_notification_handlers) {
handler->OnStateChanged(AudioSessionStateInactive);
}
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Reset() {
WRAP_VERBOSE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::SetEventHandle(HANDLE eventHandle) {
WRAP_VERBOSE;
CHECK_RESULT(this->backend->on_set_event_handle(&eventHandle));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetService(REFIID riid, void **ppv) {
WRAP_DEBUG_FMT("DummyIAudioClient::GetService({})", guid2s(riid));
if (ppv) {
if (riid == IID_IAudioRenderClient) {
*ppv = new DummyIAudioRenderClient(this);
return S_OK;
} else if (riid == IID_IAudioSessionControl) {
*ppv = new DummyIAudioSessionControl(this);
return S_OK;
} else if (riid == IID_IAudioClock) {
*ppv = new DummyIAudioClock(this->backend);
return S_OK;
}
}
CHECK_RESULT(E_NOINTERFACE);
}
#include "dummy_audio_client.h"
#include "hooks/audio/audio.h"
#include "hooks/audio/util.h"
#include "defs.h"
#include "dummy_audio_clock.h"
#include "dummy_audio_render_client.h"
#include "dummy_audio_session_control.h"
#include "util.h"
#include "wasapi_private.h"
#if 0
#define WRAP_DEBUG log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("audio::wasapi", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#if 1
#define WRAP_VERBOSE log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#else
#define WRAP_VERBOSE do {} while (0)
#endif
const char CLASS_NAME[] = "DummyIAudioClient";
// IUnknown
HRESULT STDMETHODCALLTYPE DummyIAudioClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioClient ||
riid == IID_IAudioClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioClient::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioClient::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioClient
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Initialize(
AUDCLNT_SHAREMODE ShareMode,
DWORD StreamFlags,
REFERENCE_TIME hnsBufferDuration,
REFERENCE_TIME hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid)
{
WRAP_DEBUG;
if (!pFormat) {
return E_POINTER;
}
// verbose output
log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
log_info("audio::wasapi", "... ShareMode : {}", share_mode_str(ShareMode));
log_info("audio::wasapi", "... StreamFlags : {}", stream_flags_str(StreamFlags));
log_info("audio::wasapi", "... hnsBufferDuration : {}", hnsBufferDuration);
log_info("audio::wasapi", "... hnsPeriodicity : {}", hnsPeriodicity);
print_format(pFormat);
CHECK_RESULT(this->backend->on_initialize(
&ShareMode,
&StreamFlags,
&hnsBufferDuration,
&hnsPeriodicity,
pFormat,
AudioSessionGuid));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetBufferSize(UINT32 *pNumBufferFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetBufferSize");
});
CHECK_RESULT(this->backend->on_get_buffer_size(pNumBufferFrames));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetStreamLatency(REFERENCE_TIME *phnsLatency) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetStreamLatency");
});
CHECK_RESULT(this->backend->on_get_stream_latency(phnsLatency));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetCurrentPadding(UINT32 *pNumPaddingFrames) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetCurrentPadding");
});
if (!pNumPaddingFrames) {
return E_POINTER;
}
std::optional<uint32_t> padding_frames;
HRESULT ret = this->backend->on_get_current_padding(padding_frames);
if (SUCCEEDED(ret)) {
*pNumPaddingFrames = padding_frames.value_or(0);
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::IsFormatSupported(
AUDCLNT_SHAREMODE ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch)
{
WRAP_VERBOSE;
if (!pFormat) {
return E_POINTER;
}
CHECK_RESULT(this->backend->on_is_format_supported(&ShareMode, pFormat, ppClosestMatch));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetMixFormat(WAVEFORMATEX **ppDeviceFormat) {
WRAP_VERBOSE;
if (!ppDeviceFormat) {
return E_POINTER;
}
CHECK_RESULT(this->backend->on_get_mix_format(ppDeviceFormat));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetDevicePeriod(
REFERENCE_TIME *phnsDefaultDevicePeriod,
REFERENCE_TIME *phnsMinimumDevicePeriod)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClient::GetDevicePeriod");
});
CHECK_RESULT(this->backend->on_get_device_period(
phnsDefaultDevicePeriod,
phnsMinimumDevicePeriod));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Start() {
WRAP_VERBOSE;
HRESULT ret = this->backend->on_start();
if (SUCCEEDED(ret)) {
for (auto &handler : this->session_notification_handlers) {
handler->OnStateChanged(AudioSessionStateActive);
}
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Stop() {
WRAP_VERBOSE;
HRESULT ret = this->backend->on_stop();
if (SUCCEEDED(ret)) {
for (auto &handler : this->session_notification_handlers) {
handler->OnStateChanged(AudioSessionStateInactive);
}
}
CHECK_RESULT(ret);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::Reset() {
WRAP_VERBOSE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::SetEventHandle(HANDLE eventHandle) {
WRAP_VERBOSE;
CHECK_RESULT(this->backend->on_set_event_handle(&eventHandle));
}
HRESULT STDMETHODCALLTYPE DummyIAudioClient::GetService(REFIID riid, void **ppv) {
WRAP_DEBUG_FMT("DummyIAudioClient::GetService({})", guid2s(riid));
if (ppv) {
if (riid == IID_IAudioRenderClient) {
*ppv = new DummyIAudioRenderClient(this);
return S_OK;
} else if (riid == IID_IAudioSessionControl) {
*ppv = new DummyIAudioSessionControl(this);
return S_OK;
} else if (riid == IID_IAudioClock) {
*ppv = new DummyIAudioClock(this->backend);
return S_OK;
}
}
CHECK_RESULT(E_NOINTERFACE);
}
@@ -1,63 +1,63 @@
#pragma once
#include <atomic>
#include <vector>
#include <initguid.h>
#include <audioclient.h>
#include <audiopolicy.h>
#include <mmdeviceapi.h>
#include "hooks/audio/implementations/backend.h"
#include "hooks/audio/implementations/asio.h"
#include "hooks/audio/audio_private.h"
#include "util/logging.h"
// {F0842A04-0F8E-4F5C-B3FF-0ED24C589BDA}
static const GUID IID_DummyIAudioClient = {
0xf0842a04, 0x0f8e, 0x4f5c, { 0xb3, 0xff, 0x0e, 0xd2, 0x4c, 0x58, 0x9b, 0xda }
};
struct DummyIAudioClient : IAudioClient {
explicit DummyIAudioClient(AudioBackend *backend) : backend(backend) {
if (!this->backend) {
log_fatal("audio::wasapi", "DummyIAudioClient: no backend initialized");
}
}
DummyIAudioClient(const DummyIAudioClient &) = delete;
DummyIAudioClient &operator=(const DummyIAudioClient &) = delete;
virtual ~DummyIAudioClient() {
log_misc("audio::wasapi", "~DummyIAudioClient");
delete this->backend;
}
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE Initialize(AUDCLNT_SHAREMODE ShareMode, DWORD StreamFlags, REFERENCE_TIME hnsBufferDuration, REFERENCE_TIME hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) override;
HRESULT STDMETHODCALLTYPE GetBufferSize(UINT32 *pNumBufferFrames) override;
HRESULT STDMETHODCALLTYPE GetStreamLatency(REFERENCE_TIME *phnsLatency) override;
HRESULT STDMETHODCALLTYPE GetCurrentPadding(UINT32 *pNumPaddingFrames) override;
HRESULT STDMETHODCALLTYPE IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) override;
HRESULT STDMETHODCALLTYPE GetMixFormat(WAVEFORMATEX **ppDeviceFormat) override;
HRESULT STDMETHODCALLTYPE GetDevicePeriod(REFERENCE_TIME *phnsDefaultDevicePeriod, REFERENCE_TIME *phnsMinimumDevicePeriod) override;
HRESULT STDMETHODCALLTYPE Start() override;
HRESULT STDMETHODCALLTYPE Stop() override;
HRESULT STDMETHODCALLTYPE Reset() override;
HRESULT STDMETHODCALLTYPE SetEventHandle(HANDLE eventHandle) override;
HRESULT STDMETHODCALLTYPE GetService(REFIID riid, void **ppv) override;
#pragma endregion
std::atomic<ULONG> ref_cnt = 1;
AudioBackend *const backend;
std::vector<IAudioSessionEvents *> session_notification_handlers;
};
#pragma once
#include <atomic>
#include <vector>
#include <initguid.h>
#include <audioclient.h>
#include <audiopolicy.h>
#include <mmdeviceapi.h>
#include "hooks/audio/implementations/backend.h"
#include "hooks/audio/implementations/asio.h"
#include "hooks/audio/audio_private.h"
#include "util/logging.h"
// {F0842A04-0F8E-4F5C-B3FF-0ED24C589BDA}
static const GUID IID_DummyIAudioClient = {
0xf0842a04, 0x0f8e, 0x4f5c, { 0xb3, 0xff, 0x0e, 0xd2, 0x4c, 0x58, 0x9b, 0xda }
};
struct DummyIAudioClient : IAudioClient {
explicit DummyIAudioClient(AudioBackend *backend) : backend(backend) {
if (!this->backend) {
log_fatal("audio::wasapi", "DummyIAudioClient: no backend initialized");
}
}
DummyIAudioClient(const DummyIAudioClient &) = delete;
DummyIAudioClient &operator=(const DummyIAudioClient &) = delete;
virtual ~DummyIAudioClient() {
log_misc("audio::wasapi", "~DummyIAudioClient");
delete this->backend;
}
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE Initialize(AUDCLNT_SHAREMODE ShareMode, DWORD StreamFlags, REFERENCE_TIME hnsBufferDuration, REFERENCE_TIME hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) override;
HRESULT STDMETHODCALLTYPE GetBufferSize(UINT32 *pNumBufferFrames) override;
HRESULT STDMETHODCALLTYPE GetStreamLatency(REFERENCE_TIME *phnsLatency) override;
HRESULT STDMETHODCALLTYPE GetCurrentPadding(UINT32 *pNumPaddingFrames) override;
HRESULT STDMETHODCALLTYPE IsFormatSupported(AUDCLNT_SHAREMODE ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) override;
HRESULT STDMETHODCALLTYPE GetMixFormat(WAVEFORMATEX **ppDeviceFormat) override;
HRESULT STDMETHODCALLTYPE GetDevicePeriod(REFERENCE_TIME *phnsDefaultDevicePeriod, REFERENCE_TIME *phnsMinimumDevicePeriod) override;
HRESULT STDMETHODCALLTYPE Start() override;
HRESULT STDMETHODCALLTYPE Stop() override;
HRESULT STDMETHODCALLTYPE Reset() override;
HRESULT STDMETHODCALLTYPE SetEventHandle(HANDLE eventHandle) override;
HRESULT STDMETHODCALLTYPE GetService(REFIID riid, void **ppv) override;
#pragma endregion
std::atomic<ULONG> ref_cnt = 1;
AudioBackend *const backend;
std::vector<IAudioSessionEvents *> session_notification_handlers;
};
@@ -1,62 +1,62 @@
#include "dummy_audio_clock.h"
#include "hooks/audio/backends/wasapi/dummy_audio_client.h"
#include "wasapi_private.h"
const char CLASS_NAME[] = "DummyIAudioClock";
// IUnknown
HRESULT STDMETHODCALLTYPE DummyIAudioClock::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioClock ||
riid == IID_IAudioClock)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioClock::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioClock::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioClock
HRESULT STDMETHODCALLTYPE DummyIAudioClock::GetFrequency(UINT64 *pu64Frequency) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClock::GetFrequency");
});
if (!pu64Frequency) {
return E_POINTER;
}
*pu64Frequency = static_cast<UINT64>(this->backend->format().Format.nSamplesPerSec);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioClock::GetPosition(
UINT64 *pu64Position,
UINT64 *pu64QPCPosition)
{
CHECK_RESULT(E_NOTIMPL);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClock::GetCharacteristics(DWORD *pdwCharacteristics) {
CHECK_RESULT(E_NOTIMPL);
}
#include "dummy_audio_clock.h"
#include "hooks/audio/backends/wasapi/dummy_audio_client.h"
#include "wasapi_private.h"
const char CLASS_NAME[] = "DummyIAudioClock";
// IUnknown
HRESULT STDMETHODCALLTYPE DummyIAudioClock::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioClock ||
riid == IID_IAudioClock)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioClock::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioClock::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioClock
HRESULT STDMETHODCALLTYPE DummyIAudioClock::GetFrequency(UINT64 *pu64Frequency) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioClock::GetFrequency");
});
if (!pu64Frequency) {
return E_POINTER;
}
*pu64Frequency = static_cast<UINT64>(this->backend->format().Format.nSamplesPerSec);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioClock::GetPosition(
UINT64 *pu64Position,
UINT64 *pu64QPCPosition)
{
CHECK_RESULT(E_NOTIMPL);
}
HRESULT STDMETHODCALLTYPE DummyIAudioClock::GetCharacteristics(DWORD *pdwCharacteristics) {
CHECK_RESULT(E_NOTIMPL);
}
+39 -39
View File
@@ -1,39 +1,39 @@
#pragma once
#include <atomic>
#include <initguid.h>
#include <audiopolicy.h>
struct AudioBackend;
// {8AE52B4A-ACC4-420C-9169-BA8AF07A251F}
static const GUID IID_DummyIAudioClock = {
0x8ae52b4a, 0xacc4, 0x420c, { 0x91, 0x69, 0xba, 0x8a, 0xf0, 0x7a, 0x25, 0x1f }
};
struct DummyIAudioClock : IAudioClock {
explicit DummyIAudioClock(AudioBackend *backend) : backend(backend) {
}
DummyIAudioClock(const DummyIAudioClock &) = delete;
DummyIAudioClock &operator=(const DummyIAudioClock &) = delete;
virtual ~DummyIAudioClock() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClock
HRESULT STDMETHODCALLTYPE GetFrequency(UINT64 *pu64Frequency) override;
HRESULT STDMETHODCALLTYPE GetPosition(UINT64 *pu64Position, UINT64 *pu64QPCPosition) override;
HRESULT STDMETHODCALLTYPE GetCharacteristics(DWORD *pdwCharacteristics) override;
#pragma endregion
AudioBackend *const backend;
std::atomic<ULONG> ref_cnt = 1;
};
#pragma once
#include <atomic>
#include <initguid.h>
#include <audiopolicy.h>
struct AudioBackend;
// {8AE52B4A-ACC4-420C-9169-BA8AF07A251F}
static const GUID IID_DummyIAudioClock = {
0x8ae52b4a, 0xacc4, 0x420c, { 0x91, 0x69, 0xba, 0x8a, 0xf0, 0x7a, 0x25, 0x1f }
};
struct DummyIAudioClock : IAudioClock {
explicit DummyIAudioClock(AudioBackend *backend) : backend(backend) {
}
DummyIAudioClock(const DummyIAudioClock &) = delete;
DummyIAudioClock &operator=(const DummyIAudioClock &) = delete;
virtual ~DummyIAudioClock() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClock
HRESULT STDMETHODCALLTYPE GetFrequency(UINT64 *pu64Frequency) override;
HRESULT STDMETHODCALLTYPE GetPosition(UINT64 *pu64Position, UINT64 *pu64QPCPosition) override;
HRESULT STDMETHODCALLTYPE GetCharacteristics(DWORD *pdwCharacteristics) override;
#pragma endregion
AudioBackend *const backend;
std::atomic<ULONG> ref_cnt = 1;
};
@@ -1,57 +1,57 @@
#include "dummy_audio_render_client.h"
#include "dummy_audio_client.h"
#include "wasapi_private.h"
const char CLASS_NAME[] = "DummyIAudioRenderClient";
HRESULT STDMETHODCALLTYPE DummyIAudioRenderClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioRenderClient ||
riid == IID_IAudioRenderClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioRenderClient::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioRenderClient::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioRenderClient
HRESULT STDMETHODCALLTYPE DummyIAudioRenderClient::GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioRenderClient::GetBuffer");
});
CHECK_RESULT(this->client->backend->on_get_buffer(
NumFramesRequested,
ppData));
}
HRESULT STDMETHODCALLTYPE DummyIAudioRenderClient::ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioRenderClient::ReleaseBuffer");
});
CHECK_RESULT(this->client->backend->on_release_buffer(
NumFramesWritten,
dwFlags));
}
#include "dummy_audio_render_client.h"
#include "dummy_audio_client.h"
#include "wasapi_private.h"
const char CLASS_NAME[] = "DummyIAudioRenderClient";
HRESULT STDMETHODCALLTYPE DummyIAudioRenderClient::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioRenderClient ||
riid == IID_IAudioRenderClient)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioRenderClient::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioRenderClient::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioRenderClient
HRESULT STDMETHODCALLTYPE DummyIAudioRenderClient::GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioRenderClient::GetBuffer");
});
CHECK_RESULT(this->client->backend->on_get_buffer(
NumFramesRequested,
ppData));
}
HRESULT STDMETHODCALLTYPE DummyIAudioRenderClient::ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) {
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("audio::wasapi", "DummyIAudioRenderClient::ReleaseBuffer");
});
CHECK_RESULT(this->client->backend->on_release_buffer(
NumFramesWritten,
dwFlags));
}
@@ -1,38 +1,38 @@
#pragma once
#include <atomic>
#include <initguid.h>
#include <audioclient.h>
struct DummyIAudioClient;
// {453BF965-DDA4-4234-8846-F02BA5E874B7}
static const GUID IID_DummyIAudioRenderClient = {
0x453bf965, 0xdda4, 0x4234, { 0x88, 0x46, 0xf0, 0x2b, 0xa5, 0xe8, 0x74, 0xb7 }
};
struct DummyIAudioRenderClient : IAudioRenderClient {
explicit DummyIAudioRenderClient(DummyIAudioClient *client) : client(client) {
}
DummyIAudioRenderClient(const DummyIAudioRenderClient &) = delete;
DummyIAudioRenderClient &operator=(const DummyIAudioRenderClient &) = delete;
virtual ~DummyIAudioRenderClient() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) override;
HRESULT STDMETHODCALLTYPE ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) override;
#pragma endregion
std::atomic<ULONG> ref_cnt = 1;
DummyIAudioClient *const client;
};
#pragma once
#include <atomic>
#include <initguid.h>
#include <audioclient.h>
struct DummyIAudioClient;
// {453BF965-DDA4-4234-8846-F02BA5E874B7}
static const GUID IID_DummyIAudioRenderClient = {
0x453bf965, 0xdda4, 0x4234, { 0x88, 0x46, 0xf0, 0x2b, 0xa5, 0xe8, 0x74, 0xb7 }
};
struct DummyIAudioRenderClient : IAudioRenderClient {
explicit DummyIAudioRenderClient(DummyIAudioClient *client) : client(client) {
}
DummyIAudioRenderClient(const DummyIAudioRenderClient &) = delete;
DummyIAudioRenderClient &operator=(const DummyIAudioRenderClient &) = delete;
virtual ~DummyIAudioRenderClient() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioClient
HRESULT STDMETHODCALLTYPE GetBuffer(UINT32 NumFramesRequested, BYTE **ppData) override;
HRESULT STDMETHODCALLTYPE ReleaseBuffer(UINT32 NumFramesWritten, DWORD dwFlags) override;
#pragma endregion
std::atomic<ULONG> ref_cnt = 1;
DummyIAudioClient *const client;
};
@@ -1,176 +1,176 @@
#include "dummy_audio_session_control.h"
#include <algorithm>
#include "dummy_audio_client.h"
#include "wasapi_private.h"
#if 1
#define WRAP_DEBUG log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#else
#define WRAP_DEBUG do {} while (0)
#endif
const char CLASS_NAME[] = "DummyIAudioSessionControl";
// IUnknown
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioSessionControl ||
riid == IID_IAudioSessionControl)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioSessionControl::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioSessionControl::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioSessionControl
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetState(AudioSessionState *pRetVal) {
CHECK_RESULT(E_NOTIMPL);
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetDisplayName(LPWSTR *pRetVal) {
WRAP_DEBUG;
if (!pRetVal) {
return E_POINTER;
}
auto length = this->display_name.length();
auto value = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(length + 1));
if (!value) {
CHECK_RESULT(E_OUTOFMEMORY);
}
memcpy(value, this->display_name.c_str(), length);
value[length] = L'\0';
*pRetVal = value;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::SetDisplayName(
LPCWSTR Value,
LPCGUID EventContext)
{
WRAP_DEBUG;
if (!Value) {
return E_POINTER;
}
this->display_name = std::wstring(Value);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetIconPath(LPWSTR *pRetVal) {
WRAP_DEBUG;
if (!pRetVal) {
return E_POINTER;
}
auto length = this->icon_path.length();
auto value = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(length + 1));
if (!value) {
CHECK_RESULT(E_OUTOFMEMORY);
}
memcpy(value, this->icon_path.c_str(), length);
value[length] = L'\0';
*pRetVal = value;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::SetIconPath(
LPCWSTR Value,
LPCGUID EventContext)
{
WRAP_DEBUG;
if (!Value) {
return E_POINTER;
}
this->icon_path = std::wstring(Value);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetGroupingParam(GUID *pRetVal) {
WRAP_DEBUG;
if (!pRetVal) {
return E_POINTER;
}
memcpy(pRetVal, &this->grouping_param, sizeof(this->grouping_param));
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::SetGroupingParam(
LPCGUID Override,
LPCGUID EventContext)
{
WRAP_DEBUG;
if (!Override) {
return E_POINTER;
}
memcpy(&this->grouping_param, Override, sizeof(this->grouping_param));
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::RegisterAudioSessionNotification(
IAudioSessionEvents *NewNotifications)
{
WRAP_DEBUG;
if (!NewNotifications) {
return E_POINTER;
}
this->client->session_notification_handlers.emplace_back(NewNotifications);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::UnregisterAudioSessionNotification(
IAudioSessionEvents *NewNotifications)
{
WRAP_DEBUG;
if (!NewNotifications) {
return E_POINTER;
}
this->client->session_notification_handlers.erase(
std::remove(
this->client->session_notification_handlers.begin(),
this->client->session_notification_handlers.end(),
NewNotifications
),
this->client->session_notification_handlers.end());
return S_OK;
}
#include "dummy_audio_session_control.h"
#include <algorithm>
#include "dummy_audio_client.h"
#include "wasapi_private.h"
#if 1
#define WRAP_DEBUG log_misc("audio::wasapi", "{}::{}", CLASS_NAME, __func__)
#else
#define WRAP_DEBUG do {} while (0)
#endif
const char CLASS_NAME[] = "DummyIAudioSessionControl";
// IUnknown
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_DummyIAudioSessionControl ||
riid == IID_IAudioSessionControl)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DummyIAudioSessionControl::AddRef() {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE DummyIAudioSessionControl::Release() {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
// IAudioSessionControl
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetState(AudioSessionState *pRetVal) {
CHECK_RESULT(E_NOTIMPL);
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetDisplayName(LPWSTR *pRetVal) {
WRAP_DEBUG;
if (!pRetVal) {
return E_POINTER;
}
auto length = this->display_name.length();
auto value = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(length + 1));
if (!value) {
CHECK_RESULT(E_OUTOFMEMORY);
}
memcpy(value, this->display_name.c_str(), length);
value[length] = L'\0';
*pRetVal = value;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::SetDisplayName(
LPCWSTR Value,
LPCGUID EventContext)
{
WRAP_DEBUG;
if (!Value) {
return E_POINTER;
}
this->display_name = std::wstring(Value);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetIconPath(LPWSTR *pRetVal) {
WRAP_DEBUG;
if (!pRetVal) {
return E_POINTER;
}
auto length = this->icon_path.length();
auto value = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(length + 1));
if (!value) {
CHECK_RESULT(E_OUTOFMEMORY);
}
memcpy(value, this->icon_path.c_str(), length);
value[length] = L'\0';
*pRetVal = value;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::SetIconPath(
LPCWSTR Value,
LPCGUID EventContext)
{
WRAP_DEBUG;
if (!Value) {
return E_POINTER;
}
this->icon_path = std::wstring(Value);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::GetGroupingParam(GUID *pRetVal) {
WRAP_DEBUG;
if (!pRetVal) {
return E_POINTER;
}
memcpy(pRetVal, &this->grouping_param, sizeof(this->grouping_param));
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::SetGroupingParam(
LPCGUID Override,
LPCGUID EventContext)
{
WRAP_DEBUG;
if (!Override) {
return E_POINTER;
}
memcpy(&this->grouping_param, Override, sizeof(this->grouping_param));
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::RegisterAudioSessionNotification(
IAudioSessionEvents *NewNotifications)
{
WRAP_DEBUG;
if (!NewNotifications) {
return E_POINTER;
}
this->client->session_notification_handlers.emplace_back(NewNotifications);
return S_OK;
}
HRESULT STDMETHODCALLTYPE DummyIAudioSessionControl::UnregisterAudioSessionNotification(
IAudioSessionEvents *NewNotifications)
{
WRAP_DEBUG;
if (!NewNotifications) {
return E_POINTER;
}
this->client->session_notification_handlers.erase(
std::remove(
this->client->session_notification_handlers.begin(),
this->client->session_notification_handlers.end(),
NewNotifications
),
this->client->session_notification_handlers.end());
return S_OK;
}
@@ -1,50 +1,50 @@
#pragma once
#include <atomic>
#include <string>
#include <initguid.h>
#include <audiopolicy.h>
struct DummyIAudioClient;
// {5412A875-C82F-451F-B29A-0E18DB1CDFA2}
static const GUID IID_DummyIAudioSessionControl = {
0x5412a875, 0xc82f, 0x451f, { 0xb2, 0x9a, 0x0e, 0x18, 0xdb, 0x1c, 0xdf, 0xa2 }
};
struct DummyIAudioSessionControl : IAudioSessionControl {
explicit DummyIAudioSessionControl(DummyIAudioClient *client) : client(client) {
}
DummyIAudioSessionControl(const DummyIAudioSessionControl &) = delete;
DummyIAudioSessionControl &operator=(const DummyIAudioSessionControl &) = delete;
virtual ~DummyIAudioSessionControl() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioSessionControl
HRESULT STDMETHODCALLTYPE GetState(AudioSessionState *pRetVal) override;
HRESULT STDMETHODCALLTYPE GetDisplayName(LPWSTR *pRetVal) override;
HRESULT STDMETHODCALLTYPE SetDisplayName(LPCWSTR Value, LPCGUID EventContext) override;
HRESULT STDMETHODCALLTYPE GetIconPath(LPWSTR *pRetVal) override;
HRESULT STDMETHODCALLTYPE SetIconPath(LPCWSTR Value, LPCGUID EventContext) override;
HRESULT STDMETHODCALLTYPE GetGroupingParam(GUID *pRetVal) override;
HRESULT STDMETHODCALLTYPE SetGroupingParam(LPCGUID Override, LPCGUID EventContext) override;
HRESULT STDMETHODCALLTYPE RegisterAudioSessionNotification(IAudioSessionEvents *NewNotifications) override;
HRESULT STDMETHODCALLTYPE UnregisterAudioSessionNotification(IAudioSessionEvents *NewNotifications) override;
#pragma endregion
DummyIAudioClient *const client;
std::atomic<ULONG> ref_cnt = 1;
std::wstring display_name = L"Dummy Audio Device";
std::wstring icon_path = L"";
GUID grouping_param = GUID_NULL;
#pragma once
#include <atomic>
#include <string>
#include <initguid.h>
#include <audiopolicy.h>
struct DummyIAudioClient;
// {5412A875-C82F-451F-B29A-0E18DB1CDFA2}
static const GUID IID_DummyIAudioSessionControl = {
0x5412a875, 0xc82f, 0x451f, { 0xb2, 0x9a, 0x0e, 0x18, 0xdb, 0x1c, 0xdf, 0xa2 }
};
struct DummyIAudioSessionControl : IAudioSessionControl {
explicit DummyIAudioSessionControl(DummyIAudioClient *client) : client(client) {
}
DummyIAudioSessionControl(const DummyIAudioSessionControl &) = delete;
DummyIAudioSessionControl &operator=(const DummyIAudioSessionControl &) = delete;
virtual ~DummyIAudioSessionControl() = default;
#pragma region IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IAudioSessionControl
HRESULT STDMETHODCALLTYPE GetState(AudioSessionState *pRetVal) override;
HRESULT STDMETHODCALLTYPE GetDisplayName(LPWSTR *pRetVal) override;
HRESULT STDMETHODCALLTYPE SetDisplayName(LPCWSTR Value, LPCGUID EventContext) override;
HRESULT STDMETHODCALLTYPE GetIconPath(LPWSTR *pRetVal) override;
HRESULT STDMETHODCALLTYPE SetIconPath(LPCWSTR Value, LPCGUID EventContext) override;
HRESULT STDMETHODCALLTYPE GetGroupingParam(GUID *pRetVal) override;
HRESULT STDMETHODCALLTYPE SetGroupingParam(LPCGUID Override, LPCGUID EventContext) override;
HRESULT STDMETHODCALLTYPE RegisterAudioSessionNotification(IAudioSessionEvents *NewNotifications) override;
HRESULT STDMETHODCALLTYPE UnregisterAudioSessionNotification(IAudioSessionEvents *NewNotifications) override;
#pragma endregion
DummyIAudioClient *const client;
std::atomic<ULONG> ref_cnt = 1;
std::wstring display_name = L"Dummy Audio Device";
std::wstring icon_path = L"";
GUID grouping_param = GUID_NULL;
};
+20 -20
View File
@@ -1,20 +1,20 @@
#include "util.h"
#include <audioclient.h>
#include "util/flags_helper.h"
#include "defs.h"
std::string stream_flags_str(DWORD flags) {
FLAGS_START(flags);
FLAG(flags, AUDCLNT_STREAMFLAGS_CROSSPROCESS);
FLAG(flags, AUDCLNT_STREAMFLAGS_LOOPBACK);
FLAG(flags, AUDCLNT_STREAMFLAGS_EVENTCALLBACK);
FLAG(flags, AUDCLNT_STREAMFLAGS_NOPERSIST);
FLAG(flags, AUDCLNT_STREAMFLAGS_RATEADJUST);
FLAG(flags, AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE);
FLAG(flags, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM);
FLAG(flags, AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
FLAGS_END(flags);
}
#include "util.h"
#include <audioclient.h>
#include "util/flags_helper.h"
#include "defs.h"
std::string stream_flags_str(DWORD flags) {
FLAGS_START(flags);
FLAG(flags, AUDCLNT_STREAMFLAGS_CROSSPROCESS);
FLAG(flags, AUDCLNT_STREAMFLAGS_LOOPBACK);
FLAG(flags, AUDCLNT_STREAMFLAGS_EVENTCALLBACK);
FLAG(flags, AUDCLNT_STREAMFLAGS_NOPERSIST);
FLAG(flags, AUDCLNT_STREAMFLAGS_RATEADJUST);
FLAG(flags, AUDCLNT_STREAMFLAGS_PREVENT_LOOPBACK_CAPTURE);
FLAG(flags, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM);
FLAG(flags, AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
FLAGS_END(flags);
}
+8 -8
View File
@@ -1,8 +1,8 @@
#pragma once
#include <string>
#include <windows.h>
#include <mmreg.h>
std::string stream_flags_str(DWORD flags);
#pragma once
#include <string>
#include <windows.h>
#include <mmreg.h>
std::string stream_flags_str(DWORD flags);
+29 -29
View File
@@ -1,29 +1,29 @@
#pragma once
#include <windows.h>
#include "hooks/audio/audio_private.h"
#include "util/logging.h"
#define PRINT_FAILED_RESULT(class_name, func_name, ret) \
if (AUDIO_LOG_HRESULT) { \
log_warning("audio::wasapi", "{}::{} failed, hr={}", class_name, func_name, FMT_HRESULT(ret)); \
}
#define SAFE_CALL(class_name, func_name, x) \
do { \
HRESULT __hr = (x); \
if (FAILED(__hr)) { \
PRINT_FAILED_RESULT(class_name, func_name, __hr); \
return __hr; \
} \
} while (0)
#define CHECK_RESULT(x) \
do { \
HRESULT __ret = (x); \
if (FAILED(__ret)) { \
PRINT_FAILED_RESULT(CLASS_NAME, __func__, __ret); \
} \
return __ret; \
} while (0)
#pragma once
#include <windows.h>
#include "hooks/audio/audio_private.h"
#include "util/logging.h"
#define PRINT_FAILED_RESULT(class_name, func_name, ret) \
if (AUDIO_LOG_HRESULT) { \
log_warning("audio::wasapi", "{}::{} failed, hr={}", class_name, func_name, FMT_HRESULT(ret)); \
}
#define SAFE_CALL(class_name, func_name, x) \
do { \
HRESULT __hr = (x); \
if (FAILED(__hr)) { \
PRINT_FAILED_RESULT(class_name, func_name, __hr); \
return __hr; \
} \
} while (0)
#define CHECK_RESULT(x) \
do { \
HRESULT __ret = (x); \
if (FAILED(__ret)) { \
PRINT_FAILED_RESULT(CLASS_NAME, __func__, __ret); \
} \
return __ret; \
} while (0)
+99 -99
View File
@@ -1,99 +1,99 @@
#include "buffer.h"
void convert_sample_type(
const size_t channels,
uint8_t *buffer,
const size_t source_size,
std::vector<double> &temp_buffer,
const SampleType source_type,
const SampleType dest_type)
{
// fast case: same type
if (source_type == dest_type) {
return;
}
const size_t source_sample_size = sample_type_size(source_type);
// number of samples *per channel*
const size_t num_samples = source_size / source_sample_size / channels;
// calculate the required size for the temporary buffer
// samples are converted to doubles and then converted to the target sample type
const size_t temp_size = num_samples * channels;
// resize temporary buffer if needed
if (temp_buffer.size() < temp_size) {
temp_buffer.resize(temp_size);
}
#define SAMPLE_LOOP(VAR) for (size_t VAR = 0; VAR < num_samples * channels; VAR++)
// converts to double in temporary buffer
#define CONVERT_LOOP(TY) \
do { \
const auto source = reinterpret_cast<TY *>(buffer); \
SAMPLE_LOOP(i) { \
temp_buffer[i] = convert_number_to_double<TY>(source[i]); \
} \
} while (0)
// converts double back to desired format
#define STORE_LOOP(TY) \
do { \
const auto dest = reinterpret_cast<TY *>(buffer); \
SAMPLE_LOOP(i) { \
dest[i] = convert_double_to_number<TY>(temp_buffer[i]); \
} \
} while (0)
// converts double to float
#define STORE_LOOP_FLOAT() \
do { \
const auto dest = reinterpret_cast<float *>(buffer); \
SAMPLE_LOOP(i) { \
dest[i] = static_cast<float>(temp_buffer[i]); \
} \
} while (0)
if (source_type == SampleType::SINT_16) {
CONVERT_LOOP(int16_t);
} else if (source_type == SampleType::SINT_24) {
const auto source = reinterpret_cast<int24_t *>(buffer);
SAMPLE_LOOP(i) {
temp_buffer[i] = convert_number_to_double<int32_t, int24_t>(source[i].as_int());
}
} else if (source_type == SampleType::SINT_32) {
CONVERT_LOOP(int32_t);
} else if (source_type == SampleType::FLOAT_32) {
const auto source = reinterpret_cast<float *>(buffer);
SAMPLE_LOOP(i) {
temp_buffer[i] = source[i];
}
} else if (source_type == SampleType::FLOAT_64) {
memcpy(temp_buffer.data(), buffer, temp_size);
} else {
return;
}
if (dest_type == SampleType::SINT_16) {
STORE_LOOP(int16_t);
} else if (dest_type == SampleType::SINT_24) {
STORE_LOOP(int24_t);
} else if (dest_type == SampleType::SINT_32) {
STORE_LOOP(int32_t);
} else if (dest_type == SampleType::FLOAT_32) {
STORE_LOOP_FLOAT();
} else if (dest_type == SampleType::FLOAT_64) {
memcpy(buffer, temp_buffer.data(), temp_size);
} else {
return;
}
#undef STORE_LOOP_FLOAT
#undef STORE_LOOP
#undef CONVERT_LOOP
#undef SAMPLE_LOOP
}
#include "buffer.h"
void convert_sample_type(
const size_t channels,
uint8_t *buffer,
const size_t source_size,
std::vector<double> &temp_buffer,
const SampleType source_type,
const SampleType dest_type)
{
// fast case: same type
if (source_type == dest_type) {
return;
}
const size_t source_sample_size = sample_type_size(source_type);
// number of samples *per channel*
const size_t num_samples = source_size / source_sample_size / channels;
// calculate the required size for the temporary buffer
// samples are converted to doubles and then converted to the target sample type
const size_t temp_size = num_samples * channels;
// resize temporary buffer if needed
if (temp_buffer.size() < temp_size) {
temp_buffer.resize(temp_size);
}
#define SAMPLE_LOOP(VAR) for (size_t VAR = 0; VAR < num_samples * channels; VAR++)
// converts to double in temporary buffer
#define CONVERT_LOOP(TY) \
do { \
const auto source = reinterpret_cast<TY *>(buffer); \
SAMPLE_LOOP(i) { \
temp_buffer[i] = convert_number_to_double<TY>(source[i]); \
} \
} while (0)
// converts double back to desired format
#define STORE_LOOP(TY) \
do { \
const auto dest = reinterpret_cast<TY *>(buffer); \
SAMPLE_LOOP(i) { \
dest[i] = convert_double_to_number<TY>(temp_buffer[i]); \
} \
} while (0)
// converts double to float
#define STORE_LOOP_FLOAT() \
do { \
const auto dest = reinterpret_cast<float *>(buffer); \
SAMPLE_LOOP(i) { \
dest[i] = static_cast<float>(temp_buffer[i]); \
} \
} while (0)
if (source_type == SampleType::SINT_16) {
CONVERT_LOOP(int16_t);
} else if (source_type == SampleType::SINT_24) {
const auto source = reinterpret_cast<int24_t *>(buffer);
SAMPLE_LOOP(i) {
temp_buffer[i] = convert_number_to_double<int32_t, int24_t>(source[i].as_int());
}
} else if (source_type == SampleType::SINT_32) {
CONVERT_LOOP(int32_t);
} else if (source_type == SampleType::FLOAT_32) {
const auto source = reinterpret_cast<float *>(buffer);
SAMPLE_LOOP(i) {
temp_buffer[i] = source[i];
}
} else if (source_type == SampleType::FLOAT_64) {
memcpy(temp_buffer.data(), buffer, temp_size);
} else {
return;
}
if (dest_type == SampleType::SINT_16) {
STORE_LOOP(int16_t);
} else if (dest_type == SampleType::SINT_24) {
STORE_LOOP(int24_t);
} else if (dest_type == SampleType::SINT_32) {
STORE_LOOP(int32_t);
} else if (dest_type == SampleType::FLOAT_32) {
STORE_LOOP_FLOAT();
} else if (dest_type == SampleType::FLOAT_64) {
memcpy(buffer, temp_buffer.data(), temp_size);
} else {
return;
}
#undef STORE_LOOP_FLOAT
#undef STORE_LOOP
#undef CONVERT_LOOP
#undef SAMPLE_LOOP
}
File diff suppressed because it is too large Load Diff
+153 -153
View File
@@ -1,153 +1,153 @@
#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <optional>
#include <thread>
#include "external/asio/asio.h"
#include "external/asio/iasiodrv.h"
#include "external/readerwriterqueue/readerwriterqueue.h"
#include "hooks/audio/audio_private.h"
#include "hooks/audio/buffer.h"
#include "backend.h"
struct AsioBackend;
extern AsioBackend *ASIO_BACKEND;
struct BufferEntry {
BYTE *buffer;
size_t length;
size_t read;
};
struct AsioInstanceInfo {
long inputs = 0;
long outputs = 0;
long buffer_min_size = 0;
long buffer_max_size = 0;
long buffer_preferred_size = 0;
long buffer_granularity = 0;
long input_latency = 0;
long output_latency = 0;
};
struct AsioBackend final : AudioBackend {
public:
explicit AsioBackend();
~AsioBackend() final;
const WAVEFORMATEXTENSIBLE &format() const noexcept override;
HRESULT on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) noexcept override;
HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override;
HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override;
HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept override;
HRESULT on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) noexcept override;
HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override;
HRESULT on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period) noexcept override;
HRESULT on_start() noexcept override;
HRESULT on_stop() noexcept override;
HRESULT on_set_event_handle(HANDLE *event_handle) noexcept override;
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **pp_data) noexcept override;
HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) noexcept override;
// for overlay
inline const AsioDriverInfo &driver_info() const noexcept {
return this->driver_info_;
}
inline const std::vector<AsioChannelInfo> &channel_info() const noexcept {
return this->asio_channel_info_;
}
inline const AsioInstanceInfo &asio_info() const noexcept {
return this->asio_info_;
}
void open_control_panel();
std::atomic<uint32_t> queued_frames = 0;
std::atomic<size_t> queued_bytes = 0;
private:
using AsioFunction = std::function<AsioError()>;
enum class AsioThreadState {
Closed,
Failed,
Running,
ShuttingDown,
};
struct AsioThreadMessage {
AsioFunction fn;
bool result_needed;
};
void set_thread_state(AsioThreadState state);
bool load_driver();
bool update_driver_info();
bool update_latency();
bool set_initial_format(WAVEFORMATEXTENSIBLE &target);
bool init();
bool unload_driver();
void reset();
AsioError run_on_asio_thread(AsioFunction fn, bool result_needed = true);
// ASIO callbacks
static void buffer_switch(long double_buffer_index, AsioBool direct_process);
static void sample_rate_did_change(AsioSampleRate sample_rate);
static long asio_message(long selector, long value, void *message, double *opt);
// helper methods
static bool is_supported_subformat(const WAVEFORMATEXTENSIBLE &format_ex) noexcept;
REFERENCE_TIME compute_ref_time() const;
REFERENCE_TIME compute_latency_ref_time() const;
std::thread asio_thread;
std::atomic_bool asio_thread_initialized = false;
std::mutex asio_thread_state_lock;
// TODO: use `std::atomic<T>::wait` when stabilized in MSVC
std::condition_variable asio_thread_state_cv;
std::atomic<AsioThreadState> asio_thread_state = AsioThreadState::Closed;
moodycamel::BlockingReaderWriterQueue<AsioThreadMessage> asio_msg_queue_func;
moodycamel::BlockingReaderWriterQueue<AsioError> asio_msg_queue_result;
moodycamel::ReaderWriterQueue<BufferEntry> queue;
std::optional<HANDLE> relay_handle = std::nullopt;
IAsio *asio_driver = nullptr;
AsioCallbacks asio_callbacks {};
AsioDriverInfo driver_info_ {};
AsioInstanceInfo asio_info_;
std::vector<AsioChannelInfo> asio_channel_info_;
std::vector<AsioBufferInfo> asio_buffers;
SampleType asio_sample_type = SampleType::UNSUPPORTED;
std::atomic_bool started = false;
WAVEFORMATEXTENSIBLE format_ {};
WAVEFORMATEXTENSIBLE last_checked_format {};
//std::vector<BYTE> last_sound_buffer;
std::vector<double> conversion_sound_buffer;
BYTE *active_sound_buffer = nullptr;
};
#pragma once
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <optional>
#include <thread>
#include "external/asio/asio.h"
#include "external/asio/iasiodrv.h"
#include "external/readerwriterqueue/readerwriterqueue.h"
#include "hooks/audio/audio_private.h"
#include "hooks/audio/buffer.h"
#include "backend.h"
struct AsioBackend;
extern AsioBackend *ASIO_BACKEND;
struct BufferEntry {
BYTE *buffer;
size_t length;
size_t read;
};
struct AsioInstanceInfo {
long inputs = 0;
long outputs = 0;
long buffer_min_size = 0;
long buffer_max_size = 0;
long buffer_preferred_size = 0;
long buffer_granularity = 0;
long input_latency = 0;
long output_latency = 0;
};
struct AsioBackend final : AudioBackend {
public:
explicit AsioBackend();
~AsioBackend() final;
const WAVEFORMATEXTENSIBLE &format() const noexcept override;
HRESULT on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) noexcept override;
HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override;
HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override;
HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept override;
HRESULT on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) noexcept override;
HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override;
HRESULT on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period) noexcept override;
HRESULT on_start() noexcept override;
HRESULT on_stop() noexcept override;
HRESULT on_set_event_handle(HANDLE *event_handle) noexcept override;
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **pp_data) noexcept override;
HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) noexcept override;
// for overlay
inline const AsioDriverInfo &driver_info() const noexcept {
return this->driver_info_;
}
inline const std::vector<AsioChannelInfo> &channel_info() const noexcept {
return this->asio_channel_info_;
}
inline const AsioInstanceInfo &asio_info() const noexcept {
return this->asio_info_;
}
void open_control_panel();
std::atomic<uint32_t> queued_frames = 0;
std::atomic<size_t> queued_bytes = 0;
private:
using AsioFunction = std::function<AsioError()>;
enum class AsioThreadState {
Closed,
Failed,
Running,
ShuttingDown,
};
struct AsioThreadMessage {
AsioFunction fn;
bool result_needed;
};
void set_thread_state(AsioThreadState state);
bool load_driver();
bool update_driver_info();
bool update_latency();
bool set_initial_format(WAVEFORMATEXTENSIBLE &target);
bool init();
bool unload_driver();
void reset();
AsioError run_on_asio_thread(AsioFunction fn, bool result_needed = true);
// ASIO callbacks
static void buffer_switch(long double_buffer_index, AsioBool direct_process);
static void sample_rate_did_change(AsioSampleRate sample_rate);
static long asio_message(long selector, long value, void *message, double *opt);
// helper methods
static bool is_supported_subformat(const WAVEFORMATEXTENSIBLE &format_ex) noexcept;
REFERENCE_TIME compute_ref_time() const;
REFERENCE_TIME compute_latency_ref_time() const;
std::thread asio_thread;
std::atomic_bool asio_thread_initialized = false;
std::mutex asio_thread_state_lock;
// TODO: use `std::atomic<T>::wait` when stabilized in MSVC
std::condition_variable asio_thread_state_cv;
std::atomic<AsioThreadState> asio_thread_state = AsioThreadState::Closed;
moodycamel::BlockingReaderWriterQueue<AsioThreadMessage> asio_msg_queue_func;
moodycamel::BlockingReaderWriterQueue<AsioError> asio_msg_queue_result;
moodycamel::ReaderWriterQueue<BufferEntry> queue;
std::optional<HANDLE> relay_handle = std::nullopt;
IAsio *asio_driver = nullptr;
AsioCallbacks asio_callbacks {};
AsioDriverInfo driver_info_ {};
AsioInstanceInfo asio_info_;
std::vector<AsioChannelInfo> asio_channel_info_;
std::vector<AsioBufferInfo> asio_buffers;
SampleType asio_sample_type = SampleType::UNSUPPORTED;
std::atomic_bool started = false;
WAVEFORMATEXTENSIBLE format_ {};
WAVEFORMATEXTENSIBLE last_checked_format {};
//std::vector<BYTE> last_sound_buffer;
std::vector<double> conversion_sound_buffer;
BYTE *active_sound_buffer = nullptr;
};
+55 -55
View File
@@ -1,55 +1,55 @@
#pragma once
#include <cstdint>
#include <optional>
#include <windows.h>
#include <audioclient.h>
#include <ksmedia.h>
struct WrappedIAudioClient;
struct AudioBackend {
public:
virtual ~AudioBackend() = default;
[[nodiscard]] virtual const WAVEFORMATEXTENSIBLE &format() const noexcept = 0;
#pragma region IAudioClient
virtual HRESULT on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) = 0;
virtual HRESULT on_get_buffer_size(uint32_t *buffer_frames) = 0;
virtual HRESULT on_get_stream_latency(REFERENCE_TIME *latency) = 0;
virtual HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) = 0;
virtual HRESULT on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) = 0;
virtual HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) = 0;
virtual HRESULT on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period) = 0;
virtual HRESULT on_start() = 0;
virtual HRESULT on_stop() = 0;
virtual HRESULT on_set_event_handle(HANDLE *event_handle) = 0;
#pragma endregion
#pragma region IAudioRenderClient
virtual HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) = 0;
virtual HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) = 0;
#pragma endregion
};
#pragma once
#include <cstdint>
#include <optional>
#include <windows.h>
#include <audioclient.h>
#include <ksmedia.h>
struct WrappedIAudioClient;
struct AudioBackend {
public:
virtual ~AudioBackend() = default;
[[nodiscard]] virtual const WAVEFORMATEXTENSIBLE &format() const noexcept = 0;
#pragma region IAudioClient
virtual HRESULT on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) = 0;
virtual HRESULT on_get_buffer_size(uint32_t *buffer_frames) = 0;
virtual HRESULT on_get_stream_latency(REFERENCE_TIME *latency) = 0;
virtual HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) = 0;
virtual HRESULT on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) = 0;
virtual HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) = 0;
virtual HRESULT on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period) = 0;
virtual HRESULT on_start() = 0;
virtual HRESULT on_stop() = 0;
virtual HRESULT on_set_event_handle(HANDLE *event_handle) = 0;
#pragma endregion
#pragma region IAudioRenderClient
virtual HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) = 0;
virtual HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) = 0;
#pragma endregion
};
+224 -224
View File
@@ -1,224 +1,224 @@
#include "wave_out.h"
#include "hooks/audio/audio.h"
#include "hooks/audio/backends/wasapi/audio_client.h"
#include "hooks/audio/backends/wasapi/defs.h"
static REFERENCE_TIME WASAPI_TARGET_REFTIME = TARGET_REFTIME;
HRESULT WaveOutBackend::init(uint32_t buffer_size) {
auto &format = hooks::audio::FORMAT.Format;
format.wFormatTag = WAVE_FORMAT_PCM;
log_info("audio::wave_out", "initializing waveOut backend with {} channels, {} Hz, {}-bit",
format.nChannels,
format.nSamplesPerSec,
format.wBitsPerSample);
log_info("audio::wave_out", "... nBlockAlign : {} bytes", format.nBlockAlign);
log_info("audio::wave_out", "... nAvgBytesPerSec : {} bytes", format.nAvgBytesPerSec);
log_info("audio::wave_out", "... buffer reftime : {} ms", WASAPI_TARGET_REFTIME / 10000.f);
log_info("audio::wave_out", "... buffer count : {} buffers", _countof(this->hdrs));
MMRESULT ret = waveOutOpen(
&this->handle,
WAVE_MAPPER,
reinterpret_cast<const WAVEFORMATEX *>(&hooks::audio::FORMAT.Format),
reinterpret_cast<DWORD_PTR>(this->dispatcher_event),
reinterpret_cast<DWORD_PTR>(nullptr),
CALLBACK_EVENT);
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to initialize waveOut backend, hr={:#08x}",
static_cast<unsigned>(ret));
return static_cast<HRESULT>(ret);
}
// initialize buffers
for (auto &hdr : this->hdrs) {
memset(&hdr, 0, sizeof(hdr));
hdr.lpData = new char[buffer_size] {};
hdr.dwBufferLength = buffer_size;
hdr.dwBytesRecorded = 0;
hdr.dwUser = 0;
hdr.dwFlags = 0;
hdr.dwLoops = 0;
hdr.lpNext = nullptr;
ret = waveOutPrepareHeader(this->handle, &hdr, sizeof(hdr));
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to prepare waveOut header, hr=0x{:08x}",
static_cast<unsigned>(ret));
return static_cast<HRESULT>(ret);
}
ret = waveOutWrite(this->handle, &hdr, sizeof(hdr));
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to write waveOut header, hr=0x{:08x}",
static_cast<unsigned>(ret));
return static_cast<HRESULT>(ret);
}
}
// mark as initialized
this->initialized = true;
return S_OK;
}
const WAVEFORMATEXTENSIBLE &WaveOutBackend::format() const noexcept {
return hooks::audio::FORMAT;
}
HRESULT WaveOutBackend::on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) noexcept
{
*ShareMode = AUDCLNT_SHAREMODE_SHARED;
*StreamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
AUDCLNT_STREAMFLAGS_RATEADJUST |
AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
*hnsBufferDuration = WASAPI_TARGET_REFTIME;
*hnsPeriodicity = WASAPI_TARGET_REFTIME;
// this backend only supports stereo audio
if (pFormat->nChannels > 2) {
return AUDCLNT_E_UNSUPPORTED_FORMAT;
}
return S_OK;
}
HRESULT WaveOutBackend::on_get_buffer_size(uint32_t *buffer_frames) noexcept {
*buffer_frames = _countof(this->hdrs);
return S_OK;
}
HRESULT WaveOutBackend::on_get_stream_latency(REFERENCE_TIME *latency) noexcept {
*latency = WASAPI_TARGET_REFTIME;
return S_OK;
}
HRESULT WaveOutBackend::on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept {
size_t queued_bytes = 0;
for (auto &hdr : this->hdrs) {
if (hdr.dwFlags & WHDR_DONE) {
queued_bytes += static_cast<unsigned>(hdr.dwBufferLength);
}
}
auto frames = static_cast<uint32_t>(queued_bytes / hooks::audio::FORMAT.Format.nBlockAlign);
//log_info("audio::wave_out", "queued_bytes = {}, frames = {}", queued_bytes, frames);
padding_frames = frames;
return S_OK;
}
HRESULT WaveOutBackend::on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) noexcept
{
// always support 44.1 kHz, stereo, 16-bits per channel with custom backends
if (*ShareMode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
pFormat->nChannels == 2 &&
pFormat->nSamplesPerSec == 44100 &&
pFormat->wBitsPerSample == 16)
{
return S_OK;
}
return AUDCLNT_E_UNSUPPORTED_FORMAT;
}
HRESULT WaveOutBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept {
return E_NOTIMPL;
}
HRESULT WaveOutBackend::on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period)
{
*default_device_period = WASAPI_TARGET_REFTIME;
*minimum_device_period = WASAPI_TARGET_REFTIME;
return S_OK;
}
HRESULT WaveOutBackend::on_start() noexcept {
return S_OK;
}
HRESULT WaveOutBackend::on_stop() noexcept {
return S_OK;
}
HRESULT WaveOutBackend::on_set_event_handle(HANDLE *event_handle) {
this->relay_event = *event_handle;
this->dispatcher_event = CreateEvent(nullptr, true, false, nullptr);
*event_handle = this->dispatcher_event;
return S_OK;
}
HRESULT WaveOutBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) {
auto buffer_size = hooks::audio::FORMAT.Format.nBlockAlign * num_frames_requested;
if (!this->initialized) {
this->init(buffer_size);
}
// wait for a free slot
WaitForSingleObject(this->dispatcher_event, INFINITE);
// allocate temporary sound buffer
this->active_sound_buffer = reinterpret_cast<BYTE *>(CoTaskMemAlloc(buffer_size));
// hand the buffer to the callee
*ppData = this->active_sound_buffer;
return S_OK;
}
HRESULT WaveOutBackend::on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) {
bool written = false;
// reset the dispatcher event
ResetEvent(this->dispatcher_event);
while (!written) {
for (WAVEHDR &hdr : this->hdrs) {
if (hdr.dwFlags & WHDR_DONE) {
memcpy(hdr.lpData, this->active_sound_buffer, hdr.dwBufferLength);
// write the data to the device now
MMRESULT ret = waveOutWrite(this->handle, &hdr, sizeof(hdr));
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to write waveOut data, hr={:#08x}",
static_cast<unsigned>(ret));
}
written = true;
break;
}
}
// avoid pegging the CPU
if (!written) {
Sleep(1);
}
}
// free temporary sound buffer
CoTaskMemFree(this->active_sound_buffer);
this->active_sound_buffer = nullptr;
// trigger game audio callback
SetEvent(this->relay_event);
return S_OK;
}
#include "wave_out.h"
#include "hooks/audio/audio.h"
#include "hooks/audio/backends/wasapi/audio_client.h"
#include "hooks/audio/backends/wasapi/defs.h"
static REFERENCE_TIME WASAPI_TARGET_REFTIME = TARGET_REFTIME;
HRESULT WaveOutBackend::init(uint32_t buffer_size) {
auto &format = hooks::audio::FORMAT.Format;
format.wFormatTag = WAVE_FORMAT_PCM;
log_info("audio::wave_out", "initializing waveOut backend with {} channels, {} Hz, {}-bit",
format.nChannels,
format.nSamplesPerSec,
format.wBitsPerSample);
log_info("audio::wave_out", "... nBlockAlign : {} bytes", format.nBlockAlign);
log_info("audio::wave_out", "... nAvgBytesPerSec : {} bytes", format.nAvgBytesPerSec);
log_info("audio::wave_out", "... buffer reftime : {} ms", WASAPI_TARGET_REFTIME / 10000.f);
log_info("audio::wave_out", "... buffer count : {} buffers", _countof(this->hdrs));
MMRESULT ret = waveOutOpen(
&this->handle,
WAVE_MAPPER,
reinterpret_cast<const WAVEFORMATEX *>(&hooks::audio::FORMAT.Format),
reinterpret_cast<DWORD_PTR>(this->dispatcher_event),
reinterpret_cast<DWORD_PTR>(nullptr),
CALLBACK_EVENT);
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to initialize waveOut backend, hr={:#08x}",
static_cast<unsigned>(ret));
return static_cast<HRESULT>(ret);
}
// initialize buffers
for (auto &hdr : this->hdrs) {
memset(&hdr, 0, sizeof(hdr));
hdr.lpData = new char[buffer_size] {};
hdr.dwBufferLength = buffer_size;
hdr.dwBytesRecorded = 0;
hdr.dwUser = 0;
hdr.dwFlags = 0;
hdr.dwLoops = 0;
hdr.lpNext = nullptr;
ret = waveOutPrepareHeader(this->handle, &hdr, sizeof(hdr));
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to prepare waveOut header, hr=0x{:08x}",
static_cast<unsigned>(ret));
return static_cast<HRESULT>(ret);
}
ret = waveOutWrite(this->handle, &hdr, sizeof(hdr));
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to write waveOut header, hr=0x{:08x}",
static_cast<unsigned>(ret));
return static_cast<HRESULT>(ret);
}
}
// mark as initialized
this->initialized = true;
return S_OK;
}
const WAVEFORMATEXTENSIBLE &WaveOutBackend::format() const noexcept {
return hooks::audio::FORMAT;
}
HRESULT WaveOutBackend::on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) noexcept
{
*ShareMode = AUDCLNT_SHAREMODE_SHARED;
*StreamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
AUDCLNT_STREAMFLAGS_RATEADJUST |
AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
*hnsBufferDuration = WASAPI_TARGET_REFTIME;
*hnsPeriodicity = WASAPI_TARGET_REFTIME;
// this backend only supports stereo audio
if (pFormat->nChannels > 2) {
return AUDCLNT_E_UNSUPPORTED_FORMAT;
}
return S_OK;
}
HRESULT WaveOutBackend::on_get_buffer_size(uint32_t *buffer_frames) noexcept {
*buffer_frames = _countof(this->hdrs);
return S_OK;
}
HRESULT WaveOutBackend::on_get_stream_latency(REFERENCE_TIME *latency) noexcept {
*latency = WASAPI_TARGET_REFTIME;
return S_OK;
}
HRESULT WaveOutBackend::on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept {
size_t queued_bytes = 0;
for (auto &hdr : this->hdrs) {
if (hdr.dwFlags & WHDR_DONE) {
queued_bytes += static_cast<unsigned>(hdr.dwBufferLength);
}
}
auto frames = static_cast<uint32_t>(queued_bytes / hooks::audio::FORMAT.Format.nBlockAlign);
//log_info("audio::wave_out", "queued_bytes = {}, frames = {}", queued_bytes, frames);
padding_frames = frames;
return S_OK;
}
HRESULT WaveOutBackend::on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) noexcept
{
// always support 44.1 kHz, stereo, 16-bits per channel with custom backends
if (*ShareMode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
pFormat->nChannels == 2 &&
pFormat->nSamplesPerSec == 44100 &&
pFormat->wBitsPerSample == 16)
{
return S_OK;
}
return AUDCLNT_E_UNSUPPORTED_FORMAT;
}
HRESULT WaveOutBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept {
return E_NOTIMPL;
}
HRESULT WaveOutBackend::on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period)
{
*default_device_period = WASAPI_TARGET_REFTIME;
*minimum_device_period = WASAPI_TARGET_REFTIME;
return S_OK;
}
HRESULT WaveOutBackend::on_start() noexcept {
return S_OK;
}
HRESULT WaveOutBackend::on_stop() noexcept {
return S_OK;
}
HRESULT WaveOutBackend::on_set_event_handle(HANDLE *event_handle) {
this->relay_event = *event_handle;
this->dispatcher_event = CreateEvent(nullptr, true, false, nullptr);
*event_handle = this->dispatcher_event;
return S_OK;
}
HRESULT WaveOutBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) {
auto buffer_size = hooks::audio::FORMAT.Format.nBlockAlign * num_frames_requested;
if (!this->initialized) {
this->init(buffer_size);
}
// wait for a free slot
WaitForSingleObject(this->dispatcher_event, INFINITE);
// allocate temporary sound buffer
this->active_sound_buffer = reinterpret_cast<BYTE *>(CoTaskMemAlloc(buffer_size));
// hand the buffer to the callee
*ppData = this->active_sound_buffer;
return S_OK;
}
HRESULT WaveOutBackend::on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) {
bool written = false;
// reset the dispatcher event
ResetEvent(this->dispatcher_event);
while (!written) {
for (WAVEHDR &hdr : this->hdrs) {
if (hdr.dwFlags & WHDR_DONE) {
memcpy(hdr.lpData, this->active_sound_buffer, hdr.dwBufferLength);
// write the data to the device now
MMRESULT ret = waveOutWrite(this->handle, &hdr, sizeof(hdr));
if (ret != MMSYSERR_NOERROR) {
log_warning("audio::wave_out", "failed to write waveOut data, hr={:#08x}",
static_cast<unsigned>(ret));
}
written = true;
break;
}
}
// avoid pegging the CPU
if (!written) {
Sleep(1);
}
}
// free temporary sound buffer
CoTaskMemFree(this->active_sound_buffer);
this->active_sound_buffer = nullptr;
// trigger game audio callback
SetEvent(this->relay_event);
return S_OK;
}
+58 -58
View File
@@ -1,58 +1,58 @@
#pragma once
#include <mmdeviceapi.h>
#include <mmsystem.h>
#include "backend.h"
#define WASAPI_BUFFER_COUNT 3
#define TARGET_REFTIME (100000) // 10 ms
struct WaveOutBackend final : AudioBackend {
public:
~WaveOutBackend() final = default;
HRESULT init(uint32_t buffer_size);
const WAVEFORMATEXTENSIBLE &format() const noexcept override;
HRESULT on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) noexcept override;
HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override;
HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override;
HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept override;
HRESULT on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) noexcept override;
HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override;
HRESULT on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period) override;
HRESULT on_start() noexcept override;
HRESULT on_stop() noexcept override;
HRESULT on_set_event_handle(HANDLE *event_handle) override;
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) override;
HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) override;
private:
WrappedIAudioClient *client;
bool initialized = false;
HANDLE relay_event = nullptr;
HANDLE dispatcher_event = nullptr;
HWAVEOUT handle = nullptr;
WAVEHDR hdrs[WASAPI_BUFFER_COUNT] {};
BYTE *active_sound_buffer = nullptr;
};
#pragma once
#include <mmdeviceapi.h>
#include <mmsystem.h>
#include "backend.h"
#define WASAPI_BUFFER_COUNT 3
#define TARGET_REFTIME (100000) // 10 ms
struct WaveOutBackend final : AudioBackend {
public:
~WaveOutBackend() final = default;
HRESULT init(uint32_t buffer_size);
const WAVEFORMATEXTENSIBLE &format() const noexcept override;
HRESULT on_initialize(
AUDCLNT_SHAREMODE *ShareMode,
DWORD *StreamFlags,
REFERENCE_TIME *hnsBufferDuration,
REFERENCE_TIME *hnsPeriodicity,
const WAVEFORMATEX *pFormat,
LPCGUID AudioSessionGuid) noexcept override;
HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override;
HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override;
HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept override;
HRESULT on_is_format_supported(
AUDCLNT_SHAREMODE *ShareMode,
const WAVEFORMATEX *pFormat,
WAVEFORMATEX **ppClosestMatch) noexcept override;
HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override;
HRESULT on_get_device_period(
REFERENCE_TIME *default_device_period,
REFERENCE_TIME *minimum_device_period) override;
HRESULT on_start() noexcept override;
HRESULT on_stop() noexcept override;
HRESULT on_set_event_handle(HANDLE *event_handle) override;
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) override;
HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) override;
private:
WrappedIAudioClient *client;
bool initialized = false;
HANDLE relay_event = nullptr;
HANDLE dispatcher_event = nullptr;
HWAVEOUT handle = nullptr;
WAVEHDR hdrs[WASAPI_BUFFER_COUNT] {};
BYTE *active_sound_buffer = nullptr;
};
+80 -80
View File
@@ -1,80 +1,80 @@
#include "util.h"
#include <ks.h>
#include <ksmedia.h>
#include "util/flags_helper.h"
#include "util/logging.h"
#include "util/utils.h"
std::string channel_mask_str(DWORD channel_mask) {
FLAGS_START(channel_mask);
FLAG(channel_mask, SPEAKER_FRONT_LEFT);
FLAG(channel_mask, SPEAKER_FRONT_RIGHT);
FLAG(channel_mask, SPEAKER_FRONT_CENTER);
FLAG(channel_mask, SPEAKER_LOW_FREQUENCY);
FLAG(channel_mask, SPEAKER_BACK_LEFT);
FLAG(channel_mask, SPEAKER_BACK_RIGHT);
FLAG(channel_mask, SPEAKER_FRONT_LEFT_OF_CENTER);
FLAG(channel_mask, SPEAKER_FRONT_RIGHT_OF_CENTER);
FLAG(channel_mask, SPEAKER_BACK_CENTER);
FLAG(channel_mask, SPEAKER_SIDE_LEFT);
FLAG(channel_mask, SPEAKER_SIDE_RIGHT);
FLAG(channel_mask, SPEAKER_TOP_CENTER);
FLAG(channel_mask, SPEAKER_TOP_FRONT_LEFT);
FLAG(channel_mask, SPEAKER_TOP_FRONT_CENTER);
FLAG(channel_mask, SPEAKER_TOP_FRONT_RIGHT);
FLAG(channel_mask, SPEAKER_TOP_BACK_LEFT);
FLAG(channel_mask, SPEAKER_TOP_BACK_CENTER);
FLAG(channel_mask, SPEAKER_TOP_BACK_RIGHT);
FLAGS_END(channel_mask);
}
std::string share_mode_str(AUDCLNT_SHAREMODE share_mode) {
switch (share_mode) {
ENUM_VARIANT(AUDCLNT_SHAREMODE_SHARED);
ENUM_VARIANT(AUDCLNT_SHAREMODE_EXCLUSIVE);
default:
return fmt::format("ShareMode(0x{:08x})", share_mode);
}
}
void copy_wave_format(WAVEFORMATEXTENSIBLE *destination, const WAVEFORMATEX *source) {
if (source->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
memcpy(destination, source, sizeof(WAVEFORMATEXTENSIBLE));
} else {
memcpy(destination, source, sizeof(WAVEFORMATEX));
}
}
void print_format(const WAVEFORMATEX *pFormat) {
log_info("audio", "Wave Format:");
// format specific
if (pFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
auto format = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(pFormat);
log_info("audio", "... SubFormat : {}", guid2s(format->SubFormat));
} else {
log_info("audio", "... wFormatTag : {}", pFormat->wFormatTag);
}
// generic
log_info("audio", "... nChannels : {}", pFormat->nChannels);
log_info("audio", "... nSamplesPerSec : {}", pFormat->nSamplesPerSec);
log_info("audio", "... nAvgBytesPerSec : {}", pFormat->nAvgBytesPerSec);
log_info("audio", "... nBlockAlign : {}", pFormat->nBlockAlign);
log_info("audio", "... wBitsPerSample : {}", pFormat->wBitsPerSample);
// format specific
if (pFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
auto format = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(pFormat);
if (pFormat->wBitsPerSample == 0) {
log_info("audio", "... wSamplesPerBlock : {}", format->Samples.wSamplesPerBlock);
} else {
log_info("audio", "... wValidBitsPerSample : {}", format->Samples.wValidBitsPerSample);
}
log_info("audio", "... dwChannelMask : {}", channel_mask_str(format->dwChannelMask));
}
}
#include "util.h"
#include <ks.h>
#include <ksmedia.h>
#include "util/flags_helper.h"
#include "util/logging.h"
#include "util/utils.h"
std::string channel_mask_str(DWORD channel_mask) {
FLAGS_START(channel_mask);
FLAG(channel_mask, SPEAKER_FRONT_LEFT);
FLAG(channel_mask, SPEAKER_FRONT_RIGHT);
FLAG(channel_mask, SPEAKER_FRONT_CENTER);
FLAG(channel_mask, SPEAKER_LOW_FREQUENCY);
FLAG(channel_mask, SPEAKER_BACK_LEFT);
FLAG(channel_mask, SPEAKER_BACK_RIGHT);
FLAG(channel_mask, SPEAKER_FRONT_LEFT_OF_CENTER);
FLAG(channel_mask, SPEAKER_FRONT_RIGHT_OF_CENTER);
FLAG(channel_mask, SPEAKER_BACK_CENTER);
FLAG(channel_mask, SPEAKER_SIDE_LEFT);
FLAG(channel_mask, SPEAKER_SIDE_RIGHT);
FLAG(channel_mask, SPEAKER_TOP_CENTER);
FLAG(channel_mask, SPEAKER_TOP_FRONT_LEFT);
FLAG(channel_mask, SPEAKER_TOP_FRONT_CENTER);
FLAG(channel_mask, SPEAKER_TOP_FRONT_RIGHT);
FLAG(channel_mask, SPEAKER_TOP_BACK_LEFT);
FLAG(channel_mask, SPEAKER_TOP_BACK_CENTER);
FLAG(channel_mask, SPEAKER_TOP_BACK_RIGHT);
FLAGS_END(channel_mask);
}
std::string share_mode_str(AUDCLNT_SHAREMODE share_mode) {
switch (share_mode) {
ENUM_VARIANT(AUDCLNT_SHAREMODE_SHARED);
ENUM_VARIANT(AUDCLNT_SHAREMODE_EXCLUSIVE);
default:
return fmt::format("ShareMode(0x{:08x})", share_mode);
}
}
void copy_wave_format(WAVEFORMATEXTENSIBLE *destination, const WAVEFORMATEX *source) {
if (source->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
memcpy(destination, source, sizeof(WAVEFORMATEXTENSIBLE));
} else {
memcpy(destination, source, sizeof(WAVEFORMATEX));
}
}
void print_format(const WAVEFORMATEX *pFormat) {
log_info("audio", "Wave Format:");
// format specific
if (pFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
auto format = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(pFormat);
log_info("audio", "... SubFormat : {}", guid2s(format->SubFormat));
} else {
log_info("audio", "... wFormatTag : {}", pFormat->wFormatTag);
}
// generic
log_info("audio", "... nChannels : {}", pFormat->nChannels);
log_info("audio", "... nSamplesPerSec : {}", pFormat->nSamplesPerSec);
log_info("audio", "... nAvgBytesPerSec : {}", pFormat->nAvgBytesPerSec);
log_info("audio", "... nBlockAlign : {}", pFormat->nBlockAlign);
log_info("audio", "... wBitsPerSample : {}", pFormat->wBitsPerSample);
// format specific
if (pFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
auto format = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(pFormat);
if (pFormat->wBitsPerSample == 0) {
log_info("audio", "... wSamplesPerBlock : {}", format->Samples.wSamplesPerBlock);
} else {
log_info("audio", "... wValidBitsPerSample : {}", format->Samples.wValidBitsPerSample);
}
log_info("audio", "... dwChannelMask : {}", channel_mask_str(format->dwChannelMask));
}
}
+12 -12
View File
@@ -1,12 +1,12 @@
#pragma once
#include <string>
#include <windows.h>
#include <audiosessiontypes.h>
#include <mmreg.h>
std::string channel_mask_str(DWORD channel_mask);
std::string share_mode_str(AUDCLNT_SHAREMODE share_mode);
void copy_wave_format(WAVEFORMATEXTENSIBLE *destination, const WAVEFORMATEX *source);
void print_format(const WAVEFORMATEX *pFormat);
#pragma once
#include <string>
#include <windows.h>
#include <audiosessiontypes.h>
#include <mmreg.h>
std::string channel_mask_str(DWORD channel_mask);
std::string share_mode_str(AUDCLNT_SHAREMODE share_mode);
void copy_wave_format(WAVEFORMATEXTENSIBLE *destination, const WAVEFORMATEX *source);
void print_format(const WAVEFORMATEX *pFormat);
+293 -293
View File
@@ -1,293 +1,293 @@
#include "avshook.h"
#include <optional>
#include "avs/core.h"
#include "avs/ea3.h"
#include "avs/game.h"
#include "external/layeredfs/hook.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/logging.h"
#include "util/utils.h"
#include "external/layeredfs/hook.h"
#ifdef min
#undef min
#endif
static bool FAKE_FILE_OPEN = false;
static bool ROM_FILE_OPEN = false;
static const char *ROM_FILE_PATH = nullptr;
static const char *ROM_FILE_CONTENTS = nullptr;
namespace hooks::avs::config {
bool DISABLE_VFS_DRIVE_REDIRECTION = false;
bool LOG = false;
};
using namespace hooks::avs;
#define WRAP_DEBUG_FMT(format, ...) \
if (config::LOG) { \
log_misc("avshook", "{}: " format " = 0x{:x}", __FUNCTION__, __VA_ARGS__, static_cast<unsigned>(value)); \
}
#define AVS_HOOK(f) hook_function(::avs::core::IMPORT_NAMES.f, #f, &::avs::core::f, f)
template<typename T>
static void hook_function(const char *source_name, const char *target_name, T **source, T *target) {
if (!detour::trampoline_try(avs::core::DLL_NAME.c_str(), source_name, target, source)) {
log_warning("avshook", "could not hook {} ({})", target_name, source_name);
}
}
static inline bool is_fake_fd(avs::core::avs_file_t fd) {
return FAKE_FILE_OPEN && fd == 1337;
}
static bool is_dest_file(const char *name) {
static std::string path_dest = fmt::format("/dev/raw/{}.dest", avs::game::DEST[0]);
static std::string path_bin = fmt::format("/dev/raw/{}.bin", avs::game::DEST[0]);
return !_stricmp(name, path_dest.c_str()) || !_stricmp(name, path_bin.c_str());
}
static bool is_dest_file(const char *name, uint16_t mode) {
return mode == 1 && is_dest_file(name);
}
static bool is_dest_spec_ea3_config(const char *name) {
static std::string path = fmt::format("/prop/ea3-config-{}{}.xml", avs::game::DEST[0], avs::game::SPEC[0]);
return !_stricmp(name, path.c_str());
}
static bool is_rom_file(const char *name) {
return ROM_FILE_PATH && _stricmp(name, ROM_FILE_PATH) == 0;
}
static bool is_spam_file(const char *file) {
static const char *spam_prefixes[] = {
"/mnt/bm2d/ngp",
"/afp",
"/dev/nvram/pm_eco.xml",
"/dev/nvram/pm_gamesys.xml",
"/dev/nvram/pm_clock.xml",
};
for (auto &spam : spam_prefixes) {
if (string_begins_with(file, spam)) {
return true;
}
}
return false;
}
static int avs_fs_fstat(avs::core::avs_file_t fd, struct avs::core::avs_stat *st) {
if (is_fake_fd(fd) && ROM_FILE_OPEN) {
if (st) {
st->filesize = static_cast<uint32_t>(strlen(ROM_FILE_CONTENTS));
st->padding.st_dev = 0;
}
return 1;
}
return avs::core::avs_fs_fstat(fd, st);
}
static int avs_fs_lstat(const char *name, struct avs::core::avs_stat *st) {
if (name == nullptr) {
return avs::core::avs_fs_lstat(name, st);
}
if (is_dest_file(name) || is_dest_spec_ea3_config(name)) {
if (st) {
st->filesize = 0;
st->padding.st_dev = 0;
}
return 1;
}
auto value = layeredfs::initialized
? layeredfs::hook_avs_fs_lstat(name, st) : avs::core::avs_fs_lstat(name, st);
if (!is_spam_file(name)) {
WRAP_DEBUG_FMT("name: {}", name);
}
return value;
}
static avs::core::avs_file_t avs_fs_open(const char *name, uint16_t mode, int flags) {
if (name == nullptr) {
return avs::core::avs_fs_open(name, mode, flags);
}
if (!FAKE_FILE_OPEN && (is_dest_file(name, mode) || is_rom_file(name))) {
FAKE_FILE_OPEN = true;
if (is_rom_file(name)) {
ROM_FILE_OPEN = true;
}
log_info("avshook", "opening fake file '{}'", name);
return 1337;
}
auto value = layeredfs::initialized
? layeredfs::hook_avs_fs_open(name, mode, flags) : avs::core::avs_fs_open(name, mode, flags);
if (!is_spam_file(name)) {
WRAP_DEBUG_FMT("name: {} mode: {} flags: {}", name, mode, flags);
}
return value;
}
static void avs_fs_close(avs::core::avs_file_t fd) {
if (is_fake_fd(fd)) {
FAKE_FILE_OPEN = false;
ROM_FILE_OPEN = false;
log_info("hooks::avs", "closing fake fd");
} else {
avs::core::avs_fs_close(fd);
}
}
static int avs_fs_copy(const char *sname, const char *dname) {
if (sname == nullptr || dname == nullptr) {
return avs::core::avs_fs_copy(sname, dname);
}
auto value = avs::core::avs_fs_copy(sname, dname);
WRAP_DEBUG_FMT("sname: {} dname {}", sname, dname);
return value;
}
static avs::core::avs_file_t avs_fs_opendir(const char *path) {
if (path == nullptr) {
return avs::core::avs_fs_opendir(path);
}
auto value = avs::core::avs_fs_opendir(path);
WRAP_DEBUG_FMT("path: {}", path);
return value;
}
static int avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data) {
if (mountpoint == nullptr || fsroot == nullptr || fstype == nullptr) {
return avs::core::avs_fs_mount(mountpoint, fsroot, fstype, data);
}
std::optional<std::string> new_fs_root = std::nullopt;
if (_stricmp(mountpoint, "/mnt/ea3-config.xml") == 0 && is_dest_spec_ea3_config(fsroot)) {
new_fs_root = fmt::format("/{}", avs::ea3::CFG_PATH);
}
// remap drive mounts to `dev/vfs/drive_x` where x is the drive letter
if (!config::DISABLE_VFS_DRIVE_REDIRECTION &&
(_strnicmp(fsroot, "d:", 2) == 0 ||
_strnicmp(fsroot, "e:", 2) == 0 ||
_strnicmp(fsroot, "f:", 2) == 0) &&
_stricmp(fstype, "fs") == 0)
{
// sub path is everything after the drive and colon characters
const char drive_letter[2] {
static_cast<char>(std::tolower(static_cast<unsigned char>(fsroot[0]))),
'\0',
};
const auto separator = fsroot[2] == '/' ? "" : "/";
const auto sub_path = &fsroot[2];
const std::filesystem::path mapped_path = fmt::format(
"dev/vfs/drive_{}{}{}",
drive_letter,
separator,
sub_path);
// create the mapped directory path
std::error_code err;
std::filesystem::create_directories(mapped_path, err);
if (err) {
log_warning("hooks::avs", "failed to create '{}': {}", mapped_path.string(), err.message());
} else {
// if this is the `e:\`, then create the special directories
if (drive_letter[0] == 'e' &&
(sub_path[0] == '/' || sub_path[0] == '\\') &&
sub_path[1] == '\0')
{
fileutils::dir_create_log("hooks::avs", mapped_path / "tmp");
fileutils::dir_create_log("hooks::avs", mapped_path / "up");
}
log_misc("hooks::avs", "source directory '{}' remapped to '{}'",
fsroot,
mapped_path.string());
}
new_fs_root = mapped_path.string();
}
auto fs_root_data = new_fs_root.has_value() ? new_fs_root->c_str() : fsroot;
auto value = avs::core::avs_fs_mount(mountpoint, fs_root_data, fstype, data);
WRAP_DEBUG_FMT("mountpoint: {}, fsroot: {}, fstype: {}", mountpoint, fs_root_data, fstype);
return value;
}
static size_t avs_fs_read(avs::core::avs_file_t fd, uint8_t *data, uint32_t data_size) {
if (is_fake_fd(fd) && ROM_FILE_OPEN) {
const auto size = std::min(static_cast<size_t>(data_size), strlen(ROM_FILE_CONTENTS));
memcpy(data, ROM_FILE_CONTENTS, size);
return size;
}
return avs::core::avs_fs_read(fd, data, data_size);
}
static int property_file_write(avs::core::property_ptr prop, const char* path) {
if (prop == nullptr || path == nullptr) {
return avs::core::property_file_write(prop, path);
}
// resort anthem dumps eacoin to /dev/nvram/eacoin AND /eacoin.xml
// it never reads /eacoin.xml, so it's probably a development leftover
if (avs::game::is_model("JDZ") && _stricmp(path, "/eacoin.xml") == 0) {
return 0;
}
auto value = avs::core::property_file_write(prop, path);
WRAP_DEBUG_FMT("path: {}", path);
return value;
}
void hooks::avs::init() {
log_info("hooks::avs", "initializing");
AVS_HOOK(avs_fs_fstat);
AVS_HOOK(avs_fs_lstat);
AVS_HOOK(avs_fs_open);
AVS_HOOK(avs_fs_close);
AVS_HOOK(avs_fs_copy);
AVS_HOOK(avs_fs_opendir);
AVS_HOOK(avs_fs_mount);
AVS_HOOK(avs_fs_read);
AVS_HOOK(property_file_write);
}
void hooks::avs::set_rom(const char *path, const char *contents) {
ROM_FILE_PATH = path;
ROM_FILE_CONTENTS = contents;
}
#include "avshook.h"
#include <optional>
#include "avs/core.h"
#include "avs/ea3.h"
#include "avs/game.h"
#include "external/layeredfs/hook.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/logging.h"
#include "util/utils.h"
#include "external/layeredfs/hook.h"
#ifdef min
#undef min
#endif
static bool FAKE_FILE_OPEN = false;
static bool ROM_FILE_OPEN = false;
static const char *ROM_FILE_PATH = nullptr;
static const char *ROM_FILE_CONTENTS = nullptr;
namespace hooks::avs::config {
bool DISABLE_VFS_DRIVE_REDIRECTION = false;
bool LOG = false;
};
using namespace hooks::avs;
#define WRAP_DEBUG_FMT(format, ...) \
if (config::LOG) { \
log_misc("avshook", "{}: " format " = 0x{:x}", __FUNCTION__, __VA_ARGS__, static_cast<unsigned>(value)); \
}
#define AVS_HOOK(f) hook_function(::avs::core::IMPORT_NAMES.f, #f, &::avs::core::f, f)
template<typename T>
static void hook_function(const char *source_name, const char *target_name, T **source, T *target) {
if (!detour::trampoline_try(avs::core::DLL_NAME.c_str(), source_name, target, source)) {
log_warning("avshook", "could not hook {} ({})", target_name, source_name);
}
}
static inline bool is_fake_fd(avs::core::avs_file_t fd) {
return FAKE_FILE_OPEN && fd == 1337;
}
static bool is_dest_file(const char *name) {
static std::string path_dest = fmt::format("/dev/raw/{}.dest", avs::game::DEST[0]);
static std::string path_bin = fmt::format("/dev/raw/{}.bin", avs::game::DEST[0]);
return !_stricmp(name, path_dest.c_str()) || !_stricmp(name, path_bin.c_str());
}
static bool is_dest_file(const char *name, uint16_t mode) {
return mode == 1 && is_dest_file(name);
}
static bool is_dest_spec_ea3_config(const char *name) {
static std::string path = fmt::format("/prop/ea3-config-{}{}.xml", avs::game::DEST[0], avs::game::SPEC[0]);
return !_stricmp(name, path.c_str());
}
static bool is_rom_file(const char *name) {
return ROM_FILE_PATH && _stricmp(name, ROM_FILE_PATH) == 0;
}
static bool is_spam_file(const char *file) {
static const char *spam_prefixes[] = {
"/mnt/bm2d/ngp",
"/afp",
"/dev/nvram/pm_eco.xml",
"/dev/nvram/pm_gamesys.xml",
"/dev/nvram/pm_clock.xml",
};
for (auto &spam : spam_prefixes) {
if (string_begins_with(file, spam)) {
return true;
}
}
return false;
}
static int avs_fs_fstat(avs::core::avs_file_t fd, struct avs::core::avs_stat *st) {
if (is_fake_fd(fd) && ROM_FILE_OPEN) {
if (st) {
st->filesize = static_cast<uint32_t>(strlen(ROM_FILE_CONTENTS));
st->padding.st_dev = 0;
}
return 1;
}
return avs::core::avs_fs_fstat(fd, st);
}
static int avs_fs_lstat(const char *name, struct avs::core::avs_stat *st) {
if (name == nullptr) {
return avs::core::avs_fs_lstat(name, st);
}
if (is_dest_file(name) || is_dest_spec_ea3_config(name)) {
if (st) {
st->filesize = 0;
st->padding.st_dev = 0;
}
return 1;
}
auto value = layeredfs::initialized
? layeredfs::hook_avs_fs_lstat(name, st) : avs::core::avs_fs_lstat(name, st);
if (!is_spam_file(name)) {
WRAP_DEBUG_FMT("name: {}", name);
}
return value;
}
static avs::core::avs_file_t avs_fs_open(const char *name, uint16_t mode, int flags) {
if (name == nullptr) {
return avs::core::avs_fs_open(name, mode, flags);
}
if (!FAKE_FILE_OPEN && (is_dest_file(name, mode) || is_rom_file(name))) {
FAKE_FILE_OPEN = true;
if (is_rom_file(name)) {
ROM_FILE_OPEN = true;
}
log_info("avshook", "opening fake file '{}'", name);
return 1337;
}
auto value = layeredfs::initialized
? layeredfs::hook_avs_fs_open(name, mode, flags) : avs::core::avs_fs_open(name, mode, flags);
if (!is_spam_file(name)) {
WRAP_DEBUG_FMT("name: {} mode: {} flags: {}", name, mode, flags);
}
return value;
}
static void avs_fs_close(avs::core::avs_file_t fd) {
if (is_fake_fd(fd)) {
FAKE_FILE_OPEN = false;
ROM_FILE_OPEN = false;
log_info("hooks::avs", "closing fake fd");
} else {
avs::core::avs_fs_close(fd);
}
}
static int avs_fs_copy(const char *sname, const char *dname) {
if (sname == nullptr || dname == nullptr) {
return avs::core::avs_fs_copy(sname, dname);
}
auto value = avs::core::avs_fs_copy(sname, dname);
WRAP_DEBUG_FMT("sname: {} dname {}", sname, dname);
return value;
}
static avs::core::avs_file_t avs_fs_opendir(const char *path) {
if (path == nullptr) {
return avs::core::avs_fs_opendir(path);
}
auto value = avs::core::avs_fs_opendir(path);
WRAP_DEBUG_FMT("path: {}", path);
return value;
}
static int avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data) {
if (mountpoint == nullptr || fsroot == nullptr || fstype == nullptr) {
return avs::core::avs_fs_mount(mountpoint, fsroot, fstype, data);
}
std::optional<std::string> new_fs_root = std::nullopt;
if (_stricmp(mountpoint, "/mnt/ea3-config.xml") == 0 && is_dest_spec_ea3_config(fsroot)) {
new_fs_root = fmt::format("/{}", avs::ea3::CFG_PATH);
}
// remap drive mounts to `dev/vfs/drive_x` where x is the drive letter
if (!config::DISABLE_VFS_DRIVE_REDIRECTION &&
(_strnicmp(fsroot, "d:", 2) == 0 ||
_strnicmp(fsroot, "e:", 2) == 0 ||
_strnicmp(fsroot, "f:", 2) == 0) &&
_stricmp(fstype, "fs") == 0)
{
// sub path is everything after the drive and colon characters
const char drive_letter[2] {
static_cast<char>(std::tolower(static_cast<unsigned char>(fsroot[0]))),
'\0',
};
const auto separator = fsroot[2] == '/' ? "" : "/";
const auto sub_path = &fsroot[2];
const std::filesystem::path mapped_path = fmt::format(
"dev/vfs/drive_{}{}{}",
drive_letter,
separator,
sub_path);
// create the mapped directory path
std::error_code err;
std::filesystem::create_directories(mapped_path, err);
if (err) {
log_warning("hooks::avs", "failed to create '{}': {}", mapped_path.string(), err.message());
} else {
// if this is the `e:\`, then create the special directories
if (drive_letter[0] == 'e' &&
(sub_path[0] == '/' || sub_path[0] == '\\') &&
sub_path[1] == '\0')
{
fileutils::dir_create_log("hooks::avs", mapped_path / "tmp");
fileutils::dir_create_log("hooks::avs", mapped_path / "up");
}
log_misc("hooks::avs", "source directory '{}' remapped to '{}'",
fsroot,
mapped_path.string());
}
new_fs_root = mapped_path.string();
}
auto fs_root_data = new_fs_root.has_value() ? new_fs_root->c_str() : fsroot;
auto value = avs::core::avs_fs_mount(mountpoint, fs_root_data, fstype, data);
WRAP_DEBUG_FMT("mountpoint: {}, fsroot: {}, fstype: {}", mountpoint, fs_root_data, fstype);
return value;
}
static size_t avs_fs_read(avs::core::avs_file_t fd, uint8_t *data, uint32_t data_size) {
if (is_fake_fd(fd) && ROM_FILE_OPEN) {
const auto size = std::min(static_cast<size_t>(data_size), strlen(ROM_FILE_CONTENTS));
memcpy(data, ROM_FILE_CONTENTS, size);
return size;
}
return avs::core::avs_fs_read(fd, data, data_size);
}
static int property_file_write(avs::core::property_ptr prop, const char* path) {
if (prop == nullptr || path == nullptr) {
return avs::core::property_file_write(prop, path);
}
// resort anthem dumps eacoin to /dev/nvram/eacoin AND /eacoin.xml
// it never reads /eacoin.xml, so it's probably a development leftover
if (avs::game::is_model("JDZ") && _stricmp(path, "/eacoin.xml") == 0) {
return 0;
}
auto value = avs::core::property_file_write(prop, path);
WRAP_DEBUG_FMT("path: {}", path);
return value;
}
void hooks::avs::init() {
log_info("hooks::avs", "initializing");
AVS_HOOK(avs_fs_fstat);
AVS_HOOK(avs_fs_lstat);
AVS_HOOK(avs_fs_open);
AVS_HOOK(avs_fs_close);
AVS_HOOK(avs_fs_copy);
AVS_HOOK(avs_fs_opendir);
AVS_HOOK(avs_fs_mount);
AVS_HOOK(avs_fs_read);
AVS_HOOK(property_file_write);
}
void hooks::avs::set_rom(const char *path, const char *contents) {
ROM_FILE_PATH = path;
ROM_FILE_CONTENTS = contents;
}
+17 -17
View File
@@ -1,17 +1,17 @@
#pragma once
#include <string_view>
#include <cstdint>
#include "avs/core.h"
namespace hooks::avs {
namespace config {
extern bool DISABLE_VFS_DRIVE_REDIRECTION;
extern bool LOG;
};
void init();
void set_rom(const char *path, const char *contents);
}
#pragma once
#include <string_view>
#include <cstdint>
#include "avs/core.h"
namespace hooks::avs {
namespace config {
extern bool DISABLE_VFS_DRIVE_REDIRECTION;
extern bool LOG;
};
void init();
void set_rom(const char *path, const char *contents);
}
+84 -84
View File
@@ -1,84 +1,84 @@
#include "cfgmgr32hook.h"
#include <vector>
#include <windows.h>
#include <cfgmgr32.h>
#include "util/detour.h"
typedef CONFIGRET (WINAPI *CM_Locate_DevNodeA_t)(PDEVINST, DEVINSTID_A, ULONG);
typedef CONFIGRET (WINAPI *CM_Get_Parent_t)(PDEVINST, DEVINST, ULONG);
typedef CONFIGRET (WINAPI *CM_Get_Device_IDA_t)(DEVINST, PSTR, ULONG, ULONG);
static CM_Locate_DevNodeA_t CM_Locate_DevNodeA_real = nullptr;
static CM_Get_Parent_t CM_Get_Parent_real = nullptr;
static CM_Get_Device_IDA_t CM_Get_Device_IDA_real = nullptr;
static std::vector<CFGMGR32_HOOK_SETTING> CFGMGR32_HOOK_SETTINGS;
static CONFIGRET WINAPI CM_Locate_DevNodeA_hook(PDEVINST pdnDevInst, DEVINSTID_A pDeviceID, ULONG ulFlags) {
// check device ID
if (!pDeviceID)
return CM_Locate_DevNodeA_real(pdnDevInst, pDeviceID, ulFlags);
// custom
for (auto &setting : CFGMGR32_HOOK_SETTINGS) {
if (_stricmp(pDeviceID, setting.device_node_id.c_str()) == 0) {
*pdnDevInst = (DEVINST) setting.device_instance;
return CR_SUCCESS;
}
}
// fallback
return CM_Locate_DevNodeA_real(pdnDevInst, pDeviceID, ulFlags);
}
static CONFIGRET WINAPI CM_Get_Parent_hook(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) {
// custom
for (auto &setting : CFGMGR32_HOOK_SETTINGS) {
if (dnDevInst == (DEVINST) setting.device_instance) {
*pdnDevInst = (DEVINST) setting.parent_instance;
return CR_SUCCESS;
}
}
// fallback
return CM_Get_Parent_real(pdnDevInst, dnDevInst, ulFlags);
}
static CONFIGRET WINAPI CM_Get_Device_IDA_hook(DEVINST dnDevInst, PSTR Buffer, ULONG BufferLen, ULONG ulFlags) {
// custom
for (auto &setting : CFGMGR32_HOOK_SETTINGS) {
if (dnDevInst == (DEVINST) setting.parent_instance) {
// check buffer size
if (BufferLen <= setting.device_id.length())
return CR_BUFFER_SMALL;
// copy device ID to buffer
memcpy(Buffer, setting.device_id.c_str(), setting.device_id.length() + 1);
return CR_SUCCESS;
}
}
// fallback
return CM_Get_Device_IDA_real(dnDevInst, Buffer, BufferLen, ulFlags);
}
void cfgmgr32hook_init(HINSTANCE module) {
// hook functions
CM_Locate_DevNodeA_real = (CM_Locate_DevNodeA_t) detour::iat_try(
"CM_Locate_DevNodeA", (void *) &CM_Locate_DevNodeA_hook, module);
CM_Get_Parent_real = (CM_Get_Parent_t) detour::iat_try(
"CM_Get_Parent", (void *) &CM_Get_Parent_hook, module);
CM_Get_Device_IDA_real = (CM_Get_Device_IDA_t) detour::iat_try(
"CM_Get_Device_IDA", (void *) &CM_Get_Device_IDA_hook, module);
}
void cfgmgr32hook_add(CFGMGR32_HOOK_SETTING setting) {
CFGMGR32_HOOK_SETTINGS.push_back(setting);
}
#include "cfgmgr32hook.h"
#include <vector>
#include <windows.h>
#include <cfgmgr32.h>
#include "util/detour.h"
typedef CONFIGRET (WINAPI *CM_Locate_DevNodeA_t)(PDEVINST, DEVINSTID_A, ULONG);
typedef CONFIGRET (WINAPI *CM_Get_Parent_t)(PDEVINST, DEVINST, ULONG);
typedef CONFIGRET (WINAPI *CM_Get_Device_IDA_t)(DEVINST, PSTR, ULONG, ULONG);
static CM_Locate_DevNodeA_t CM_Locate_DevNodeA_real = nullptr;
static CM_Get_Parent_t CM_Get_Parent_real = nullptr;
static CM_Get_Device_IDA_t CM_Get_Device_IDA_real = nullptr;
static std::vector<CFGMGR32_HOOK_SETTING> CFGMGR32_HOOK_SETTINGS;
static CONFIGRET WINAPI CM_Locate_DevNodeA_hook(PDEVINST pdnDevInst, DEVINSTID_A pDeviceID, ULONG ulFlags) {
// check device ID
if (!pDeviceID)
return CM_Locate_DevNodeA_real(pdnDevInst, pDeviceID, ulFlags);
// custom
for (auto &setting : CFGMGR32_HOOK_SETTINGS) {
if (_stricmp(pDeviceID, setting.device_node_id.c_str()) == 0) {
*pdnDevInst = (DEVINST) setting.device_instance;
return CR_SUCCESS;
}
}
// fallback
return CM_Locate_DevNodeA_real(pdnDevInst, pDeviceID, ulFlags);
}
static CONFIGRET WINAPI CM_Get_Parent_hook(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags) {
// custom
for (auto &setting : CFGMGR32_HOOK_SETTINGS) {
if (dnDevInst == (DEVINST) setting.device_instance) {
*pdnDevInst = (DEVINST) setting.parent_instance;
return CR_SUCCESS;
}
}
// fallback
return CM_Get_Parent_real(pdnDevInst, dnDevInst, ulFlags);
}
static CONFIGRET WINAPI CM_Get_Device_IDA_hook(DEVINST dnDevInst, PSTR Buffer, ULONG BufferLen, ULONG ulFlags) {
// custom
for (auto &setting : CFGMGR32_HOOK_SETTINGS) {
if (dnDevInst == (DEVINST) setting.parent_instance) {
// check buffer size
if (BufferLen <= setting.device_id.length())
return CR_BUFFER_SMALL;
// copy device ID to buffer
memcpy(Buffer, setting.device_id.c_str(), setting.device_id.length() + 1);
return CR_SUCCESS;
}
}
// fallback
return CM_Get_Device_IDA_real(dnDevInst, Buffer, BufferLen, ulFlags);
}
void cfgmgr32hook_init(HINSTANCE module) {
// hook functions
CM_Locate_DevNodeA_real = (CM_Locate_DevNodeA_t) detour::iat_try(
"CM_Locate_DevNodeA", (void *) &CM_Locate_DevNodeA_hook, module);
CM_Get_Parent_real = (CM_Get_Parent_t) detour::iat_try(
"CM_Get_Parent", (void *) &CM_Get_Parent_hook, module);
CM_Get_Device_IDA_real = (CM_Get_Device_IDA_t) detour::iat_try(
"CM_Get_Device_IDA", (void *) &CM_Get_Device_IDA_hook, module);
}
void cfgmgr32hook_add(CFGMGR32_HOOK_SETTING setting) {
CFGMGR32_HOOK_SETTINGS.push_back(setting);
}
+15 -15
View File
@@ -1,15 +1,15 @@
#pragma once
#include <string>
#include <windows.h>
struct CFGMGR32_HOOK_SETTING {
DWORD device_instance;
DWORD parent_instance;
std::string device_node_id;
std::string device_id;
};
void cfgmgr32hook_init(HINSTANCE module);
void cfgmgr32hook_add(CFGMGR32_HOOK_SETTING setting);
#pragma once
#include <string>
#include <windows.h>
struct CFGMGR32_HOOK_SETTING {
DWORD device_instance;
DWORD parent_instance;
std::string device_node_id;
std::string device_id;
};
void cfgmgr32hook_init(HINSTANCE module);
void cfgmgr32hook_add(CFGMGR32_HOOK_SETTING setting);
+103 -103
View File
@@ -1,103 +1,103 @@
#include "debughook.h"
#include "util/utils.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "avs/core.h"
#include "avs/ea3.h"
#include "avs/game.h"
namespace debughook {
// settings
bool DEBUGHOOK_LOGGING = true;
// function pointers
static decltype(OutputDebugStringA) *OutputDebugStringA_orig = nullptr;
static decltype(OutputDebugStringW) *OutputDebugStringW_orig = nullptr;
static void WINAPI OutputDebugStringA_hook(LPCTSTR str) {
// check if logging is enabled
if (!DEBUGHOOK_LOGGING) {
return;
}
// create buffer
auto len = strlen(str);
auto buf = new TCHAR[len + 1];
memset(buf, 0, len + 1);
// copy to buffer, log message on new lines
size_t buf_i = 0;
for (size_t i = 0; str[i] != 0 && i < len; i++) {
if (str[i] == '\r') {
// skip carriage return
continue;
} else if (str[i] == '\n') {
// null terminate buffer
buf[buf_i] = '\0';
// log buffer
log_info("debughook", "{}", buf);
// reset buffer
len -= buf_i;
buf_i = 0;
memset(buf, 0, len + 1);
} else {
buf[buf_i] = str[i];
buf_i++;
}
}
// log buffer if there are remaining characters
if (buf_i > 0) {
log_info("debughook", "{}", buf);
}
// delete buffer
delete[] buf;
}
static void WINAPI OutputDebugStringW_hook(const wchar_t *str) {
// check if logging is enabled
if (!DEBUGHOOK_LOGGING) {
return;
}
OutputDebugStringA_hook(ws2s(str).c_str());
}
void attach() {
log_info("debughook", "attaching...");
HMODULE kernel32 = libutils::try_module("kernel32.dll");
detour::inline_hook((void *) OutputDebugStringA_hook,
libutils::try_proc(kernel32, "OutputDebugStringA"));
detour::inline_hook((void *) OutputDebugStringW_hook,
libutils::try_proc(kernel32, "OutputDebugStringW"));
OutputDebugStringA_orig = detour::iat_try(
"OutputDebugStringA", OutputDebugStringA_hook, nullptr);
OutputDebugStringW_orig = detour::iat_try(
"OutputDebugStringW", OutputDebugStringW_hook, nullptr);
log_info("debughook", "attached");
}
void detach() {
log_info("debughook", "detaching...");
if (OutputDebugStringA_orig != nullptr) {
detour::iat_try("OutputDebugStringA", OutputDebugStringA_orig, nullptr);
}
if (OutputDebugStringW_orig != nullptr) {
detour::iat_try("OutputDebugStringW", OutputDebugStringW_orig, nullptr);
}
log_info("debughook", "detached");
}
}
#include "debughook.h"
#include "util/utils.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "avs/core.h"
#include "avs/ea3.h"
#include "avs/game.h"
namespace debughook {
// settings
bool DEBUGHOOK_LOGGING = true;
// function pointers
static decltype(OutputDebugStringA) *OutputDebugStringA_orig = nullptr;
static decltype(OutputDebugStringW) *OutputDebugStringW_orig = nullptr;
static void WINAPI OutputDebugStringA_hook(LPCTSTR str) {
// check if logging is enabled
if (!DEBUGHOOK_LOGGING) {
return;
}
// create buffer
auto len = strlen(str);
auto buf = new TCHAR[len + 1];
memset(buf, 0, len + 1);
// copy to buffer, log message on new lines
size_t buf_i = 0;
for (size_t i = 0; str[i] != 0 && i < len; i++) {
if (str[i] == '\r') {
// skip carriage return
continue;
} else if (str[i] == '\n') {
// null terminate buffer
buf[buf_i] = '\0';
// log buffer
log_info("debughook", "{}", buf);
// reset buffer
len -= buf_i;
buf_i = 0;
memset(buf, 0, len + 1);
} else {
buf[buf_i] = str[i];
buf_i++;
}
}
// log buffer if there are remaining characters
if (buf_i > 0) {
log_info("debughook", "{}", buf);
}
// delete buffer
delete[] buf;
}
static void WINAPI OutputDebugStringW_hook(const wchar_t *str) {
// check if logging is enabled
if (!DEBUGHOOK_LOGGING) {
return;
}
OutputDebugStringA_hook(ws2s(str).c_str());
}
void attach() {
log_info("debughook", "attaching...");
HMODULE kernel32 = libutils::try_module("kernel32.dll");
detour::inline_hook((void *) OutputDebugStringA_hook,
libutils::try_proc(kernel32, "OutputDebugStringA"));
detour::inline_hook((void *) OutputDebugStringW_hook,
libutils::try_proc(kernel32, "OutputDebugStringW"));
OutputDebugStringA_orig = detour::iat_try(
"OutputDebugStringA", OutputDebugStringA_hook, nullptr);
OutputDebugStringW_orig = detour::iat_try(
"OutputDebugStringW", OutputDebugStringW_hook, nullptr);
log_info("debughook", "attached");
}
void detach() {
log_info("debughook", "detaching...");
if (OutputDebugStringA_orig != nullptr) {
detour::iat_try("OutputDebugStringA", OutputDebugStringA_orig, nullptr);
}
if (OutputDebugStringW_orig != nullptr) {
detour::iat_try("OutputDebugStringW", OutputDebugStringW_orig, nullptr);
}
log_info("debughook", "detached");
}
}
+16 -16
View File
@@ -1,16 +1,16 @@
#pragma once
#include <windows.h>
#include "util/detour.h"
#include "util/logging.h"
namespace debughook {
// settings
extern bool DEBUGHOOK_LOGGING;
// functions
void attach();
void detach();
}
#pragma once
#include <windows.h>
#include "util/detour.h"
#include "util/logging.h"
namespace debughook {
// settings
extern bool DEBUGHOOK_LOGGING;
// functions
void attach();
void detach();
}
+575 -575
View File
File diff suppressed because it is too large Load Diff
+75 -75
View File
@@ -1,75 +1,75 @@
#pragma once
#include <windows.h>
#include <string>
namespace hooks::device {
extern bool ENABLE;
}
extern bool DEVICE_CREATEFILE_DEBUG;
class CustomHandle {
public:
HANDLE handle = INVALID_HANDLE_VALUE;
bool com_pass = false;
virtual ~CustomHandle() = default;
virtual bool open(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
return open(lpFileName);
}
virtual bool open(LPCWSTR lpFileName) {
return false;
};
virtual int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
return -1;
};
virtual int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
return -1;
};
virtual int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) {
return -1;
};
virtual bool close() {
return true;
};
virtual void file_info(LPBY_HANDLE_FILE_INFORMATION lpFileInformation) {
memset(lpFileInformation, 0, sizeof(*lpFileInformation));
};
DCB comm_state {};
COMMTIMEOUTS comm_timeouts {};
};
class MITMHandle : public CustomHandle {
protected:
LPCWSTR lpFileName = L"";
bool lpFileNameContains = false;
std::string rec_file = "";
public:
MITMHandle(LPCWSTR lpFileName, std::string rec_file = "", bool lpFileNameContains = false);
bool open(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
void devicehook_init(HMODULE module = nullptr);
void devicehook_add(CustomHandle *device_handle);
void devicehook_dispose();
#pragma once
#include <windows.h>
#include <string>
namespace hooks::device {
extern bool ENABLE;
}
extern bool DEVICE_CREATEFILE_DEBUG;
class CustomHandle {
public:
HANDLE handle = INVALID_HANDLE_VALUE;
bool com_pass = false;
virtual ~CustomHandle() = default;
virtual bool open(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
return open(lpFileName);
}
virtual bool open(LPCWSTR lpFileName) {
return false;
};
virtual int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
return -1;
};
virtual int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
return -1;
};
virtual int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) {
return -1;
};
virtual bool close() {
return true;
};
virtual void file_info(LPBY_HANDLE_FILE_INFORMATION lpFileInformation) {
memset(lpFileInformation, 0, sizeof(*lpFileInformation));
};
DCB comm_state {};
COMMTIMEOUTS comm_timeouts {};
};
class MITMHandle : public CustomHandle {
protected:
LPCWSTR lpFileName = L"";
bool lpFileNameContains = false;
std::string rec_file = "";
public:
MITMHandle(LPCWSTR lpFileName, std::string rec_file = "", bool lpFileNameContains = false);
bool open(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
void devicehook_init(HMODULE module = nullptr);
void devicehook_add(CustomHandle *device_handle);
void devicehook_dispose();
+65 -65
View File
@@ -1,65 +1,65 @@
#pragma once
#include <d3d9.h>
// {EEE9CCF6-53D6-4326-9AE5-60921B3DB394}
static const GUID IID_WrappedIDirect3D9 = {
0xeee9ccf6, 0x53d6, 0x4326, { 0x9a, 0xe5, 0x60, 0x92, 0x1b, 0x3d, 0xb3, 0x94 }
};
void graphics_d3d9_init();
void graphics_d3d9_on_present(
HWND hFocusWindow,
IDirect3DDevice9 *device,
IDirect3DDevice9 *wrapped_device);
IDirect3DSurface9 *graphics_d3d9_ldj_get_sub_screen();
struct WrappedIDirect3D9 : IDirect3D9Ex {
explicit WrappedIDirect3D9(IDirect3D9 *orig) : pReal(orig), is_d3d9ex(false) {}
explicit WrappedIDirect3D9(IDirect3D9Ex *orig) : pReal(orig), is_d3d9ex(true) {}
WrappedIDirect3D9(const WrappedIDirect3D9 &) = delete;
WrappedIDirect3D9 &operator=(const WrappedIDirect3D9 &) = delete;
virtual ~WrappedIDirect3D9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirect3D9
virtual HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void *pInitializeFunction) override;
virtual UINT STDMETHODCALLTYPE GetAdapterCount() override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier) override;
virtual UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) override;
virtual HRESULT STDMETHODCALLTYPE EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels) override;
virtual HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps) override;
virtual HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) override;
virtual HRESULT STDMETHODCALLTYPE CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface) override;
#pragma endregion
#pragma region IDirect3D9Ex
virtual UINT STDMETHODCALLTYPE GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter) override;
virtual HRESULT STDMETHODCALLTYPE EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode, D3DDISPLAYMODEEX *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
virtual HRESULT STDMETHODCALLTYPE CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3DDevice9Ex **ppReturnedDeviceInterface) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID *pLUID) override;
#pragma endregion
private:
IDirect3D9 *pReal;
bool is_d3d9ex = false;
//bool attempted_sub_swap_chain_acquire = false;
//IDirect3DSwapChain9 *sub_swap_chain = nullptr;
};
#pragma once
#include <d3d9.h>
// {EEE9CCF6-53D6-4326-9AE5-60921B3DB394}
static const GUID IID_WrappedIDirect3D9 = {
0xeee9ccf6, 0x53d6, 0x4326, { 0x9a, 0xe5, 0x60, 0x92, 0x1b, 0x3d, 0xb3, 0x94 }
};
void graphics_d3d9_init();
void graphics_d3d9_on_present(
HWND hFocusWindow,
IDirect3DDevice9 *device,
IDirect3DDevice9 *wrapped_device);
IDirect3DSurface9 *graphics_d3d9_ldj_get_sub_screen();
struct WrappedIDirect3D9 : IDirect3D9Ex {
explicit WrappedIDirect3D9(IDirect3D9 *orig) : pReal(orig), is_d3d9ex(false) {}
explicit WrappedIDirect3D9(IDirect3D9Ex *orig) : pReal(orig), is_d3d9ex(true) {}
WrappedIDirect3D9(const WrappedIDirect3D9 &) = delete;
WrappedIDirect3D9 &operator=(const WrappedIDirect3D9 &) = delete;
virtual ~WrappedIDirect3D9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirect3D9
virtual HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void *pInitializeFunction) override;
virtual UINT STDMETHODCALLTYPE GetAdapterCount() override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier) override;
virtual UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) override;
virtual HRESULT STDMETHODCALLTYPE EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels) override;
virtual HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps) override;
virtual HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter) override;
virtual HRESULT STDMETHODCALLTYPE CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DDevice9 **ppReturnedDeviceInterface) override;
#pragma endregion
#pragma region IDirect3D9Ex
virtual UINT STDMETHODCALLTYPE GetAdapterModeCountEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter) override;
virtual HRESULT STDMETHODCALLTYPE EnumAdapterModesEx(UINT Adapter, const D3DDISPLAYMODEFILTER *pFilter, UINT Mode, D3DDISPLAYMODEEX *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterDisplayModeEx(UINT Adapter, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
virtual HRESULT STDMETHODCALLTYPE CreateDeviceEx(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode, IDirect3DDevice9Ex **ppReturnedDeviceInterface) override;
virtual HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID *pLUID) override;
#pragma endregion
private:
IDirect3D9 *pReal;
bool is_d3d9ex = false;
//bool attempted_sub_swap_chain_acquire = false;
//IDirect3DSwapChain9 *sub_swap_chain = nullptr;
};
+210 -210
View File
@@ -1,210 +1,210 @@
#pragma once
#include <atomic>
#include <initguid.h>
#include <d3d9.h>
#include "util/logging.h"
#include "d3d9_fake_swapchain.h"
#include "d3d9_swapchain.h"
/*
* Logging Helpers
*/
#if 0
#define WRAP_VERBOSE log_misc("graphics::d3d9", "{}", __FUNCTION__)
#define WRAP_VERBOSE_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_VERBOSE do {} while (0)
#define WRAP_VERBOSE_FMT(format, ...) do {} while (0)
#endif
#if 0
#define WRAP_DEBUG log_misc("graphics::d3d9", "{}", __FUNCTION__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
// {6DEC0D40-1339-4BDA-A5F2-2231D4010FD1}
static const GUID IID_WrappedIDirect3DDevice9 = {
0x6dec0d40, 0x1339, 0x4bda, { 0xa5, 0xf2, 0x22, 0x31, 0xd4, 0x1, 0xf, 0xd1 }
};
struct WrappedIDirect3DDevice9 : IDirect3DDevice9Ex {
explicit WrappedIDirect3DDevice9(HWND hFocusWindow, IDirect3DDevice9 *orig)
: hFocusWindow(hFocusWindow), pReal(orig), is_d3d9ex(false) {
IDirect3DDevice9Ex *device = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&device))) && device != nullptr) {
device->Release();
}
}
explicit WrappedIDirect3DDevice9(HWND hFocusWindow, IDirect3DDevice9Ex *orig)
: hFocusWindow(hFocusWindow), pReal(orig), is_d3d9ex(true) {}
WrappedIDirect3DDevice9(const WrappedIDirect3DDevice9 &) = delete;
WrappedIDirect3DDevice9 &operator=(const WrappedIDirect3DDevice9 &) = delete;
virtual ~WrappedIDirect3DDevice9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirect3DDevice9
virtual HRESULT STDMETHODCALLTYPE TestCooperativeLevel() override;
virtual UINT STDMETHODCALLTYPE GetAvailableTextureMem() override;
virtual HRESULT STDMETHODCALLTYPE EvictManagedResources() override;
virtual HRESULT STDMETHODCALLTYPE GetDirect3D(IDirect3D9 **ppD3D9) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceCaps(D3DCAPS9 *pCaps) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters) override;
virtual HRESULT STDMETHODCALLTYPE SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap) override;
virtual void STDMETHODCALLTYPE SetCursorPosition(int X, int Y, DWORD Flags) override;
virtual BOOL STDMETHODCALLTYPE ShowCursor(BOOL bShow) override;
virtual HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **ppSwapChain) override;
virtual HRESULT STDMETHODCALLTYPE GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9 **ppSwapChain) override;
virtual UINT STDMETHODCALLTYPE GetNumberOfSwapChains() override;
virtual HRESULT STDMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE SetDialogBoxMode(BOOL bEnableDialogs) override;
virtual void STDMETHODCALLTYPE SetGammaRamp(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP *pRamp) override;
virtual void STDMETHODCALLTYPE GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP *pRamp) override;
virtual HRESULT STDMETHODCALLTYPE CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE UpdateSurface(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, const POINT *pDestPoint) override;
virtual HRESULT STDMETHODCALLTYPE UpdateTexture(IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderTargetData(IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE StretchRect(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter) override;
virtual HRESULT STDMETHODCALLTYPE ColorFill(IDirect3DSurface9 *pSurface, const RECT *pRect, D3DCOLOR color) override;
virtual HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget) override;
virtual HRESULT STDMETHODCALLTYPE SetDepthStencilSurface(IDirect3DSurface9 *pNewZStencil) override;
virtual HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface9 **ppZStencilSurface) override;
virtual HRESULT STDMETHODCALLTYPE BeginScene() override;
virtual HRESULT STDMETHODCALLTYPE EndScene() override;
virtual HRESULT STDMETHODCALLTYPE Clear(DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override;
virtual HRESULT STDMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE MultiplyTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE SetViewport(const D3DVIEWPORT9 *pViewport) override;
virtual HRESULT STDMETHODCALLTYPE GetViewport(D3DVIEWPORT9 *pViewport) override;
virtual HRESULT STDMETHODCALLTYPE SetMaterial(const D3DMATERIAL9 *pMaterial) override;
virtual HRESULT STDMETHODCALLTYPE GetMaterial(D3DMATERIAL9 *pMaterial) override;
virtual HRESULT STDMETHODCALLTYPE SetLight(DWORD Index, const D3DLIGHT9 *pLight) override;
virtual HRESULT STDMETHODCALLTYPE GetLight(DWORD Index, D3DLIGHT9 *pLight) override;
virtual HRESULT STDMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable) override;
virtual HRESULT STDMETHODCALLTYPE GetLightEnable(DWORD Index, BOOL *pEnable) override;
virtual HRESULT STDMETHODCALLTYPE SetClipPlane(DWORD Index, const float *pPlane) override;
virtual HRESULT STDMETHODCALLTYPE GetClipPlane(DWORD Index, float *pPlane) override;
virtual HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB) override;
virtual HRESULT STDMETHODCALLTYPE BeginStateBlock() override;
virtual HRESULT STDMETHODCALLTYPE EndStateBlock(IDirect3DStateBlock9 **ppSB) override;
virtual HRESULT STDMETHODCALLTYPE SetClipStatus(const D3DCLIPSTATUS9 *pClipStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetClipStatus(D3DCLIPSTATUS9 *pClipStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetTexture(DWORD Stage, IDirect3DBaseTexture9 **ppTexture) override;
virtual HRESULT STDMETHODCALLTYPE SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture) override;
virtual HRESULT STDMETHODCALLTYPE GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE ValidateDevice(DWORD *pNumPasses) override;
virtual HRESULT STDMETHODCALLTYPE SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY *pEntries) override;
virtual HRESULT STDMETHODCALLTYPE GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY *pEntries) override;
virtual HRESULT STDMETHODCALLTYPE SetCurrentTexturePalette(UINT PaletteNumber) override;
virtual HRESULT STDMETHODCALLTYPE GetCurrentTexturePalette(UINT *PaletteNumber) override;
virtual HRESULT STDMETHODCALLTYPE SetScissorRect(const RECT *pRect) override;
virtual HRESULT STDMETHODCALLTYPE GetScissorRect(RECT *pRect) override;
virtual HRESULT STDMETHODCALLTYPE SetSoftwareVertexProcessing(BOOL bSoftware) override;
virtual BOOL STDMETHODCALLTYPE GetSoftwareVertexProcessing() override;
virtual HRESULT STDMETHODCALLTYPE SetNPatchMode(float nSegments) override;
virtual float STDMETHODCALLTYPE GetNPatchMode() override;
virtual HRESULT STDMETHODCALLTYPE DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
virtual HRESULT STDMETHODCALLTYPE DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void *pIndexData, D3DFORMAT IndexDataFormat, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
virtual HRESULT STDMETHODCALLTYPE ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexDeclaration(const D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexDeclaration(IDirect3DVertexDeclaration9 *pDecl) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexDeclaration(IDirect3DVertexDeclaration9 **ppDecl) override;
virtual HRESULT STDMETHODCALLTYPE SetFVF(DWORD FVF) override;
virtual HRESULT STDMETHODCALLTYPE GetFVF(DWORD *pFVF) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexShader(const DWORD *pFunction, IDirect3DVertexShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShader(IDirect3DVertexShader9 *pShader) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShader(IDirect3DVertexShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride) override;
virtual HRESULT STDMETHODCALLTYPE GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *OffsetInBytes, UINT *pStride) override;
virtual HRESULT STDMETHODCALLTYPE SetStreamSourceFreq(UINT StreamNumber, UINT Divider) override;
virtual HRESULT STDMETHODCALLTYPE GetStreamSourceFreq(UINT StreamNumber, UINT *Divider) override;
virtual HRESULT STDMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer9 *pIndexData) override;
virtual HRESULT STDMETHODCALLTYPE GetIndices(IDirect3DIndexBuffer9 **ppIndexData) override;
virtual HRESULT STDMETHODCALLTYPE CreatePixelShader(const DWORD *pFunction, IDirect3DPixelShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShader(IDirect3DPixelShader9 *pShader) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShader(IDirect3DPixelShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawRectPatch(UINT Handle, const float *pNumSegs, const D3DRECTPATCH_INFO *pRectPatchInfo) override;
virtual HRESULT STDMETHODCALLTYPE DrawTriPatch(UINT Handle, const float *pNumSegs, const D3DTRIPATCH_INFO *pTriPatchInfo) override;
virtual HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle) override;
virtual HRESULT STDMETHODCALLTYPE CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery) override;
#pragma endregion
#pragma region IDirect3DDevice9Ex
virtual HRESULT STDMETHODCALLTYPE SetConvolutionMonoKernel(UINT width, UINT height, float *rows, float *columns) override;
virtual HRESULT STDMETHODCALLTYPE ComposeRects(IDirect3DSurface9 *pSrc, IDirect3DSurface9 *pDst, IDirect3DVertexBuffer9 *pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9 *pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset) override;
virtual HRESULT STDMETHODCALLTYPE PresentEx(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority(INT *pPriority) override;
virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority(INT Priority) override;
virtual HRESULT STDMETHODCALLTYPE WaitForVBlank(UINT iSwapChain) override;
virtual HRESULT STDMETHODCALLTYPE CheckResourceResidency(IDirect3DResource9 **pResourceArray, UINT32 NumResources) override;
virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(UINT MaxLatency) override;
virtual HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(UINT *pMaxLatency) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceState(HWND hDestinationWindow) override;
virtual HRESULT STDMETHODCALLTYPE CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE ResetEx(D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
HWND const hFocusWindow;
IDirect3DDevice9 *pReal;
bool is_d3d9ex = false;
std::atomic_ulong refs = 1;
WrappedIDirect3DSwapChain9 *main_swapchain = nullptr;
WrappedIDirect3DSwapChain9 *sub_swapchain = nullptr;
FakeIDirect3DSwapChain9 *fake_sub_swapchain = nullptr;
IDirect3DVertexShader9 *vertex_shader = nullptr;
};
#pragma once
#include <atomic>
#include <initguid.h>
#include <d3d9.h>
#include "util/logging.h"
#include "d3d9_fake_swapchain.h"
#include "d3d9_swapchain.h"
/*
* Logging Helpers
*/
#if 0
#define WRAP_VERBOSE log_misc("graphics::d3d9", "{}", __FUNCTION__)
#define WRAP_VERBOSE_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_VERBOSE do {} while (0)
#define WRAP_VERBOSE_FMT(format, ...) do {} while (0)
#endif
#if 0
#define WRAP_DEBUG log_misc("graphics::d3d9", "{}", __FUNCTION__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
// {6DEC0D40-1339-4BDA-A5F2-2231D4010FD1}
static const GUID IID_WrappedIDirect3DDevice9 = {
0x6dec0d40, 0x1339, 0x4bda, { 0xa5, 0xf2, 0x22, 0x31, 0xd4, 0x1, 0xf, 0xd1 }
};
struct WrappedIDirect3DDevice9 : IDirect3DDevice9Ex {
explicit WrappedIDirect3DDevice9(HWND hFocusWindow, IDirect3DDevice9 *orig)
: hFocusWindow(hFocusWindow), pReal(orig), is_d3d9ex(false) {
IDirect3DDevice9Ex *device = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&device))) && device != nullptr) {
device->Release();
}
}
explicit WrappedIDirect3DDevice9(HWND hFocusWindow, IDirect3DDevice9Ex *orig)
: hFocusWindow(hFocusWindow), pReal(orig), is_d3d9ex(true) {}
WrappedIDirect3DDevice9(const WrappedIDirect3DDevice9 &) = delete;
WrappedIDirect3DDevice9 &operator=(const WrappedIDirect3DDevice9 &) = delete;
virtual ~WrappedIDirect3DDevice9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirect3DDevice9
virtual HRESULT STDMETHODCALLTYPE TestCooperativeLevel() override;
virtual UINT STDMETHODCALLTYPE GetAvailableTextureMem() override;
virtual HRESULT STDMETHODCALLTYPE EvictManagedResources() override;
virtual HRESULT STDMETHODCALLTYPE GetDirect3D(IDirect3D9 **ppD3D9) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceCaps(D3DCAPS9 *pCaps) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters) override;
virtual HRESULT STDMETHODCALLTYPE SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap) override;
virtual void STDMETHODCALLTYPE SetCursorPosition(int X, int Y, DWORD Flags) override;
virtual BOOL STDMETHODCALLTYPE ShowCursor(BOOL bShow) override;
virtual HRESULT STDMETHODCALLTYPE CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS *pPresentationParameters, IDirect3DSwapChain9 **ppSwapChain) override;
virtual HRESULT STDMETHODCALLTYPE GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9 **ppSwapChain) override;
virtual UINT STDMETHODCALLTYPE GetNumberOfSwapChains() override;
virtual HRESULT STDMETHODCALLTYPE Reset(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE SetDialogBoxMode(BOOL bEnableDialogs) override;
virtual void STDMETHODCALLTYPE SetGammaRamp(UINT iSwapChain, DWORD Flags, const D3DGAMMARAMP *pRamp) override;
virtual void STDMETHODCALLTYPE GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP *pRamp) override;
virtual HRESULT STDMETHODCALLTYPE CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9 **ppTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9 **ppVolumeTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9 **ppCubeTexture, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9 **ppVertexBuffer, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9 **ppIndexBuffer, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE UpdateSurface(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestinationSurface, const POINT *pDestPoint) override;
virtual HRESULT STDMETHODCALLTYPE UpdateTexture(IDirect3DBaseTexture9 *pSourceTexture, IDirect3DBaseTexture9 *pDestinationTexture) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderTargetData(IDirect3DSurface9 *pRenderTarget, IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE StretchRect(IDirect3DSurface9 *pSourceSurface, const RECT *pSourceRect, IDirect3DSurface9 *pDestSurface, const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter) override;
virtual HRESULT STDMETHODCALLTYPE ColorFill(IDirect3DSurface9 *pSurface, const RECT *pRect, D3DCOLOR color) override;
virtual HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle) override;
virtual HRESULT STDMETHODCALLTYPE SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 *pRenderTarget) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9 **ppRenderTarget) override;
virtual HRESULT STDMETHODCALLTYPE SetDepthStencilSurface(IDirect3DSurface9 *pNewZStencil) override;
virtual HRESULT STDMETHODCALLTYPE GetDepthStencilSurface(IDirect3DSurface9 **ppZStencilSurface) override;
virtual HRESULT STDMETHODCALLTYPE BeginScene() override;
virtual HRESULT STDMETHODCALLTYPE EndScene() override;
virtual HRESULT STDMETHODCALLTYPE Clear(DWORD Count, const D3DRECT *pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) override;
virtual HRESULT STDMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE MultiplyTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix) override;
virtual HRESULT STDMETHODCALLTYPE SetViewport(const D3DVIEWPORT9 *pViewport) override;
virtual HRESULT STDMETHODCALLTYPE GetViewport(D3DVIEWPORT9 *pViewport) override;
virtual HRESULT STDMETHODCALLTYPE SetMaterial(const D3DMATERIAL9 *pMaterial) override;
virtual HRESULT STDMETHODCALLTYPE GetMaterial(D3DMATERIAL9 *pMaterial) override;
virtual HRESULT STDMETHODCALLTYPE SetLight(DWORD Index, const D3DLIGHT9 *pLight) override;
virtual HRESULT STDMETHODCALLTYPE GetLight(DWORD Index, D3DLIGHT9 *pLight) override;
virtual HRESULT STDMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable) override;
virtual HRESULT STDMETHODCALLTYPE GetLightEnable(DWORD Index, BOOL *pEnable) override;
virtual HRESULT STDMETHODCALLTYPE SetClipPlane(DWORD Index, const float *pPlane) override;
virtual HRESULT STDMETHODCALLTYPE GetClipPlane(DWORD Index, float *pPlane) override;
virtual HRESULT STDMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE GetRenderState(D3DRENDERSTATETYPE State, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9 **ppSB) override;
virtual HRESULT STDMETHODCALLTYPE BeginStateBlock() override;
virtual HRESULT STDMETHODCALLTYPE EndStateBlock(IDirect3DStateBlock9 **ppSB) override;
virtual HRESULT STDMETHODCALLTYPE SetClipStatus(const D3DCLIPSTATUS9 *pClipStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetClipStatus(D3DCLIPSTATUS9 *pClipStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetTexture(DWORD Stage, IDirect3DBaseTexture9 **ppTexture) override;
virtual HRESULT STDMETHODCALLTYPE SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture) override;
virtual HRESULT STDMETHODCALLTYPE GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD *pValue) override;
virtual HRESULT STDMETHODCALLTYPE SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) override;
virtual HRESULT STDMETHODCALLTYPE ValidateDevice(DWORD *pNumPasses) override;
virtual HRESULT STDMETHODCALLTYPE SetPaletteEntries(UINT PaletteNumber, const PALETTEENTRY *pEntries) override;
virtual HRESULT STDMETHODCALLTYPE GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY *pEntries) override;
virtual HRESULT STDMETHODCALLTYPE SetCurrentTexturePalette(UINT PaletteNumber) override;
virtual HRESULT STDMETHODCALLTYPE GetCurrentTexturePalette(UINT *PaletteNumber) override;
virtual HRESULT STDMETHODCALLTYPE SetScissorRect(const RECT *pRect) override;
virtual HRESULT STDMETHODCALLTYPE GetScissorRect(RECT *pRect) override;
virtual HRESULT STDMETHODCALLTYPE SetSoftwareVertexProcessing(BOOL bSoftware) override;
virtual BOOL STDMETHODCALLTYPE GetSoftwareVertexProcessing() override;
virtual HRESULT STDMETHODCALLTYPE SetNPatchMode(float nSegments) override;
virtual float STDMETHODCALLTYPE GetNPatchMode() override;
virtual HRESULT STDMETHODCALLTYPE DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
virtual HRESULT STDMETHODCALLTYPE DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, const void *pIndexData, D3DFORMAT IndexDataFormat, const void *pVertexStreamZeroData, UINT VertexStreamZeroStride) override;
virtual HRESULT STDMETHODCALLTYPE ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9 *pDestBuffer, IDirect3DVertexDeclaration9 *pVertexDecl, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexDeclaration(const D3DVERTEXELEMENT9 *pVertexElements, IDirect3DVertexDeclaration9 **ppDecl) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexDeclaration(IDirect3DVertexDeclaration9 *pDecl) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexDeclaration(IDirect3DVertexDeclaration9 **ppDecl) override;
virtual HRESULT STDMETHODCALLTYPE SetFVF(DWORD FVF) override;
virtual HRESULT STDMETHODCALLTYPE GetFVF(DWORD *pFVF) override;
virtual HRESULT STDMETHODCALLTYPE CreateVertexShader(const DWORD *pFunction, IDirect3DVertexShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShader(IDirect3DVertexShader9 *pShader) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShader(IDirect3DVertexShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE SetVertexShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE GetVertexShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride) override;
virtual HRESULT STDMETHODCALLTYPE GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 **ppStreamData, UINT *OffsetInBytes, UINT *pStride) override;
virtual HRESULT STDMETHODCALLTYPE SetStreamSourceFreq(UINT StreamNumber, UINT Divider) override;
virtual HRESULT STDMETHODCALLTYPE GetStreamSourceFreq(UINT StreamNumber, UINT *Divider) override;
virtual HRESULT STDMETHODCALLTYPE SetIndices(IDirect3DIndexBuffer9 *pIndexData) override;
virtual HRESULT STDMETHODCALLTYPE GetIndices(IDirect3DIndexBuffer9 **ppIndexData) override;
virtual HRESULT STDMETHODCALLTYPE CreatePixelShader(const DWORD *pFunction, IDirect3DPixelShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShader(IDirect3DPixelShader9 *pShader) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShader(IDirect3DPixelShader9 **ppShader) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantF(UINT StartRegister, const float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantF(UINT StartRegister, float *pConstantData, UINT Vector4fCount) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantI(UINT StartRegister, const int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantI(UINT StartRegister, int *pConstantData, UINT Vector4iCount) override;
virtual HRESULT STDMETHODCALLTYPE SetPixelShaderConstantB(UINT StartRegister, const BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPixelShaderConstantB(UINT StartRegister, BOOL *pConstantData, UINT BoolCount) override;
virtual HRESULT STDMETHODCALLTYPE DrawRectPatch(UINT Handle, const float *pNumSegs, const D3DRECTPATCH_INFO *pRectPatchInfo) override;
virtual HRESULT STDMETHODCALLTYPE DrawTriPatch(UINT Handle, const float *pNumSegs, const D3DTRIPATCH_INFO *pTriPatchInfo) override;
virtual HRESULT STDMETHODCALLTYPE DeletePatch(UINT Handle) override;
virtual HRESULT STDMETHODCALLTYPE CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9 **ppQuery) override;
#pragma endregion
#pragma region IDirect3DDevice9Ex
virtual HRESULT STDMETHODCALLTYPE SetConvolutionMonoKernel(UINT width, UINT height, float *rows, float *columns) override;
virtual HRESULT STDMETHODCALLTYPE ComposeRects(IDirect3DSurface9 *pSrc, IDirect3DSurface9 *pDst, IDirect3DVertexBuffer9 *pSrcRectDescs, UINT NumRects, IDirect3DVertexBuffer9 *pDstRectDescs, D3DCOMPOSERECTSOP Operation, int Xoffset, int Yoffset) override;
virtual HRESULT STDMETHODCALLTYPE PresentEx(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority(INT *pPriority) override;
virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority(INT Priority) override;
virtual HRESULT STDMETHODCALLTYPE WaitForVBlank(UINT iSwapChain) override;
virtual HRESULT STDMETHODCALLTYPE CheckResourceResidency(IDirect3DResource9 **pResourceArray, UINT32 NumResources) override;
virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(UINT MaxLatency) override;
virtual HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(UINT *pMaxLatency) override;
virtual HRESULT STDMETHODCALLTYPE CheckDeviceState(HWND hDestinationWindow) override;
virtual HRESULT STDMETHODCALLTYPE CreateRenderTargetEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE CreateOffscreenPlainSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilSurfaceEx(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9 **ppSurface, HANDLE *pSharedHandle, DWORD Usage) override;
virtual HRESULT STDMETHODCALLTYPE ResetEx(D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(UINT iSwapChain, D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
HWND const hFocusWindow;
IDirect3DDevice9 *pReal;
bool is_d3d9ex = false;
std::atomic_ulong refs = 1;
WrappedIDirect3DSwapChain9 *main_swapchain = nullptr;
WrappedIDirect3DSwapChain9 *sub_swapchain = nullptr;
FakeIDirect3DSwapChain9 *fake_sub_swapchain = nullptr;
IDirect3DVertexShader9 *vertex_shader = nullptr;
};
@@ -1,130 +1,130 @@
#include "d3d9_fake_swapchain.h"
#include <cassert>
#include <mutex>
#include "util/logging.h"
#if 1
#define WRAP_VERBOSE log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::{}", __FUNCTION__)
#define WRAP_VERBOSE_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_VERBOSE
#define WRAP_VERBOSE_FMT(format, ...)
#endif
// IDirect3DSwapChain9
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IUnknown ||
riid == IID_IDirect3DSwapChain9 ||
riid == IID_IDirect3DSwapChain9Ex)
{
#pragma region Update to IDirect3DSwapChain9Ex interface
if (!is_d3d9ex && riid == IID_IDirect3DSwapChain9Ex) {
is_d3d9ex = true;
}
#pragma endregion
AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirect3DSwapChain9::AddRef(void) {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE FakeIDirect3DSwapChain9::Release(void) {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::Present(const RECT *pSourceRect, const RECT *pDestRect,
HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::Present");
});
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *pDestSurface) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type,
IDirect3DSurface9 **ppBackBuffer)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::GetBackBuffer");
});
if (iBackBuffer >= render_targets.size() || Type != D3DBACKBUFFER_TYPE_MONO || !ppBackBuffer) {
return D3DERR_INVALIDCALL;
}
auto &render_target = render_targets[iBackBuffer];
render_target->AddRef();
*ppBackBuffer = render_target;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *pMode) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDevice(IDirect3DDevice9 **ppDevice) {
WRAP_VERBOSE;
if (ppDevice == nullptr) {
return D3DERR_INVALIDCALL;
}
pDev->AddRef();
*ppDevice = pDev;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetPresentParameters(
D3DPRESENT_PARAMETERS *pPresentationParameters)
{
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
// IDirect3DSwapChain9Ex
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetLastPresentCount(UINT *pLastPresentCount) {
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) {
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDisplayModeEx(D3DDISPLAYMODEEX *pMode,
D3DDISPLAYROTATION *pRotation)
{
WRAP_VERBOSE;
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
#include "d3d9_fake_swapchain.h"
#include <cassert>
#include <mutex>
#include "util/logging.h"
#if 1
#define WRAP_VERBOSE log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::{}", __FUNCTION__)
#define WRAP_VERBOSE_FMT(format, ...) log_misc("graphics::d3d9", format, __VA_ARGS__)
#else
#define WRAP_VERBOSE
#define WRAP_VERBOSE_FMT(format, ...)
#endif
// IDirect3DSwapChain9
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IUnknown ||
riid == IID_IDirect3DSwapChain9 ||
riid == IID_IDirect3DSwapChain9Ex)
{
#pragma region Update to IDirect3DSwapChain9Ex interface
if (!is_d3d9ex && riid == IID_IDirect3DSwapChain9Ex) {
is_d3d9ex = true;
}
#pragma endregion
AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirect3DSwapChain9::AddRef(void) {
return ++this->ref_cnt;
}
ULONG STDMETHODCALLTYPE FakeIDirect3DSwapChain9::Release(void) {
ULONG refs = --this->ref_cnt;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::Present(const RECT *pSourceRect, const RECT *pDestRect,
HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::Present");
});
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *pDestSurface) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type,
IDirect3DSurface9 **ppBackBuffer)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "FakeIDirect3DSwapChain9::GetBackBuffer");
});
if (iBackBuffer >= render_targets.size() || Type != D3DBACKBUFFER_TYPE_MONO || !ppBackBuffer) {
return D3DERR_INVALIDCALL;
}
auto &render_target = render_targets[iBackBuffer];
render_target->AddRef();
*ppBackBuffer = render_target;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *pMode) {
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDevice(IDirect3DDevice9 **ppDevice) {
WRAP_VERBOSE;
if (ppDevice == nullptr) {
return D3DERR_INVALIDCALL;
}
pDev->AddRef();
*ppDevice = pDev;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetPresentParameters(
D3DPRESENT_PARAMETERS *pPresentationParameters)
{
WRAP_VERBOSE;
return D3DERR_INVALIDCALL;
}
// IDirect3DSwapChain9Ex
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetLastPresentCount(UINT *pLastPresentCount) {
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) {
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
HRESULT STDMETHODCALLTYPE FakeIDirect3DSwapChain9::GetDisplayModeEx(D3DDISPLAYMODEEX *pMode,
D3DDISPLAYROTATION *pRotation)
{
WRAP_VERBOSE;
assert(is_d3d9ex);
return D3DERR_INVALIDCALL;
}
@@ -1,86 +1,86 @@
#pragma once
// this file uses the C++ interface of Direct3D9
#ifdef CINTERFACE
#undef CINTERFACE
#endif
#include <atomic>
#include <d3d9.h>
#include "util/logging.h"
struct FakeIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
FakeIDirect3DSwapChain9(IDirect3DDevice9 *pDev, D3DPRESENT_PARAMETERS *present_params, bool is_d3d9ex) :
pDev(pDev), is_d3d9ex(is_d3d9ex)
{
// copy presentation parameters
memcpy(&this->present_params, present_params, sizeof(this->present_params));
// From MSDN https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dpresent-parameters:
// Values of 0 are treated as 1
if (this->present_params.BackBufferCount == 0) {
this->present_params.BackBufferCount = 1;
}
for (size_t i = 0; i < this->present_params.BackBufferCount; i++) {
IDirect3DSurface9 *render_target = nullptr;
HRESULT hr = pDev->CreateRenderTarget(
this->present_params.BackBufferWidth,
this->present_params.BackBufferHeight,
this->present_params.BackBufferFormat,
this->present_params.MultiSampleType,
this->present_params.MultiSampleQuality,
FALSE,
&render_target,
nullptr
);
if (SUCCEEDED(hr)) {
this->render_targets.push_back(render_target);
} else {
log_warning("graphics::d3d9", "failed to create backing render target for fake swap chain, hr={}",
FMT_HRESULT(hr));
}
}
}
FakeIDirect3DSwapChain9(const FakeIDirect3DSwapChain9 &) = delete;
FakeIDirect3DSwapChain9 &operator=(const FakeIDirect3DSwapChain9 &) = delete;
virtual ~FakeIDirect3DSwapChain9(void) {
for (auto &render_target : this->render_targets) {
render_target->Release();
}
}
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
IDirect3DDevice9 *const pDev;
bool is_d3d9ex;
std::atomic<ULONG> ref_cnt = 1;
D3DPRESENT_PARAMETERS present_params {};
std::vector<IDirect3DSurface9 *> render_targets;
};
#pragma once
// this file uses the C++ interface of Direct3D9
#ifdef CINTERFACE
#undef CINTERFACE
#endif
#include <atomic>
#include <d3d9.h>
#include "util/logging.h"
struct FakeIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
FakeIDirect3DSwapChain9(IDirect3DDevice9 *pDev, D3DPRESENT_PARAMETERS *present_params, bool is_d3d9ex) :
pDev(pDev), is_d3d9ex(is_d3d9ex)
{
// copy presentation parameters
memcpy(&this->present_params, present_params, sizeof(this->present_params));
// From MSDN https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dpresent-parameters:
// Values of 0 are treated as 1
if (this->present_params.BackBufferCount == 0) {
this->present_params.BackBufferCount = 1;
}
for (size_t i = 0; i < this->present_params.BackBufferCount; i++) {
IDirect3DSurface9 *render_target = nullptr;
HRESULT hr = pDev->CreateRenderTarget(
this->present_params.BackBufferWidth,
this->present_params.BackBufferHeight,
this->present_params.BackBufferFormat,
this->present_params.MultiSampleType,
this->present_params.MultiSampleQuality,
FALSE,
&render_target,
nullptr
);
if (SUCCEEDED(hr)) {
this->render_targets.push_back(render_target);
} else {
log_warning("graphics::d3d9", "failed to create backing render target for fake swap chain, hr={}",
FMT_HRESULT(hr));
}
}
}
FakeIDirect3DSwapChain9(const FakeIDirect3DSwapChain9 &) = delete;
FakeIDirect3DSwapChain9 &operator=(const FakeIDirect3DSwapChain9 &) = delete;
virtual ~FakeIDirect3DSwapChain9(void) {
for (auto &render_target : this->render_targets) {
render_target->Release();
}
}
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
IDirect3DDevice9 *const pDev;
bool is_d3d9ex;
std::atomic<ULONG> ref_cnt = 1;
D3DPRESENT_PARAMETERS present_params {};
std::vector<IDirect3DSurface9 *> render_targets;
};
+141 -141
View File
@@ -1,141 +1,141 @@
#include "d3d9_swapchain.h"
#include <cassert>
#include <mutex>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "d3d9_backend.h"
#include "d3d9_device.h"
// std::min
#ifdef min
#undef min
#endif
#define CHECK_RESULT(x) \
HRESULT ret = (x); \
if (GRAPHICS_LOG_HRESULT && FAILED(ret)) [[unlikely]] { \
log_warning("graphics::d3d9", "{} failed, hr={}", __FUNCTION__, FMT_HRESULT(ret)); \
} \
return ret
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (//riid == __uuidof(IUnknown) || Ignore IUnknown, it's often queried to test object equality between different interfaces
riid == IID_IDirect3DSwapChain9 ||
riid == IID_IDirect3DSwapChain9Ex)
{
#pragma region Update to IDirect3DSwapChain9Ex interface
if (!is_d3d9ex && riid == IID_IDirect3DSwapChain9Ex) {
IDirect3DSwapChain9Ex *swapchainex = nullptr;
if (FAILED(pReal->QueryInterface(IID_PPV_ARGS(&swapchainex)))) {
return E_NOINTERFACE;
}
pReal->Release();
pReal = swapchainex;
is_d3d9ex = true;
}
#pragma endregion
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::AddRef(void) {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Release(void) {
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
// Metal Gear Arcade expects the swap chain to only have one reference. The parent
// `WrappedIDirect3DDevice9` holds a strong reference to this swap chain which means
// the reference count will be above one. Workaround this by returning a maximum of one.
if (avs::game::is_model("I36")) {
return std::min(refs, 1lu);
}
return refs;
}
/*
* IDirect3DSwapChain9
*/
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Present(const RECT *pSourceRect, const RECT *pDestRect,
HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "WrappedIDirect3DSwapChain9::Present");
});
if (should_run_hooks) {
graphics_d3d9_on_present(pDev->hFocusWindow, pDev->pReal, pDev);
}
CHECK_RESULT(pReal->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *pDestSurface) {
CHECK_RESULT(pReal->GetFrontBufferData(pDestSurface));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type,
IDirect3DSurface9 **ppBackBuffer)
{
CHECK_RESULT(pReal->GetBackBuffer(iBackBuffer, Type, ppBackBuffer));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) {
CHECK_RESULT(pReal->GetRasterStatus(pRasterStatus));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *pMode) {
CHECK_RESULT(pReal->GetDisplayMode(pMode));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDevice(IDirect3DDevice9 **ppDevice) {
if (ppDevice == nullptr) {
return D3DERR_INVALIDCALL;
}
pDev->AddRef();
*ppDevice = pDev;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetPresentParameters(
D3DPRESENT_PARAMETERS *pPresentationParameters)
{
CHECK_RESULT(pReal->GetPresentParameters(pPresentationParameters));
}
/*
* IDirect3DSwapChain9Ex
*/
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetLastPresentCount(UINT *pLastPresentCount) {
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetLastPresentCount(pLastPresentCount));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) {
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetPresentStats(pPresentationStatistics));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDisplayModeEx(D3DDISPLAYMODEEX *pMode,
D3DDISPLAYROTATION *pRotation)
{
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetDisplayModeEx(pMode, pRotation));
}
#include "d3d9_swapchain.h"
#include <cassert>
#include <mutex>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "d3d9_backend.h"
#include "d3d9_device.h"
// std::min
#ifdef min
#undef min
#endif
#define CHECK_RESULT(x) \
HRESULT ret = (x); \
if (GRAPHICS_LOG_HRESULT && FAILED(ret)) [[unlikely]] { \
log_warning("graphics::d3d9", "{} failed, hr={}", __FUNCTION__, FMT_HRESULT(ret)); \
} \
return ret
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::QueryInterface(REFIID riid, void **ppvObj) {
if (ppvObj == nullptr) {
return E_POINTER;
}
if (//riid == __uuidof(IUnknown) || Ignore IUnknown, it's often queried to test object equality between different interfaces
riid == IID_IDirect3DSwapChain9 ||
riid == IID_IDirect3DSwapChain9Ex)
{
#pragma region Update to IDirect3DSwapChain9Ex interface
if (!is_d3d9ex && riid == IID_IDirect3DSwapChain9Ex) {
IDirect3DSwapChain9Ex *swapchainex = nullptr;
if (FAILED(pReal->QueryInterface(IID_PPV_ARGS(&swapchainex)))) {
return E_NOINTERFACE;
}
pReal->Release();
pReal = swapchainex;
is_d3d9ex = true;
}
#pragma endregion
this->AddRef();
*ppvObj = this;
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::AddRef(void) {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Release(void) {
ULONG refs = pReal != nullptr ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
// Metal Gear Arcade expects the swap chain to only have one reference. The parent
// `WrappedIDirect3DDevice9` holds a strong reference to this swap chain which means
// the reference count will be above one. Workaround this by returning a maximum of one.
if (avs::game::is_model("I36")) {
return std::min(refs, 1lu);
}
return refs;
}
/*
* IDirect3DSwapChain9
*/
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::Present(const RECT *pSourceRect, const RECT *pDestRect,
HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags)
{
static std::once_flag printed;
std::call_once(printed, []() {
log_misc("graphics::d3d9", "WrappedIDirect3DSwapChain9::Present");
});
if (should_run_hooks) {
graphics_d3d9_on_present(pDev->hFocusWindow, pDev->pReal, pDev);
}
CHECK_RESULT(pReal->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetFrontBufferData(IDirect3DSurface9 *pDestSurface) {
CHECK_RESULT(pReal->GetFrontBufferData(pDestSurface));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type,
IDirect3DSurface9 **ppBackBuffer)
{
CHECK_RESULT(pReal->GetBackBuffer(iBackBuffer, Type, ppBackBuffer));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) {
CHECK_RESULT(pReal->GetRasterStatus(pRasterStatus));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDisplayMode(D3DDISPLAYMODE *pMode) {
CHECK_RESULT(pReal->GetDisplayMode(pMode));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDevice(IDirect3DDevice9 **ppDevice) {
if (ppDevice == nullptr) {
return D3DERR_INVALIDCALL;
}
pDev->AddRef();
*ppDevice = pDev;
return D3D_OK;
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetPresentParameters(
D3DPRESENT_PARAMETERS *pPresentationParameters)
{
CHECK_RESULT(pReal->GetPresentParameters(pPresentationParameters));
}
/*
* IDirect3DSwapChain9Ex
*/
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetLastPresentCount(UINT *pLastPresentCount) {
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetLastPresentCount(pLastPresentCount));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) {
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetPresentStats(pPresentationStatistics));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DSwapChain9::GetDisplayModeEx(D3DDISPLAYMODEEX *pMode,
D3DDISPLAYROTATION *pRotation)
{
assert(is_d3d9ex);
CHECK_RESULT(static_cast<IDirect3DSwapChain9Ex *>(pReal)->GetDisplayModeEx(pMode, pRotation));
}
+58 -58
View File
@@ -1,58 +1,58 @@
#pragma once
#include <d3d9.h>
interface WrappedIDirect3DDevice9;
struct WrappedIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
WrappedIDirect3DSwapChain9(WrappedIDirect3DDevice9 *dev, IDirect3DSwapChain9 *orig) :
pDev(dev), pReal(orig), is_d3d9ex(false)
{
IDirect3DSwapChain9Ex *swapchain = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&swapchain))) && swapchain != nullptr) {
swapchain->Release();
}
}
WrappedIDirect3DSwapChain9(WrappedIDirect3DDevice9 *dev, IDirect3DSwapChain9Ex *orig) :
pDev(dev), pReal(orig), is_d3d9ex(true)
{
}
virtual ~WrappedIDirect3DSwapChain9(void) {
}
WrappedIDirect3DSwapChain9(const WrappedIDirect3DSwapChain9 &) = delete;
WrappedIDirect3DSwapChain9 &operator=(const WrappedIDirect3DSwapChain9 &) = delete;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
WrappedIDirect3DDevice9 *const pDev;
IDirect3DSwapChain9 *pReal;
bool is_d3d9ex = false;
bool should_run_hooks = true;
};
#pragma once
#include <d3d9.h>
interface WrappedIDirect3DDevice9;
struct WrappedIDirect3DSwapChain9 : IDirect3DSwapChain9Ex {
WrappedIDirect3DSwapChain9(WrappedIDirect3DDevice9 *dev, IDirect3DSwapChain9 *orig) :
pDev(dev), pReal(orig), is_d3d9ex(false)
{
IDirect3DSwapChain9Ex *swapchain = nullptr;
// attempt to upgrade handle
if (SUCCEEDED(this->QueryInterface(IID_PPV_ARGS(&swapchain))) && swapchain != nullptr) {
swapchain->Release();
}
}
WrappedIDirect3DSwapChain9(WrappedIDirect3DDevice9 *dev, IDirect3DSwapChain9Ex *orig) :
pDev(dev), pReal(orig), is_d3d9ex(true)
{
}
virtual ~WrappedIDirect3DSwapChain9(void) {
}
WrappedIDirect3DSwapChain9(const WrappedIDirect3DSwapChain9 &) = delete;
WrappedIDirect3DSwapChain9 &operator=(const WrappedIDirect3DSwapChain9 &) = delete;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DSwapChain9
virtual HRESULT STDMETHODCALLTYPE Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9 *pDestSurface) override;
virtual HRESULT STDMETHODCALLTYPE GetBackBuffer(UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer) override;
virtual HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE *pMode) override;
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters) override;
#pragma endregion
#pragma region IDirect3DSwapChain9Ex
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT *pLastPresentCount) override;
virtual HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS *pPresentationStatistics) override;
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) override;
#pragma endregion
WrappedIDirect3DDevice9 *const pDev;
IDirect3DSwapChain9 *pReal;
bool is_d3d9ex = false;
bool should_run_hooks = true;
};
+127 -127
View File
@@ -1,127 +1,127 @@
#include "d3d9_texture.h"
#include "hooks/graphics/graphics.h"
#include "util/logging.h"
#include "util/utils.h"
#if 0
#define WRAP_DEBUG log_misc("graphics::d3d9::texture", "{}", __FUNCTION__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("graphics::d3d9::texture", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#define CHECK_RESULT(x) \
HRESULT ret = (x); \
if (GRAPHICS_LOG_HRESULT && FAILED(ret)) [[unlikely]] { \
log_warning("graphics::d3d9::texture", "{} failed, hr={}", __FUNCTION__, FMT_HRESULT(ret)); \
} \
return ret;
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::QueryInterface(REFIID riid, void **ppvObj) {
#ifndef __GNUC__
// fast path without incrementing the reference count for texture updates
if (riid == IID_WrappedIDirect3DTexture9) {
return S_OK;
}
#endif
if (ppvObj == nullptr) {
return E_POINTER;
}
if (/* riid == IID_IUnknown || */
riid == IID_IDirect3DResource9 ||
riid == IID_IDirect3DBaseTexture9 ||
riid == IID_IDirect3DTexture9)
{
this->AddRef();
*ppvObj = this;
log_info("graphics::d3d9::texture", "WrappedIDirect3DTexture9::QueryInterface({})", guid2s(riid));
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DTexture9::AddRef(void) {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DTexture9::Release(void) {
ULONG refs = (pReal != nullptr) ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IDirect3DResource9 methods
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetDevice(IDirect3DDevice9 **ppDevice) {
CHECK_RESULT(pReal->GetDevice(ppDevice));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData,
DWORD Flags)
{
CHECK_RESULT(pReal->SetPrivateData(refguid, pData, SizeOfData, Flags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetPrivateData(REFGUID refguid, void *pData, DWORD* pSizeOfData) {
CHECK_RESULT(pReal->GetPrivateData(refguid, pData, pSizeOfData));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::FreePrivateData(REFGUID refguid) {
CHECK_RESULT(pReal->FreePrivateData(refguid));
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetPriority(DWORD PriorityNew) {
return pReal->SetPriority(PriorityNew);
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetPriority(void) {
return pReal->GetPriority();
}
void STDMETHODCALLTYPE WrappedIDirect3DTexture9::PreLoad(void) {
return pReal->PreLoad();
}
D3DRESOURCETYPE STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetType(void) {
return pReal->GetType();
}
// IDirect3DBaseTexture9 methods
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetLOD(DWORD LODNew) {
return pReal->SetLOD(LODNew);
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLOD(void) {
return pReal->GetLOD();
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLevelCount(void) {
return pReal->GetLevelCount();
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) {
CHECK_RESULT(pReal->SetAutoGenFilterType(FilterType));
}
D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetAutoGenFilterType(void) {
return pReal->GetAutoGenFilterType();
}
void STDMETHODCALLTYPE WrappedIDirect3DTexture9::GenerateMipSubLevels(void) {
return pReal->GenerateMipSubLevels();
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
CHECK_RESULT(pReal->GetLevelDesc(Level, pDesc));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) {
CHECK_RESULT(pReal->GetSurfaceLevel(Level, ppSurfaceLevel));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) {
WRAP_DEBUG_FMT("LockRect({}, {}, {}, 0x{:x})", Level, fmt::ptr(pLockedRect), fmt::ptr(pRect), Flags);
CHECK_RESULT(pReal->LockRect(Level, pLockedRect, pRect, Flags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::UnlockRect(UINT Level) {
CHECK_RESULT(pReal->UnlockRect(Level));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::AddDirtyRect(const RECT *pDirtyRect) {
CHECK_RESULT(pReal->AddDirtyRect(pDirtyRect));
}
#include "d3d9_texture.h"
#include "hooks/graphics/graphics.h"
#include "util/logging.h"
#include "util/utils.h"
#if 0
#define WRAP_DEBUG log_misc("graphics::d3d9::texture", "{}", __FUNCTION__)
#define WRAP_DEBUG_FMT(format, ...) log_misc("graphics::d3d9::texture", format, __VA_ARGS__)
#else
#define WRAP_DEBUG do {} while (0)
#define WRAP_DEBUG_FMT(format, ...) do {} while (0)
#endif
#define CHECK_RESULT(x) \
HRESULT ret = (x); \
if (GRAPHICS_LOG_HRESULT && FAILED(ret)) [[unlikely]] { \
log_warning("graphics::d3d9::texture", "{} failed, hr={}", __FUNCTION__, FMT_HRESULT(ret)); \
} \
return ret;
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::QueryInterface(REFIID riid, void **ppvObj) {
#ifndef __GNUC__
// fast path without incrementing the reference count for texture updates
if (riid == IID_WrappedIDirect3DTexture9) {
return S_OK;
}
#endif
if (ppvObj == nullptr) {
return E_POINTER;
}
if (/* riid == IID_IUnknown || */
riid == IID_IDirect3DResource9 ||
riid == IID_IDirect3DBaseTexture9 ||
riid == IID_IDirect3DTexture9)
{
this->AddRef();
*ppvObj = this;
log_info("graphics::d3d9::texture", "WrappedIDirect3DTexture9::QueryInterface({})", guid2s(riid));
return S_OK;
}
return pReal->QueryInterface(riid, ppvObj);
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DTexture9::AddRef(void) {
return pReal->AddRef();
}
ULONG STDMETHODCALLTYPE WrappedIDirect3DTexture9::Release(void) {
ULONG refs = (pReal != nullptr) ? pReal->Release() : 0;
if (refs == 0) {
delete this;
}
return refs;
}
// IDirect3DResource9 methods
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetDevice(IDirect3DDevice9 **ppDevice) {
CHECK_RESULT(pReal->GetDevice(ppDevice));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData,
DWORD Flags)
{
CHECK_RESULT(pReal->SetPrivateData(refguid, pData, SizeOfData, Flags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetPrivateData(REFGUID refguid, void *pData, DWORD* pSizeOfData) {
CHECK_RESULT(pReal->GetPrivateData(refguid, pData, pSizeOfData));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::FreePrivateData(REFGUID refguid) {
CHECK_RESULT(pReal->FreePrivateData(refguid));
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetPriority(DWORD PriorityNew) {
return pReal->SetPriority(PriorityNew);
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetPriority(void) {
return pReal->GetPriority();
}
void STDMETHODCALLTYPE WrappedIDirect3DTexture9::PreLoad(void) {
return pReal->PreLoad();
}
D3DRESOURCETYPE STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetType(void) {
return pReal->GetType();
}
// IDirect3DBaseTexture9 methods
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetLOD(DWORD LODNew) {
return pReal->SetLOD(LODNew);
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLOD(void) {
return pReal->GetLOD();
}
DWORD STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLevelCount(void) {
return pReal->GetLevelCount();
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) {
CHECK_RESULT(pReal->SetAutoGenFilterType(FilterType));
}
D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetAutoGenFilterType(void) {
return pReal->GetAutoGenFilterType();
}
void STDMETHODCALLTYPE WrappedIDirect3DTexture9::GenerateMipSubLevels(void) {
return pReal->GenerateMipSubLevels();
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
CHECK_RESULT(pReal->GetLevelDesc(Level, pDesc));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) {
CHECK_RESULT(pReal->GetSurfaceLevel(Level, ppSurfaceLevel));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) {
WRAP_DEBUG_FMT("LockRect({}, {}, {}, 0x{:x})", Level, fmt::ptr(pLockedRect), fmt::ptr(pRect), Flags);
CHECK_RESULT(pReal->LockRect(Level, pLockedRect, pRect, Flags));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::UnlockRect(UINT Level) {
CHECK_RESULT(pReal->UnlockRect(Level));
}
HRESULT STDMETHODCALLTYPE WrappedIDirect3DTexture9::AddDirtyRect(const RECT *pDirtyRect) {
CHECK_RESULT(pReal->AddDirtyRect(pDirtyRect));
}
+58 -58
View File
@@ -1,58 +1,58 @@
#pragma once
#include <d3d9.h>
#include "util/logging.h"
// {22E9B203-6506-4BC5-B304-A48F3001630F}
static const GUID IID_WrappedIDirect3DTexture9 = {
0x22e9b203, 0x6506, 0x4bc5, { 0xb3, 0x04, 0xa4, 0x8f, 0x30, 0x01, 0x63, 0x0f }
};
struct WrappedIDirect3DTexture9 : IDirect3DTexture9 {
explicit WrappedIDirect3DTexture9(IDirect3DDevice9 *dev, IDirect3DTexture9 *orig) : pDev(dev), pReal(orig) {
log_misc("graphics::d3d9::texture", "Creating texture wrapper around {} => {}", fmt::ptr(orig), fmt::ptr(this));
}
WrappedIDirect3DTexture9(const WrappedIDirect3DTexture9 &) = delete;
WrappedIDirect3DTexture9 &operator=(const WrappedIDirect3DTexture9 &) = delete;
virtual ~WrappedIDirect3DTexture9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DResource9
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID refguid, void *pData, DWORD* pSizeOfData) override;
virtual HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) override;
virtual DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) override;
virtual DWORD STDMETHODCALLTYPE GetPriority(void) override;
virtual void STDMETHODCALLTYPE PreLoad(void) override;
virtual D3DRESOURCETYPE STDMETHODCALLTYPE GetType(void) override;
#pragma endregion
#pragma region IDirect3DBaseTexture9
virtual DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) override;
virtual DWORD STDMETHODCALLTYPE GetLOD(void) override;
virtual DWORD STDMETHODCALLTYPE GetLevelCount(void) override;
virtual HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) override;
virtual D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(void) override;
virtual void STDMETHODCALLTYPE GenerateMipSubLevels(void) override;
#pragma endregion
#pragma region IDirect3DTexture9
virtual HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) override;
virtual HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) override;
virtual HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level) override;
virtual HRESULT STDMETHODCALLTYPE AddDirtyRect(const RECT *pDirtyRect) override;
#pragma endregion
IDirect3DDevice9 *const pDev;
IDirect3DTexture9 *const pReal;
};
#pragma once
#include <d3d9.h>
#include "util/logging.h"
// {22E9B203-6506-4BC5-B304-A48F3001630F}
static const GUID IID_WrappedIDirect3DTexture9 = {
0x22e9b203, 0x6506, 0x4bc5, { 0xb3, 0x04, 0xa4, 0x8f, 0x30, 0x01, 0x63, 0x0f }
};
struct WrappedIDirect3DTexture9 : IDirect3DTexture9 {
explicit WrappedIDirect3DTexture9(IDirect3DDevice9 *dev, IDirect3DTexture9 *orig) : pDev(dev), pReal(orig) {
log_misc("graphics::d3d9::texture", "Creating texture wrapper around {} => {}", fmt::ptr(orig), fmt::ptr(this));
}
WrappedIDirect3DTexture9(const WrappedIDirect3DTexture9 &) = delete;
WrappedIDirect3DTexture9 &operator=(const WrappedIDirect3DTexture9 &) = delete;
virtual ~WrappedIDirect3DTexture9() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
#pragma endregion
#pragma region IDirect3DResource9
virtual HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9 **ppDevice) override;
virtual HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID refguid, void *pData, DWORD* pSizeOfData) override;
virtual HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) override;
virtual DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) override;
virtual DWORD STDMETHODCALLTYPE GetPriority(void) override;
virtual void STDMETHODCALLTYPE PreLoad(void) override;
virtual D3DRESOURCETYPE STDMETHODCALLTYPE GetType(void) override;
#pragma endregion
#pragma region IDirect3DBaseTexture9
virtual DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) override;
virtual DWORD STDMETHODCALLTYPE GetLOD(void) override;
virtual DWORD STDMETHODCALLTYPE GetLevelCount(void) override;
virtual HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) override;
virtual D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType(void) override;
virtual void STDMETHODCALLTYPE GenerateMipSubLevels(void) override;
#pragma endregion
#pragma region IDirect3DTexture9
virtual HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) override;
virtual HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface9 **ppSurfaceLevel) override;
virtual HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags) override;
virtual HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level) override;
virtual HRESULT STDMETHODCALLTYPE AddDirtyRect(const RECT *pDirtyRect) override;
#pragma endregion
IDirect3DDevice9 *const pDev;
IDirect3DTexture9 *const pReal;
};
+112 -112
View File
@@ -1,112 +1,112 @@
#include <initguid.h>
#include "fake_backend.h"
#include <dinput.h>
#include "util/logging.h"
#include "fake_device.h"
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::QueryInterface(
REFIID riid,
void **ppvObj)
{
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IDirectInput8A ||
riid == IID_IDirectInput8W)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirectInput8W::AddRef() {
return ++this->ref_count;
}
ULONG STDMETHODCALLTYPE FakeIDirectInput8W::Release() {
ULONG refs = --this->ref_count;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::CreateDevice(
REFGUID rguid,
LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice,
LPUNKNOWN pUnkOuter)
{
log_misc("input::dinput8", "IDirectInput8::CreateDevice hook hit");
if (lplpDirectInputDevice == nullptr) {
return DIERR_INVALIDPARAM;
}
if (rguid == GUID_SysKeyboard ||
rguid == GUID_SysMouse)
{
log_misc("input::dinput8", "returning stub device");
*lplpDirectInputDevice = new FakeIDirectInputDevice8W();
return DI_OK;
}
return DIERR_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::EnumDevices(
DWORD dwDevType,
LPDIENUMDEVICESCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
log_misc("input::dinput8", "IDirectInput8::EnumDevices hook hit");
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::GetDeviceStatus(REFGUID rguidInstance) {
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::RunControlPanel(HWND hwndOwner, DWORD dwFlags) {
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::Initialize(HINSTANCE hinst, DWORD dwVersion) {
log_misc("input::dinput8", "IDirectInput8::Initialize({}, 0x{:x})",
fmt::ptr(hinst),
dwVersion);
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::FindDevice(
REFGUID rguid,
LPCWSTR pszName,
LPGUID pguidInstance)
{
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::EnumDevicesBySemantics(
LPCWSTR ptszUserName,
LPDIACTIONFORMATW lpdiActionFormat,
LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::ConfigureDevices(
LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
DWORD dwFlags,
LPVOID pvRefData)
{
return DIERR_GENERIC;
}
#include <initguid.h>
#include "fake_backend.h"
#include <dinput.h>
#include "util/logging.h"
#include "fake_device.h"
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::QueryInterface(
REFIID riid,
void **ppvObj)
{
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IDirectInput8A ||
riid == IID_IDirectInput8W)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirectInput8W::AddRef() {
return ++this->ref_count;
}
ULONG STDMETHODCALLTYPE FakeIDirectInput8W::Release() {
ULONG refs = --this->ref_count;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::CreateDevice(
REFGUID rguid,
LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice,
LPUNKNOWN pUnkOuter)
{
log_misc("input::dinput8", "IDirectInput8::CreateDevice hook hit");
if (lplpDirectInputDevice == nullptr) {
return DIERR_INVALIDPARAM;
}
if (rguid == GUID_SysKeyboard ||
rguid == GUID_SysMouse)
{
log_misc("input::dinput8", "returning stub device");
*lplpDirectInputDevice = new FakeIDirectInputDevice8W();
return DI_OK;
}
return DIERR_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::EnumDevices(
DWORD dwDevType,
LPDIENUMDEVICESCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
log_misc("input::dinput8", "IDirectInput8::EnumDevices hook hit");
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::GetDeviceStatus(REFGUID rguidInstance) {
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::RunControlPanel(HWND hwndOwner, DWORD dwFlags) {
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::Initialize(HINSTANCE hinst, DWORD dwVersion) {
log_misc("input::dinput8", "IDirectInput8::Initialize({}, 0x{:x})",
fmt::ptr(hinst),
dwVersion);
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::FindDevice(
REFGUID rguid,
LPCWSTR pszName,
LPGUID pguidInstance)
{
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::EnumDevicesBySemantics(
LPCWSTR ptszUserName,
LPDIACTIONFORMATW lpdiActionFormat,
LPDIENUMDEVICESBYSEMANTICSCBW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_GENERIC;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInput8W::ConfigureDevices(
LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
DWORD dwFlags,
LPVOID pvRefData)
{
return DIERR_GENERIC;
}
+35 -35
View File
@@ -1,35 +1,35 @@
#pragma once
#include <atomic>
#include <dinput.h>
struct FakeIDirectInput8W : IDirectInput8W {
explicit FakeIDirectInput8W() {
}
FakeIDirectInput8W(const FakeIDirectInput8W &) = delete;
FakeIDirectInput8W &operator=(const FakeIDirectInput8W &) = delete;
virtual ~FakeIDirectInput8W() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirectInput8W
virtual HRESULT STDMETHODCALLTYPE CreateDevice(REFGUID rguid, LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) override;
virtual HRESULT STDMETHODCALLTYPE EnumDevices(DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceStatus(REFGUID rguidInstance) override;
virtual HRESULT STDMETHODCALLTYPE RunControlPanel(HWND hwndOwner, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE Initialize(HINSTANCE hinst, DWORD dwVersion) override;
virtual HRESULT STDMETHODCALLTYPE FindDevice(REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) override;
virtual HRESULT STDMETHODCALLTYPE EnumDevicesBySemantics(LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE ConfigureDevices(LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) override;
#pragma endregion
private:
std::atomic<ULONG> ref_count = 1;
};
#pragma once
#include <atomic>
#include <dinput.h>
struct FakeIDirectInput8W : IDirectInput8W {
explicit FakeIDirectInput8W() {
}
FakeIDirectInput8W(const FakeIDirectInput8W &) = delete;
FakeIDirectInput8W &operator=(const FakeIDirectInput8W &) = delete;
virtual ~FakeIDirectInput8W() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirectInput8W
virtual HRESULT STDMETHODCALLTYPE CreateDevice(REFGUID rguid, LPDIRECTINPUTDEVICE8W *lplpDirectInputDevice, LPUNKNOWN pUnkOuter) override;
virtual HRESULT STDMETHODCALLTYPE EnumDevices(DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceStatus(REFGUID rguidInstance) override;
virtual HRESULT STDMETHODCALLTYPE RunControlPanel(HWND hwndOwner, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE Initialize(HINSTANCE hinst, DWORD dwVersion) override;
virtual HRESULT STDMETHODCALLTYPE FindDevice(REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) override;
virtual HRESULT STDMETHODCALLTYPE EnumDevicesBySemantics(LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE ConfigureDevices(LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) override;
#pragma endregion
private:
std::atomic<ULONG> ref_count = 1;
};
+207 -207
View File
@@ -1,207 +1,207 @@
#include <initguid.h>
#include "fake_device.h"
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::QueryInterface(
REFIID riid,
void **ppvObj)
{
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IDirectInputDeviceA ||
riid == IID_IDirectInputDeviceW ||
riid == IID_IDirectInputDevice2A ||
riid == IID_IDirectInputDevice2W ||
riid == IID_IDirectInputDevice7A ||
riid == IID_IDirectInputDevice7W ||
riid == IID_IDirectInputDevice8A ||
riid == IID_IDirectInputDevice8W)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirectInputDevice8W::AddRef() {
return ++this->ref_count;
}
ULONG STDMETHODCALLTYPE FakeIDirectInputDevice8W::Release() {
ULONG refs = --this->ref_count;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetCapabilities(LPDIDEVCAPS lpDIDevCaps) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumObjects(
LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetProperty(
REFGUID rguidProp,
LPDIPROPHEADER pdiph)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetProperty(
REFGUID rguidProp,
LPCDIPROPHEADER pdiph)
{
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Acquire() {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Unacquire() {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetDeviceState(
DWORD cbData,
LPVOID lpvData)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetDeviceData(
DWORD cbObjectData,
LPDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetDataFormat(LPCDIDATAFORMAT lpdf) {
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetEventNotification(HANDLE hEvent) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetCooperativeLevel(
HWND hWnd,
DWORD dwFlags)
{
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetObjectInfo(
LPDIDEVICEOBJECTINSTANCEW pdidoi,
DWORD dwObj,
DWORD dwHow)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetDeviceInfo(
LPDIDEVICEINSTANCEW pdidi)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::RunControlPanel(
HWND hwndOwner,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Initialize(
HINSTANCE hinst,
DWORD dwVersion,
REFGUID rguid)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::CreateEffect(
REFGUID rguid,
LPCDIEFFECT lpeff,
LPDIRECTINPUTEFFECT *ppdeff,
LPUNKNOWN punkOuter)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumEffects(
LPDIENUMEFFECTSCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwEffType)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetEffectInfo(
LPDIEFFECTINFOW pdei,
REFGUID rguid)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetForceFeedbackState(LPDWORD pdwOut) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SendForceFeedbackCommand(DWORD dwFlags) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumCreatedEffectObjects(
LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
LPVOID pvRef,
DWORD fl)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Escape(LPDIEFFESCAPE pesc) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Poll() {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SendDeviceData(
DWORD cbObjectData,
LPCDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD fl)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumEffectsInFile(
LPCWSTR lpszFileName,
LPDIENUMEFFECTSINFILECALLBACK pec,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::WriteEffectToFile(
LPCWSTR lpszFileName,
DWORD dwEntries,
LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::BuildActionMap(
LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetActionMap(
LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetImageInfo(
LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
{
return DIERR_INVALIDPARAM;
}
#include <initguid.h>
#include "fake_device.h"
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::QueryInterface(
REFIID riid,
void **ppvObj)
{
if (ppvObj == nullptr) {
return E_POINTER;
}
if (riid == IID_IDirectInputDeviceA ||
riid == IID_IDirectInputDeviceW ||
riid == IID_IDirectInputDevice2A ||
riid == IID_IDirectInputDevice2W ||
riid == IID_IDirectInputDevice7A ||
riid == IID_IDirectInputDevice7W ||
riid == IID_IDirectInputDevice8A ||
riid == IID_IDirectInputDevice8W)
{
this->AddRef();
*ppvObj = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE FakeIDirectInputDevice8W::AddRef() {
return ++this->ref_count;
}
ULONG STDMETHODCALLTYPE FakeIDirectInputDevice8W::Release() {
ULONG refs = --this->ref_count;
if (refs == 0) {
delete this;
}
return refs;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetCapabilities(LPDIDEVCAPS lpDIDevCaps) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumObjects(
LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetProperty(
REFGUID rguidProp,
LPDIPROPHEADER pdiph)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetProperty(
REFGUID rguidProp,
LPCDIPROPHEADER pdiph)
{
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Acquire() {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Unacquire() {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetDeviceState(
DWORD cbData,
LPVOID lpvData)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetDeviceData(
DWORD cbObjectData,
LPDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetDataFormat(LPCDIDATAFORMAT lpdf) {
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetEventNotification(HANDLE hEvent) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetCooperativeLevel(
HWND hWnd,
DWORD dwFlags)
{
return DI_OK;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetObjectInfo(
LPDIDEVICEOBJECTINSTANCEW pdidoi,
DWORD dwObj,
DWORD dwHow)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetDeviceInfo(
LPDIDEVICEINSTANCEW pdidi)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::RunControlPanel(
HWND hwndOwner,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Initialize(
HINSTANCE hinst,
DWORD dwVersion,
REFGUID rguid)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::CreateEffect(
REFGUID rguid,
LPCDIEFFECT lpeff,
LPDIRECTINPUTEFFECT *ppdeff,
LPUNKNOWN punkOuter)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumEffects(
LPDIENUMEFFECTSCALLBACKW lpCallback,
LPVOID pvRef,
DWORD dwEffType)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetEffectInfo(
LPDIEFFECTINFOW pdei,
REFGUID rguid)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetForceFeedbackState(LPDWORD pdwOut) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SendForceFeedbackCommand(DWORD dwFlags) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumCreatedEffectObjects(
LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
LPVOID pvRef,
DWORD fl)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Escape(LPDIEFFESCAPE pesc) {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::Poll() {
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SendDeviceData(
DWORD cbObjectData,
LPCDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD fl)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::EnumEffectsInFile(
LPCWSTR lpszFileName,
LPDIENUMEFFECTSINFILECALLBACK pec,
LPVOID pvRef,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::WriteEffectToFile(
LPCWSTR lpszFileName,
DWORD dwEntries,
LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::BuildActionMap(
LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::SetActionMap(
LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
return DIERR_INVALIDPARAM;
}
HRESULT STDMETHODCALLTYPE FakeIDirectInputDevice8W::GetImageInfo(
LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
{
return DIERR_INVALIDPARAM;
}
+65 -65
View File
@@ -1,65 +1,65 @@
#pragma once
#include <atomic>
#include <dinput.h>
struct FakeIDirectInputDevice8W : IDirectInputDevice8W {
explicit FakeIDirectInputDevice8W() {
}
FakeIDirectInputDevice8W(const FakeIDirectInputDevice8W &) = delete;
FakeIDirectInputDevice8W &operator=(const FakeIDirectInputDevice8W &) = delete;
virtual ~FakeIDirectInputDevice8W() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirectInputDeviceW
virtual HRESULT STDMETHODCALLTYPE GetCapabilities(LPDIDEVCAPS lpDIDevCaps) override;
virtual HRESULT STDMETHODCALLTYPE EnumObjects(LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetProperty(REFGUID rguidProp, LPDIPROPHEADER pdiph) override;
virtual HRESULT STDMETHODCALLTYPE SetProperty(REFGUID rguidProp, LPCDIPROPHEADER pdiph) override;
virtual HRESULT STDMETHODCALLTYPE Acquire() override;
virtual HRESULT STDMETHODCALLTYPE Unacquire() override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceState(DWORD cbData, LPVOID lpvData) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceData(DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE SetDataFormat(LPCDIDATAFORMAT lpdf) override;
virtual HRESULT STDMETHODCALLTYPE SetEventNotification(HANDLE hEvent) override;
virtual HRESULT STDMETHODCALLTYPE SetCooperativeLevel(HWND hWnd, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetObjectInfo(LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceInfo(LPDIDEVICEINSTANCEW pdidi) override;
virtual HRESULT STDMETHODCALLTYPE RunControlPanel(HWND hwndOwner, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE Initialize(HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) override;
#pragma endregion
#pragma region IDirectInputDevice2W
virtual HRESULT STDMETHODCALLTYPE CreateEffect(REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) override;
virtual HRESULT STDMETHODCALLTYPE EnumEffects(LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) override;
virtual HRESULT STDMETHODCALLTYPE GetEffectInfo(LPDIEFFECTINFOW pdei, REFGUID rguid) override;
virtual HRESULT STDMETHODCALLTYPE GetForceFeedbackState(LPDWORD pdwOut) override;
virtual HRESULT STDMETHODCALLTYPE SendForceFeedbackCommand(DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE EnumCreatedEffectObjects(LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) override;
virtual HRESULT STDMETHODCALLTYPE Escape(LPDIEFFESCAPE pesc) override;
virtual HRESULT STDMETHODCALLTYPE Poll() override;
virtual HRESULT STDMETHODCALLTYPE SendDeviceData(DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) override;
#pragma endregion
#pragma region IDirectInputDevice7W
virtual HRESULT STDMETHODCALLTYPE EnumEffectsInFile(LPCWSTR lpszFileName, LPDIENUMEFFECTSINFILECALLBACK pec, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE WriteEffectToFile(LPCWSTR lpszFileName, DWORD dwEntries, LPDIFILEEFFECT rgDiFileEft, DWORD dwFlags) override;
#pragma endregion
#pragma region IDirectInputDevice8W
virtual HRESULT STDMETHODCALLTYPE BuildActionMap(LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE SetActionMap(LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetImageInfo(LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) override;
#pragma endregion
private:
std::atomic<ULONG> ref_count = 1;
};
#pragma once
#include <atomic>
#include <dinput.h>
struct FakeIDirectInputDevice8W : IDirectInputDevice8W {
explicit FakeIDirectInputDevice8W() {
}
FakeIDirectInputDevice8W(const FakeIDirectInputDevice8W &) = delete;
FakeIDirectInputDevice8W &operator=(const FakeIDirectInputDevice8W &) = delete;
virtual ~FakeIDirectInputDevice8W() = default;
#pragma region IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObj) override;
virtual ULONG STDMETHODCALLTYPE AddRef() override;
virtual ULONG STDMETHODCALLTYPE Release() override;
#pragma endregion
#pragma region IDirectInputDeviceW
virtual HRESULT STDMETHODCALLTYPE GetCapabilities(LPDIDEVCAPS lpDIDevCaps) override;
virtual HRESULT STDMETHODCALLTYPE EnumObjects(LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetProperty(REFGUID rguidProp, LPDIPROPHEADER pdiph) override;
virtual HRESULT STDMETHODCALLTYPE SetProperty(REFGUID rguidProp, LPCDIPROPHEADER pdiph) override;
virtual HRESULT STDMETHODCALLTYPE Acquire() override;
virtual HRESULT STDMETHODCALLTYPE Unacquire() override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceState(DWORD cbData, LPVOID lpvData) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceData(DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE SetDataFormat(LPCDIDATAFORMAT lpdf) override;
virtual HRESULT STDMETHODCALLTYPE SetEventNotification(HANDLE hEvent) override;
virtual HRESULT STDMETHODCALLTYPE SetCooperativeLevel(HWND hWnd, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetObjectInfo(LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) override;
virtual HRESULT STDMETHODCALLTYPE GetDeviceInfo(LPDIDEVICEINSTANCEW pdidi) override;
virtual HRESULT STDMETHODCALLTYPE RunControlPanel(HWND hwndOwner, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE Initialize(HINSTANCE hinst, DWORD dwVersion, REFGUID rguid) override;
#pragma endregion
#pragma region IDirectInputDevice2W
virtual HRESULT STDMETHODCALLTYPE CreateEffect(REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdeff, LPUNKNOWN punkOuter) override;
virtual HRESULT STDMETHODCALLTYPE EnumEffects(LPDIENUMEFFECTSCALLBACKW lpCallback, LPVOID pvRef, DWORD dwEffType) override;
virtual HRESULT STDMETHODCALLTYPE GetEffectInfo(LPDIEFFECTINFOW pdei, REFGUID rguid) override;
virtual HRESULT STDMETHODCALLTYPE GetForceFeedbackState(LPDWORD pdwOut) override;
virtual HRESULT STDMETHODCALLTYPE SendForceFeedbackCommand(DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE EnumCreatedEffectObjects(LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef, DWORD fl) override;
virtual HRESULT STDMETHODCALLTYPE Escape(LPDIEFFESCAPE pesc) override;
virtual HRESULT STDMETHODCALLTYPE Poll() override;
virtual HRESULT STDMETHODCALLTYPE SendDeviceData(DWORD cbObjectData, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl) override;
#pragma endregion
#pragma region IDirectInputDevice7W
virtual HRESULT STDMETHODCALLTYPE EnumEffectsInFile(LPCWSTR lpszFileName, LPDIENUMEFFECTSINFILECALLBACK pec, LPVOID pvRef, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE WriteEffectToFile(LPCWSTR lpszFileName, DWORD dwEntries, LPDIFILEEFFECT rgDiFileEft, DWORD dwFlags) override;
#pragma endregion
#pragma region IDirectInputDevice8W
virtual HRESULT STDMETHODCALLTYPE BuildActionMap(LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE SetActionMap(LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags) override;
virtual HRESULT STDMETHODCALLTYPE GetImageInfo(LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) override;
#pragma endregion
private:
std::atomic<ULONG> ref_count = 1;
};
+51 -51
View File
@@ -1,51 +1,51 @@
#include "hook.h"
#include <windows.h>
#include <dinput.h>
#include "util/detour.h"
#include "util/logging.h"
#include "fake_backend.h"
//static decltype(DirectInput8Create) *DirectInput8Create_orig = nullptr;
static HRESULT WINAPI DirectInput8Create_hook(
HINSTANCE hinst,
DWORD dwVersion,
REFIID riidltf,
LPVOID *ppvOut,
LPUNKNOWN punkOuter)
{
log_misc("input::dinput8", "DirectInput8Create hook hit");
if (ppvOut == nullptr) {
return E_POINTER;
}
*ppvOut = new FakeIDirectInput8W();
return DI_OK;
}
void hooks::input::dinput8::init(HMODULE module) {
/*
* This is for the games using DirectInput for keyboard/gamepad controls themselves,
* for things such as debug controls. We don't want that, neither do we want the game to
* interfere with our RawInput stuff.
*/
log_info("input::dinput8", "attaching...");
// patch IAT
detour::iat_try("DirectInput8Create", DirectInput8Create_hook, module, "dinput8.dll");
/*
if (DirectInput8Create_orig == nullptr) {
DirectInput8Create_orig = orig;
}
*/
log_info("input::dinput8", "attached");
}
#include "hook.h"
#include <windows.h>
#include <dinput.h>
#include "util/detour.h"
#include "util/logging.h"
#include "fake_backend.h"
//static decltype(DirectInput8Create) *DirectInput8Create_orig = nullptr;
static HRESULT WINAPI DirectInput8Create_hook(
HINSTANCE hinst,
DWORD dwVersion,
REFIID riidltf,
LPVOID *ppvOut,
LPUNKNOWN punkOuter)
{
log_misc("input::dinput8", "DirectInput8Create hook hit");
if (ppvOut == nullptr) {
return E_POINTER;
}
*ppvOut = new FakeIDirectInput8W();
return DI_OK;
}
void hooks::input::dinput8::init(HMODULE module) {
/*
* This is for the games using DirectInput for keyboard/gamepad controls themselves,
* for things such as debug controls. We don't want that, neither do we want the game to
* interfere with our RawInput stuff.
*/
log_info("input::dinput8", "attaching...");
// patch IAT
detour::iat_try("DirectInput8Create", DirectInput8Create_hook, module, "dinput8.dll");
/*
if (DirectInput8Create_orig == nullptr) {
DirectInput8Create_orig = orig;
}
*/
log_info("input::dinput8", "attached");
}
+7 -7
View File
@@ -1,7 +1,7 @@
#pragma once
#include <windows.h>
namespace hooks::input::dinput8 {
void init(HMODULE module = nullptr);
}
#pragma once
#include <windows.h>
namespace hooks::input::dinput8 {
void init(HMODULE module = nullptr);
}
+130 -130
View File
@@ -1,130 +1,130 @@
#include "lang.h"
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include "avs/game.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/utils.h"
// ANSI/OEM Japanese; Japanese (Shift-JIS)
constexpr UINT CODEPAGE_SHIFT_JIS = 932;
static decltype(GetACP) *GetACP_orig = nullptr;
static decltype(GetOEMCP) *GetOEMCP_orig = nullptr;
static decltype(MultiByteToWideChar) *MultiByteToWideChar_orig = nullptr;
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
PWCH UnicodeString,
ULONG MaxBytesInUnicodeString,
PULONG BytesInUnicodeString,
const CHAR *MultiByteString,
ULONG BytesInMultiByteString)
{
// try to convert
auto wc_num = MultiByteToWideChar(
CODEPAGE_SHIFT_JIS,
0,
MultiByteString,
static_cast<int>(BytesInMultiByteString),
UnicodeString,
static_cast<int>(MaxBytesInUnicodeString)
);
// error handling
if (!wc_num) {
auto error = GetLastError();
switch (error) {
case ERROR_INSUFFICIENT_BUFFER:
return STATUS_BUFFER_TOO_SMALL;
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_FLAGS:
return STATUS_INVALID_PARAMETER;
case ERROR_NO_UNICODE_TRANSLATION:
return STATUS_UNMAPPABLE_CHARACTER;
default:
return STATUS_UNSUCCESSFUL;
}
}
// set byte count
if (BytesInUnicodeString) {
*BytesInUnicodeString = 2 * static_cast<UINT>(wc_num);
}
// return success
return STATUS_SUCCESS;
}
static UINT WINAPI GetACP_hook() {
return CODEPAGE_SHIFT_JIS;
}
static UINT WINAPI GetOEMCP_hook() {
return CODEPAGE_SHIFT_JIS;
}
static int WINAPI MultiByteToWideChar_hook(
UINT CodePage,
DWORD dwFlags,
LPCCH lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar)
{
switch (CodePage) {
case CP_ACP:
case CP_THREAD_ACP:
// this fixes pop'n music's mojibake issue with the system locale not set to Japanese
SetThreadLocale(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN));
CodePage = CODEPAGE_SHIFT_JIS;
break;
default:
break;
}
return MultiByteToWideChar_orig(
CodePage,
dwFlags,
lpMultiByteStr,
cbMultiByte,
lpWideCharStr,
cchWideChar);
}
void hooks::lang::early_init() {
log_info("hooks::lang", "early initialization");
// hooking these two functions fixes the jubeat mojibake
detour::trampoline_try("kernel32.dll", "GetACP", GetACP_hook, &GetACP_orig);
detour::trampoline_try("kernel32.dll", "GetOEMCP", GetOEMCP_hook, &GetOEMCP_orig);
}
void hooks::lang::init() {
log_info("hooks::lang", "initializing");
detour::iat_try("RtlMultiByteToUnicodeN", RtlMultiByteToUnicodeN_hook, nullptr, "ntdll.dll");
MultiByteToWideChar_orig = detour::iat_try(
"MultiByteToWideChar",
MultiByteToWideChar_hook,
nullptr,
"kernel32.dll");
}
bool hooks::lang::is_native_shiftjis() {
return GetACP() == CODEPAGE_SHIFT_JIS;
}
#include "lang.h"
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <winternl.h>
#include <ntstatus.h>
#include "avs/game.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/utils.h"
// ANSI/OEM Japanese; Japanese (Shift-JIS)
constexpr UINT CODEPAGE_SHIFT_JIS = 932;
static decltype(GetACP) *GetACP_orig = nullptr;
static decltype(GetOEMCP) *GetOEMCP_orig = nullptr;
static decltype(MultiByteToWideChar) *MultiByteToWideChar_orig = nullptr;
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
PWCH UnicodeString,
ULONG MaxBytesInUnicodeString,
PULONG BytesInUnicodeString,
const CHAR *MultiByteString,
ULONG BytesInMultiByteString)
{
// try to convert
auto wc_num = MultiByteToWideChar(
CODEPAGE_SHIFT_JIS,
0,
MultiByteString,
static_cast<int>(BytesInMultiByteString),
UnicodeString,
static_cast<int>(MaxBytesInUnicodeString)
);
// error handling
if (!wc_num) {
auto error = GetLastError();
switch (error) {
case ERROR_INSUFFICIENT_BUFFER:
return STATUS_BUFFER_TOO_SMALL;
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_FLAGS:
return STATUS_INVALID_PARAMETER;
case ERROR_NO_UNICODE_TRANSLATION:
return STATUS_UNMAPPABLE_CHARACTER;
default:
return STATUS_UNSUCCESSFUL;
}
}
// set byte count
if (BytesInUnicodeString) {
*BytesInUnicodeString = 2 * static_cast<UINT>(wc_num);
}
// return success
return STATUS_SUCCESS;
}
static UINT WINAPI GetACP_hook() {
return CODEPAGE_SHIFT_JIS;
}
static UINT WINAPI GetOEMCP_hook() {
return CODEPAGE_SHIFT_JIS;
}
static int WINAPI MultiByteToWideChar_hook(
UINT CodePage,
DWORD dwFlags,
LPCCH lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar)
{
switch (CodePage) {
case CP_ACP:
case CP_THREAD_ACP:
// this fixes pop'n music's mojibake issue with the system locale not set to Japanese
SetThreadLocale(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN));
CodePage = CODEPAGE_SHIFT_JIS;
break;
default:
break;
}
return MultiByteToWideChar_orig(
CodePage,
dwFlags,
lpMultiByteStr,
cbMultiByte,
lpWideCharStr,
cchWideChar);
}
void hooks::lang::early_init() {
log_info("hooks::lang", "early initialization");
// hooking these two functions fixes the jubeat mojibake
detour::trampoline_try("kernel32.dll", "GetACP", GetACP_hook, &GetACP_orig);
detour::trampoline_try("kernel32.dll", "GetOEMCP", GetOEMCP_hook, &GetOEMCP_orig);
}
void hooks::lang::init() {
log_info("hooks::lang", "initializing");
detour::iat_try("RtlMultiByteToUnicodeN", RtlMultiByteToUnicodeN_hook, nullptr, "ntdll.dll");
MultiByteToWideChar_orig = detour::iat_try(
"MultiByteToWideChar",
MultiByteToWideChar_hook,
nullptr,
"kernel32.dll");
}
bool hooks::lang::is_native_shiftjis() {
return GetACP() == CODEPAGE_SHIFT_JIS;
}
+7 -7
View File
@@ -1,7 +1,7 @@
#pragma once
namespace hooks::lang {
void early_init();
void init();
bool is_native_shiftjis();
}
#pragma once
namespace hooks::lang {
void early_init();
void init();
bool is_native_shiftjis();
}
+125 -125
View File
@@ -1,125 +1,125 @@
#include "libraryhook.h"
#include "external/robin_hood.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/utils.h"
static bool LHOOK_ENABLED = false;
static robin_hood::unordered_map<std::string, HMODULE> LIBRARIES_A;
static robin_hood::unordered_map<std::wstring, HMODULE> LIBRARIES_W;
static robin_hood::unordered_map<std::string, FARPROC> PROCS;
static decltype(LoadLibraryA) *LoadLibraryA_orig = nullptr;
static decltype(LoadLibraryW) *LoadLibraryW_orig = nullptr;
static decltype(GetModuleHandleA) *GetModuleHandleA_orig = nullptr;
static decltype(GetModuleHandleW) *GetModuleHandleW_orig = nullptr;
static decltype(GetProcAddress) *GetProcAddress_orig = nullptr;
static HMODULE WINAPI LoadLibraryA_hook(LPCTSTR lpFileName) {
// check hooks
if (lpFileName) {
auto module = LIBRARIES_A.find(lpFileName);
if (module != LIBRARIES_A.end()) {
return module->second;
}
}
// fallback
return LoadLibraryA_orig(lpFileName);
}
static HMODULE WINAPI LoadLibraryW_hook(LPCWSTR lpFileName) {
// check hooks
if (lpFileName) {
auto module = LIBRARIES_W.find(lpFileName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return LoadLibraryW_orig(lpFileName);
}
static HMODULE WINAPI GetModuleHandleA_hook(LPCSTR lpModuleName) {
// check hooks
if (lpModuleName) {
auto module = LIBRARIES_A.find(lpModuleName);
if (module != LIBRARIES_A.end()) {
return module->second;
}
}
// fallback
return GetModuleHandleA_orig(lpModuleName);
}
static HMODULE WINAPI GetModuleHandleW_hook(LPCWSTR lpModuleName) {
// check hooks
if (lpModuleName) {
auto module = LIBRARIES_W.find(lpModuleName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return GetModuleHandleW_orig(lpModuleName);
}
static FARPROC WINAPI GetProcAddress_hook(HMODULE hModule, LPCSTR lpProcName) {
// check for ordinal
if (reinterpret_cast<uintptr_t>(lpProcName) <= UINT16_MAX) {
// fallback
return GetProcAddress_orig(hModule, lpProcName);
}
// check hooks
if (lpProcName) {
auto proc = PROCS.find(lpProcName);
if (proc != PROCS.end()) {
return proc->second;
}
}
// fallback
return GetProcAddress_orig(hModule, lpProcName);
}
void libraryhook_enable(HMODULE module) {
log_info("libraryhook", "LibraryHook Attach");
if (LHOOK_ENABLED) {
return;
}
// detour
detour::trampoline_try("kernel32.dll", "LoadLibraryA", LoadLibraryA_hook, &LoadLibraryA_orig);
detour::trampoline_try("kernel32.dll", "LoadLibraryW", LoadLibraryW_hook, &LoadLibraryW_orig);
detour::trampoline_try("kernel32.dll", "GetModuleHandleA", GetModuleHandleA_hook, &GetModuleHandleA_orig);
detour::trampoline_try("kernel32.dll", "GetModuleHandleW", GetModuleHandleW_hook, &GetModuleHandleW_orig);
detour::trampoline_try("kernel32.dll", "GetProcAddress", GetProcAddress_hook, &GetProcAddress_orig);
// set enabled
LHOOK_ENABLED = true;
}
void libraryhook_hook_library(std::string library_name, HMODULE library_address) {
// add library to list
LIBRARIES_W.insert_or_assign(s2ws(library_name), library_address);
LIBRARIES_A.insert_or_assign(std::move(library_name), library_address);
}
void libraryhook_hook_proc(std::string proc_name, FARPROC proc_address) {
// add proc to list
PROCS.insert_or_assign(std::move(proc_name), proc_address);
}
#include "libraryhook.h"
#include "external/robin_hood.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/utils.h"
static bool LHOOK_ENABLED = false;
static robin_hood::unordered_map<std::string, HMODULE> LIBRARIES_A;
static robin_hood::unordered_map<std::wstring, HMODULE> LIBRARIES_W;
static robin_hood::unordered_map<std::string, FARPROC> PROCS;
static decltype(LoadLibraryA) *LoadLibraryA_orig = nullptr;
static decltype(LoadLibraryW) *LoadLibraryW_orig = nullptr;
static decltype(GetModuleHandleA) *GetModuleHandleA_orig = nullptr;
static decltype(GetModuleHandleW) *GetModuleHandleW_orig = nullptr;
static decltype(GetProcAddress) *GetProcAddress_orig = nullptr;
static HMODULE WINAPI LoadLibraryA_hook(LPCTSTR lpFileName) {
// check hooks
if (lpFileName) {
auto module = LIBRARIES_A.find(lpFileName);
if (module != LIBRARIES_A.end()) {
return module->second;
}
}
// fallback
return LoadLibraryA_orig(lpFileName);
}
static HMODULE WINAPI LoadLibraryW_hook(LPCWSTR lpFileName) {
// check hooks
if (lpFileName) {
auto module = LIBRARIES_W.find(lpFileName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return LoadLibraryW_orig(lpFileName);
}
static HMODULE WINAPI GetModuleHandleA_hook(LPCSTR lpModuleName) {
// check hooks
if (lpModuleName) {
auto module = LIBRARIES_A.find(lpModuleName);
if (module != LIBRARIES_A.end()) {
return module->second;
}
}
// fallback
return GetModuleHandleA_orig(lpModuleName);
}
static HMODULE WINAPI GetModuleHandleW_hook(LPCWSTR lpModuleName) {
// check hooks
if (lpModuleName) {
auto module = LIBRARIES_W.find(lpModuleName);
if (module != LIBRARIES_W.end()) {
return module->second;
}
}
// fallback
return GetModuleHandleW_orig(lpModuleName);
}
static FARPROC WINAPI GetProcAddress_hook(HMODULE hModule, LPCSTR lpProcName) {
// check for ordinal
if (reinterpret_cast<uintptr_t>(lpProcName) <= UINT16_MAX) {
// fallback
return GetProcAddress_orig(hModule, lpProcName);
}
// check hooks
if (lpProcName) {
auto proc = PROCS.find(lpProcName);
if (proc != PROCS.end()) {
return proc->second;
}
}
// fallback
return GetProcAddress_orig(hModule, lpProcName);
}
void libraryhook_enable(HMODULE module) {
log_info("libraryhook", "LibraryHook Attach");
if (LHOOK_ENABLED) {
return;
}
// detour
detour::trampoline_try("kernel32.dll", "LoadLibraryA", LoadLibraryA_hook, &LoadLibraryA_orig);
detour::trampoline_try("kernel32.dll", "LoadLibraryW", LoadLibraryW_hook, &LoadLibraryW_orig);
detour::trampoline_try("kernel32.dll", "GetModuleHandleA", GetModuleHandleA_hook, &GetModuleHandleA_orig);
detour::trampoline_try("kernel32.dll", "GetModuleHandleW", GetModuleHandleW_hook, &GetModuleHandleW_orig);
detour::trampoline_try("kernel32.dll", "GetProcAddress", GetProcAddress_hook, &GetProcAddress_orig);
// set enabled
LHOOK_ENABLED = true;
}
void libraryhook_hook_library(std::string library_name, HMODULE library_address) {
// add library to list
LIBRARIES_W.insert_or_assign(s2ws(library_name), library_address);
LIBRARIES_A.insert_or_assign(std::move(library_name), library_address);
}
void libraryhook_hook_proc(std::string proc_name, FARPROC proc_address) {
// add proc to list
PROCS.insert_or_assign(std::move(proc_name), proc_address);
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
#include <string>
#include <windows.h>
void libraryhook_enable(HMODULE module = nullptr);
void libraryhook_hook_library(std::string library_name, HMODULE library_address);
void libraryhook_hook_proc(std::string proc_name, FARPROC proc_address);
template<typename T>
inline void libraryhook_hook_proc(std::string proc_name, T proc_address) {
libraryhook_hook_proc(std::move(proc_name), reinterpret_cast<FARPROC>(proc_address));
}
#pragma once
#include <string>
#include <windows.h>
void libraryhook_enable(HMODULE module = nullptr);
void libraryhook_hook_library(std::string library_name, HMODULE library_address);
void libraryhook_hook_proc(std::string proc_name, FARPROC proc_address);
template<typename T>
inline void libraryhook_hook_proc(std::string proc_name, T proc_address) {
libraryhook_hook_proc(std::move(proc_name), reinterpret_cast<FARPROC>(proc_address));
}
+224 -224
View File
@@ -1,224 +1,224 @@
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
#include <stdlib.h>
#include <string>
#include "avs/core.h"
#include "avs/ea3.h"
#include "avs/game.h"
#include "util/logging.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/libutils.h"
// hooking related stuff
static decltype(GetAdaptersInfo) *GetAdaptersInfo_orig = nullptr;
static decltype(bind) *bind_orig = nullptr;
// settings
std::string NETWORK_ADDRESS = "10.9.0.0";
std::string NETWORK_SUBNET = "255.255.0.0";
static bool GetAdaptersInfo_log = true;
// network structs
static struct in_addr network;
static struct in_addr prefix;
static struct in_addr subnet;
static ULONG WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) {
// call orig
ULONG ret = GetAdaptersInfo_orig(pAdapterInfo, pOutBufLen);
if (ret != ERROR_SUCCESS) {
// workaround for QMA not having enough buffer space
if (pAdapterInfo != nullptr && avs::game::is_model({ "LMA", "MMA" })) {
// allocate the output buffer size
auto pAdapterInfo2 = (PIP_ADAPTER_INFO) malloc(*pOutBufLen);
// call ourself with an appropriate buffer size
ret = GetAdaptersInfo_hook(pAdapterInfo2, pOutBufLen);
if (ret != ERROR_SUCCESS) {
return ret;
}
// copy best interface
memcpy(pAdapterInfo, pAdapterInfo2, sizeof(*pAdapterInfo));
pAdapterInfo->Next = nullptr;
// free our allocated memory
free(pAdapterInfo2);
}
return ret;
}
// set the best network adapter
PIP_ADAPTER_INFO info = pAdapterInfo;
while (info != nullptr) {
// set subnet
struct in_addr info_subnet;
info_subnet.s_addr = inet_addr(info->IpAddressList.IpMask.String);
// set prefix
struct in_addr info_prefix;
info_prefix.s_addr = inet_addr(info->IpAddressList.IpAddress.String) & info_subnet.s_addr;
// check base IP and subnet
bool isCorrectBaseIp = prefix.s_addr == info_prefix.s_addr;
bool isCorrectSubnetMask = subnet.s_addr == info_subnet.s_addr;
// check if requirements are met
if (isCorrectBaseIp && isCorrectSubnetMask) {
// log adapter
if (GetAdaptersInfo_log)
log_info("network", "Using preferred network adapter: {}, {}, {}",
info->AdapterName,
info->IpAddressList.IpAddress.String,
info->IpAddressList.IpMask.String);
// set adapter information
memcpy(pAdapterInfo, info, sizeof(*info));
pAdapterInfo->Next = nullptr;
// we're done
GetAdaptersInfo_log = false;
return ret;
}
// iterate
info = info->Next;
}
// get IP forward table
PMIB_IPFORWARDTABLE pIpForwardTable = (MIB_IPFORWARDTABLE *) malloc(sizeof(MIB_IPFORWARDTABLE));
DWORD dwSize = 0;
if (GetIpForwardTable(pIpForwardTable, &dwSize, 1) == ERROR_INSUFFICIENT_BUFFER) {
free(pIpForwardTable);
pIpForwardTable = (MIB_IPFORWARDTABLE *) malloc(dwSize);
}
if (GetIpForwardTable(pIpForwardTable, &dwSize, 1) != NO_ERROR || pIpForwardTable->dwNumEntries == 0)
return ret;
// determine best interface
DWORD best = pIpForwardTable->table[0].dwForwardIfIndex;
free(pIpForwardTable);
// find fallback adapter
info = pAdapterInfo;
while (info != nullptr) {
// check if this the adapter we search for
if (info->Index == best) {
// log information
if (GetAdaptersInfo_log)
log_info("network", "Using fallback adapter: {}, {}, {}",
info->AdapterName,
info->IpAddressList.IpAddress.String,
info->IpAddressList.IpMask.String);
// set adapter information
memcpy(pAdapterInfo, info, sizeof(*info));
pAdapterInfo->Next = nullptr;
// exit the loop
break;
}
// iterate
info = info->Next;
}
// return original value
GetAdaptersInfo_log = false;
return ret;
}
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCDFAInspection"
// cast to sockaddr_in
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
#pragma clang diagnostic pop
// override bind to allow all hosts
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
// call original
int ret = bind_orig(s, name, namelen);
if (ret != 0) {
log_warning("network", "bind failed: {}", WSAGetLastError());
}
// return result
return ret;
}
void networkhook_init() {
// announce init
log_info("network", "SpiceTools Network");
// set some same defaults
network.s_addr = inet_addr(NETWORK_ADDRESS.c_str());
subnet.s_addr = inet_addr(NETWORK_SUBNET.c_str());
prefix.s_addr = network.s_addr & subnet.s_addr;
// inet_ntoa(...) reuses the same char array so the results must be copied
char s_network[17]{}, s_subnet[17]{}, s_prefix[17]{};
strncpy(s_network, inet_ntoa(network), 16);
strncpy(s_subnet, inet_ntoa(subnet), 16);
strncpy(s_prefix, inet_ntoa(prefix), 16);
// log preferences
log_info("network", "Network preferences: {}", s_network, s_subnet, s_prefix);
// GetAdaptersInfo hook
auto orig_addr = detour::iat_try(
"GetAdaptersInfo", GetAdaptersInfo_hook, nullptr);
if (!orig_addr) {
log_warning("network", "Could not hook GetAdaptersInfo");
} else if (GetAdaptersInfo_orig == nullptr) {
GetAdaptersInfo_orig = orig_addr;
}
/*
* Bind Hook
*/
bool bind_hook_enabled = true;
// disable hook for DDR A since the bind hook crashes there for some reason
if (fileutils::file_exists(MODULE_PATH / "gamemdx.dll")) {
bind_hook_enabled = false;
}
// hook bind
if (bind_hook_enabled) {
// hook by name
auto new_bind_orig = detour::iat_try("bind", bind_hook, nullptr);
if (bind_orig == nullptr) {
bind_orig = new_bind_orig;
}
// hook ESS by ordinal
HMODULE ess = libutils::try_module("ess.dll");
if (ess) {
auto new_bind_orig2 = detour::iat_try_ordinal("WS2_32.dll", 2, bind_hook, ess);
// try to get some valid pointer
if (bind_orig == nullptr && new_bind_orig2 != nullptr) {
bind_orig = new_bind_orig2;
}
}
}
}
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
#include <stdlib.h>
#include <string>
#include "avs/core.h"
#include "avs/ea3.h"
#include "avs/game.h"
#include "util/logging.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/libutils.h"
// hooking related stuff
static decltype(GetAdaptersInfo) *GetAdaptersInfo_orig = nullptr;
static decltype(bind) *bind_orig = nullptr;
// settings
std::string NETWORK_ADDRESS = "10.9.0.0";
std::string NETWORK_SUBNET = "255.255.0.0";
static bool GetAdaptersInfo_log = true;
// network structs
static struct in_addr network;
static struct in_addr prefix;
static struct in_addr subnet;
static ULONG WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) {
// call orig
ULONG ret = GetAdaptersInfo_orig(pAdapterInfo, pOutBufLen);
if (ret != ERROR_SUCCESS) {
// workaround for QMA not having enough buffer space
if (pAdapterInfo != nullptr && avs::game::is_model({ "LMA", "MMA" })) {
// allocate the output buffer size
auto pAdapterInfo2 = (PIP_ADAPTER_INFO) malloc(*pOutBufLen);
// call ourself with an appropriate buffer size
ret = GetAdaptersInfo_hook(pAdapterInfo2, pOutBufLen);
if (ret != ERROR_SUCCESS) {
return ret;
}
// copy best interface
memcpy(pAdapterInfo, pAdapterInfo2, sizeof(*pAdapterInfo));
pAdapterInfo->Next = nullptr;
// free our allocated memory
free(pAdapterInfo2);
}
return ret;
}
// set the best network adapter
PIP_ADAPTER_INFO info = pAdapterInfo;
while (info != nullptr) {
// set subnet
struct in_addr info_subnet;
info_subnet.s_addr = inet_addr(info->IpAddressList.IpMask.String);
// set prefix
struct in_addr info_prefix;
info_prefix.s_addr = inet_addr(info->IpAddressList.IpAddress.String) & info_subnet.s_addr;
// check base IP and subnet
bool isCorrectBaseIp = prefix.s_addr == info_prefix.s_addr;
bool isCorrectSubnetMask = subnet.s_addr == info_subnet.s_addr;
// check if requirements are met
if (isCorrectBaseIp && isCorrectSubnetMask) {
// log adapter
if (GetAdaptersInfo_log)
log_info("network", "Using preferred network adapter: {}, {}, {}",
info->AdapterName,
info->IpAddressList.IpAddress.String,
info->IpAddressList.IpMask.String);
// set adapter information
memcpy(pAdapterInfo, info, sizeof(*info));
pAdapterInfo->Next = nullptr;
// we're done
GetAdaptersInfo_log = false;
return ret;
}
// iterate
info = info->Next;
}
// get IP forward table
PMIB_IPFORWARDTABLE pIpForwardTable = (MIB_IPFORWARDTABLE *) malloc(sizeof(MIB_IPFORWARDTABLE));
DWORD dwSize = 0;
if (GetIpForwardTable(pIpForwardTable, &dwSize, 1) == ERROR_INSUFFICIENT_BUFFER) {
free(pIpForwardTable);
pIpForwardTable = (MIB_IPFORWARDTABLE *) malloc(dwSize);
}
if (GetIpForwardTable(pIpForwardTable, &dwSize, 1) != NO_ERROR || pIpForwardTable->dwNumEntries == 0)
return ret;
// determine best interface
DWORD best = pIpForwardTable->table[0].dwForwardIfIndex;
free(pIpForwardTable);
// find fallback adapter
info = pAdapterInfo;
while (info != nullptr) {
// check if this the adapter we search for
if (info->Index == best) {
// log information
if (GetAdaptersInfo_log)
log_info("network", "Using fallback adapter: {}, {}, {}",
info->AdapterName,
info->IpAddressList.IpAddress.String,
info->IpAddressList.IpMask.String);
// set adapter information
memcpy(pAdapterInfo, info, sizeof(*info));
pAdapterInfo->Next = nullptr;
// exit the loop
break;
}
// iterate
info = info->Next;
}
// return original value
GetAdaptersInfo_log = false;
return ret;
}
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCDFAInspection"
// cast to sockaddr_in
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
#pragma clang diagnostic pop
// override bind to allow all hosts
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
// call original
int ret = bind_orig(s, name, namelen);
if (ret != 0) {
log_warning("network", "bind failed: {}", WSAGetLastError());
}
// return result
return ret;
}
void networkhook_init() {
// announce init
log_info("network", "SpiceTools Network");
// set some same defaults
network.s_addr = inet_addr(NETWORK_ADDRESS.c_str());
subnet.s_addr = inet_addr(NETWORK_SUBNET.c_str());
prefix.s_addr = network.s_addr & subnet.s_addr;
// inet_ntoa(...) reuses the same char array so the results must be copied
char s_network[17]{}, s_subnet[17]{}, s_prefix[17]{};
strncpy(s_network, inet_ntoa(network), 16);
strncpy(s_subnet, inet_ntoa(subnet), 16);
strncpy(s_prefix, inet_ntoa(prefix), 16);
// log preferences
log_info("network", "Network preferences: {}", s_network, s_subnet, s_prefix);
// GetAdaptersInfo hook
auto orig_addr = detour::iat_try(
"GetAdaptersInfo", GetAdaptersInfo_hook, nullptr);
if (!orig_addr) {
log_warning("network", "Could not hook GetAdaptersInfo");
} else if (GetAdaptersInfo_orig == nullptr) {
GetAdaptersInfo_orig = orig_addr;
}
/*
* Bind Hook
*/
bool bind_hook_enabled = true;
// disable hook for DDR A since the bind hook crashes there for some reason
if (fileutils::file_exists(MODULE_PATH / "gamemdx.dll")) {
bind_hook_enabled = false;
}
// hook bind
if (bind_hook_enabled) {
// hook by name
auto new_bind_orig = detour::iat_try("bind", bind_hook, nullptr);
if (bind_orig == nullptr) {
bind_orig = new_bind_orig;
}
// hook ESS by ordinal
HMODULE ess = libutils::try_module("ess.dll");
if (ess) {
auto new_bind_orig2 = detour::iat_try_ordinal("WS2_32.dll", 2, bind_hook, ess);
// try to get some valid pointer
if (bind_orig == nullptr && new_bind_orig2 != nullptr) {
bind_orig = new_bind_orig2;
}
}
}
}
+8 -8
View File
@@ -1,8 +1,8 @@
#pragma once
#include <string>
extern std::string NETWORK_ADDRESS;
extern std::string NETWORK_SUBNET;
void networkhook_init();
#pragma once
#include <string>
extern std::string NETWORK_ADDRESS;
extern std::string NETWORK_SUBNET;
void networkhook_init();
+75 -75
View File
@@ -1,75 +1,75 @@
#include "rom.h"
#include "util/logging.h"
#include "util/utils.h"
#include "avs/game.h"
#include "hooks/devicehook.h"
namespace hooks::rom {
static std::string MODEL;
class ROMFileHandle : public CustomHandle {
private:
int offset = 0;
public:
bool open(LPCWSTR lpFileName) override {
if (wcsicmp(lpFileName, L"D:\\001rom.txt")
&& wcsicmp(lpFileName, L"D:\\\\001rom.txt")) {
return false;
}
log_info("romhook", "opened 001rom.txt");
offset = 0;
return true;
}
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override {
int ret = 0;
for (int i = 0; i < (signed) MIN(nNumberOfBytesToRead, MODEL.length() - offset); i++) {
*((char*) lpBuffer + i) = MODEL[i + offset];
ret++;
}
offset += ret;
if (offset == (int) MODEL.length()) {
log_info("romhook", "read complete: {}", MODEL);
}
return ret;
}
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override {
return 0;
}
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) override {
return -1;
}
bool close() override {
return true;
}
void file_info(LPBY_HANDLE_FILE_INFORMATION lpFileInformation) override {
*lpFileInformation = BY_HANDLE_FILE_INFORMATION {};
lpFileInformation->nFileSizeLow = MODEL.length();
}
};
void init() {
log_info("romhook", "init");
// populate model
if (MODEL.empty()) {
MODEL = avs::game::MODEL;
}
// add device hook
devicehook_init();
devicehook_add(new ROMFileHandle());
}
void set_model(const std::string &model) {
MODEL = model;
}
}
#include "rom.h"
#include "util/logging.h"
#include "util/utils.h"
#include "avs/game.h"
#include "hooks/devicehook.h"
namespace hooks::rom {
static std::string MODEL;
class ROMFileHandle : public CustomHandle {
private:
int offset = 0;
public:
bool open(LPCWSTR lpFileName) override {
if (wcsicmp(lpFileName, L"D:\\001rom.txt")
&& wcsicmp(lpFileName, L"D:\\\\001rom.txt")) {
return false;
}
log_info("romhook", "opened 001rom.txt");
offset = 0;
return true;
}
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override {
int ret = 0;
for (int i = 0; i < (signed) MIN(nNumberOfBytesToRead, MODEL.length() - offset); i++) {
*((char*) lpBuffer + i) = MODEL[i + offset];
ret++;
}
offset += ret;
if (offset == (int) MODEL.length()) {
log_info("romhook", "read complete: {}", MODEL);
}
return ret;
}
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override {
return 0;
}
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) override {
return -1;
}
bool close() override {
return true;
}
void file_info(LPBY_HANDLE_FILE_INFORMATION lpFileInformation) override {
*lpFileInformation = BY_HANDLE_FILE_INFORMATION {};
lpFileInformation->nFileSizeLow = MODEL.length();
}
};
void init() {
log_info("romhook", "init");
// populate model
if (MODEL.empty()) {
MODEL = avs::game::MODEL;
}
// add device hook
devicehook_init();
devicehook_add(new ROMFileHandle());
}
void set_model(const std::string &model) {
MODEL = model;
}
}
+9 -9
View File
@@ -1,9 +1,9 @@
#pragma once
#include <string>
namespace hooks::rom {
void init();
void set_model(const std::string &model);
}
#pragma once
#include <string>
namespace hooks::rom {
void init();
void set_model(const std::string &model);
}
+14 -14
View File
@@ -1,14 +1,14 @@
#pragma once
#include <windows.h>
struct SETUPAPI_SETTINGS {
unsigned int class_guid[4] {};
char property_devicedesc[256] {};
char property_hardwareid[256] {};
DWORD property_address[2] {};
char interface_detail[256] {};
};
void setupapihook_init(HINSTANCE module);
void setupapihook_add(SETUPAPI_SETTINGS settings);
#pragma once
#include <windows.h>
struct SETUPAPI_SETTINGS {
unsigned int class_guid[4] {};
char property_devicedesc[256] {};
char property_hardwareid[256] {};
DWORD property_address[2] {};
char interface_detail[256] {};
};
void setupapihook_init(HINSTANCE module);
void setupapihook_add(SETUPAPI_SETTINGS settings);
+43 -43
View File
@@ -1,43 +1,43 @@
#include "sleephook.h"
#include "avs/game.h"
#include "util/detour.h"
// settings
static DWORD SLEEPHOOK_MS_MAX;
static DWORD SLEEPHOOK_MS_REPLACE;
static decltype(Sleep) *Sleep_orig = nullptr;
static decltype(SleepEx) *SleepEx_orig = nullptr;
static VOID WINAPI Sleep_hook(DWORD dwMilliseconds) {
if (dwMilliseconds > SLEEPHOOK_MS_MAX) {
dwMilliseconds = SLEEPHOOK_MS_REPLACE;
}
Sleep_orig(dwMilliseconds);
}
static DWORD WINAPI SleepEx_hook(DWORD dwMilliseconds, BOOL bAltertable) {
if (dwMilliseconds > SLEEPHOOK_MS_MAX) {
dwMilliseconds = SLEEPHOOK_MS_REPLACE;
}
return SleepEx_orig(dwMilliseconds, bAltertable);
}
void hooks::sleep::init(DWORD ms_max, DWORD ms_replace, HMODULE module) {
// auto module
if (!module) {
module = avs::game::DLL_INSTANCE;
}
// settings
SLEEPHOOK_MS_MAX = ms_max;
SLEEPHOOK_MS_REPLACE = ms_replace;
// hook functions
Sleep_orig = detour::iat_try("Sleep", Sleep_hook, module);
SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, module);
}
#include "sleephook.h"
#include "avs/game.h"
#include "util/detour.h"
// settings
static DWORD SLEEPHOOK_MS_MAX;
static DWORD SLEEPHOOK_MS_REPLACE;
static decltype(Sleep) *Sleep_orig = nullptr;
static decltype(SleepEx) *SleepEx_orig = nullptr;
static VOID WINAPI Sleep_hook(DWORD dwMilliseconds) {
if (dwMilliseconds > SLEEPHOOK_MS_MAX) {
dwMilliseconds = SLEEPHOOK_MS_REPLACE;
}
Sleep_orig(dwMilliseconds);
}
static DWORD WINAPI SleepEx_hook(DWORD dwMilliseconds, BOOL bAltertable) {
if (dwMilliseconds > SLEEPHOOK_MS_MAX) {
dwMilliseconds = SLEEPHOOK_MS_REPLACE;
}
return SleepEx_orig(dwMilliseconds, bAltertable);
}
void hooks::sleep::init(DWORD ms_max, DWORD ms_replace, HMODULE module) {
// auto module
if (!module) {
module = avs::game::DLL_INSTANCE;
}
// settings
SLEEPHOOK_MS_MAX = ms_max;
SLEEPHOOK_MS_REPLACE = ms_replace;
// hook functions
Sleep_orig = detour::iat_try("Sleep", Sleep_hook, module);
SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, module);
}
+7 -7
View File
@@ -1,7 +1,7 @@
#pragma once
#include <windows.h>
namespace hooks::sleep {
void init(DWORD ms_max, DWORD ms_replace, HMODULE module = nullptr);
}
#pragma once
#include <windows.h>
namespace hooks::sleep {
void init(DWORD ms_max, DWORD ms_replace, HMODULE module = nullptr);
}
+144 -144
View File
@@ -1,144 +1,144 @@
#include "unisintrhook.h"
#include "avs/game.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/libutils.h"
bool CreateInstance() {
return true;
}
int GetGMT() {
// fallback to avs clock
return -1;
}
int GetQRcodeLen(void*) {
return 0;
}
void GetQRcodeURL(void*, char* dest) {
}
void InitModel(char* model, int) {
}
void InitPlayerCount(int players) {
}
void InitPrivilege(int) {
}
void InitVersion(int unis_ver_major, int unis_ver_minor) {
}
bool IsConnectServer(void) {
if (avs::game::is_model("KFC") || avs::game::is_model("REC")) {
return false;
}
return true;
}
bool IsInComm(void) {
return true;
}
bool IsPlayerForbidState(int) {
return false;
}
void RcfAddCoin(void* callback) {}
void RcfCommFailed(void* callback) {}
void RcfCommSucceed(void* callback) {}
void RcfCountdown(void* callback) {}
void RcfDebugLog(void* callback) {}
void RcfGameSwitch(void* callback) {}
void RcfMachineEffects(void* callback) {}
void RcfMachineMode(void* callback) {}
void RcfOtherInfo(void* callback) {}
void RcfPayoutFailed(void* callback) {}
void RcfPayoutSucceed(void* callback) {}
void RcfPlayerInfo(void* callback) {}
void RcfPrintTicket(void* callback) {}
void RcfPrivilege(void* callback) {}
void RcfRankingResult(void* callback) {}
void RcfRecvComm(void* callback) {}
void RcfRecvPayout(void* callback) {}
void RcfRecvTransp(void* callback) {}
void RcfTranspFailed(void* callback) {}
void RcfTranspSucceed(void* callback) {}
void RcfWinPrize(void* callback) {}
int RefreshPlayerState(int player) {
return 0;
}
void ReleaseInstance(void) {
}
int SendCoinSignal(int, int, int) {
return 0;
}
int SendTransp(int, int) {
return 1;
}
void StartDevice(void) {
}
void unisintrhook_init(void) {
// check for module
auto unisintr = libutils::try_module("unisintr.dll");
if (unisintr != nullptr) {
log_info("unisintrhook", "attaching...");
// TODO: SDVX CN doesn't like this...?
if (!avs::game::is_model("KFC")) {
detour::iat_try("GetGMT", GetGMT, nullptr, "unisintr.dll");
}
// hooks
detour::iat_try("CreateInstance", CreateInstance, nullptr, "unisintr.dll");
detour::iat_try("GetQRcodeLen", GetQRcodeLen, nullptr, "unisintr.dll");
detour::iat_try("GetQRcodeURL", GetQRcodeURL, nullptr, "unisintr.dll");
detour::iat_try("InitModel", InitModel, nullptr, "unisintr.dll");
detour::iat_try("InitPlayerCount", InitPlayerCount, nullptr, "unisintr.dll");
detour::iat_try("InitPrivilege", InitPrivilege, nullptr, "unisintr.dll");
detour::iat_try("InitVersion", InitVersion, nullptr, "unisintr.dll");
detour::iat_try("IsConnectServer", IsConnectServer, nullptr, "unisintr.dll");
detour::iat_try("IsInComm", IsInComm, nullptr, "unisintr.dll");
detour::iat_try("IsPlayerForbidState", IsPlayerForbidState, nullptr, "unisintr.dll");
detour::iat_try("RcfAddCoin", RcfAddCoin, nullptr, "unisintr.dll");
detour::iat_try("RcfCommFailed", RcfCommFailed, nullptr, "unisintr.dll");
detour::iat_try("RcfCommSucceed", RcfCommSucceed, nullptr, "unisintr.dll");
detour::iat_try("RcfCountdown", RcfCountdown, nullptr, "unisintr.dll");
detour::iat_try("RcfDebugLog", RcfDebugLog, nullptr, "unisintr.dll");
detour::iat_try("RcfGameSwitch", RcfGameSwitch, nullptr, "unisintr.dll");
detour::iat_try("RcfMachineEffects", RcfMachineEffects, nullptr, "unisintr.dll");
detour::iat_try("RcfMachineMode", RcfMachineMode, nullptr, "unisintr.dll");
detour::iat_try("RcfOtherInfo", RcfOtherInfo, nullptr, "unisintr.dll");
detour::iat_try("RcfPayoutFailed", RcfPayoutFailed, nullptr, "unisintr.dll");
detour::iat_try("RcfPayoutSucceed", RcfPayoutSucceed, nullptr, "unisintr.dll");
detour::iat_try("RcfPlayerInfo", RcfPlayerInfo, nullptr, "unisintr.dll");
detour::iat_try("RcfPrintTicket", RcfPrintTicket, nullptr, "unisintr.dll");
detour::iat_try("RcfPrivilege", RcfPrivilege, nullptr, "unisintr.dll");
detour::iat_try("RcfRankingResult", RcfRankingResult, nullptr, "unisintr.dll");
detour::iat_try("RcfRecvComm", RcfRecvComm, nullptr, "unisintr.dll");
detour::iat_try("RcfRecvPayout", RcfRecvPayout, nullptr, "unisintr.dll");
detour::iat_try("RcfRecvTransp", RcfRecvTransp, nullptr, "unisintr.dll");
detour::iat_try("RcfTranspFailed", RcfTranspFailed, nullptr, "unisintr.dll");
detour::iat_try("RcfTranspSucceed", RcfTranspSucceed, nullptr, "unisintr.dll");
detour::iat_try("RcfWinPrize", RcfWinPrize, nullptr, "unisintr.dll");
detour::iat_try("RefreshPlayerState", RefreshPlayerState, nullptr, "unisintr.dll");
detour::iat_try("ReleaseInstance", ReleaseInstance, nullptr, "unisintr.dll");
detour::iat_try("SendCoinSignal", SendCoinSignal, nullptr, "unisintr.dll");
detour::iat_try("SendTransp", SendTransp, nullptr, "unisintr.dll");
detour::iat_try("StartDevice", StartDevice, nullptr, "unisintr.dll");
log_info("unisintrhook", "attached");
}
}
#include "unisintrhook.h"
#include "avs/game.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/libutils.h"
bool CreateInstance() {
return true;
}
int GetGMT() {
// fallback to avs clock
return -1;
}
int GetQRcodeLen(void*) {
return 0;
}
void GetQRcodeURL(void*, char* dest) {
}
void InitModel(char* model, int) {
}
void InitPlayerCount(int players) {
}
void InitPrivilege(int) {
}
void InitVersion(int unis_ver_major, int unis_ver_minor) {
}
bool IsConnectServer(void) {
if (avs::game::is_model("KFC") || avs::game::is_model("REC")) {
return false;
}
return true;
}
bool IsInComm(void) {
return true;
}
bool IsPlayerForbidState(int) {
return false;
}
void RcfAddCoin(void* callback) {}
void RcfCommFailed(void* callback) {}
void RcfCommSucceed(void* callback) {}
void RcfCountdown(void* callback) {}
void RcfDebugLog(void* callback) {}
void RcfGameSwitch(void* callback) {}
void RcfMachineEffects(void* callback) {}
void RcfMachineMode(void* callback) {}
void RcfOtherInfo(void* callback) {}
void RcfPayoutFailed(void* callback) {}
void RcfPayoutSucceed(void* callback) {}
void RcfPlayerInfo(void* callback) {}
void RcfPrintTicket(void* callback) {}
void RcfPrivilege(void* callback) {}
void RcfRankingResult(void* callback) {}
void RcfRecvComm(void* callback) {}
void RcfRecvPayout(void* callback) {}
void RcfRecvTransp(void* callback) {}
void RcfTranspFailed(void* callback) {}
void RcfTranspSucceed(void* callback) {}
void RcfWinPrize(void* callback) {}
int RefreshPlayerState(int player) {
return 0;
}
void ReleaseInstance(void) {
}
int SendCoinSignal(int, int, int) {
return 0;
}
int SendTransp(int, int) {
return 1;
}
void StartDevice(void) {
}
void unisintrhook_init(void) {
// check for module
auto unisintr = libutils::try_module("unisintr.dll");
if (unisintr != nullptr) {
log_info("unisintrhook", "attaching...");
// TODO: SDVX CN doesn't like this...?
if (!avs::game::is_model("KFC")) {
detour::iat_try("GetGMT", GetGMT, nullptr, "unisintr.dll");
}
// hooks
detour::iat_try("CreateInstance", CreateInstance, nullptr, "unisintr.dll");
detour::iat_try("GetQRcodeLen", GetQRcodeLen, nullptr, "unisintr.dll");
detour::iat_try("GetQRcodeURL", GetQRcodeURL, nullptr, "unisintr.dll");
detour::iat_try("InitModel", InitModel, nullptr, "unisintr.dll");
detour::iat_try("InitPlayerCount", InitPlayerCount, nullptr, "unisintr.dll");
detour::iat_try("InitPrivilege", InitPrivilege, nullptr, "unisintr.dll");
detour::iat_try("InitVersion", InitVersion, nullptr, "unisintr.dll");
detour::iat_try("IsConnectServer", IsConnectServer, nullptr, "unisintr.dll");
detour::iat_try("IsInComm", IsInComm, nullptr, "unisintr.dll");
detour::iat_try("IsPlayerForbidState", IsPlayerForbidState, nullptr, "unisintr.dll");
detour::iat_try("RcfAddCoin", RcfAddCoin, nullptr, "unisintr.dll");
detour::iat_try("RcfCommFailed", RcfCommFailed, nullptr, "unisintr.dll");
detour::iat_try("RcfCommSucceed", RcfCommSucceed, nullptr, "unisintr.dll");
detour::iat_try("RcfCountdown", RcfCountdown, nullptr, "unisintr.dll");
detour::iat_try("RcfDebugLog", RcfDebugLog, nullptr, "unisintr.dll");
detour::iat_try("RcfGameSwitch", RcfGameSwitch, nullptr, "unisintr.dll");
detour::iat_try("RcfMachineEffects", RcfMachineEffects, nullptr, "unisintr.dll");
detour::iat_try("RcfMachineMode", RcfMachineMode, nullptr, "unisintr.dll");
detour::iat_try("RcfOtherInfo", RcfOtherInfo, nullptr, "unisintr.dll");
detour::iat_try("RcfPayoutFailed", RcfPayoutFailed, nullptr, "unisintr.dll");
detour::iat_try("RcfPayoutSucceed", RcfPayoutSucceed, nullptr, "unisintr.dll");
detour::iat_try("RcfPlayerInfo", RcfPlayerInfo, nullptr, "unisintr.dll");
detour::iat_try("RcfPrintTicket", RcfPrintTicket, nullptr, "unisintr.dll");
detour::iat_try("RcfPrivilege", RcfPrivilege, nullptr, "unisintr.dll");
detour::iat_try("RcfRankingResult", RcfRankingResult, nullptr, "unisintr.dll");
detour::iat_try("RcfRecvComm", RcfRecvComm, nullptr, "unisintr.dll");
detour::iat_try("RcfRecvPayout", RcfRecvPayout, nullptr, "unisintr.dll");
detour::iat_try("RcfRecvTransp", RcfRecvTransp, nullptr, "unisintr.dll");
detour::iat_try("RcfTranspFailed", RcfTranspFailed, nullptr, "unisintr.dll");
detour::iat_try("RcfTranspSucceed", RcfTranspSucceed, nullptr, "unisintr.dll");
detour::iat_try("RcfWinPrize", RcfWinPrize, nullptr, "unisintr.dll");
detour::iat_try("RefreshPlayerState", RefreshPlayerState, nullptr, "unisintr.dll");
detour::iat_try("ReleaseInstance", ReleaseInstance, nullptr, "unisintr.dll");
detour::iat_try("SendCoinSignal", SendCoinSignal, nullptr, "unisintr.dll");
detour::iat_try("SendTransp", SendTransp, nullptr, "unisintr.dll");
detour::iat_try("StartDevice", StartDevice, nullptr, "unisintr.dll");
log_info("unisintrhook", "attached");
}
}
+3 -3
View File
@@ -1,3 +1,3 @@
#pragma once
void unisintrhook_init(void);
#pragma once
void unisintrhook_init(void);