Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
avsdlls += iidxhook8
|
||||
|
||||
ldflags_iidxhook8 := \
|
||||
-liphlpapi \
|
||||
-lsetupapi \
|
||||
-lcfgmgr32 \
|
||||
-lmf \
|
||||
-lmfplat \
|
||||
-lole32 \
|
||||
|
||||
deplibs_iidxhook8 := \
|
||||
avs \
|
||||
|
||||
libs_iidxhook8 := \
|
||||
iidxhook-util \
|
||||
acioemu \
|
||||
iidxio \
|
||||
hook \
|
||||
hooklib \
|
||||
cconfig \
|
||||
util \
|
||||
eamio \
|
||||
|
||||
src_iidxhook8 := \
|
||||
bi2a.c \
|
||||
bio2.c \
|
||||
cam.c \
|
||||
config-cam.c \
|
||||
config-io.c \
|
||||
dllmain.c \
|
||||
setupapi.c \
|
||||
@@ -0,0 +1,251 @@
|
||||
#define LOG_MODULE "bio2emu-bi2a"
|
||||
|
||||
#include "iidxhook8/bi2a.h"
|
||||
|
||||
#include <windows.h> /* for _BitScanForward */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "acioemu/emu.h"
|
||||
|
||||
#include "bemanitools/iidxio.h"
|
||||
|
||||
static int get_default_slider_valid(size_t idx);
|
||||
static void bio2_emu_bi2a_cmd_send_version(const struct ac_io_message *req);
|
||||
static void bio2_emu_bi2a_send_state(const struct ac_io_message *req);
|
||||
static void bio2_emu_bi2a_send_empty(const struct ac_io_message *req);
|
||||
static void bio2_emu_bi2a_send_status(const struct ac_io_message *req, uint8_t status);
|
||||
|
||||
static struct ac_io_emu *bi2a_bio2;
|
||||
static int default_sliders[5];
|
||||
static bool poll_delay;
|
||||
|
||||
int get_default_slider_valid(size_t idx) {
|
||||
if (default_sliders[idx] >= 0 && default_sliders[idx] <= 15) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bio2_emu_bi2a_init(struct ac_io_emu *bio2_emu, bool disable_poll_limiter)
|
||||
{
|
||||
FILE* f;
|
||||
bi2a_bio2 = bio2_emu;
|
||||
poll_delay = !disable_poll_limiter;
|
||||
if (!poll_delay) {
|
||||
log_warning("bio2_emu_bi2a_init: poll_delay has been disabled");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
default_sliders[i] = -1;
|
||||
}
|
||||
|
||||
f = fopen("vefx.txt", "r");
|
||||
if (f) {
|
||||
fscanf(f, "%d %d %d %d %d", &default_sliders[0], &default_sliders[1], &default_sliders[2], &default_sliders[3], &default_sliders[4]);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void bio2_emu_bi2a_dispatch_request(const struct ac_io_message *req)
|
||||
{
|
||||
uint16_t cmd_code;
|
||||
|
||||
cmd_code = ac_io_u16(req->cmd.code);
|
||||
|
||||
switch (cmd_code) {
|
||||
case BIO2_BI2A_CMD_UNK_0100:
|
||||
case BIO2_BI2A_CMD_UNK_0120:
|
||||
log_misc("BIO2_BI2A_CMD_UNK_%04X(%d)", cmd_code, req->addr);
|
||||
bio2_emu_bi2a_send_status(req, 0x00);
|
||||
break;
|
||||
|
||||
case BIO2_BI2A_CMD_POLL:
|
||||
// log_misc("BIO2_BI2A_CMD_POLL");
|
||||
bio2_emu_bi2a_send_state(req);
|
||||
break;
|
||||
|
||||
case AC_IO_CMD_GET_VERSION:
|
||||
log_misc("BIO2_CMD_GET_VERSION(%d)", req->addr);
|
||||
bio2_emu_bi2a_cmd_send_version(req);
|
||||
break;
|
||||
|
||||
case AC_IO_CMD_START_UP:
|
||||
log_misc("BIO2_CMD_START_UP(%d)", req->addr);
|
||||
bio2_emu_bi2a_send_status(req, 0x00);
|
||||
break;
|
||||
|
||||
case AC_IO_CMD_KEEPALIVE:
|
||||
log_misc("BIO2_CMD_KEEPALIVE(%d)", req->addr);
|
||||
bio2_emu_bi2a_send_empty(req);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("Unknown BIO2 message %04x on BI2A node, addr=%d", cmd_code, req->addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bio2_emu_bi2a_cmd_send_version(const struct ac_io_message *req)
|
||||
{
|
||||
struct ac_io_message resp;
|
||||
|
||||
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
|
||||
resp.cmd.code = req->cmd.code;
|
||||
resp.cmd.seq_no = req->cmd.seq_no;
|
||||
resp.cmd.nbytes = sizeof(resp.cmd.version);
|
||||
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_BI2A);
|
||||
resp.cmd.version.flag = 0x00;
|
||||
resp.cmd.version.major = 0x04;
|
||||
resp.cmd.version.minor = 0x00;
|
||||
resp.cmd.version.revision = 0x04;
|
||||
memcpy(resp.cmd.version.product_code, "BI2A",
|
||||
sizeof(resp.cmd.version.product_code));
|
||||
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
|
||||
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
|
||||
|
||||
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
|
||||
}
|
||||
|
||||
static void bio2_emu_bi2a_send_empty(const struct ac_io_message *req)
|
||||
{
|
||||
struct ac_io_message resp;
|
||||
|
||||
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
|
||||
resp.cmd.code = req->cmd.code;
|
||||
resp.cmd.seq_no = req->cmd.seq_no;
|
||||
resp.cmd.nbytes = 0;
|
||||
|
||||
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
|
||||
}
|
||||
|
||||
static void bio2_emu_bi2a_send_status(const struct ac_io_message *req, uint8_t status)
|
||||
{
|
||||
struct ac_io_message resp;
|
||||
|
||||
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
|
||||
resp.cmd.code = req->cmd.code;
|
||||
resp.cmd.seq_no = req->cmd.seq_no;
|
||||
resp.cmd.nbytes = sizeof(resp.cmd.status);
|
||||
resp.cmd.status = status;
|
||||
|
||||
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
|
||||
}
|
||||
|
||||
|
||||
static void bio2_emu_bi2a_send_state(const struct ac_io_message *req)
|
||||
{
|
||||
struct ac_io_message resp;
|
||||
struct bio2_bi2a_state *body;
|
||||
struct bio2_bi2a_state_in *req_bi2a;
|
||||
|
||||
uint8_t input_sys = 0;
|
||||
uint8_t input_panel = 0;
|
||||
uint16_t input_keys = 0;
|
||||
|
||||
struct {
|
||||
uint8_t panel_lights;
|
||||
uint16_t deck_lights;
|
||||
uint8_t top_lamps;
|
||||
} packed_lights;
|
||||
|
||||
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
|
||||
resp.cmd.code = req->cmd.code;
|
||||
resp.cmd.seq_no = req->cmd.seq_no;
|
||||
resp.cmd.nbytes = sizeof(struct bio2_bi2a_state);
|
||||
req_bi2a = (struct bio2_bi2a_state_in*)req->cmd.raw;
|
||||
|
||||
packed_lights.panel_lights = 0;
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
if (req_bi2a->PANEL[i].l_state) {
|
||||
packed_lights.panel_lights |= (1 << i);
|
||||
}
|
||||
}
|
||||
packed_lights.deck_lights = 0;
|
||||
for (size_t i = 0; i < 14; ++i) {
|
||||
if (req_bi2a->DECKSW[i].l_state) {
|
||||
packed_lights.deck_lights |= (1 << i);
|
||||
}
|
||||
}
|
||||
packed_lights.top_lamps = 0;
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
if (req_bi2a->SPOTLIGHT1[i].l_state) {
|
||||
packed_lights.top_lamps |= (1 << i);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
if (req_bi2a->SPOTLIGHT2[i].l_state) {
|
||||
packed_lights.top_lamps |= (1 << (i + 4));
|
||||
}
|
||||
}
|
||||
|
||||
iidx_io_ep1_set_deck_lights(packed_lights.deck_lights);
|
||||
iidx_io_ep1_set_panel_lights(packed_lights.panel_lights);
|
||||
iidx_io_ep1_set_top_lamps(packed_lights.top_lamps);
|
||||
iidx_io_ep1_set_top_neons(req_bi2a->NEONLAMP.l_state);
|
||||
|
||||
if (!iidx_io_ep1_send()) {
|
||||
log_warning("BIO2: iidx_io_ep1_send error");
|
||||
return bio2_emu_bi2a_send_status(req, 0);
|
||||
}
|
||||
|
||||
if (!iidx_io_ep3_write_16seg((const char*) req_bi2a->SEG16)) {
|
||||
log_warning("BIO2: iidx_io_ep3_write_16seg error");
|
||||
return bio2_emu_bi2a_send_status(req, 0);
|
||||
}
|
||||
|
||||
body = (struct bio2_bi2a_state *)&resp.cmd.raw;
|
||||
memset(body, 0, sizeof(struct bio2_bi2a_state));
|
||||
|
||||
// IIDX25 polls really really fast, this limits it to 1000Hz
|
||||
if (poll_delay) {
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
if (!iidx_io_ep2_recv()) {
|
||||
log_warning("BIO2: iidx_io_ep2_recv error");
|
||||
return bio2_emu_bi2a_send_status(req, 0);
|
||||
}
|
||||
|
||||
body->TURNTABLE1 = iidx_io_ep2_get_turntable(0);
|
||||
body->TURNTABLE2 = iidx_io_ep2_get_turntable(1);
|
||||
|
||||
body->SLIDER1.s_val = get_default_slider_valid(0) ? default_sliders[0] : iidx_io_ep2_get_slider(0);
|
||||
body->SLIDER2.s_val = get_default_slider_valid(1) ? default_sliders[1] : iidx_io_ep2_get_slider(1);
|
||||
body->SLIDER3.s_val = get_default_slider_valid(2) ? default_sliders[2] : iidx_io_ep2_get_slider(2);
|
||||
body->SLIDER4.s_val = get_default_slider_valid(3) ? default_sliders[3] : iidx_io_ep2_get_slider(3);
|
||||
body->SLIDER5.s_val = get_default_slider_valid(4) ? default_sliders[4] : iidx_io_ep2_get_slider(4);
|
||||
|
||||
input_keys = iidx_io_ep2_get_keys();
|
||||
input_sys = iidx_io_ep2_get_sys();
|
||||
input_panel = iidx_io_ep2_get_panel();
|
||||
body->P1SW1.b_val = (input_keys >> IIDX_IO_KEY_P1_1) & 1;
|
||||
body->P1SW2.b_val = (input_keys >> IIDX_IO_KEY_P1_2) & 1;
|
||||
body->P1SW3.b_val = (input_keys >> IIDX_IO_KEY_P1_3) & 1;
|
||||
body->P1SW4.b_val = (input_keys >> IIDX_IO_KEY_P1_4) & 1;
|
||||
body->P1SW5.b_val = (input_keys >> IIDX_IO_KEY_P1_5) & 1;
|
||||
body->P1SW6.b_val = (input_keys >> IIDX_IO_KEY_P1_6) & 1;
|
||||
body->P1SW7.b_val = (input_keys >> IIDX_IO_KEY_P1_7) & 1;
|
||||
body->P2SW1.b_val = (input_keys >> IIDX_IO_KEY_P2_1) & 1;
|
||||
body->P2SW2.b_val = (input_keys >> IIDX_IO_KEY_P2_2) & 1;
|
||||
body->P2SW3.b_val = (input_keys >> IIDX_IO_KEY_P2_3) & 1;
|
||||
body->P2SW4.b_val = (input_keys >> IIDX_IO_KEY_P2_4) & 1;
|
||||
body->P2SW5.b_val = (input_keys >> IIDX_IO_KEY_P2_5) & 1;
|
||||
body->P2SW6.b_val = (input_keys >> IIDX_IO_KEY_P2_6) & 1;
|
||||
body->P2SW7.b_val = (input_keys >> IIDX_IO_KEY_P2_7) & 1;
|
||||
|
||||
body->PANEL.y_start1 = (input_panel >> IIDX_IO_PANEL_P1_START) & 1;
|
||||
body->PANEL.y_start2 = (input_panel >> IIDX_IO_PANEL_P2_START) & 1;
|
||||
body->PANEL.y_vefx = (input_panel >> IIDX_IO_PANEL_VEFX) & 1;
|
||||
body->PANEL.y_effect = (input_panel >> IIDX_IO_PANEL_EFFECT) & 1;
|
||||
|
||||
body->SYSTEM.v_test = (input_sys >> IIDX_IO_SYS_TEST) & 1;
|
||||
body->SYSTEM.v_service = (input_sys >> IIDX_IO_SYS_SERVICE) & 1;
|
||||
body->SYSTEM.v_coin = (input_sys >> IIDX_IO_SYS_COIN) & 1;
|
||||
|
||||
ac_io_emu_response_push(bi2a_bio2, &resp, 0);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef IIDXHOOK_BI2A_H
|
||||
#define IIDXHOOK_BI2A_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "acioemu/emu.h"
|
||||
|
||||
enum bio2_bi2a_cmd {
|
||||
// Custom Stuff
|
||||
BIO2_BI2A_CMD_UNK_0100 = 0x0100,
|
||||
BIO2_BI2A_CMD_UNK_0120 = 0x0120,
|
||||
BIO2_BI2A_CMD_POLL = 0x0152,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct _slider {
|
||||
uint8_t s_unk : 4;
|
||||
uint8_t s_val : 4;
|
||||
};
|
||||
|
||||
struct _system {
|
||||
uint8_t v_unk1 : 1;
|
||||
uint8_t v_coin : 1;
|
||||
uint8_t v_service : 1;
|
||||
uint8_t v_test : 1;
|
||||
uint8_t v_unk2 : 4;
|
||||
};
|
||||
|
||||
struct _button {
|
||||
uint8_t b_unk : 7;
|
||||
uint8_t b_val : 1;
|
||||
};
|
||||
|
||||
struct _panel {
|
||||
uint8_t y_unk : 4;
|
||||
uint8_t y_effect : 1;
|
||||
uint8_t y_vefx : 1;
|
||||
uint8_t y_start2 : 1;
|
||||
uint8_t y_start1 : 1;
|
||||
};
|
||||
|
||||
struct bio2_bi2a_state {
|
||||
struct _slider SLIDER1;
|
||||
struct _system SYSTEM;
|
||||
struct _slider SLIDER2;
|
||||
uint8_t UNK1;
|
||||
struct _slider SLIDER3;
|
||||
uint8_t UNK2;
|
||||
struct _slider SLIDER4;
|
||||
struct _slider SLIDER5;
|
||||
uint8_t UNK3; // coin mech?
|
||||
struct _panel PANEL;
|
||||
uint8_t UNK4;
|
||||
uint8_t UNK5;
|
||||
uint8_t UNK6;
|
||||
uint8_t UNK7;
|
||||
uint8_t UNK8;
|
||||
uint8_t UNK9;
|
||||
uint8_t TURNTABLE1;
|
||||
uint8_t TURNTABLE2;
|
||||
struct _button P1SW1;
|
||||
uint8_t UNK11;
|
||||
struct _button P1SW2;
|
||||
uint8_t UNK12;
|
||||
struct _button P1SW3;
|
||||
uint8_t UNK13;
|
||||
struct _button P1SW4;
|
||||
uint8_t UNK14;
|
||||
struct _button P1SW5;
|
||||
uint8_t UNK15;
|
||||
struct _button P1SW6;
|
||||
uint8_t UNK16;
|
||||
struct _button P1SW7;
|
||||
uint8_t UNK17;
|
||||
struct _button P2SW1;
|
||||
uint8_t UNK21;
|
||||
struct _button P2SW2;
|
||||
uint8_t UNK22;
|
||||
struct _button P2SW3;
|
||||
uint8_t UNK23;
|
||||
struct _button P2SW4;
|
||||
uint8_t UNK24;
|
||||
struct _button P2SW5;
|
||||
uint8_t UNK25;
|
||||
struct _button P2SW6;
|
||||
uint8_t UNK26;
|
||||
struct _button P2SW7;
|
||||
uint8_t UNK27;
|
||||
};
|
||||
|
||||
struct _light {
|
||||
uint8_t l_unk : 7;
|
||||
uint8_t l_state : 1;
|
||||
};
|
||||
|
||||
struct bio2_bi2a_state_in {
|
||||
struct _light UNK1[3];
|
||||
struct _light PANEL[4];
|
||||
struct _light DECKSW[14];
|
||||
uint8_t UNK2[2];
|
||||
uint8_t SEG16[9];
|
||||
struct _light SPOTLIGHT1[4];
|
||||
struct _light NEONLAMP;
|
||||
struct _light SPOTLIGHT2[4];
|
||||
uint8_t UNK3[7];
|
||||
};
|
||||
_Static_assert(sizeof(struct bio2_bi2a_state_in) == 48, "bio2_bi2a_state_in is the wrong size");
|
||||
#pragma pack(pop)
|
||||
|
||||
void bio2_emu_bi2a_init(struct ac_io_emu *in, bool disable_poll_limiter);
|
||||
void bio2_emu_bi2a_dispatch_request(const struct ac_io_message *req);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <ntdef.h>
|
||||
#include <devioctl.h>
|
||||
#include <ntddser.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "acioemu/addr.h"
|
||||
#include "acioemu/emu.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "iidxhook8/bi2a.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/iobuf.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static struct ac_io_emu bio2_emu;
|
||||
|
||||
void bio2_port_init(bool disable_poll_limiter)
|
||||
{
|
||||
// yes I'm using acio
|
||||
// they use the same framing
|
||||
ac_io_emu_init(&bio2_emu, L"COM4");
|
||||
bio2_emu_bi2a_init(&bio2_emu, disable_poll_limiter);
|
||||
}
|
||||
|
||||
void bio2_port_fini(void)
|
||||
{
|
||||
ac_io_emu_fini(&bio2_emu);
|
||||
}
|
||||
|
||||
HRESULT bio2_port_dispatch_irp(struct irp *irp)
|
||||
{
|
||||
const struct ac_io_message *msg;
|
||||
HRESULT hr;
|
||||
|
||||
log_assert(irp != NULL);
|
||||
|
||||
if (!ac_io_emu_match_irp(&bio2_emu, irp)) {
|
||||
return irp_invoke_next(irp);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
hr = ac_io_emu_dispatch_irp(&bio2_emu, irp);
|
||||
|
||||
if (hr != S_OK) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
msg = ac_io_emu_request_peek(&bio2_emu);
|
||||
|
||||
switch (msg->addr) {
|
||||
case 0:
|
||||
ac_io_emu_cmd_assign_addrs(&bio2_emu, msg, 1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
bio2_emu_bi2a_dispatch_request(msg);
|
||||
break;
|
||||
|
||||
case AC_IO_BROADCAST:
|
||||
log_warning("Broadcast(?) message on IIDX BIO2 bus?");
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("BIO2 message on unhandled bus address: %d", msg->addr);
|
||||
break;
|
||||
}
|
||||
|
||||
ac_io_emu_request_pop(&bio2_emu);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef IIDXHOOK_BIO2_H
|
||||
#define IIDXHOOK_BIO2_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
void bio2_port_init(bool disable_poll_limiter);
|
||||
void bio2_port_fini(void);
|
||||
HRESULT bio2_port_dispatch_irp(struct irp *irp);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,731 @@
|
||||
#define LOG_MODULE "cam-hook"
|
||||
|
||||
#include <initguid.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <mfobjects.h>
|
||||
#include <mfidl.h>
|
||||
#include <mfapi.h>
|
||||
|
||||
#include <setupapi.h>
|
||||
#include <cfgmgr32.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "hook/com-proxy.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "iidxhook8/cam.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
#include "util/time.h"
|
||||
|
||||
#define CAMERA_DATA_STRING_SIZE 0x100
|
||||
|
||||
EXTERN_GUID(MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, 0xc60ac5fe, 0x252a, 0x478f, 0xa0, 0xef, 0xbc, 0x8f, 0xa5, 0xf7, 0xca, 0xd3);
|
||||
EXTERN_GUID(MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID, 0x8ac3587a, 0x4ae7, 0x42d8, 0x99, 0xe0, 0x0a, 0x60, 0x13, 0xee, 0xf9, 0x0f);
|
||||
EXTERN_GUID(MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, 0x58f0aad8, 0x22bf, 0x4f8a, 0xbb, 0x3d, 0xd2, 0xc4, 0x97, 0x8c, 0x6e, 0x2f);
|
||||
// define ourselves cause mingw has these wrong
|
||||
|
||||
struct CameraData {
|
||||
bool setup;
|
||||
char name[CAMERA_DATA_STRING_SIZE];
|
||||
char deviceInstancePath[CAMERA_DATA_STRING_SIZE];
|
||||
wchar_t deviceSymbolicLink[CAMERA_DATA_STRING_SIZE];
|
||||
char extra_upper[CAMERA_DATA_STRING_SIZE];
|
||||
int address;
|
||||
char parent_name[CAMERA_DATA_STRING_SIZE];
|
||||
char parent_deviceInstancePath[CAMERA_DATA_STRING_SIZE];
|
||||
int parent_address;
|
||||
};
|
||||
|
||||
static struct CameraData camData[2];
|
||||
|
||||
|
||||
static CONFIGRET my_CM_Locate_DevNodeA(
|
||||
PDEVINST pdnDevInst,
|
||||
DEVINSTID_A pDeviceID,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static CONFIGRET my_CM_Get_Parent(
|
||||
PDEVINST pdnDevInst,
|
||||
DEVINST dnDevInst,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static CONFIGRET my_CM_Get_Device_IDA(
|
||||
DEVINST dnDevInst,
|
||||
PSTR Buffer,
|
||||
ULONG BufferLen,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static CONFIGRET(*real_CM_Locate_DevNodeA)(
|
||||
PDEVINST pdnDevInst,
|
||||
DEVINSTID_A pDeviceID,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static CONFIGRET(*real_CM_Get_Parent)(
|
||||
PDEVINST pdnDevInst,
|
||||
DEVINST dnDevInst,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static CONFIGRET(*real_CM_Get_Device_IDA)(
|
||||
DEVINST dnDevInst,
|
||||
PSTR Buffer,
|
||||
ULONG BufferLen,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static HRESULT my_MFEnumDeviceSources(
|
||||
IMFAttributes *pAttributes,
|
||||
IMFActivate ***pppSourceActivate,
|
||||
UINT32 *pcSourceActivate
|
||||
);
|
||||
|
||||
static HRESULT (*real_MFEnumDeviceSources)(
|
||||
IMFAttributes *pAttributes,
|
||||
IMFActivate ***pppSourceActivate,
|
||||
UINT32 *pcSourceActivate
|
||||
);
|
||||
|
||||
static BOOL my_SetupDiDestroyDeviceInfoList(
|
||||
HDEVINFO DeviceInfoSet
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiDestroyDeviceInfoList)(
|
||||
HDEVINFO DeviceInfoSet
|
||||
);
|
||||
|
||||
static BOOL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
DWORD MemberIndex,
|
||||
PSP_DEVINFO_DATA DeviceInfoData
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiEnumDeviceInfo)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
DWORD MemberIndex,
|
||||
PSP_DEVINFO_DATA DeviceInfoData
|
||||
);
|
||||
|
||||
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiGetDeviceRegistryPropertyA)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize
|
||||
);
|
||||
|
||||
static HDEVINFO my_SetupDiGetClassDevsA(
|
||||
CONST GUID *ClassGuid,
|
||||
PCSTR Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags
|
||||
);
|
||||
|
||||
static HDEVINFO(*real_SetupDiGetClassDevsA)(
|
||||
CONST GUID *ClassGuid,
|
||||
PCSTR Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags
|
||||
);
|
||||
|
||||
static const struct hook_symbol iidxhook5_cfgmgr32_syms[] = {
|
||||
{
|
||||
.name = "CM_Locate_DevNodeA",
|
||||
.patch = my_CM_Locate_DevNodeA,
|
||||
.link = (void **) &real_CM_Locate_DevNodeA
|
||||
},
|
||||
{
|
||||
.name = "CM_Get_Parent",
|
||||
.patch = my_CM_Get_Parent,
|
||||
.link = (void **) &real_CM_Get_Parent
|
||||
},
|
||||
{
|
||||
.name = "CM_Get_Device_IDA",
|
||||
.patch = my_CM_Get_Device_IDA,
|
||||
.link = (void **) &real_CM_Get_Device_IDA
|
||||
},
|
||||
{
|
||||
.name = "SetupDiDestroyDeviceInfoList",
|
||||
.patch = my_SetupDiDestroyDeviceInfoList,
|
||||
.link = (void **) &real_SetupDiDestroyDeviceInfoList
|
||||
},
|
||||
{
|
||||
.name = "SetupDiEnumDeviceInfo",
|
||||
.patch = my_SetupDiEnumDeviceInfo,
|
||||
.link = (void **) &real_SetupDiEnumDeviceInfo
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetDeviceRegistryPropertyA",
|
||||
.patch = my_SetupDiGetDeviceRegistryPropertyA,
|
||||
.link = (void **) &real_SetupDiGetDeviceRegistryPropertyA
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetClassDevsA",
|
||||
.patch = my_SetupDiGetClassDevsA,
|
||||
.link = (void **) &real_SetupDiGetClassDevsA
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol iidxhook5_mf_syms[] = {
|
||||
{
|
||||
.name = "MFEnumDeviceSources",
|
||||
.patch = my_MFEnumDeviceSources,
|
||||
.link = (void **) &real_MFEnumDeviceSources
|
||||
},
|
||||
};
|
||||
|
||||
#define CUSTOM_DEV_NODE1 0x04040004
|
||||
#define CUSTOM_DEV_NODE2 0x04040008
|
||||
|
||||
#define CUSTOM_DEV_PARENT_NODE1 0x04040014
|
||||
#define CUSTOM_DEV_PARENT_NODE2 0x04040018
|
||||
|
||||
static CONFIGRET my_CM_Locate_DevNodeA(
|
||||
PDEVINST pdnDevInst,
|
||||
DEVINSTID_A pDeviceID,
|
||||
ULONG ulFlags
|
||||
){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
char builtString1[CAMERA_DATA_STRING_SIZE] = {0};
|
||||
char builtString2[CAMERA_DATA_STRING_SIZE] = {0};
|
||||
|
||||
if (camData[0].setup) {
|
||||
snprintf(builtString1, CAMERA_DATA_STRING_SIZE, "USB\\VID_288C&PID_0002&MI_00\\%s", camData[0].extra_upper);
|
||||
if(camData[1].setup) {
|
||||
snprintf(builtString2, CAMERA_DATA_STRING_SIZE, "USB\\VID_288C&PID_0002&MI_00\\%s", camData[1].extra_upper);
|
||||
}
|
||||
} else if(camData[1].setup) {
|
||||
snprintf(builtString1, CAMERA_DATA_STRING_SIZE, "USB\\VID_288C&PID_0002&MI_00\\%s", camData[1].extra_upper);
|
||||
}
|
||||
|
||||
if (pdnDevInst) {
|
||||
if (strcmp(pDeviceID, builtString1) == 0) {
|
||||
log_info("Injecting custom device 1");
|
||||
*pdnDevInst = CUSTOM_DEV_NODE1;
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
if (strcmp(pDeviceID, builtString2) == 0) {
|
||||
log_info("Injecting custom device 2");
|
||||
*pdnDevInst = CUSTOM_DEV_NODE2;
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
}
|
||||
return real_CM_Locate_DevNodeA(pdnDevInst, pDeviceID, ulFlags);
|
||||
}
|
||||
|
||||
static CONFIGRET my_CM_Get_Parent(
|
||||
PDEVINST pdnDevInst,
|
||||
DEVINST dnDevInst,
|
||||
ULONG ulFlags
|
||||
){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
|
||||
if (pdnDevInst) {
|
||||
if (dnDevInst == CUSTOM_DEV_NODE1) {
|
||||
log_info("Injecting custom parent 1");
|
||||
*pdnDevInst = CUSTOM_DEV_PARENT_NODE1;
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
if (dnDevInst == CUSTOM_DEV_NODE2) {
|
||||
log_info("Injecting custom parent 2");
|
||||
*pdnDevInst = CUSTOM_DEV_PARENT_NODE2;
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return real_CM_Get_Parent(pdnDevInst, dnDevInst, ulFlags);
|
||||
}
|
||||
|
||||
static CONFIGRET my_CM_Get_Device_IDA(
|
||||
DEVINST dnDevInst,
|
||||
PSTR Buffer,
|
||||
ULONG BufferLen,
|
||||
ULONG ulFlags
|
||||
){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
|
||||
if (Buffer) {
|
||||
if (dnDevInst == CUSTOM_DEV_PARENT_NODE1) {
|
||||
log_info("Injecting custom parent 1 ID");
|
||||
strncpy(Buffer, "USB\\VEN_1022&DEV_7908", BufferLen);
|
||||
Buffer[BufferLen - 1] = '\0';
|
||||
log_info("%s", Buffer);
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
if (dnDevInst == CUSTOM_DEV_PARENT_NODE2) {
|
||||
log_info("Injecting custom parent 2 ID");
|
||||
strncpy(Buffer, "USB\\VEN_1022&DEV_7914", BufferLen);
|
||||
Buffer[BufferLen - 1] = '\0';
|
||||
log_info("%s", Buffer);
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
}
|
||||
return real_CM_Get_Device_IDA(dnDevInst, Buffer, BufferLen, ulFlags);
|
||||
}
|
||||
|
||||
|
||||
static HRESULT (STDCALL *real_GetAllocatedString)(
|
||||
IMFActivate* self,
|
||||
REFGUID guidKey,
|
||||
LPWSTR *ppwszValue,
|
||||
UINT32 *pcchLength);
|
||||
|
||||
HRESULT my_GetAllocatedString(
|
||||
IMFActivate* self,
|
||||
REFGUID guidKey,
|
||||
LPWSTR *ppwszValue,
|
||||
UINT32 *pcchLength
|
||||
){
|
||||
HRESULT ret;
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
|
||||
// should probably check GUID, oh well
|
||||
ret = real_GetAllocatedString(self, guidKey, ppwszValue, pcchLength);
|
||||
log_info("Obtained: %ls", *ppwszValue);
|
||||
|
||||
wchar_t *pwc = NULL;
|
||||
|
||||
if (camData[0].setup) {
|
||||
pwc = wcsstr(*ppwszValue, camData[0].deviceSymbolicLink);
|
||||
}
|
||||
if (camData[1].setup) {
|
||||
if (!pwc) {
|
||||
pwc = wcsstr(*ppwszValue, camData[1].deviceSymbolicLink);
|
||||
}
|
||||
}
|
||||
|
||||
if (pwc){
|
||||
// \\?\usb#vid_288c&pid_0002&mi_00
|
||||
pwc[12] = L'2';
|
||||
pwc[13] = L'8';
|
||||
pwc[14] = L'8';
|
||||
pwc[15] = L'c';
|
||||
|
||||
pwc[21] = L'0';
|
||||
pwc[22] = L'0';
|
||||
pwc[23] = L'0';
|
||||
pwc[24] = L'2';
|
||||
|
||||
pwc[29] = L'0';
|
||||
pwc[30] = L'0';
|
||||
log_info("Replaced: %ls", *ppwszValue);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static HRESULT my_MFEnumDeviceSources(
|
||||
IMFAttributes *pAttributes,
|
||||
IMFActivate ***pppSourceActivate,
|
||||
UINT32 *pcSourceActivate
|
||||
){
|
||||
IMFActivate *api;
|
||||
IMFActivateVtbl *api_vtbl;
|
||||
struct com_proxy *api_proxy;
|
||||
|
||||
UINT32 nsrcs;
|
||||
|
||||
HRESULT ret;
|
||||
|
||||
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
ret = real_MFEnumDeviceSources(pAttributes, pppSourceActivate, pcSourceActivate);
|
||||
nsrcs = *pcSourceActivate;
|
||||
|
||||
for (UINT32 i = 0; i < nsrcs; ++i) {
|
||||
api = (*pppSourceActivate)[i];
|
||||
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
|
||||
api_vtbl = api_proxy->vptr;
|
||||
|
||||
real_GetAllocatedString = api_vtbl->GetAllocatedString;
|
||||
api_vtbl->GetAllocatedString = my_GetAllocatedString;
|
||||
|
||||
(*pppSourceActivate)[i] = (IMFActivate *)api_proxy;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CUSTOM_DEVICE_HANDLE (void*)0x04041110
|
||||
static HDEVINFO RealReplacedHandle;
|
||||
|
||||
static BOOL my_SetupDiDestroyDeviceInfoList(
|
||||
HDEVINFO DeviceInfoSet
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
DeviceInfoSet = RealReplacedHandle;
|
||||
RealReplacedHandle = NULL;
|
||||
|
||||
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
DWORD MemberIndex,
|
||||
PSP_DEVINFO_DATA DeviceInfoData
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE) {
|
||||
// log_info("Inside: %s", __FUNCTION__);
|
||||
return real_SetupDiEnumDeviceInfo(RealReplacedHandle, MemberIndex, DeviceInfoData);
|
||||
}
|
||||
return real_SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, DeviceInfoData);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE) {
|
||||
BOOL ret = real_SetupDiGetDeviceRegistryPropertyA(RealReplacedHandle, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
|
||||
|
||||
if (Property == SPDRP_DEVICEDESC) {
|
||||
if (PropertyBuffer){
|
||||
if (camData[0].setup) {
|
||||
if (strcmp((char*)PropertyBuffer, camData[0].parent_name) == 0) {
|
||||
log_info("%s: replacing %s", __FUNCTION__, camData[0].parent_name);
|
||||
strncpy((char*)PropertyBuffer, "USB Composite Device", PropertyBufferSize);
|
||||
}
|
||||
}
|
||||
if (camData[1].setup) {
|
||||
if (strcmp((char*)PropertyBuffer, camData[1].parent_name) == 0) {
|
||||
log_info("%s: replacing %s", __FUNCTION__, camData[1].parent_name);
|
||||
strncpy((char*)PropertyBuffer, "USB Composite Device", PropertyBufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if (Property == SPDRP_ADDRESS) {
|
||||
if (PropertyBuffer){
|
||||
int addr = *(int*)PropertyBuffer;
|
||||
|
||||
if (camData[0].setup) {
|
||||
if (addr == camData[0].parent_address) {
|
||||
log_info("%s: replacing addr1", __FUNCTION__);
|
||||
*(int*)PropertyBuffer = 1;
|
||||
} else if (camData[1].setup) {
|
||||
if (addr == camData[1].parent_address) {
|
||||
log_info("%s: replacing addr7", __FUNCTION__);
|
||||
*(int*)PropertyBuffer = 7;
|
||||
}
|
||||
}
|
||||
} else if (camData[1].setup) {
|
||||
if (addr == camData[1].parent_address) {
|
||||
log_info("%s: replacing addr1 (alt)", __FUNCTION__);
|
||||
*(int*)PropertyBuffer = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return real_SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
|
||||
}
|
||||
|
||||
static HDEVINFO my_SetupDiGetClassDevsA(
|
||||
CONST GUID *ClassGuid,
|
||||
PCSTR Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags
|
||||
){
|
||||
if (ClassGuid == NULL && Enumerator != NULL && hwndParent == NULL && Flags == (DIGCF_PRESENT | DIGCF_ALLCLASSES)) {
|
||||
if (RealReplacedHandle) {
|
||||
log_info("Replacement handle is already set?");
|
||||
}
|
||||
if (strcmp(Enumerator, "USB") == 0) {
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
RealReplacedHandle = real_SetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
|
||||
if (RealReplacedHandle == INVALID_HANDLE_VALUE) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
return CUSTOM_DEVICE_HANDLE;
|
||||
}
|
||||
}
|
||||
return real_SetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
|
||||
}
|
||||
|
||||
bool check_four(const char inA[4], const char inB[4]) {
|
||||
return (*(uint32_t*)inA == *(uint32_t*)inB);
|
||||
}
|
||||
|
||||
char* grab_next_camera_id(char* buffer, size_t bsz) {
|
||||
static size_t gotten = 0;
|
||||
|
||||
IMFAttributes *pAttributes = NULL;
|
||||
IMFActivate **ppDevices = NULL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
|
||||
if (FAILED(hr)) {
|
||||
log_info("MFCreateAttributes failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
hr = pAttributes->lpVtbl->SetGUID(pAttributes, &MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
||||
if (FAILED(hr)) {
|
||||
log_info("SetGUID failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
UINT32 count;
|
||||
hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
|
||||
if (FAILED(hr)) {
|
||||
log_info("MFEnumDeviceSources failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (count <= gotten) {
|
||||
log_info("gotten failed: %d < %d", count, (int)gotten);
|
||||
// not enough remaining
|
||||
goto done;
|
||||
}
|
||||
|
||||
wchar_t wSymLink[CAMERA_DATA_STRING_SIZE];
|
||||
UINT32 sz;
|
||||
|
||||
hr = ppDevices[gotten]->lpVtbl->GetString(ppDevices[gotten], &MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, wSymLink, CAMERA_DATA_STRING_SIZE, &sz);
|
||||
if (FAILED(hr)) {
|
||||
log_info("GetString failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
log_info("Detected webcam: %s\n", buffer);
|
||||
wcstombs(buffer, wSymLink, bsz);
|
||||
++gotten;
|
||||
|
||||
done:
|
||||
if (pAttributes) {
|
||||
pAttributes->lpVtbl->Release(pAttributes);
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < count; i++) {
|
||||
if (ppDevices != NULL && ppDevices[i]) {
|
||||
ppDevices[i]->lpVtbl->Release(ppDevices[i]);
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(ppDevices);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool convert_sym_to_path(const char* sym, char* path) {
|
||||
HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
|
||||
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
|
||||
log_info("Could not open SetupDiCreateDeviceInfoList\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = {0};
|
||||
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
|
||||
if (!SetupDiOpenDeviceInterfaceA(DeviceInfoSet, sym, 0, &DeviceInterfaceData)) {
|
||||
log_info("Could not SetupDiOpenDeviceInterfaceA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SP_DEVINFO_DATA DeviceInfoData = {0};
|
||||
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
if (!SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, &DeviceInterfaceData, NULL, 0, NULL, &DeviceInfoData)) {
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
log_info("Could not SetupDiGetDeviceInterfaceDetailA\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD sz;
|
||||
if (!SetupDiGetDeviceInstanceIdA(DeviceInfoSet, &DeviceInfoData, path, CAMERA_DATA_STRING_SIZE, &sz)){
|
||||
log_info("Could not SetupDiGetDeviceInstanceIdA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DeviceInfoSet != INVALID_HANDLE_VALUE){
|
||||
if (!SetupDiDeleteDeviceInterfaceData(DeviceInfoSet, &DeviceInterfaceData)){
|
||||
log_info("Could not SetupDiDeleteDeviceInterfaceData\n");
|
||||
return 0;
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void strtolower(char* str) {
|
||||
for (size_t i = 0; str[i]; i++){
|
||||
str[i] = tolower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool convert_path_to_fakesym(const char* path, wchar_t* sym, char* extra_o) {
|
||||
char root[16] = {0};
|
||||
char vidstr[16] = {0};
|
||||
char pidstr[16] = {0};
|
||||
char mistr[16] = {0};
|
||||
char extra[64] = {0};
|
||||
sscanf(path, "%[^\\]\\%[^&]&%[^&]&%[^\\]\\%s", root, vidstr, pidstr, mistr, extra);
|
||||
strcpy(extra_o, extra);
|
||||
|
||||
strtolower(root);
|
||||
strtolower(vidstr);
|
||||
strtolower(pidstr);
|
||||
strtolower(mistr);
|
||||
strtolower(extra);
|
||||
|
||||
swprintf(sym, CAMERA_DATA_STRING_SIZE, L"\\\\?\\%S#%S&%S&%S#%S", root, vidstr, pidstr, mistr, extra);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fill_cam_struct(struct CameraData* data, const char* devid)
|
||||
{
|
||||
char buffer[CAMERA_DATA_STRING_SIZE];
|
||||
|
||||
data->setup = false;
|
||||
if (!devid || strlen(devid) == 0) {
|
||||
devid = grab_next_camera_id(buffer, CAMERA_DATA_STRING_SIZE);
|
||||
}
|
||||
if (!devid || strlen(devid) == 0) {
|
||||
// no more cameras remain?
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(devid) >= CAMERA_DATA_STRING_SIZE) {
|
||||
// error probably log something?
|
||||
return;
|
||||
}
|
||||
// detect input type
|
||||
if (check_four(devid, "\\\\?\\")) {
|
||||
// SYMBOLIC_LINK
|
||||
if (!convert_sym_to_path(devid, data->deviceInstancePath)){
|
||||
log_info("Could not convert %s to path", devid);
|
||||
return;
|
||||
}
|
||||
} else if (check_four(devid, "USB\\")) {
|
||||
// Device instance path
|
||||
strcpy(data->deviceInstancePath, devid);
|
||||
// continue
|
||||
} else {
|
||||
// UNKNOWN ENTRY
|
||||
log_info("UNK: %s", devid);
|
||||
log_info("Please enter the device instance path");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!convert_path_to_fakesym(data->deviceInstancePath, data->deviceSymbolicLink, data->extra_upper)){
|
||||
log_info("Could not convert %s to sym", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
log_info("dev path: %s", data->deviceInstancePath);
|
||||
|
||||
|
||||
// locate device nodes
|
||||
DEVINST dnDevInst;
|
||||
DEVINST parentDev;
|
||||
CONFIGRET cmret;
|
||||
|
||||
cmret = CM_Locate_DevNodeA(&dnDevInst, data->deviceInstancePath, CM_LOCATE_DEVNODE_NORMAL);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Locate_DevNodeA fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
cmret = CM_Get_Parent(&parentDev, dnDevInst, 0);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_Parent fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
cmret = CM_Get_Device_IDA(parentDev, data->parent_deviceInstancePath, CAMERA_DATA_STRING_SIZE, 0);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_Device_IDA parent fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
ULONG szAddr;
|
||||
ULONG szDesc;
|
||||
|
||||
szAddr = 4;
|
||||
szDesc = CAMERA_DATA_STRING_SIZE;
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(dnDevInst, CM_DRP_ADDRESS, NULL, &data->address, &szAddr, 0);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_DevNode_Registry_PropertyA fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(dnDevInst, CM_DRP_DEVICEDESC, NULL, &data->name, &szDesc, 0);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_DevNode_Registry_PropertyA fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
szAddr = 4;
|
||||
szDesc = CAMERA_DATA_STRING_SIZE;
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(parentDev, CM_DRP_ADDRESS, NULL, &data->parent_address, &szAddr, 0);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_DevNode_Registry_PropertyA parent fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(parentDev, CM_DRP_DEVICEDESC, NULL, &data->parent_name, &szDesc, 0);
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_DevNode_Registry_PropertyA parent fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Found %s @ %d", data->name, data->address);
|
||||
log_info("Parent %s @ %d", data->parent_name, data->parent_address);
|
||||
data->setup = true;
|
||||
}
|
||||
|
||||
void cam_hook_init(const char* devID1, const char* devID2)
|
||||
{
|
||||
// fill before applying hooks
|
||||
fill_cam_struct(&camData[0], devID1);
|
||||
fill_cam_struct(&camData[1], devID2);
|
||||
|
||||
if (camData[0].setup || camData[1].setup) {
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"setupapi.dll",
|
||||
iidxhook5_cfgmgr32_syms,
|
||||
lengthof(iidxhook5_cfgmgr32_syms));
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"Mf.dll",
|
||||
iidxhook5_mf_syms,
|
||||
lengthof(iidxhook5_mf_syms));
|
||||
|
||||
log_info("Inserted cam hooks");
|
||||
} else {
|
||||
log_info("No cams detected, not hooking");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef IIDXHOOK5_CAM_H
|
||||
#define IIDXHOOK5_CAM_H
|
||||
|
||||
void cam_hook_init(const char* devID1, const char* devID2);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "iidxhook8/config-cam.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define IIDXHOOK8_CONFIG_CAM_DISABLE_EMU_KEY "cam.disable_emu"
|
||||
#define IIDXHOOK8_CONFIG_CAM_DEVICE_ID1_KEY "cam.device_id1"
|
||||
#define IIDXHOOK8_CONFIG_CAM_DEVICE_ID2_KEY "cam.device_id2"
|
||||
|
||||
#define IIDXHOOK8_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE false
|
||||
#define IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID1_VALUE ""
|
||||
#define IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID2_VALUE ""
|
||||
|
||||
void iidxhook8_config_cam_init(struct cconfig* config)
|
||||
{
|
||||
cconfig_util_set_bool(config,
|
||||
IIDXHOOK8_CONFIG_CAM_DISABLE_EMU_KEY,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE,
|
||||
"Disables the camera emulation");
|
||||
|
||||
cconfig_util_set_str(config,
|
||||
IIDXHOOK8_CONFIG_CAM_DEVICE_ID1_KEY,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID1_VALUE,
|
||||
"Override camera device ID 1 detection (copy from device manager, do "
|
||||
"not escape)");
|
||||
|
||||
cconfig_util_set_str(config,
|
||||
IIDXHOOK8_CONFIG_CAM_DEVICE_ID2_KEY,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID2_VALUE,
|
||||
"Override camera device ID 2 detection (copy from device manager, do "
|
||||
"not escape)");
|
||||
}
|
||||
|
||||
void iidxhook8_config_cam_get(struct iidxhook8_config_cam* config_cam,
|
||||
struct cconfig* config)
|
||||
{
|
||||
if (!cconfig_util_get_bool(config, IIDXHOOK8_CONFIG_CAM_DISABLE_EMU_KEY,
|
||||
&config_cam->disable_emu,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE)) {
|
||||
log_warning("Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'", IIDXHOOK8_CONFIG_CAM_DISABLE_EMU_KEY,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_str(config, IIDXHOOK8_CONFIG_CAM_DEVICE_ID1_KEY,
|
||||
config_cam->device_id1, sizeof(config_cam->device_id1) - 1,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID1_VALUE)) {
|
||||
log_warning("Invalid value for key '%s' specified, fallback "
|
||||
"to default '%s'", IIDXHOOK8_CONFIG_CAM_DEVICE_ID1_KEY,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID1_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_str(config, IIDXHOOK8_CONFIG_CAM_DEVICE_ID2_KEY,
|
||||
config_cam->device_id2, sizeof(config_cam->device_id2) - 1,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID2_VALUE)) {
|
||||
log_warning("Invalid value for key '%s' specified, fallback "
|
||||
"to default '%s'", IIDXHOOK8_CONFIG_CAM_DEVICE_ID2_KEY,
|
||||
IIDXHOOK8_CONFIG_CAM_DEFAULT_DEVICE_ID2_VALUE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef IIDXHOOK8_CONFIG_CAM_H
|
||||
#define IIDXHOOK8_CONFIG_CAM_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
struct iidxhook8_config_cam {
|
||||
bool disable_emu;
|
||||
char device_id1[MAX_PATH];
|
||||
char device_id2[MAX_PATH];
|
||||
};
|
||||
|
||||
void iidxhook8_config_cam_init(struct cconfig* config);
|
||||
|
||||
void iidxhook8_config_cam_get(struct iidxhook8_config_cam* config_cam,
|
||||
struct cconfig* config);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "iidxhook8/config-io.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define IIDXHOOK8_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY "io.disable_card_reader_emu"
|
||||
#define IIDXHOOK8_CONFIG_IO_DISABLE_BIO2_EMU_KEY "io.disable_bio2_emu"
|
||||
#define IIDXHOOK8_CONFIG_IO_DISABLE_POLL_LIMITER_KEY "io.disable_poll_limiter"
|
||||
|
||||
#define IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE false
|
||||
#define IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE false
|
||||
#define IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE false
|
||||
|
||||
void iidxhook8_config_io_init(struct cconfig* config)
|
||||
{
|
||||
cconfig_util_set_bool(config,
|
||||
IIDXHOOK8_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE,
|
||||
"Disable card reader emulation and enable usage of real card reader "
|
||||
"hardware on COM0 (for games supporting slotted readers)");
|
||||
|
||||
cconfig_util_set_bool(config,
|
||||
IIDXHOOK8_CONFIG_IO_DISABLE_BIO2_EMU_KEY,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE,
|
||||
"Disable BIO2 emulation and enable usage of real BIO2 hardware");
|
||||
|
||||
cconfig_util_set_bool(config,
|
||||
IIDXHOOK8_CONFIG_IO_DISABLE_POLL_LIMITER_KEY,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE,
|
||||
"Disables the poll limiter, warning very high CPU usage may arise");
|
||||
}
|
||||
|
||||
void iidxhook8_config_io_get(struct iidxhook8_config_io* config_io,
|
||||
struct cconfig* config)
|
||||
{
|
||||
if (!cconfig_util_get_bool(config,
|
||||
IIDXHOOK8_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY,
|
||||
&config_io->disable_card_reader_emu,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE)) {
|
||||
log_warning("Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'", IIDXHOOK8_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_bool(config,
|
||||
IIDXHOOK8_CONFIG_IO_DISABLE_BIO2_EMU_KEY,
|
||||
&config_io->disable_bio2_emu,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE)) {
|
||||
log_warning("Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'", IIDXHOOK8_CONFIG_IO_DISABLE_BIO2_EMU_KEY,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE);
|
||||
}
|
||||
|
||||
if (!cconfig_util_get_bool(config,
|
||||
IIDXHOOK8_CONFIG_IO_DISABLE_POLL_LIMITER_KEY,
|
||||
&config_io->disable_poll_limiter,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE)) {
|
||||
log_warning("Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'", IIDXHOOK8_CONFIG_IO_DISABLE_POLL_LIMITER_KEY,
|
||||
IIDXHOOK8_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef IIDXHOOK8_CONFIG_IO_H
|
||||
#define IIDXHOOK8_CONFIG_IO_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
struct iidxhook8_config_io {
|
||||
bool disable_card_reader_emu;
|
||||
bool disable_bio2_emu;
|
||||
bool disable_poll_limiter;
|
||||
};
|
||||
|
||||
void iidxhook8_config_io_init(struct cconfig* config);
|
||||
|
||||
void iidxhook8_config_io_get(struct iidxhook8_config_io* config_io,
|
||||
struct cconfig* config);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,194 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bemanitools/eamio.h"
|
||||
#include "bemanitools/iidxio.h"
|
||||
|
||||
#include "cconfig/cconfig-hook.h"
|
||||
|
||||
#include "hooklib/acp.h"
|
||||
#include "hooklib/adapter.h"
|
||||
#include "hooklib/app.h"
|
||||
#include "hooklib/rs232.h"
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
#include "iidxhook-util/acio.h"
|
||||
#include "iidxhook-util/config-gfx.h"
|
||||
#include "iidxhook-util/d3d9.h"
|
||||
#include "iidxhook-util/log-server.h"
|
||||
|
||||
#include "iidxhook8/bio2.h"
|
||||
#include "iidxhook8/cam.h"
|
||||
#include "iidxhook8/config-cam.h"
|
||||
#include "iidxhook8/config-io.h"
|
||||
#include "iidxhook8/setupapi.h"
|
||||
#include "iidxhook8/cam.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
#define IIDXHOOK8_INFO_HEADER \
|
||||
"iidxhook for Cannon Ballers" \
|
||||
", build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n"
|
||||
#define IIDXHOOK8_CMD_USAGE \
|
||||
"Usage: launcher.exe -K iidxhook8.dll <bm2dx.dll> [options...]"
|
||||
|
||||
static const irp_handler_t iidxhook_handlers[] = {
|
||||
iidxhook_util_acio_dispatch_irp,
|
||||
bio2_port_dispatch_irp,
|
||||
};
|
||||
|
||||
struct iidxhook8_config_io iidxhook8_config_io;
|
||||
|
||||
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
|
||||
{
|
||||
struct cconfig* config;
|
||||
|
||||
struct iidxhook_config_gfx config_gfx;
|
||||
struct iidxhook8_config_cam config_cam;
|
||||
|
||||
// log_server_init is not required anymore
|
||||
|
||||
log_info("-------------------------------------------------------------");
|
||||
log_info("--------------- Begin iidxhook dll_entry_init ---------------");
|
||||
log_info("-------------------------------------------------------------");
|
||||
|
||||
config = cconfig_init();
|
||||
|
||||
iidxhook_config_gfx_init(config);
|
||||
iidxhook8_config_cam_init(config);
|
||||
iidxhook8_config_io_init(config);
|
||||
|
||||
if (!cconfig_hook_config_init(config, IIDXHOOK8_INFO_HEADER "\n" IIDXHOOK8_CMD_USAGE, CCONFIG_CMD_USAGE_OUT_DBG)) {
|
||||
cconfig_finit(config);
|
||||
log_server_fini();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
iidxhook_config_gfx_get(&config_gfx, config);
|
||||
iidxhook8_config_cam_get(&config_cam, config);
|
||||
iidxhook8_config_io_get(&iidxhook8_config_io, config);
|
||||
|
||||
cconfig_finit(config);
|
||||
|
||||
log_info(IIDXHOOK8_INFO_HEADER);
|
||||
log_info("Initializing iidxhook...");
|
||||
|
||||
if (config_gfx.windowed) {
|
||||
d3d9_set_windowed(config_gfx.framed, config_gfx.window_width,
|
||||
config_gfx.window_height);
|
||||
}
|
||||
|
||||
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
|
||||
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
|
||||
}
|
||||
|
||||
if (config_gfx.frame_rate_limit > 0) {
|
||||
d3d9_set_frame_rate_limit(config_gfx.frame_rate_limit);
|
||||
}
|
||||
|
||||
if (config_gfx.scale_back_buffer_width > 0 && config_gfx.scale_back_buffer_height > 0) {
|
||||
d3d9_scale_back_buffer(config_gfx.scale_back_buffer_width, config_gfx.scale_back_buffer_height,
|
||||
config_gfx.scale_back_buffer_filter);
|
||||
}
|
||||
|
||||
/* Start up IIDXIO.DLL */
|
||||
if (!iidxhook8_config_io.disable_bio2_emu) {
|
||||
log_info("Starting IIDX IO backend");
|
||||
iidx_io_set_loggers(log_impl_misc, log_impl_info, log_impl_warning,
|
||||
log_impl_fatal);
|
||||
|
||||
if (!iidx_io_init(avs_thread_create, avs_thread_join, avs_thread_destroy)) {
|
||||
log_fatal("Initializing IIDX IO backend failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* Start up EAMIO.DLL */
|
||||
if (!iidxhook8_config_io.disable_card_reader_emu) {
|
||||
log_misc("Initializing card reader backend");
|
||||
eam_io_set_loggers(log_impl_misc, log_impl_info, log_impl_warning,
|
||||
log_impl_fatal);
|
||||
|
||||
if (!eam_io_init(avs_thread_create, avs_thread_join, avs_thread_destroy)) {
|
||||
log_fatal("Initializing card reader backend failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* iohooks are okay, even if emu is diabled since the fake handlers won't be used */
|
||||
/* Set up IO emulation hooks _after_ IO API setup to allow
|
||||
API implementations with real IO devices */
|
||||
iohook_init(iidxhook_handlers, lengthof(iidxhook_handlers));
|
||||
rs232_hook_init();
|
||||
|
||||
if (!iidxhook8_config_io.disable_bio2_emu) {
|
||||
bio2_port_init(iidxhook8_config_io.disable_poll_limiter);
|
||||
setupapi_hook_init();
|
||||
}
|
||||
|
||||
if (!iidxhook8_config_io.disable_card_reader_emu) {
|
||||
iidxhook_util_acio_init(false);
|
||||
}
|
||||
|
||||
// camera hooks
|
||||
if (!config_cam.disable_emu) {
|
||||
cam_hook_init(config_cam.device_id1, config_cam.device_id2);
|
||||
}
|
||||
|
||||
log_info("-------------------------------------------------------------");
|
||||
log_info("---------------- End iidxhook dll_entry_init ----------------");
|
||||
log_info("-------------------------------------------------------------");
|
||||
|
||||
return app_hook_invoke_init(sidcode, param);
|
||||
}
|
||||
|
||||
static bool my_dll_entry_main(void)
|
||||
{
|
||||
bool result;
|
||||
|
||||
result = app_hook_invoke_main();
|
||||
|
||||
if (!iidxhook8_config_io.disable_card_reader_emu) {
|
||||
log_misc("Shutting down card reader backend");
|
||||
eam_io_fini();
|
||||
}
|
||||
|
||||
if (!iidxhook8_config_io.disable_bio2_emu) {
|
||||
log_misc("Shutting down IIDX IO backend");
|
||||
iidx_io_fini();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook library Resort Anthem onwards
|
||||
*/
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
|
||||
{
|
||||
if (reason != DLL_PROCESS_ATTACH) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
log_to_external(
|
||||
log_body_misc,
|
||||
log_body_info,
|
||||
log_body_warning,
|
||||
log_body_fatal);
|
||||
|
||||
app_hook_init(my_dll_entry_init, my_dll_entry_main);
|
||||
|
||||
acp_hook_init();
|
||||
adapter_hook_init();
|
||||
d3d9_hook_init();
|
||||
|
||||
end:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
LIBRARY iidxhook8
|
||||
|
||||
EXPORTS
|
||||
DllMain@12 @1 NONAME
|
||||
@@ -0,0 +1,287 @@
|
||||
#define LOG_MODULE "setupapi-hook"
|
||||
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <initguid.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "iidxhook8/setupapi.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
#include "util/time.h"
|
||||
|
||||
static BOOL my_SetupDiDestroyDeviceInfoList(
|
||||
HDEVINFO DeviceInfoSet
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiDestroyDeviceInfoList)(
|
||||
HDEVINFO DeviceInfoSet
|
||||
);
|
||||
|
||||
static BOOL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
DWORD MemberIndex,
|
||||
PSP_DEVINFO_DATA DeviceInfoData
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiEnumDeviceInfo)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
DWORD MemberIndex,
|
||||
PSP_DEVINFO_DATA DeviceInfoData
|
||||
);
|
||||
|
||||
static HKEY my_SetupDiOpenDevRegKey(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Scope,
|
||||
DWORD HwProfile,
|
||||
DWORD KeyType,
|
||||
REGSAM samDesired
|
||||
);
|
||||
|
||||
static HKEY (*real_SetupDiOpenDevRegKey)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Scope,
|
||||
DWORD HwProfile,
|
||||
DWORD KeyType,
|
||||
REGSAM samDesired
|
||||
);
|
||||
|
||||
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiGetDeviceRegistryPropertyA)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize
|
||||
);
|
||||
|
||||
static BOOL my_SetupDiGetDeviceInfoListDetailA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
|
||||
);
|
||||
|
||||
static BOOL (*real_SetupDiGetDeviceInfoListDetailA)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
|
||||
);
|
||||
|
||||
static HDEVINFO my_SetupDiGetClassDevsA(
|
||||
CONST GUID *ClassGuid,
|
||||
PCSTR Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags
|
||||
);
|
||||
|
||||
static HDEVINFO(*real_SetupDiGetClassDevsA)(
|
||||
CONST GUID *ClassGuid,
|
||||
PCSTR Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags
|
||||
);
|
||||
|
||||
static const struct hook_symbol iidxhook5_setupapi_syms[] = {
|
||||
{
|
||||
.name = "SetupDiDestroyDeviceInfoList",
|
||||
.patch = my_SetupDiDestroyDeviceInfoList,
|
||||
.link = (void **) &real_SetupDiDestroyDeviceInfoList
|
||||
},
|
||||
{
|
||||
.name = "SetupDiEnumDeviceInfo",
|
||||
.patch = my_SetupDiEnumDeviceInfo,
|
||||
.link = (void **) &real_SetupDiEnumDeviceInfo
|
||||
},
|
||||
{
|
||||
.name = "SetupDiOpenDevRegKey",
|
||||
.patch = my_SetupDiOpenDevRegKey,
|
||||
.link = (void **) &real_SetupDiOpenDevRegKey
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetDeviceRegistryPropertyA",
|
||||
.patch = my_SetupDiGetDeviceRegistryPropertyA,
|
||||
.link = (void **) &real_SetupDiGetDeviceRegistryPropertyA
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetDeviceInfoListDetailA",
|
||||
.patch = my_SetupDiGetDeviceInfoListDetailA,
|
||||
.link = (void **) &real_SetupDiGetDeviceInfoListDetailA
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetClassDevsA",
|
||||
.patch = my_SetupDiGetClassDevsA,
|
||||
.link = (void **) &real_SetupDiGetClassDevsA
|
||||
},
|
||||
};
|
||||
|
||||
static LSTATUS my_RegQueryValueExA(
|
||||
HKEY hKey,
|
||||
LPCSTR lpValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData
|
||||
);
|
||||
static LSTATUS (*real_RegQueryValueExA)(
|
||||
HKEY hKey,
|
||||
LPCSTR lpValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData
|
||||
);
|
||||
|
||||
static const struct hook_symbol iidxhook5_Advapi32_syms[] = {
|
||||
{
|
||||
.name = "RegQueryValueExA",
|
||||
.patch = my_RegQueryValueExA,
|
||||
.link = (void **) &real_RegQueryValueExA
|
||||
},
|
||||
};
|
||||
|
||||
#define CUSTOM_DEVICE_HANDLE (void*)0x12341230
|
||||
#define CUSTOM_REGISTRY_HANDLE (void*)0x4242ccc0
|
||||
|
||||
static BOOL my_SetupDiDestroyDeviceInfoList(
|
||||
HDEVINFO DeviceInfoSet
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
DWORD MemberIndex,
|
||||
PSP_DEVINFO_DATA DeviceInfoData
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
return real_SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex, DeviceInfoData);
|
||||
}
|
||||
|
||||
static HKEY my_SetupDiOpenDevRegKey(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Scope,
|
||||
DWORD HwProfile,
|
||||
DWORD KeyType,
|
||||
REGSAM samDesired
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
return CUSTOM_REGISTRY_HANDLE;
|
||||
}
|
||||
return real_SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
log_info("%s: Found CUSTOM HANDLE", __FUNCTION__);
|
||||
if (PropertyBuffer && (PropertyBufferSize >= 12)){
|
||||
log_info("%s: Copying property name (%ld)", __FUNCTION__, PropertyBufferSize);
|
||||
strncpy((char*)PropertyBuffer, "BIO2(VIDEO)", PropertyBufferSize);
|
||||
log_info("%s: Done copying property name", __FUNCTION__);
|
||||
// Sleep(500);
|
||||
} else {
|
||||
log_info("%s: Returning size", __FUNCTION__);
|
||||
*RequiredSize = 12;
|
||||
}
|
||||
log_info("%s: STUB RETURN", __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
return real_SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, DeviceInfoData, Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiGetDeviceInfoListDetailA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_LIST_DETAIL_DATA_A DeviceInfoSetDetailData
|
||||
){
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
return real_SetupDiGetDeviceInfoListDetailA(DeviceInfoSet, DeviceInfoSetDetailData);
|
||||
}
|
||||
|
||||
DEFINE_GUID(GUID_COM_BUS_ENUMERATOR,
|
||||
0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
|
||||
|
||||
static HDEVINFO my_SetupDiGetClassDevsA(
|
||||
CONST GUID *ClassGuid,
|
||||
PCSTR Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags
|
||||
){
|
||||
if (ClassGuid) {
|
||||
if (IsEqualGUID(ClassGuid, &GUID_COM_BUS_ENUMERATOR)){
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
return CUSTOM_DEVICE_HANDLE;
|
||||
}
|
||||
}
|
||||
return real_SetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
|
||||
}
|
||||
|
||||
static LSTATUS my_RegQueryValueExA(
|
||||
HKEY hKey,
|
||||
LPCSTR lpValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData
|
||||
){
|
||||
if (hKey == CUSTOM_REGISTRY_HANDLE){
|
||||
if (strcmp(lpValueName, "PortName") == 0) {
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
if (lpData){
|
||||
strncpy((char*)lpData, "COM4", *lpcbData);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
return ERROR_MORE_DATA;
|
||||
}
|
||||
}
|
||||
return real_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
||||
}
|
||||
|
||||
void setupapi_hook_init(void)
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"setupapi.dll",
|
||||
iidxhook5_setupapi_syms,
|
||||
lengthof(iidxhook5_setupapi_syms));
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"Advapi32.dll",
|
||||
iidxhook5_Advapi32_syms,
|
||||
lengthof(iidxhook5_Advapi32_syms));
|
||||
|
||||
log_info("Inserted setupapi hooks");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef IIDXHOOK_SETUPAPI_H
|
||||
#define IIDXHOOK_SETUPAPI_H
|
||||
|
||||
void setupapi_hook_init(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user