Compare commits
No commits in common. "master" and "master" have entirely different histories.
|
@ -1,17 +1,6 @@
|
|||
.*.swp
|
||||
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
.vscode/
|
||||
|
||||
# Suggested names for build dirs
|
||||
build/
|
||||
|
|
|
@ -1,19 +1,3 @@
|
|||
{
|
||||
"editor.formatOnSave": false,
|
||||
"mesonbuild.configureOnOpen": false,
|
||||
"files.associations": {
|
||||
"string.h": "c",
|
||||
"stdbool.h": "c",
|
||||
"windows.h": "c",
|
||||
"dprintf.h": "c",
|
||||
"touch.h": "c",
|
||||
"mai2-dll.h": "c",
|
||||
"led.h": "c",
|
||||
"path.h": "c",
|
||||
"reg.h": "c",
|
||||
"platform.h": "c",
|
||||
"procaddr.h": "c",
|
||||
"table.h": "c",
|
||||
"serial.h": "c"
|
||||
},
|
||||
}
|
||||
|
|
13
Makefile
13
Makefile
|
@ -5,12 +5,16 @@ V ?= @
|
|||
BUILD_DIR := build
|
||||
BUILD_DIR_32 := $(BUILD_DIR)/build32
|
||||
BUILD_DIR_64 := $(BUILD_DIR)/build64
|
||||
BUILD_DIR_DOCKER := $(BUILD_DIR)/docker
|
||||
BUILD_DIR_ZIP := $(BUILD_DIR)/zip
|
||||
|
||||
DOC_DIR := doc
|
||||
|
||||
DIST_DIR := dist
|
||||
|
||||
DOCKER_CONTAINER_NAME := "segatools-build"
|
||||
DOCKER_IMAGE_NAME := "segatools:build"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Targets
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -38,6 +42,15 @@ zip: $(BUILD_DIR_ZIP)/segatools.zip
|
|||
clean:
|
||||
$(V)rm -rf $(BUILD_DIR) subprojects/capnhook
|
||||
|
||||
.PHONY: build-docker # Build the project in a docker container
|
||||
build-docker:
|
||||
$(V)docker rm -f $(DOCKER_CONTAINER_NAME) 2> /dev/null || true
|
||||
$(V)docker build -t $(DOCKER_IMAGE_NAME) -f Dockerfile .
|
||||
$(V)docker create --name $(DOCKER_CONTAINER_NAME) $(DOCKER_IMAGE_NAME)
|
||||
$(V)rm -rf $(BUILD_DIR_DOCKER)
|
||||
$(V)mkdir -p $(BUILD_DIR_DOCKER)
|
||||
$(V)docker cp $(DOCKER_CONTAINER_NAME):/segatools/$(BUILD_DIR_ZIP) $(BUILD_DIR_DOCKER)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Utility, combo and alias targets
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
16
Package.mk
16
Package.mk
|
@ -104,21 +104,6 @@ $(BUILD_DIR_ZIP)/mu3.zip:
|
|||
$(V)strip $(BUILD_DIR_ZIP)/mu3/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/mu3 ; zip -r ../mu3.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/mai2.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_64)/mai2hook/mai2hook.dll \
|
||||
$(DIST_DIR)/mai2/segatools.ini \
|
||||
$(DIST_DIR)/mai2/start.bat \
|
||||
$(BUILD_DIR_ZIP)/mai2
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/mai2/DEVICE
|
||||
$(V)strip $(BUILD_DIR_ZIP)/mai2/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/mai2 ; zip -r ../mai2.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||
$(DOC_DIR)/config \
|
||||
$(DOC_DIR)/chunihook.md \
|
||||
|
@ -136,7 +121,6 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
|
|||
$(BUILD_DIR_ZIP)/idz.zip \
|
||||
$(BUILD_DIR_ZIP)/mercury.zip \
|
||||
$(BUILD_DIR_ZIP)/mu3.zip \
|
||||
$(BUILD_DIR_ZIP)/mai2.zip \
|
||||
CHANGELOG.md \
|
||||
README.md \
|
||||
|
||||
|
|
|
@ -21,18 +21,9 @@ const struct dll_bind_sym carol_dll_syms[] = {
|
|||
}, {
|
||||
.sym = "carol_io_touch_init",
|
||||
.off = offsetof(struct carol_dll, touch_init),
|
||||
}, {
|
||||
.sym = "carol_io_ledbd_init",
|
||||
.off = offsetof(struct carol_dll, ledbd_init),
|
||||
}, {
|
||||
.sym = "carol_io_controlbd_init",
|
||||
.off = offsetof(struct carol_dll, controlbd_init),
|
||||
}, {
|
||||
.sym = "carol_io_touch_start",
|
||||
.off = offsetof(struct carol_dll, touch_start),
|
||||
}, {
|
||||
.sym = "carol_io_touch_stop",
|
||||
.off = offsetof(struct carol_dll, touch_stop),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,10 +10,7 @@ struct carol_dll {
|
|||
void (*jvs_poll)(uint8_t *opbtn, uint8_t *beams);
|
||||
void (*jvs_read_coin_counter)(uint16_t *total);
|
||||
HRESULT (*touch_init)();
|
||||
HRESULT (*ledbd_init)();
|
||||
HRESULT (*controlbd_init)();
|
||||
void (*touch_start)(carol_io_touch_callback_t callback);
|
||||
void (*touch_stop)();
|
||||
};
|
||||
|
||||
struct carol_dll_config {
|
||||
|
|
|
@ -16,7 +16,4 @@ EXPORTS
|
|||
carol_io_jvs_poll
|
||||
carol_io_jvs_read_coin_counter
|
||||
carol_io_touch_init
|
||||
carol_io_ledbd_init
|
||||
carol_io_controlbd_init
|
||||
carol_io_touch_start
|
||||
carol_io_touch_stop
|
||||
|
|
|
@ -58,20 +58,6 @@ void controlbd_config_load(
|
|||
filename);
|
||||
}
|
||||
|
||||
void ledbd_config_load(
|
||||
struct ledbd_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(
|
||||
L"ledbd",
|
||||
L"enable",
|
||||
1,
|
||||
filename);
|
||||
}
|
||||
|
||||
|
||||
void carol_hook_config_load(
|
||||
struct carol_hook_config *cfg,
|
||||
|
@ -87,5 +73,4 @@ void carol_hook_config_load(
|
|||
gfx_config_load(&cfg->gfx, filename);
|
||||
touch_config_load(&cfg->touch, filename);
|
||||
controlbd_config_load(&cfg->controlbd, filename);
|
||||
ledbd_config_load(&cfg->ledbd, filename);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "carolhook/touch.h"
|
||||
#include "carolhook/ledbd.h"
|
||||
#include "carolhook/controlbd.h"
|
||||
|
||||
struct carol_hook_config {
|
||||
|
@ -23,7 +22,6 @@ struct carol_hook_config {
|
|||
struct carol_dll_config dll;
|
||||
struct gfx_config gfx;
|
||||
struct touch_config touch;
|
||||
struct ledbd_config ledbd;
|
||||
struct controlbd_config controlbd;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,18 +18,10 @@
|
|||
|
||||
static HRESULT controlbd_handle_irp(struct irp *irp);
|
||||
static HRESULT controlbd_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT controlbd_frame_decode(struct controlbd_req_any *dest, struct iobuf *src);
|
||||
static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len);
|
||||
static uint8_t calc_checksum(void *data, size_t len);
|
||||
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf);
|
||||
static HRESULT controlbd_frame_dispatch(struct controlbd_req *dest);
|
||||
|
||||
static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req);
|
||||
static HRESULT controlbd_req_ack_any(uint8_t cmd);
|
||||
static HRESULT controlbd_req_reset(void);
|
||||
static HRESULT controlbd_req_get_board_info(void);
|
||||
static HRESULT controlbd_req_firmware_checksum(void);
|
||||
static HRESULT controlbd_req_polling(const struct controlbd_req_any *req);
|
||||
|
||||
const uint8_t CONTROLBD_SYNC_BYTE = 0xE0;
|
||||
static HRESULT controlbd_req_nop(uint8_t cmd);
|
||||
|
||||
static CRITICAL_SECTION controlbd_lock;
|
||||
static struct uart controlbd_uart;
|
||||
|
@ -44,7 +36,7 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg)
|
|||
|
||||
InitializeCriticalSection(&controlbd_lock);
|
||||
|
||||
uart_init(&controlbd_uart, 12);
|
||||
uart_init(&controlbd_uart, 11);
|
||||
controlbd_uart.written.bytes = controlbd_written_bytes;
|
||||
controlbd_uart.written.nbytes = sizeof(controlbd_written_bytes);
|
||||
controlbd_uart.readable.bytes = controlbd_readable_bytes;
|
||||
|
@ -72,49 +64,10 @@ static HRESULT controlbd_handle_irp(struct irp *irp)
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobuf *src)
|
||||
{
|
||||
uint8_t data_len = 0;
|
||||
uint8_t checksum_pos = src->pos - 1;
|
||||
uint8_t calculated_checksum = 0;
|
||||
uint8_t checksum = 0;
|
||||
|
||||
if (src->pos < 6) {
|
||||
dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos);
|
||||
return SEC_E_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
req->hdr.sync = src->bytes[0];
|
||||
req->hdr.dest = src->bytes[1];
|
||||
req->hdr.src = src->bytes[2];
|
||||
req->hdr.len = src->bytes[3];
|
||||
req->hdr.cmd = src->bytes[4];
|
||||
data_len = req->hdr.len;
|
||||
src->pos -= 5;
|
||||
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
if (src->pos == 0) {
|
||||
break;
|
||||
}
|
||||
req->bytes[i] = src->bytes[i + 5];
|
||||
src->pos --;
|
||||
}
|
||||
|
||||
checksum = src->bytes[checksum_pos];
|
||||
calculated_checksum = calc_checksum(req, checksum_pos);
|
||||
|
||||
if (checksum != calculated_checksum) {
|
||||
dprintf("Control Board: Decode Error, checksum failure (expected 0x%02X, got 0x%02X)\n", calculated_checksum, checksum);
|
||||
return HRESULT_FROM_WIN32(ERROR_CRC);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
struct controlbd_req req;
|
||||
HRESULT hr;
|
||||
struct controlbd_req_any req;
|
||||
|
||||
assert(carol_dll.controlbd_init != NULL);
|
||||
|
||||
|
@ -123,7 +76,7 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
|||
hr = carol_dll.controlbd_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Backend DLL error: 0X%X\n", (int) hr);
|
||||
dprintf("Control Board: Backend DLL error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -136,204 +89,90 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
|
|||
}
|
||||
|
||||
for (;;) {
|
||||
if (controlbd_uart.written.bytes[0] == 0xE0) {
|
||||
#if 0
|
||||
dprintf("Control Board: TX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.written);
|
||||
dprintf("Control Board: TX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.written);
|
||||
#endif
|
||||
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Deframe error: %x\n", (int) hr);
|
||||
return hr;
|
||||
}
|
||||
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Deframe Error: %x\n", (int) hr);
|
||||
|
||||
hr = controlbd_req_dispatch(&req);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
|
||||
return hr;
|
||||
}
|
||||
#if 0
|
||||
dprintf("Control Board: RX Buffer:\n");
|
||||
dump_iobuf(&controlbd_uart.readable);
|
||||
#endif
|
||||
controlbd_uart.written.pos = 0;
|
||||
return hr;
|
||||
}
|
||||
|
||||
// The board has a LPC111x bootloader that gets ran over every boot
|
||||
// this is to account for that.
|
||||
char cmd[255];
|
||||
strcpy_s(cmd, 255, (char *)controlbd_uart.written.bytes);
|
||||
cmd[controlbd_uart.written.pos] = '\0';
|
||||
hr = controlbd_frame_dispatch(&req);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Control Board: Dispatch Error: %x\n", (int) hr);
|
||||
|
||||
if (!strcmp(cmd, "?")) {
|
||||
dprintf("Control Board: Bootloader Hello\n");
|
||||
}
|
||||
else if (!strcmp(cmd, "Synchronized\r\n")) {
|
||||
iobuf_write(&controlbd_uart.readable, "Synchronized\r\nNG\r\n", 19);
|
||||
// Set this to OK instead of NG to do an update
|
||||
}
|
||||
else if (!strcmp(cmd, "12000\r\n")) {
|
||||
iobuf_write(&controlbd_uart.readable, "12000\r\nOK\r\n", 12);
|
||||
}
|
||||
else {
|
||||
// Everything other then the two commands above just want 0\r\n
|
||||
// appended to the request as the response. Given that it only checks sometimes,
|
||||
// it's safe to just run over the readable buffer every response.
|
||||
controlbd_uart.readable.pos = 0;
|
||||
cmd[controlbd_uart.written.pos] = '0';
|
||||
cmd[controlbd_uart.written.pos + 1] = '\r';
|
||||
cmd[controlbd_uart.written.pos + 2] = '\n';
|
||||
cmd[controlbd_uart.written.pos + 3] = '\0';
|
||||
// dprintf("Control Board: Return %s\n", cmd);
|
||||
iobuf_write(&controlbd_uart.readable, cmd, controlbd_uart.written.pos + 3);
|
||||
return hr;
|
||||
}
|
||||
|
||||
controlbd_uart.written.pos = 0;
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req)
|
||||
static HRESULT controlbd_frame_dispatch(struct controlbd_req *req)
|
||||
{
|
||||
switch (req->hdr.cmd) {
|
||||
case CONTROLBD_CMD_RESET:
|
||||
return controlbd_req_reset();
|
||||
|
||||
case CONTROLBD_CMD_BDINFO:
|
||||
return controlbd_req_get_board_info();
|
||||
|
||||
case CONTROLBD_CMD_FIRM_SUM:
|
||||
return controlbd_req_firmware_checksum();
|
||||
|
||||
case CONTROLBD_CMD_TIMEOUT:
|
||||
dprintf("Control Board: Acknowledge Timeout\n");
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
|
||||
case CONTROLBD_CMD_PORT_SETTING:
|
||||
dprintf("Control Board: Acknowledge Port Setting\n");
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
|
||||
case CONTROLBD_CMD_INITIALIZE:
|
||||
dprintf("Control Board: Acknowledge Initialize\n");
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
|
||||
case CONTROLBD_CMD_POLLING:
|
||||
return controlbd_req_polling(req);
|
||||
|
||||
switch (req->cmd) {
|
||||
case CONTROLBD_CMD_UNK_11:
|
||||
return controlbd_req_nop(req->cmd);
|
||||
default:
|
||||
dprintf("Unhandled command 0x%02x\n", req->hdr.cmd);
|
||||
return controlbd_req_ack_any(req->hdr.cmd);
|
||||
dprintf("Unhandled command %#02x\n", req->cmd);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len)
|
||||
static HRESULT controlbd_req_nop(uint8_t cmd)
|
||||
{
|
||||
resp->sync = CONTROLBD_SYNC_BYTE;
|
||||
resp->dest = 0x01;
|
||||
resp->src = 0x02;
|
||||
resp->len = len;
|
||||
resp->report = 0x01;
|
||||
resp->cmd = cmd;
|
||||
dprintf("Control Board: No-op cmd %#02x\n", cmd);
|
||||
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0xE0;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x11;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x03;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x10;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x01;
|
||||
controlbd_uart.readable.bytes[controlbd_uart.readable.pos++] = 0x27;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static uint8_t calc_checksum(void *data, size_t len)
|
||||
/* Decodes the response into a struct that's easier to work with. */
|
||||
static HRESULT controlbd_frame_decode(struct controlbd_req *dest, struct iobuf *iobuf)
|
||||
{
|
||||
uint8_t *stuff;
|
||||
stuff = data;
|
||||
uint8_t checksum = 0;
|
||||
uint16_t tmp = 0;
|
||||
int initial_pos = iobuf->pos;
|
||||
uint8_t check = 0;
|
||||
|
||||
for (int i = 1; i < len; i++) {
|
||||
tmp = checksum + stuff[i];
|
||||
checksum = tmp & 0xFF;
|
||||
dest->sync = iobuf->bytes[0];
|
||||
iobuf->pos--;
|
||||
|
||||
dest->cmd = iobuf->bytes[1];
|
||||
iobuf->pos--;
|
||||
check += dest->cmd;
|
||||
|
||||
dest->checksum = iobuf->bytes[initial_pos - 1];
|
||||
iobuf->pos--;
|
||||
|
||||
dest->data_length = initial_pos - 3; // sync, cmd, checksum
|
||||
if (dest->data_length > 0) {
|
||||
for (int i = 0; i < dest->data_length; i++) {
|
||||
dest->data[i] = iobuf->bytes[i+2];
|
||||
check += dest->data[i];
|
||||
}
|
||||
}
|
||||
iobuf->pos -= dest->data_length;
|
||||
|
||||
if (dest->sync != 0xe0) {
|
||||
dprintf("Control Board: Sync error, expected 0xe0, got %x\n", dest->sync);
|
||||
return E_FAIL;
|
||||
}
|
||||
if (dest->checksum != check) {
|
||||
dprintf("Control Board: Checksum error, expected %x, got %x\n", check, dest->checksum);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
static HRESULT controlbd_req_reset(void)
|
||||
{
|
||||
struct controlbd_resp_reset resp;
|
||||
|
||||
dprintf("Control Board: Reset\n");
|
||||
|
||||
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_RESET, 2);
|
||||
resp.checksum = 0;
|
||||
|
||||
// No data, just ack
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||
|
||||
}
|
||||
|
||||
static HRESULT controlbd_req_get_board_info(void)
|
||||
{
|
||||
struct controlbd_resp_bdinfo resp;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Control Board: Get Board Info\n");
|
||||
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_BDINFO, 21);
|
||||
|
||||
resp.rev = 0x90;
|
||||
resp.bfr_size = 0x0001;
|
||||
resp.ack = 1;
|
||||
|
||||
strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 ");
|
||||
strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 ");
|
||||
resp.chip_no[5] = 0xFF;
|
||||
resp.bd_no[8] = 0x0A;
|
||||
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
|
||||
static HRESULT controlbd_req_firmware_checksum(void)
|
||||
{
|
||||
struct controlbd_resp_fw_checksum resp;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
dprintf("Control Board: Get Firmware Checksum\n");
|
||||
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_FIRM_SUM, 5);
|
||||
|
||||
resp.ack = 1;
|
||||
resp.fw_checksum = 0x1b36; // This could change with an update... oh well
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
|
||||
static HRESULT controlbd_req_polling(const struct controlbd_req_any *req)
|
||||
{
|
||||
struct controlbd_req_polling req_struct;
|
||||
memset(&req_struct, 0, sizeof(req_struct));
|
||||
memcpy_s(&req_struct, sizeof(req_struct), req, sizeof(req_struct));
|
||||
struct controlbd_resp_polling resp;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
controlbd_set_header(&resp.hdr, CONTROLBD_CMD_POLLING, 16);
|
||||
// TODO: Figure out output (pen vibration, etc)
|
||||
|
||||
resp.ack = 1;
|
||||
resp.unk7 = 3;
|
||||
resp.unk8 = 1;
|
||||
resp.unk9 = 1;
|
||||
|
||||
resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge
|
||||
resp.coord_x = 0x0;
|
||||
resp.coord_y = 0x0;
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
|
||||
static HRESULT controlbd_req_ack_any(uint8_t cmd)
|
||||
{
|
||||
struct controlbd_resp_any_ack resp;
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
controlbd_set_header(&resp.hdr, cmd, 3);
|
||||
|
||||
resp.ack = 1;
|
||||
resp.checksum = calc_checksum(&resp, sizeof(resp));
|
||||
|
||||
return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
@ -9,140 +7,15 @@
|
|||
struct controlbd_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct controlbd_req_hdr {
|
||||
uint8_t sync;
|
||||
uint8_t dest; // unsure
|
||||
uint8_t src; // unsure
|
||||
uint8_t len; // length of the rest of the request minus checksum
|
||||
uint8_t cmd;
|
||||
enum controlbd_cmd {
|
||||
CONTROLBD_CMD_UNK_11 = 0x11
|
||||
};
|
||||
struct controlbd_req {
|
||||
uint8_t sync; // First byte is the sync
|
||||
uint8_t cmd; // Command byte
|
||||
uint8_t data[256]; // Request body goes here
|
||||
uint8_t checksum; // Final byte is all bytes added, except the sync
|
||||
uint8_t data_length; // Size of the data including command byte
|
||||
};
|
||||
|
||||
struct controlbd_req_any {
|
||||
struct controlbd_req_hdr hdr;
|
||||
uint8_t bytes[255];
|
||||
};
|
||||
|
||||
struct controlbd_req_reset {
|
||||
struct controlbd_req_hdr hdr;
|
||||
uint8_t payload;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_req_bdinfo {
|
||||
struct controlbd_req_hdr hdr;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_req_fw_checksum {
|
||||
struct controlbd_req_hdr hdr;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_req_timeout {
|
||||
struct controlbd_req_hdr hdr;
|
||||
uint8_t unknown;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_req_polling {
|
||||
struct controlbd_req_hdr hdr;
|
||||
uint8_t unknown[20];
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_resp_hdr {
|
||||
uint8_t sync;
|
||||
uint8_t dest; // unsure
|
||||
uint8_t src; // unsure
|
||||
uint8_t len; // length of the rest of the request minus checksum
|
||||
uint8_t report; // 0x01 for success, anything else for failure
|
||||
uint8_t cmd;
|
||||
};
|
||||
|
||||
struct controlbd_resp_any {
|
||||
struct controlbd_resp_hdr hdr;
|
||||
uint8_t bytes[255];
|
||||
};
|
||||
|
||||
struct controlbd_resp_any_ack {
|
||||
struct controlbd_resp_hdr hdr;
|
||||
uint8_t ack;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_resp_reset {
|
||||
struct controlbd_resp_hdr hdr;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_resp_bdinfo {
|
||||
struct controlbd_resp_hdr hdr;
|
||||
uint8_t ack;
|
||||
char bd_no[9];
|
||||
char chip_no[6];
|
||||
uint8_t rev;
|
||||
uint16_t bfr_size;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_resp_fw_checksum {
|
||||
struct controlbd_resp_hdr hdr;
|
||||
uint8_t ack;
|
||||
uint16_t fw_checksum;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
struct controlbd_resp_polling {
|
||||
struct controlbd_resp_hdr hdr;
|
||||
uint8_t ack;
|
||||
uint8_t unk7;
|
||||
uint8_t unk8;
|
||||
uint8_t unk9;
|
||||
uint8_t btns_pressed;
|
||||
uint8_t blob[7];
|
||||
int8_t coord_x;
|
||||
int8_t coord_y;
|
||||
uint8_t checksum;
|
||||
};
|
||||
|
||||
enum {
|
||||
PEN_BTN_PRESSED_BIT = 1,
|
||||
DODGE_BTN_PRESSED_BIT = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
CONTROLBD_CMD_RESET = 0x10,
|
||||
CONTROLBD_CMD_TIMEOUT = 0x11,
|
||||
CONTROLBD_CMD_RETRY = 0x12,
|
||||
|
||||
CONTROLBD_CMD_GETIN = 0x20,
|
||||
CONTROLBD_CMD_GETADI = 0x21,
|
||||
|
||||
CONTROLBD_CMD_SETOUTPUT = 0x30,
|
||||
|
||||
CONTROLBD_CMD_INITIALIZE = 0x80,
|
||||
CONTROLBD_CMD_POLLING = 0x81,
|
||||
CONTROLBD_CMD_CUSTOM_PATTERN = 0x82,
|
||||
CONTROLBD_CMD_DEBUG_CAROL = 0x83,
|
||||
CONTROLBD_CMD_POLLING_GENERAL = 0x84,
|
||||
|
||||
CONTROLBD_CMD_CMD_STATUS = 0x90,
|
||||
CONTROLBD_CMD_PORT_SETTING = 0x91,
|
||||
CONTROLBD_CMD_PWM_DUTY = 0x92,
|
||||
CONTROLBD_CMD_LED_SET = 0x93,
|
||||
CONTROLBD_CMD_LED_REFRESH = 0x94,
|
||||
|
||||
CONTROLBD_CMD_DEBUG_UART = 0xB0,
|
||||
CONTROLBD_CMD_DEBUG_I2C = 0xB1,
|
||||
|
||||
CONTROLBD_CMD_DEBUG_STATUS = 0xC0,
|
||||
|
||||
CONTROLBD_CMD_BDINFO = 0xF0,
|
||||
CONTROLBD_CMD_FIRM_SUM = 0xF2,
|
||||
CONTROLBD_CMD_PROTOCOL = 0xF3,
|
||||
CONTROLBD_CMD_UPDATE = 0xFE,
|
||||
};
|
||||
#pragma pack(pop)
|
||||
HRESULT controlbd_hook_init(const struct controlbd_config *cfg);
|
|
@ -12,15 +12,13 @@
|
|||
#include "carolhook/carol-dll.h"
|
||||
#include "carolhook/jvs.h"
|
||||
#include "carolhook/touch.h"
|
||||
#include "carolhook/ledbd.h"
|
||||
#include "carolhook/controlbd.h"
|
||||
#include "carolhook/serial.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
|
||||
#include "hooklib/serial.h"
|
||||
#include "hooklib/spike.h"
|
||||
#include "hooklib/createprocess.h"
|
||||
#include "hooklib/cursor.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
|
@ -32,43 +30,17 @@ static struct carol_hook_config carol_hook_cfg;
|
|||
|
||||
/*
|
||||
COM Layout
|
||||
01: Touchscreen
|
||||
01:(?) Touchscreen
|
||||
10: Aime reader
|
||||
11: LED board
|
||||
12: Control Board
|
||||
11: Control board
|
||||
12(?): LED Board
|
||||
*/
|
||||
|
||||
static DWORD CALLBACK carol_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
HMODULE d3dc;
|
||||
HMODULE dbghelp;
|
||||
|
||||
dprintf("--- Begin carol_pre_startup ---\n");
|
||||
if ( !SetProcessDPIAware() )
|
||||
dprintf("Failed to set process DPI awareness level!\n");
|
||||
|
||||
/* Pin the D3D shader compiler. This makes startup much faster. */
|
||||
|
||||
d3dc = LoadLibraryW(L"D3DCompiler_43.dll");
|
||||
|
||||
if (d3dc != NULL) {
|
||||
dprintf("Pinned shader compiler, hMod=%p\n", d3dc);
|
||||
} else {
|
||||
dprintf("Failed to load shader compiler!\n");
|
||||
}
|
||||
|
||||
/* Pin dbghelp so the path hooks apply to it. */
|
||||
|
||||
dbghelp = LoadLibraryW(L"dbghelp.dll");
|
||||
|
||||
if (dbghelp != NULL) {
|
||||
dprintf("Pinned debug helper library, hMod=%p\n", dbghelp);
|
||||
} else {
|
||||
dprintf("Failed to load debug helper library!\n");
|
||||
}
|
||||
|
||||
cursor_hook_init();
|
||||
|
||||
/* Config load */
|
||||
|
||||
|
@ -109,7 +81,9 @@ static DWORD CALLBACK carol_pre_startup(void)
|
|||
}
|
||||
|
||||
gfx_hook_init(&carol_hook_cfg.gfx);
|
||||
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
|
||||
gfx_d3d9_hook_init(&carol_hook_cfg.gfx, carol_hook_mod);
|
||||
//serial_init();
|
||||
|
||||
|
||||
hr = touch_hook_init(&carol_hook_cfg.touch);
|
||||
|
||||
|
@ -117,23 +91,12 @@ static DWORD CALLBACK carol_pre_startup(void)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
hr = ledbd_hook_init(&carol_hook_cfg.ledbd);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = controlbd_hook_init(&carol_hook_cfg.controlbd);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = createprocess_push_hook_a(".\\15312firm\\firmupdate_1113.exe", "inject -d -k carolhook.dll ", NULL, false);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\segatools.ini");
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "carolhook/carol-dll.h"
|
||||
#include "carolhook/ledbd.h"
|
||||
|
||||
#include "hooklib/uart.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
#include "board/slider-frame.h"
|
||||
#include "board/slider-cmd.h"
|
||||
|
||||
static HRESULT ledbd_handle_irp(struct irp *irp);
|
||||
static HRESULT ledbd_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT ledbd_frame_dispatch(const union slider_req_any *dest);
|
||||
|
||||
static HRESULT ledbd_req_noop(uint8_t cmd);
|
||||
static HRESULT ledbd_req_unk7c(uint8_t cmd);
|
||||
static HRESULT ledbd_req_unkF0(uint8_t cmd);
|
||||
|
||||
static CRITICAL_SECTION ledbd_lock;
|
||||
static struct uart ledbd_uart;
|
||||
static uint8_t ledbd_written_bytes[520];
|
||||
static uint8_t ledbd_readable_bytes[520];
|
||||
|
||||
HRESULT ledbd_hook_init(const struct ledbd_config *cfg)
|
||||
{
|
||||
if (!cfg->enable) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&ledbd_lock);
|
||||
|
||||
uart_init(&ledbd_uart, 11);
|
||||
ledbd_uart.written.bytes = ledbd_written_bytes;
|
||||
ledbd_uart.written.nbytes = sizeof(ledbd_written_bytes);
|
||||
ledbd_uart.readable.bytes = ledbd_readable_bytes;
|
||||
ledbd_uart.readable.nbytes = sizeof(ledbd_readable_bytes);
|
||||
|
||||
dprintf("LED Board: Init\n");
|
||||
|
||||
return iohook_push_handler(ledbd_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT ledbd_handle_irp(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(irp != NULL);
|
||||
|
||||
if (!uart_match_irp(&ledbd_uart, irp)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&ledbd_lock);
|
||||
hr = ledbd_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&ledbd_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT ledbd_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
union slider_req_any req;
|
||||
struct iobuf req_iobuf;
|
||||
HRESULT hr;
|
||||
|
||||
assert(carol_dll.ledbd_init != NULL);
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("LED Board: Starting backend DLL\n");
|
||||
hr = carol_dll.ledbd_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("LED Board: Backend DLL error: 0X%X\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&ledbd_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("LED Board: TX Buffer:\n");
|
||||
dump_iobuf(&ledbd_uart.written);
|
||||
#endif
|
||||
req_iobuf.bytes = req.bytes;
|
||||
req_iobuf.nbytes = sizeof(req.bytes);
|
||||
req_iobuf.pos = 0;
|
||||
|
||||
hr = slider_frame_decode(&req_iobuf, &ledbd_uart.written);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = ledbd_frame_dispatch(&req);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("LED Board: Dispatch Error: 0X%X\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ledbd_frame_dispatch(const union slider_req_any *req)
|
||||
{
|
||||
switch (req->hdr.cmd) {
|
||||
case LEDBD_CMD_UNK_10:
|
||||
return ledbd_req_noop(req->hdr.cmd);
|
||||
case LEDBD_CMD_UNK_7C:
|
||||
return ledbd_req_unk7c(req->hdr.cmd);
|
||||
case LEDBD_CMD_UNK_F0:
|
||||
return ledbd_req_unkF0(req->hdr.cmd);
|
||||
case LEDBD_CMD_UNK_30:
|
||||
return ledbd_req_noop(req->hdr.cmd);
|
||||
default:
|
||||
//dprintf("Unhandled command 0x%02X\n", req->cmd);
|
||||
return ledbd_req_noop(req->hdr.cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ledbd_req_noop(uint8_t cmd)
|
||||
{
|
||||
//dprintf("LED Board: Noop cmd 0x%02X\n", cmd);
|
||||
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 };
|
||||
resp[5] = cmd;
|
||||
resp[7] = 0x17 + cmd;
|
||||
iobuf_write(&ledbd_uart.readable, resp, 8);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ledbd_req_unk7c(uint8_t cmd)
|
||||
{
|
||||
//dprintf("LED Board: Cmd 0x7C\n");
|
||||
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B };
|
||||
iobuf_write(&ledbd_uart.readable, resp, 9);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ledbd_req_unkF0(uint8_t cmd)
|
||||
{
|
||||
//dprintf("LED Board: Cmd 0xF0\n");
|
||||
uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E };
|
||||
iobuf_write(&ledbd_uart.readable, resp, 16);
|
||||
|
||||
return S_OK;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct ledbd_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
enum ledbd_cmd {
|
||||
LEDBD_CMD_UNK_10 = 0x10,
|
||||
LEDBD_CMD_UNK_7C = 0x7C,
|
||||
LEDBD_CMD_UNK_30 = 0x30,
|
||||
LEDBD_CMD_UNK_F0 = 0xF0,
|
||||
};
|
||||
|
||||
struct ledbd_req {
|
||||
uint8_t sync; // Sync byte, always 0xE0
|
||||
uint8_t dest; // command destination id?
|
||||
uint8_t src; // command source id?
|
||||
uint8_t data_len; // length of the proceeding data bytes
|
||||
uint8_t cmd; // might be the command byte?
|
||||
uint8_t data[255]; // rest of the data, len = data_len - 1
|
||||
uint8_t checksum; // final byte is all bytes (excluding sync) added
|
||||
};
|
||||
|
||||
HRESULT ledbd_hook_init(const struct ledbd_config *cfg);
|
|
@ -32,7 +32,7 @@ shared_library(
|
|||
'touch.h',
|
||||
'controlbd.c',
|
||||
'controlbd.h',
|
||||
'ledbd.c',
|
||||
'ledbd.h',
|
||||
'serial.c',
|
||||
'serial.h',
|
||||
],
|
||||
)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL (WINAPI *next_SetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static void com_hook_insert_hooks(HMODULE target);
|
||||
|
||||
static const struct hook_symbol win32_hooks[] = {
|
||||
{
|
||||
.name = "SetCommState",
|
||||
.patch = my_SetCommState,
|
||||
.link = (void **) &next_SetCommState
|
||||
}
|
||||
};
|
||||
|
||||
void serial_init()
|
||||
{
|
||||
com_hook_insert_hooks(NULL);
|
||||
dprintf("Serial: Spy init\n");
|
||||
}
|
||||
|
||||
static void com_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
}
|
||||
|
||||
static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB)
|
||||
{
|
||||
dprintf("Serial: my_SetCommState with baudrate %ld\n", lpDCB->BaudRate);
|
||||
return next_SetCommState(hFile, lpDCB);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
|
||||
void serial_init();
|
|
@ -8,46 +8,19 @@
|
|||
#include "carolhook/carol-dll.h"
|
||||
#include "carolhook/touch.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/uart.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
/**
|
||||
* CMDS for touch thing
|
||||
* CX -> Calibrate Extend, preform callibration
|
||||
* MS -> Mode Stream, enters stream mode
|
||||
* R -> Reset, resets the device
|
||||
* RD -> Reset Default, Resets the device to factory
|
||||
* Z -> Null, keepalive command
|
||||
* NM -> Name, return the name of the device (not documented?)
|
||||
* OI -> Output Identity, output unique device identity, SC followed by 4 characters
|
||||
* UT -> Unit Type, returns controller unit type + status
|
||||
*/
|
||||
|
||||
static HRESULT touch_handle_irp(struct irp *irp);
|
||||
static HRESULT touch_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf);
|
||||
|
||||
static HRESULT handle_touch_ack_cmd(const struct touch_req *req);
|
||||
static HRESULT handle_touch_name_cmd(const struct touch_req *req);
|
||||
static HRESULT handle_touch_id_cmd(const struct touch_req *req);
|
||||
static HRESULT handle_touch_unit_type_cmd(const struct touch_req *req);
|
||||
static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y);
|
||||
|
||||
static CRITICAL_SECTION touch_lock;
|
||||
static struct uart touch_uart;
|
||||
static uint8_t touch_written_bytes[528];
|
||||
static uint8_t touch_readable_bytes[528];
|
||||
static bool should_stream = false;
|
||||
static bool last_pressed;
|
||||
static uint8_t last_x1;
|
||||
static uint8_t last_x2;
|
||||
static uint8_t last_y1;
|
||||
static uint8_t last_y2;
|
||||
|
||||
static uint8_t touch_written_bytes[520];
|
||||
static uint8_t touch_readable_bytes[520];
|
||||
|
||||
HRESULT touch_hook_init(const struct touch_config *cfg)
|
||||
{
|
||||
|
@ -96,10 +69,9 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
|||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Touchscreen: Starting backend DLL\n");
|
||||
hr = carol_dll.touch_init();
|
||||
carol_dll.touch_start(touch_scan_auto);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr);
|
||||
dprintf("Touchscreen: Backend DLL error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -112,142 +84,35 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
|
|||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
#if 1
|
||||
dprintf("Touchscreen: TX Buffer:\n");
|
||||
dump_iobuf(&touch_uart.written);
|
||||
#endif
|
||||
hr = touch_frame_decode(&req, &touch_uart.written);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Touchscreen: Deframe Error: %X\n", (int) hr);
|
||||
dprintf("Touchscreen: Deframe Error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (!strcmp("Z", (char *)req.cmd)) {
|
||||
hr = handle_touch_ack_cmd(&req);
|
||||
}
|
||||
else if (!strcmp("OI", (char *)req.cmd)) {
|
||||
hr = handle_touch_id_cmd(&req);
|
||||
}
|
||||
else if (!strcmp("UT", (char *)req.cmd)) {
|
||||
hr = handle_touch_unit_type_cmd(&req);
|
||||
}
|
||||
else if (!strcmp("NM", (char *)req.cmd)) {
|
||||
hr = handle_touch_name_cmd(&req);
|
||||
}
|
||||
else if (!strcmp("R", (char *)req.cmd)) {
|
||||
carol_dll.touch_stop();
|
||||
dprintf("Touch: Reset\n");
|
||||
hr = handle_touch_ack_cmd(&req);
|
||||
}
|
||||
else {
|
||||
dprintf("Touchscreen: Unhandled cmd %s\n", (char *)req.cmd);
|
||||
hr = handle_touch_ack_cmd(&req);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT handle_touch_ack_cmd(const struct touch_req *req)
|
||||
{
|
||||
return iobuf_write(&touch_uart.readable, "\0010\015", 3);
|
||||
}
|
||||
|
||||
static HRESULT handle_touch_name_cmd(const struct touch_req *req)
|
||||
{
|
||||
dprintf("Touch: Get Name\n");
|
||||
return iobuf_write(&touch_uart.readable, "\001AD1000\015", 15);
|
||||
}
|
||||
|
||||
static HRESULT handle_touch_id_cmd(const struct touch_req *req)
|
||||
{
|
||||
dprintf("Touch: Get ID\n");
|
||||
return iobuf_write(&touch_uart.readable, "\001AD1000\015", 8);
|
||||
}
|
||||
|
||||
static HRESULT handle_touch_unit_type_cmd(const struct touch_req *req)
|
||||
{
|
||||
dprintf("Touch: Get Unit Type\n");
|
||||
return iobuf_write(&touch_uart.readable, "\001AD****00\015", 8);
|
||||
}
|
||||
|
||||
static void touch_scan_auto(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y)
|
||||
{
|
||||
struct touch_auto_resp resp;
|
||||
uint16_t tmp_x;
|
||||
uint16_t tmp_y;
|
||||
bool flg = false;
|
||||
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
resp.touches[0].status |= 1 << 7;
|
||||
|
||||
if (is_pressed) {
|
||||
resp.touches[0].status |= (1 << 7) | (1 << 6);
|
||||
resp.touches[0].touch_id = 1;
|
||||
tmp_x = mouse_x & 0x7FFF;
|
||||
tmp_y = mouse_y & 0x7FFF;
|
||||
|
||||
resp.touches[0].x1 = tmp_x & 0x7F;
|
||||
resp.touches[0].x2 = (tmp_x >> 7) & 0x7F;
|
||||
resp.touches[0].y1 = tmp_y & 0x7F;
|
||||
resp.touches[0].y2 = (tmp_y >> 7) & 0x7F;
|
||||
|
||||
flg = resp.touches[0].x1 != last_x1 || resp.touches[0].x2 != last_x2 || resp.touches[0].y1 != last_y1 || resp.touches[0].y2 != last_y2;
|
||||
|
||||
#if 1
|
||||
if (flg)
|
||||
dprintf("Touch: Mouse down! x %02X %02X y: %02X %02X\n", resp.touches[0].x1, resp.touches[0].x2, resp.touches[0].y1, resp.touches[0].y2);
|
||||
#endif
|
||||
|
||||
|
||||
last_x1 = resp.touches[0].x1;
|
||||
last_x2 = resp.touches[0].x2;
|
||||
last_y1 = resp.touches[0].y1;
|
||||
last_y2 = resp.touches[0].y2;
|
||||
|
||||
} else if (last_pressed) {
|
||||
resp.touches[0].x1 = last_x1;
|
||||
resp.touches[0].x2 = last_x2;
|
||||
resp.touches[0].y1 = last_y1;
|
||||
resp.touches[0].y2 = last_y2;
|
||||
}
|
||||
|
||||
last_pressed = is_pressed;
|
||||
|
||||
EnterCriticalSection(&touch_lock);
|
||||
iobuf_write(&touch_uart.readable, &resp, sizeof(resp));
|
||||
LeaveCriticalSection(&touch_lock);
|
||||
|
||||
#if 0
|
||||
dprintf("Touch: RX Buffer: (pos %08x)\n", (uint32_t)touch_uart.readable.pos);
|
||||
dump_iobuf(&touch_uart.readable);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Decodes the response into a struct that's easier to work with. */
|
||||
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf)
|
||||
{
|
||||
dest->sync = iobuf->bytes[0];
|
||||
memset(dest->cmd, 0, sizeof(dest->cmd));
|
||||
size_t data_len = 0;
|
||||
dest->cmd = iobuf->bytes[0];
|
||||
iobuf->pos--;
|
||||
dest->data_length = iobuf->pos;
|
||||
|
||||
for (int i = 1; i < 255; i++) {
|
||||
if (iobuf->bytes[i] == 0x0D) { break; }
|
||||
dest->cmd[i - 1] = iobuf->bytes[i];
|
||||
data_len++;
|
||||
}
|
||||
|
||||
dest->tail = iobuf->bytes[data_len + 1];
|
||||
dest->data_len = data_len;
|
||||
|
||||
iobuf->pos = 0;
|
||||
|
||||
if (dest->sync != 1 || dest->tail != 0x0D) {
|
||||
dprintf("Touch: Data recieve error, sync: 0x%02X (expected 0x01) tail: 0x%02X (expected 0x0D)", dest->sync, dest->tail);
|
||||
return E_FAIL;
|
||||
if (dest->data_length > 0) {
|
||||
for (int i = 1; i < dest->data_length; i++) {
|
||||
dest->data[i-1] = iobuf->bytes[i];
|
||||
}
|
||||
}
|
||||
iobuf->pos -= dest->data_length;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
|
@ -4,42 +4,14 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct touch_config {
|
||||
bool enable;
|
||||
unsigned int port_no;
|
||||
char board_id[7];
|
||||
char unit_type[9];
|
||||
};
|
||||
|
||||
// Always starts with 0x01, always ends with 0x0D
|
||||
struct touch_req {
|
||||
uint8_t sync; // Always 0x01
|
||||
uint8_t cmd[256]; // rest of the data goes here
|
||||
uint8_t tail; // Always 0x0D
|
||||
size_t data_len; // length of data
|
||||
uint8_t cmd; // First byte is the command byte
|
||||
uint8_t data[256]; // rest of the data goes here
|
||||
uint8_t data_length; // Size of the data including command byte
|
||||
};
|
||||
|
||||
struct touch_report {
|
||||
uint8_t status;
|
||||
uint8_t x1;
|
||||
uint8_t x2;
|
||||
uint8_t y1;
|
||||
uint8_t y2;
|
||||
uint8_t touch_id;
|
||||
};
|
||||
|
||||
struct touch_auto_resp {
|
||||
struct touch_report touches[10];
|
||||
};
|
||||
|
||||
enum {
|
||||
TOUCH_MODE_STREAM = 0x01,
|
||||
TOUCH_MODE_DOWN_UP = 0x02,
|
||||
TOUCH_MODE_INACTIVE = 0x03,
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
HRESULT touch_hook_init(const struct touch_config *cfg);
|
|
@ -7,16 +7,10 @@
|
|||
|
||||
#include "carolio/carolio.h"
|
||||
#include "carolio/config.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx);
|
||||
|
||||
static bool carol_io_coin;
|
||||
static uint16_t carol_io_coins;
|
||||
static struct carol_io_config carol_io_cfg;
|
||||
static bool carol_io_touch_stop_flag;
|
||||
static HANDLE carol_io_touch_thread;
|
||||
static bool carol_io_window_focus = false;
|
||||
|
||||
uint16_t carol_io_get_api_version(void)
|
||||
{
|
||||
|
@ -79,103 +73,7 @@ HRESULT carol_io_touch_init()
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT carol_io_ledbd_init()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT carol_io_controlbd_init()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void carol_io_touch_start(carol_io_touch_callback_t callback)
|
||||
{
|
||||
if (carol_io_touch_thread != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
carol_io_touch_stop_flag = false;
|
||||
|
||||
carol_io_touch_thread = (HANDLE) _beginthreadex(
|
||||
NULL,
|
||||
0,
|
||||
carol_io_touch_thread_proc,
|
||||
callback,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
void carol_io_touch_stop()
|
||||
{
|
||||
carol_io_touch_stop_flag = true;
|
||||
}
|
||||
|
||||
void check_fg_wind(void)
|
||||
{
|
||||
HWND hwnd = GetForegroundWindow();
|
||||
wchar_t window_class[MAX_PATH];
|
||||
|
||||
/* Unlike every other game, we can't use GetWindowText here. Why?
|
||||
|
||||
From MSDN:
|
||||
|
||||
"If the window does not have a caption, the return value is a null
|
||||
string. This behavior is by design. It allows applications to call
|
||||
GetWindowText without becoming unresponsive if the process that owns
|
||||
the target window is not responding. However, if the target window
|
||||
is not responding and it belongs to the calling application,
|
||||
GetWindowText will cause the calling application to become
|
||||
unresponsive."
|
||||
|
||||
Great, thanks Microsoft, very cool. Luckily Carol sets its class
|
||||
name to the window title too so we can use that. */
|
||||
|
||||
GetClassNameW(hwnd, window_class, MAX_PATH);
|
||||
|
||||
if (wcscmp(window_class, L"WONDER Master")) {
|
||||
if (carol_io_window_focus) {
|
||||
dprintf("Carol IO: Window focus lost\n");
|
||||
carol_io_window_focus = false;
|
||||
}
|
||||
} else if (!carol_io_window_focus) {
|
||||
dprintf("Carol IO: Window focus regained\n");
|
||||
carol_io_window_focus = true;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int __stdcall carol_io_touch_thread_proc(void *ctx)
|
||||
{
|
||||
carol_io_touch_callback_t callback;
|
||||
bool mouse_is_down = false;
|
||||
uint16_t mX = 0;
|
||||
uint16_t mY = 0;
|
||||
POINT lpPoint;
|
||||
HWND hwnd;
|
||||
|
||||
callback = ctx;
|
||||
|
||||
while (!carol_io_touch_stop_flag) {
|
||||
check_fg_wind();
|
||||
if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) {
|
||||
mouse_is_down = true;
|
||||
if (GetCursorPos(&lpPoint)) {
|
||||
hwnd = GetForegroundWindow();
|
||||
if (ScreenToClient(hwnd, &lpPoint)) {
|
||||
if (lpPoint.x < 0) lpPoint.x = 0;
|
||||
if (lpPoint.y < 0) lpPoint.y = 0;
|
||||
mX = (uint16_t)lpPoint.x;
|
||||
mY = (uint16_t)lpPoint.y;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mouse_is_down = false;
|
||||
}
|
||||
|
||||
callback(mouse_is_down, mX, mY);
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -5,8 +5,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*carol_io_touch_callback_t)(const bool is_pressed, const uint16_t mouse_x, const uint16_t mouse_y);
|
||||
|
||||
/* Get the version of the Project carol IO API that this DLL supports. This
|
||||
function should return a positive 16-bit integer, where the high byte is
|
||||
the major version and the low byte is the minor version (as defined by the
|
||||
|
@ -51,10 +49,4 @@ void carol_io_jvs_read_coin_counter(uint16_t *out);
|
|||
|
||||
HRESULT carol_io_touch_init();
|
||||
|
||||
HRESULT carol_io_ledbd_init();
|
||||
|
||||
HRESULT carol_io_controlbd_init();
|
||||
|
||||
void carol_io_touch_start(carol_io_touch_callback_t callback);
|
||||
|
||||
void carol_io_touch_stop();
|
||||
HRESULT carol_io_controlbd_init();
|
|
@ -5,7 +5,7 @@
|
|||
#include "cxbhook/led.h"
|
||||
#include "cxbhook/cxb-dll.h"
|
||||
|
||||
#include "hook/procaddr.h"
|
||||
#include "hooklib/procaddr.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
|
@ -50,7 +50,7 @@ static struct hook_symbol lamp_syms[] = {
|
|||
HRESULT led_hook_init(struct led_config *cfg)
|
||||
{
|
||||
dprintf("LED: Init\n");
|
||||
return proc_addr_table_push(NULL, "CommLamp.dll", lamp_syms, _countof(lamp_syms));
|
||||
return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms));
|
||||
}
|
||||
|
||||
static int my_cCommLamp_Open(char *port)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "cxbhook/revio.h"
|
||||
#include "cxbhook/cxb-dll.h"
|
||||
|
||||
#include "hook/procaddr.h"
|
||||
#include "hooklib/procaddr.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
|
@ -83,7 +83,7 @@ static struct hook_symbol revio_syms[] = {
|
|||
HRESULT revio_hook_init(struct revio_config *cfg)
|
||||
{
|
||||
dprintf("Revio: Init\n");
|
||||
return proc_addr_table_push(NULL, "CommIo.dll", revio_syms, _countof(revio_syms));
|
||||
return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms));
|
||||
}
|
||||
|
||||
static int my_cCommIo_Open(char *port)
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=amfs
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=appdata
|
||||
option=option
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[ds]
|
||||
; Region code on the emulated AMEX board DS EEPROM.
|
||||
; 1: Japan
|
||||
; 4: Export (some UI elements in English)
|
||||
;
|
||||
; NOTE: Changing this setting causes a factory reset.
|
||||
region=1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
[keychip]
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.172.0
|
||||
|
||||
[gfx]
|
||||
enable=1
|
||||
|
||||
[io4]
|
||||
; Delete
|
||||
test=0x2E
|
||||
; End
|
||||
service=0x23
|
||||
; Insert
|
||||
coin=0x2D
|
|
@ -1,11 +0,0 @@
|
|||
@echo off
|
||||
pushd %~dp0
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
start inject -d -k mai2hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json
|
||||
inject.exe -d -k mai2hook.dll Sinmai.exe -screen-fullscreen 0 -screen-width 2160 -screen-height 1920
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo Game processes have terminated
|
|
@ -30,7 +30,7 @@ enable=1
|
|||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.162.0
|
||||
subnet=192.168.250.0
|
||||
|
||||
[gfx]
|
||||
enable=1
|
||||
|
@ -57,4 +57,4 @@ RIGHT_SIDE=0x55
|
|||
SLIDER_LEFT=0x54
|
||||
SLIDER_RIGHT=0x59
|
||||
;Change move speed of slider when use dinput
|
||||
SLIDER_SPEED=1000
|
||||
SLIDER_SPEED=1000
|
|
@ -3,8 +3,12 @@ pushd %~dp0
|
|||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
start inject -d -k mu3hook.dll amdaemon.exe -f -c config_client.json config_common.json config_server.json
|
||||
inject -d -k mu3hook.dll mu3.exe
|
||||
REM USA
|
||||
REM start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json
|
||||
|
||||
REM JP
|
||||
start inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
||||
inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
setlocal enabledelayedexpansion
|
||||
|
||||
:: Static Environment Variables
|
||||
set BUILD_OUTPUT_PATH=build\docker
|
||||
set IMAGE_NAME=djhackers/segatools-build:latest
|
||||
set CONTAINER_NAME=segatools-build
|
||||
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/createprocess.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
void createprocess_hook_init();
|
||||
static BOOL WINAPI my_CreateProcessA(
|
||||
LPCSTR lpApplicationName,
|
||||
LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOA lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
BOOL my_CreateProcessW(
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CreateProcessA)(
|
||||
LPCSTR lpApplicationName,
|
||||
LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOA lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CreateProcessW)(
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
static const struct hook_symbol win32_hooks[] = {
|
||||
{
|
||||
.name = "CreateProcessA",
|
||||
.patch = my_CreateProcessA,
|
||||
.link = (void **) &next_CreateProcessA
|
||||
},
|
||||
{
|
||||
.name = "CreateProcessW",
|
||||
.patch = my_CreateProcessW,
|
||||
.link = (void **) &next_CreateProcessW
|
||||
},
|
||||
};
|
||||
|
||||
static bool did_init = false;
|
||||
|
||||
static struct process_hook_sym_w *process_syms_w;
|
||||
static struct process_hook_sym_a *process_syms_a;
|
||||
|
||||
static size_t process_nsyms_a = 0;
|
||||
static size_t process_nsyms_w = 0;
|
||||
|
||||
static CRITICAL_SECTION createproc_lock;
|
||||
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all) {
|
||||
struct process_hook_sym_w *new_mem;
|
||||
struct process_hook_sym_w *new_proc;
|
||||
HRESULT hr;
|
||||
|
||||
assert(name != NULL);
|
||||
assert(head != NULL);
|
||||
|
||||
createprocess_hook_init();
|
||||
EnterCriticalSection(&createproc_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
process_syms_w,
|
||||
(process_nsyms_w + 1) * sizeof(struct process_hook_sym_w));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
new_proc = &new_mem[process_nsyms_w];
|
||||
memset(new_proc, 0, sizeof(*new_proc));
|
||||
new_proc->name = name;
|
||||
new_proc->head = head;
|
||||
new_proc->tail = tail;
|
||||
new_proc->replace_all = replace_all;
|
||||
|
||||
process_syms_w = new_mem;
|
||||
process_nsyms_w++;
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all) {
|
||||
struct process_hook_sym_a *new_mem;
|
||||
struct process_hook_sym_a *new_proc;
|
||||
|
||||
assert(name != NULL);
|
||||
assert(head != NULL);
|
||||
|
||||
createprocess_hook_init();
|
||||
|
||||
EnterCriticalSection(&createproc_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
process_syms_a,
|
||||
(process_nsyms_a + 1) * sizeof(struct process_hook_sym_a));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
new_proc = &new_mem[process_nsyms_a];
|
||||
memset(new_proc, 0, sizeof(*new_proc));
|
||||
new_proc->name = name;
|
||||
new_proc->head = head;
|
||||
new_proc->tail = tail;
|
||||
new_proc->replace_all = replace_all;
|
||||
|
||||
process_syms_a = new_mem;
|
||||
process_nsyms_a++;
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void createprocess_hook_init() {
|
||||
if (did_init) {
|
||||
return;
|
||||
}
|
||||
did_init = true;
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
InitializeCriticalSection(&createproc_lock);
|
||||
dprintf("CreateProcess: Init\n");
|
||||
}
|
||||
|
||||
|
||||
static BOOL WINAPI my_CreateProcessA(
|
||||
LPCSTR lpApplicationName,
|
||||
LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOA lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
)
|
||||
{
|
||||
for (int i = 0; i < process_nsyms_a; i++) {
|
||||
if (strncmp(process_syms_a[i].name, lpCommandLine, strlen(process_syms_a[i].name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("CreateProcess: Hooking child process %s %s\n", lpApplicationName, lpCommandLine);
|
||||
char new_cmd[MAX_PATH] = {0};
|
||||
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].head);
|
||||
|
||||
if (!process_syms_a[i].replace_all) {
|
||||
strcat_s(new_cmd, MAX_PATH, lpCommandLine);
|
||||
}
|
||||
|
||||
if (process_syms_a[i].tail != NULL) {
|
||||
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].tail);
|
||||
}
|
||||
|
||||
dprintf("CreateProcess: Replaced CreateProcessA %s\n", new_cmd);
|
||||
return next_CreateProcessA(
|
||||
lpApplicationName,
|
||||
new_cmd,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
||||
return next_CreateProcessA(
|
||||
lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
||||
|
||||
BOOL my_CreateProcessW(
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation)
|
||||
{
|
||||
return next_CreateProcessW(
|
||||
lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all);
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all);
|
||||
|
||||
struct process_hook_sym_w {
|
||||
const wchar_t *name;
|
||||
const wchar_t *head;
|
||||
const wchar_t *tail;
|
||||
bool replace_all;
|
||||
};
|
||||
|
||||
struct process_hook_sym_a {
|
||||
const char *name;
|
||||
const char *head;
|
||||
const char *tail;
|
||||
bool replace_all;
|
||||
};
|
|
@ -1,71 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HCURSOR my_SetCursor(HCURSOR hCursor);
|
||||
static HCURSOR (*next_SetCursor)(HCURSOR hCursor);
|
||||
static BOOL my_SetCursorPos(int x, int y);
|
||||
static BOOL my_SetPhysicalCursorPos(int x, int y);
|
||||
static int my_ShowCursor(BOOL bShow);
|
||||
|
||||
static const struct hook_symbol cursor_syms[] = {
|
||||
{
|
||||
.name = "SetCursor",
|
||||
.patch = my_SetCursor,
|
||||
.link = (void **) &next_SetCursor
|
||||
},/*{
|
||||
.name = "SetCursorPos",
|
||||
.patch = my_SetCursorPos,
|
||||
},*/ {
|
||||
.name = "SetPhysicalCursorPos",
|
||||
.patch = my_SetPhysicalCursorPos
|
||||
}, {
|
||||
.name = "ShowCursor",
|
||||
.patch = my_ShowCursor
|
||||
}
|
||||
};
|
||||
|
||||
void cursor_hook_init()
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"user32.dll",
|
||||
cursor_syms,
|
||||
_countof(cursor_syms));
|
||||
|
||||
dprintf("Cursor: Init\n");
|
||||
}
|
||||
|
||||
static BOOL my_SetCursorPos(int x, int y)
|
||||
{
|
||||
dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static BOOL my_SetPhysicalCursorPos(int x, int y)
|
||||
{
|
||||
dprintf("my_SetPhysicalCursorPos Hit! x %d y %d\n", x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int my_ShowCursor(BOOL bShow)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HCURSOR my_SetCursor(HCURSOR hCursor)
|
||||
{
|
||||
HCURSOR fake_cursor;
|
||||
|
||||
if ( hCursor )
|
||||
return next_SetCursor(hCursor);
|
||||
fake_cursor = LoadCursorA(0, (LPCSTR)0x7F00);
|
||||
next_SetCursor(fake_cursor);
|
||||
return 0;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void cursor_hook_init();
|
|
@ -7,12 +7,8 @@ hooklib_lib = static_library(
|
|||
capnhook.get_variable('hook_dep'),
|
||||
],
|
||||
sources : [
|
||||
'cursor.c',
|
||||
'cursor.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'createprocess.c',
|
||||
'createprocess.h',
|
||||
'dll.c',
|
||||
'dll.h',
|
||||
'dns.c',
|
||||
|
@ -23,6 +19,8 @@ hooklib_lib = static_library(
|
|||
'fdshark.h',
|
||||
'path.c',
|
||||
'path.h',
|
||||
'procaddr.c',
|
||||
'procaddr.h',
|
||||
'reg.c',
|
||||
'reg.h',
|
||||
'setupapi.c',
|
||||
|
|
|
@ -97,10 +97,6 @@ static BOOL WINAPI hook_RemoveDirectoryA(const char *lpFileName);
|
|||
|
||||
static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName);
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath);
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static BOOL (WINAPI *next_CreateDirectoryA)(
|
||||
|
@ -181,10 +177,6 @@ static BOOL (WINAPI *next_RemoveDirectoryA)(const char *lpFileName);
|
|||
|
||||
static BOOL (WINAPI *next_RemoveDirectoryW)(const wchar_t *lpFileName);
|
||||
|
||||
static BOOL (WINAPI *next_PathFileExistsA)(LPCSTR pszPath);
|
||||
|
||||
static BOOL (WINAPI *next_PathFileExistsW)(LPCWSTR pszPath);
|
||||
|
||||
/* Hook table */
|
||||
|
||||
static const struct hook_symbol path_hook_syms[] = {
|
||||
|
@ -252,14 +244,6 @@ static const struct hook_symbol path_hook_syms[] = {
|
|||
.name = "RemoveDirectoryW",
|
||||
.patch = hook_RemoveDirectoryW,
|
||||
.link = (void **) &next_RemoveDirectoryW,
|
||||
}, {
|
||||
.name = "PathFileExistsA",
|
||||
.patch = hook_PathFileExistsA,
|
||||
.link = (void **) &next_PathFileExistsA,
|
||||
}, {
|
||||
.name = "PathFileExistsW",
|
||||
.patch = hook_PathFileExistsW,
|
||||
.link = (void **) &next_PathFileExistsW,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -870,39 +854,3 @@ static BOOL WINAPI hook_RemoveDirectoryW(const wchar_t *lpFileName)
|
|||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsA(LPCSTR pszPath)
|
||||
{
|
||||
char *trans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&trans, pszPath);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_PathFileExistsA(trans ? trans : pszPath);
|
||||
|
||||
free(trans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_PathFileExistsW(LPCWSTR pszPath)
|
||||
{
|
||||
wchar_t *trans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&trans, pszPath);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_PathFileExistsW(trans ? trans : pszPath);
|
||||
|
||||
free(trans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "hooklib/procaddr.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static struct proc_addr_table *proc_addr_hook_list;
|
||||
static size_t proc_addr_hook_count;
|
||||
static CRITICAL_SECTION proc_addr_hook_lock;
|
||||
static bool proc_addr_hook_initted;
|
||||
|
||||
static FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name);
|
||||
static FARPROC (WINAPI *next_GetProcAddress)(HMODULE hModule, const char *name);
|
||||
static void proc_addr_hook_init(void);
|
||||
|
||||
static const struct hook_symbol win32_hooks[] = {
|
||||
{
|
||||
.name = "GetProcAddress",
|
||||
.patch = my_GetProcAddress,
|
||||
.link = (void **) &next_GetProcAddress
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT proc_addr_table_push(
|
||||
const char *target,
|
||||
struct hook_symbol *syms,
|
||||
size_t nsyms
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
struct proc_addr_table *new_item;
|
||||
struct proc_addr_table *new_mem;
|
||||
|
||||
proc_addr_hook_init();
|
||||
|
||||
EnterCriticalSection(&proc_addr_hook_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
proc_addr_hook_list,
|
||||
(proc_addr_hook_count + 1) * sizeof(struct proc_addr_table));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
LeaveCriticalSection(&proc_addr_hook_lock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
new_item = &new_mem[proc_addr_hook_count];
|
||||
new_item->name = target;
|
||||
new_item->nsyms = nsyms;
|
||||
new_item->syms = syms;
|
||||
|
||||
proc_addr_hook_list = new_mem;
|
||||
proc_addr_hook_count++;
|
||||
hr = S_OK;
|
||||
|
||||
LeaveCriticalSection(&proc_addr_hook_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void proc_addr_hook_init(void)
|
||||
{
|
||||
if (proc_addr_hook_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("ProcAddr: Hook init\n");
|
||||
proc_addr_hook_initted = true;
|
||||
|
||||
InitializeCriticalSection(&proc_addr_hook_lock);
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
}
|
||||
|
||||
FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name)
|
||||
{
|
||||
uintptr_t ordinal = (uintptr_t) name;
|
||||
char mod_path[PATH_MAX];
|
||||
char *mod_name;
|
||||
const struct hook_symbol *sym;
|
||||
FARPROC result = next_GetProcAddress(hModule, name);
|
||||
|
||||
GetModuleFileNameA(hModule, mod_path, PATH_MAX);
|
||||
mod_name = basename(mod_path);
|
||||
|
||||
for (int i = 0; i < proc_addr_hook_count; i++) {
|
||||
|
||||
if (strcmp(proc_addr_hook_list[i].name, mod_name) == 0) {
|
||||
|
||||
for (int j = 0; j < proc_addr_hook_list[i].nsyms; j++) {
|
||||
sym = &proc_addr_hook_list[i].syms[j];
|
||||
|
||||
if (ordinal > 0xFFFF) {
|
||||
|
||||
if (strcmp(sym->name, name) == 0) {
|
||||
|
||||
dprintf("ProcAddr: Hooking %s from %s\n", name, mod_name);
|
||||
result = (FARPROC) sym->patch;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (sym->ordinal == ordinal) {
|
||||
|
||||
dprintf("ProcAddr: Hooking Ord %p from %s\n", (void *)ordinal, mod_name);
|
||||
result = (FARPROC) sym->patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
struct proc_addr_table {
|
||||
const char *name;
|
||||
size_t nsyms;
|
||||
struct hook_symbol *syms;
|
||||
};
|
||||
|
||||
HRESULT proc_addr_table_push(
|
||||
const char *target,
|
||||
struct hook_symbol *syms,
|
||||
size_t nsyms
|
||||
);
|
165
hooklib/reg.c
165
hooklib/reg.c
|
@ -7,7 +7,6 @@
|
|||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/reg.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/str.h"
|
||||
|
@ -100,29 +99,6 @@ static LSTATUS WINAPI hook_RegGetValueW(
|
|||
uint32_t *numData
|
||||
);
|
||||
|
||||
static LSTATUS WINAPI hook_RegQueryInfoKeyW(
|
||||
HKEY hKey,
|
||||
LPWSTR lpClass,
|
||||
LPDWORD lpcchClass,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys,
|
||||
LPDWORD lpcbMaxSubKeyLen,
|
||||
LPDWORD lpcbMaxClassLen,
|
||||
LPDWORD lpcValues,
|
||||
LPDWORD lpcbMaxValueNameLen,
|
||||
LPDWORD lpcbMaxValueLen,
|
||||
LPDWORD lpcbSecurityDescriptor,
|
||||
PFILETIME lpftLastWriteTime);
|
||||
|
||||
static LSTATUS WINAPI hook_RegEnumValueW(
|
||||
HKEY hkey,
|
||||
DWORD dwIndex,
|
||||
LPWSTR lpValueName,
|
||||
LPDWORD lpcchValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData);
|
||||
/* Link pointers */
|
||||
|
||||
static LSTATUS (WINAPI *next_RegOpenKeyExW)(
|
||||
|
@ -179,30 +155,6 @@ static LSTATUS (WINAPI *next_RegGetValueW)(
|
|||
uint32_t *numData
|
||||
);
|
||||
|
||||
static LSTATUS (WINAPI *next_RegQueryInfoKeyW)(
|
||||
HKEY hKey,
|
||||
LPWSTR lpClass,
|
||||
LPDWORD lpcchClass,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys,
|
||||
LPDWORD lpcbMaxSubKeyLen,
|
||||
LPDWORD lpcbMaxClassLen,
|
||||
LPDWORD lpcValues,
|
||||
LPDWORD lpcbMaxValueNameLen,
|
||||
LPDWORD lpcbMaxValueLen,
|
||||
LPDWORD lpcbSecurityDescriptor,
|
||||
PFILETIME lpftLastWriteTime);
|
||||
|
||||
static LSTATUS (WINAPI *next_RegEnumValueW)(
|
||||
HKEY hkey,
|
||||
DWORD dwIndex,
|
||||
LPWSTR lpValueName,
|
||||
LPDWORD lpcchValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData);
|
||||
|
||||
static const struct hook_symbol reg_hook_syms[] = {
|
||||
{
|
||||
.name = "RegOpenKeyExW",
|
||||
|
@ -232,14 +184,6 @@ static const struct hook_symbol reg_hook_syms[] = {
|
|||
.name = "RegGetValueW",
|
||||
.patch = hook_RegGetValueW,
|
||||
.link = (void **) &next_RegGetValueW,
|
||||
}, {
|
||||
.name = "RegQueryInfoKeyW",
|
||||
.patch = hook_RegQueryInfoKeyW,
|
||||
.link = (void **) &next_RegQueryInfoKeyW,
|
||||
}, {
|
||||
.name = "RegEnumValueW",
|
||||
.patch = hook_RegEnumValueW,
|
||||
.link = (void **) &next_RegEnumValueW,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -310,24 +254,11 @@ static void reg_hook_init(void)
|
|||
InitializeCriticalSection(®_hook_lock);
|
||||
dprintf("Reg hook init\n");
|
||||
|
||||
reg_hook_insert_hooks(NULL);
|
||||
|
||||
proc_addr_table_push(
|
||||
NULL,
|
||||
"ADVAPI32.dll",
|
||||
(struct hook_symbol *) reg_hook_syms,
|
||||
_countof(reg_hook_syms));
|
||||
|
||||
}
|
||||
|
||||
void reg_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
NULL,
|
||||
"advapi32.dll",
|
||||
reg_hook_syms,
|
||||
_countof(reg_hook_syms));
|
||||
|
||||
}
|
||||
|
||||
static LRESULT reg_hook_propagate_hr(HRESULT hr)
|
||||
|
@ -400,7 +331,6 @@ static LSTATUS reg_hook_open_locked(
|
|||
/* Assume reg keys are referenced from a root key and not from some
|
||||
intermediary key */
|
||||
key = ®_hook_keys[i];
|
||||
//dprintf("Reg: %ls vs %ls\n", name, key->name);
|
||||
|
||||
if (key->root == parent && wstr_ieq(key->name, name)) {
|
||||
break;
|
||||
|
@ -891,99 +821,6 @@ static LSTATUS WINAPI hook_RegGetValueW(
|
|||
return err;
|
||||
}
|
||||
|
||||
static LSTATUS WINAPI hook_RegQueryInfoKeyW(
|
||||
HKEY hKey,
|
||||
LPWSTR lpClass,
|
||||
LPDWORD lpcchClass,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpcSubKeys,
|
||||
LPDWORD lpcbMaxSubKeyLen,
|
||||
LPDWORD lpcbMaxClassLen,
|
||||
LPDWORD lpcValues,
|
||||
LPDWORD lpcbMaxValueNameLen,
|
||||
LPDWORD lpcbMaxValueLen,
|
||||
LPDWORD lpcbSecurityDescriptor,
|
||||
PFILETIME lpftLastWriteTime)
|
||||
{
|
||||
struct reg_hook_key *key;
|
||||
LSTATUS err;
|
||||
|
||||
EnterCriticalSection(®_hook_lock);
|
||||
|
||||
key = reg_hook_match_key_locked(hKey);
|
||||
|
||||
/* Check if this is a virtualized registry key */
|
||||
|
||||
if (key == NULL) {
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
|
||||
return next_RegQueryInfoKeyW(
|
||||
hKey,
|
||||
lpClass,
|
||||
lpcchClass,
|
||||
lpReserved,
|
||||
lpcSubKeys,
|
||||
lpcbMaxSubKeyLen,
|
||||
lpcbMaxClassLen,
|
||||
lpcValues,
|
||||
lpcbMaxValueNameLen,
|
||||
lpcbMaxValueLen,
|
||||
lpcbSecurityDescriptor,
|
||||
lpftLastWriteTime);
|
||||
}
|
||||
|
||||
// This is the only one I've seen even be changed, so it's all I'm doing
|
||||
// until I see otherwise.
|
||||
*lpcValues = key->nvals;
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static LSTATUS WINAPI hook_RegEnumValueW(
|
||||
HKEY hkey,
|
||||
DWORD dwIndex,
|
||||
LPWSTR lpValueName,
|
||||
LPDWORD lpcchValueName,
|
||||
LPDWORD lpReserved,
|
||||
LPDWORD lpType,
|
||||
LPBYTE lpData,
|
||||
LPDWORD lpcbData)
|
||||
{
|
||||
struct reg_hook_key *key;
|
||||
HRESULT hr;
|
||||
LSTATUS err;
|
||||
|
||||
EnterCriticalSection(®_hook_lock);
|
||||
|
||||
key = reg_hook_match_key_locked(hkey);
|
||||
|
||||
/* Check if this is a virtualized registry key */
|
||||
|
||||
if (key == NULL) {
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
|
||||
return next_RegEnumValueW(
|
||||
hkey,
|
||||
dwIndex,
|
||||
lpValueName,
|
||||
lpcchValueName,
|
||||
lpReserved,
|
||||
lpType,
|
||||
lpData,
|
||||
lpcbData);
|
||||
}
|
||||
|
||||
if (dwIndex >= key->nvals) {
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
return ERROR_NO_MORE_ITEMS; // Pretty sure this is what it actually returns here?
|
||||
}
|
||||
|
||||
wcscpy_s(lpValueName, *lpcchValueName, key->vals[dwIndex].name);
|
||||
*lpcchValueName = wcslen(key->vals[dwIndex].name);
|
||||
LeaveCriticalSection(®_hook_lock);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
HRESULT reg_hook_read_bin(
|
||||
void *bytes,
|
||||
uint32_t *nbytes,
|
||||
|
|
|
@ -12,8 +12,6 @@ struct reg_hook_val {
|
|||
uint32_t type;
|
||||
};
|
||||
|
||||
void reg_hook_insert_hooks(HMODULE target);
|
||||
|
||||
HRESULT reg_hook_push_key(
|
||||
HKEY root,
|
||||
const wchar_t *name,
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "gfxhook/config.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "mai2hook/config.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
void mai2_dll_config_load(
|
||||
struct mai2_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"mai2io",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void touch_config_load(
|
||||
struct touch_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void led_config_load(
|
||||
struct led_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"led", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void mai2_hook_config_load(
|
||||
struct mai2_hook_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
platform_config_load(&cfg->platform, filename);
|
||||
aime_config_load(&cfg->aime, filename);
|
||||
dvd_config_load(&cfg->dvd, filename);
|
||||
io4_config_load(&cfg->io4, filename);
|
||||
gfx_config_load(&cfg->gfx, filename);
|
||||
mai2_dll_config_load(&cfg->dll, filename);
|
||||
touch_config_load(&cfg->touch, filename);
|
||||
led_config_load(&cfg->led, filename);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "board/config.h"
|
||||
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "mai2hook/mai2-dll.h"
|
||||
#include "mai2hook/touch.h"
|
||||
#include "mai2hook/led.h"
|
||||
|
||||
#include "platform/config.h"
|
||||
|
||||
struct mai2_hook_config {
|
||||
struct platform_config platform;
|
||||
struct aime_config aime;
|
||||
struct dvd_config dvd;
|
||||
struct io4_config io4;
|
||||
struct gfx_config gfx;
|
||||
struct mai2_dll_config dll;
|
||||
struct touch_config touch;
|
||||
struct led_config led;
|
||||
};
|
||||
|
||||
void mai2_dll_config_load(
|
||||
struct mai2_dll_config *cfg,
|
||||
const wchar_t *filename);
|
||||
|
||||
void mai2_hook_config_load(
|
||||
struct mai2_hook_config *cfg,
|
||||
const wchar_t *filename);
|
|
@ -1,148 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/vfd.h"
|
||||
|
||||
#include "gfxhook/d3d9.h"
|
||||
#include "gfxhook/d3d11.h"
|
||||
#include "gfxhook/dxgi.h"
|
||||
#include "gfxhook/gfx.h"
|
||||
|
||||
#include "hook/process.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/spike.h"
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/reg.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "hooklib/serial.h"
|
||||
|
||||
#include "mai2hook/config.h"
|
||||
#include "mai2hook/io4.h"
|
||||
#include "mai2hook/mai2-dll.h"
|
||||
#include "mai2hook/unity.h"
|
||||
#include "mai2hook/touch.h"
|
||||
#include "mai2hook/led.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HMODULE mai2_hook_mod;
|
||||
static process_entry_t mai2_startup;
|
||||
static struct mai2_hook_config mai2_hook_cfg;
|
||||
|
||||
static DWORD CALLBACK mai2_pre_startup(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("--- Begin mai2_pre_startup ---\n");
|
||||
|
||||
/* Load config */
|
||||
|
||||
mai2_hook_config_load(&mai2_hook_cfg, L".\\segatools.ini");
|
||||
|
||||
/* Hook Win32 APIs */
|
||||
|
||||
dvd_hook_init(&mai2_hook_cfg.dvd, mai2_hook_mod);
|
||||
gfx_hook_init(&mai2_hook_cfg.gfx);
|
||||
gfx_d3d9_hook_init(&mai2_hook_cfg.gfx, mai2_hook_mod);
|
||||
gfx_d3d11_hook_init(&mai2_hook_cfg.gfx, mai2_hook_mod);
|
||||
gfx_dxgi_hook_init(&mai2_hook_cfg.gfx, mai2_hook_mod);
|
||||
serial_hook_init();
|
||||
|
||||
/* Initialize emulation hooks */
|
||||
|
||||
hr = platform_hook_init(
|
||||
&mai2_hook_cfg.platform,
|
||||
"SDEZ",
|
||||
"ACA1",
|
||||
mai2_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = sg_reader_hook_init(&mai2_hook_cfg.aime, 1, mai2_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = vfd_hook_init(2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mai2_dll_init(&mai2_hook_cfg.dll, mai2_hook_mod);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = mai2_io4_hook_init(&mai2_hook_cfg.io4);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// TODO: The handling of the fake registry COM values is extraordinarly lazy
|
||||
// and I need to make a better method for tacking fake values onto common keys
|
||||
// that multiple modules may try to use.
|
||||
hr = led_hook_init(&mai2_hook_cfg.led);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hr = touch_hook_init(&mai2_hook_cfg.touch);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize Unity native plugin DLL hooks
|
||||
|
||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||
hooked earlier in the `mai2hook` initialization. */
|
||||
|
||||
unity_hook_init();
|
||||
|
||||
/* Initialize debug helpers */
|
||||
|
||||
spike_hook_init(L".\\segatools.ini");
|
||||
|
||||
dprintf("--- End mai2_pre_startup ---\n");
|
||||
|
||||
/* Jump to EXE start address */
|
||||
|
||||
return mai2_startup();
|
||||
|
||||
fail:
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (cause != DLL_PROCESS_ATTACH) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mai2_hook_mod = mod;
|
||||
|
||||
hr = process_hijack_startup(mai2_pre_startup, &mai2_startup);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
147
mai2hook/io4.c
147
mai2hook/io4.c
|
@ -1,147 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
#include "mai2hook/mai2-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
bool mai2_io_coin = false;
|
||||
uint16_t mai2_io_coins = 0;
|
||||
|
||||
static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state);
|
||||
|
||||
static const struct io4_ops mai2_io4_ops = {
|
||||
.poll = mai2_io4_poll,
|
||||
};
|
||||
|
||||
HRESULT mai2_io4_hook_init(const struct io4_config *cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(mai2_dll.init != NULL);
|
||||
|
||||
hr = io4_hook_init(cfg, &mai2_io4_ops, NULL);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mai2_dll.init();
|
||||
}
|
||||
|
||||
static HRESULT mai2_io4_poll(void *ctx, struct io4_state *state)
|
||||
{
|
||||
uint8_t opbtn = 0;
|
||||
uint8_t player1 = 0;
|
||||
uint8_t player2 = 0;
|
||||
HRESULT hr;
|
||||
|
||||
assert(mai2_dll.poll != NULL);
|
||||
|
||||
hr = mai2_dll.poll(&opbtn, &player1, &player2);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (opbtn & MAI2_IO_OPBTN_TEST) {
|
||||
state->buttons[0] |= IO4_BUTTON_TEST;
|
||||
}
|
||||
|
||||
if (opbtn & MAI2_IO_OPBTN_SERVICE) {
|
||||
state->buttons[0] |= IO4_BUTTON_SERVICE;
|
||||
}
|
||||
|
||||
if (opbtn & MAI2_IO_P1_START) {
|
||||
state->buttons[0] |= 1 << 1;
|
||||
}
|
||||
|
||||
if (opbtn & MAI2_IO_P2_START) {
|
||||
state->buttons[1] |= 1 << 4;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_1)) {
|
||||
state->buttons[0] |= 1 << 2;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_2)) {
|
||||
state->buttons[0] |= 1 << 3;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_3)) {
|
||||
state->buttons[0] |= 1 << 0;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_4)) {
|
||||
state->buttons[0] |= 1 << 15;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_5)) {
|
||||
state->buttons[0] |= 1 << 14;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_6)) {
|
||||
state->buttons[0] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_7)) {
|
||||
state->buttons[0] |= 1 << 12;
|
||||
}
|
||||
|
||||
if (!(player1 & MAI2_IO_GAMEBTN_8)) {
|
||||
state->buttons[0] |= 1 << 11;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_1)) {
|
||||
state->buttons[1] |= 1 << 2;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_2)) {
|
||||
state->buttons[1] |= 1 << 3;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_3)) {
|
||||
state->buttons[1] |= 1 << 0;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_4)) {
|
||||
state->buttons[1] |= 1 << 15;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_5)) {
|
||||
state->buttons[1] |= 1 << 14;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_6)) {
|
||||
state->buttons[1] |= 1 << 13;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_7)) {
|
||||
state->buttons[1] |= 1 << 12;
|
||||
}
|
||||
|
||||
if (!(player2 & MAI2_IO_GAMEBTN_8)) {
|
||||
state->buttons[1] |= 1 << 11;
|
||||
}
|
||||
|
||||
|
||||
if (opbtn & MAI2_IO_OPBTN_COIN) {
|
||||
if (!mai2_io_coin) {
|
||||
mai2_io_coin = true;
|
||||
mai2_io_coins++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mai2_io_coin = false;
|
||||
}
|
||||
|
||||
state->chutes[0] = 128 + 256 * mai2_io_coins;
|
||||
|
||||
return S_OK;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "board/io4.h"
|
||||
|
||||
HRESULT mai2_io4_hook_init(const struct io4_config *cfg);
|
210
mai2hook/led.c
210
mai2hook/led.c
|
@ -1,210 +0,0 @@
|
|||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hooklib/reg.h"
|
||||
#include "hooklib/uart.h"
|
||||
#include "hooklib/fdshark.h"
|
||||
|
||||
#include "mai2hook/led.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT read_fake_com0(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT read_fake_com1(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT read_fake_com2(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT led_handle_irp(struct irp *irp);
|
||||
static HRESULT led0_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT led1_handle_irp_locked(struct irp *irp);
|
||||
|
||||
static CRITICAL_SECTION led0_lock;
|
||||
static struct uart led0_uart;
|
||||
static uint8_t led0_written_bytes[520];
|
||||
static uint8_t led0_readable_bytes[520];
|
||||
|
||||
static CRITICAL_SECTION led1_lock;
|
||||
static struct uart led1_uart;
|
||||
static uint8_t led1_written_bytes[520];
|
||||
static uint8_t led1_readable_bytes[520];
|
||||
|
||||
static const struct reg_hook_val fake_com_keys[] = {
|
||||
{
|
||||
.name = L"\\Device\\RealTouchBoard0",
|
||||
.read = read_fake_com0,
|
||||
.type = REG_SZ,
|
||||
},{
|
||||
.name = L"\\Device\\RealTouchBoard1",
|
||||
.read = read_fake_com1,
|
||||
.type = REG_SZ,
|
||||
},{
|
||||
.name = L"\\Device\\RealLedBoard0",
|
||||
.read = read_fake_com2,
|
||||
.type = REG_SZ,
|
||||
},
|
||||
};
|
||||
|
||||
HRESULT led_hook_init(const struct led_config *cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
dprintf("Mai2 LED: Init\n");
|
||||
InitializeCriticalSection(&led0_lock);
|
||||
InitializeCriticalSection(&led1_lock);
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"HARDWARE\\DEVICEMAP\\SERIALCOMM",
|
||||
fake_com_keys,
|
||||
_countof(fake_com_keys));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
uart_init(&led0_uart, 21);
|
||||
led0_uart.written.bytes = led0_written_bytes;
|
||||
led0_uart.written.nbytes = sizeof(led0_written_bytes);
|
||||
led0_uart.readable.bytes = led0_readable_bytes;
|
||||
led0_uart.readable.nbytes = sizeof(led0_readable_bytes);
|
||||
|
||||
uart_init(&led1_uart, 23);
|
||||
led1_uart.written.bytes = led1_written_bytes;
|
||||
led1_uart.written.nbytes = sizeof(led1_written_bytes);
|
||||
led1_uart.readable.bytes = led1_readable_bytes;
|
||||
led1_uart.readable.nbytes = sizeof(led1_readable_bytes);
|
||||
|
||||
return iohook_push_handler(led_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT read_fake_com0(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
//dprintf("Mai2 Touch: Read COM3 reg val\n");
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"COM3");
|
||||
}
|
||||
|
||||
static HRESULT read_fake_com1(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
//dprintf("Mai2 Touch: Read COM4 reg val\n");
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"COM4");
|
||||
}
|
||||
|
||||
static HRESULT read_fake_com2(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
//dprintf("Mai2 LED: Read COM20 reg val\n");
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"COM20");
|
||||
}
|
||||
|
||||
static HRESULT led_handle_irp(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(irp != NULL);
|
||||
|
||||
if (uart_match_irp(&led0_uart, irp)) {
|
||||
EnterCriticalSection(&led0_lock);
|
||||
hr = led0_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&led0_lock);
|
||||
}
|
||||
else if (uart_match_irp(&led1_uart, irp)) {
|
||||
EnterCriticalSection(&led1_lock);
|
||||
hr = led1_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&led1_lock);
|
||||
}
|
||||
else {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
static HRESULT led0_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Mai2 led0: Starting backend\n");
|
||||
//hr = mai2_dll.led_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 led: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&led0_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("TX0 Buffer:\n");
|
||||
dump_iobuf(&led0_uart.written);
|
||||
#endif
|
||||
//hr = led_frame_decode(&req, &led0_uart.written, 0);
|
||||
|
||||
if (hr != S_OK) {
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 led: Deframe error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//hr = led_req_dispatch(&req);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 led: Processing error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT led1_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Mai2 led1: Starting backend\n");
|
||||
//hr = mai2_dll.led_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 led: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&led0_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("TX0 Buffer:\n");
|
||||
dump_iobuf(&led0_uart.written);
|
||||
#endif
|
||||
//hr = led_frame_decode(&req, &led0_uart.written, 0);
|
||||
|
||||
if (hr != S_OK) {
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 led: Deframe error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//hr = led_req_dispatch(&req);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 led: Processing error: %x\n", (int) hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct led_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
HRESULT led_hook_init(const struct led_config *cfg);
|
|
@ -1,103 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mai2hook/mai2-dll.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
const struct dll_bind_sym mai2_dll_syms[] = {
|
||||
{
|
||||
.sym = "mai2_io_init",
|
||||
.off = offsetof(struct mai2_dll, init),
|
||||
}, {
|
||||
.sym = "mai2_io_poll",
|
||||
.off = offsetof(struct mai2_dll, poll),
|
||||
},
|
||||
};
|
||||
|
||||
struct mai2_dll mai2_dll;
|
||||
|
||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||
// Not much of this lends itself to being easily factored out. Also there
|
||||
// will be a lot of API-specific branching code here eventually as new API
|
||||
// versions get defined, so even though these functions all look the same
|
||||
// now this won't remain the case forever.
|
||||
|
||||
HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self)
|
||||
{
|
||||
uint16_t (*get_api_version)(void);
|
||||
const struct dll_bind_sym *sym;
|
||||
HINSTANCE owned;
|
||||
HINSTANCE src;
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (cfg->path[0] != L'\0') {
|
||||
owned = LoadLibraryW(cfg->path);
|
||||
|
||||
if (owned == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("Mai2 IO: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Mai2 IO: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "mai2_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
mai2_dll.api_version = get_api_version();
|
||||
} else {
|
||||
mai2_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose mai2_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (mai2_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Mai2 IO: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
mai2_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = mai2_dll_syms;
|
||||
hr = dll_bind(&mai2_dll, src, &sym, _countof(mai2_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Mai2 IO: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mai2io/mai2io.h"
|
||||
|
||||
struct mai2_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*poll)(uint8_t *opbtn, uint8_t *p1, uint8_t *p2);
|
||||
};
|
||||
|
||||
struct mai2_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
extern struct mai2_dll mai2_dll;
|
||||
|
||||
HRESULT mai2_dll_init(const struct mai2_dll_config *cfg, HINSTANCE self);
|
|
@ -1,22 +0,0 @@
|
|||
LIBRARY mai2hook
|
||||
|
||||
EXPORTS
|
||||
CreateDXGIFactory
|
||||
CreateDXGIFactory1
|
||||
CreateDXGIFactory2
|
||||
D3D11CreateDevice
|
||||
D3D11CreateDeviceAndSwapChain
|
||||
Direct3DCreate9
|
||||
aime_io_get_api_version
|
||||
aime_io_init
|
||||
aime_io_led_set_color
|
||||
aime_io_nfc_get_aime_id
|
||||
aime_io_nfc_get_felica_id
|
||||
aime_io_nfc_poll
|
||||
amDllVideoClose @2
|
||||
amDllVideoGetVBiosVersion @4
|
||||
amDllVideoOpen @1
|
||||
amDllVideoSetResolution @3
|
||||
mai2_io_get_api_version
|
||||
mai2_io_init
|
||||
mai2_io_poll
|
|
@ -1,37 +0,0 @@
|
|||
shared_library(
|
||||
'mai2hook',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'mai2hook.def',
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep'),
|
||||
xinput_lib,
|
||||
],
|
||||
link_with : [
|
||||
aimeio_lib,
|
||||
board_lib,
|
||||
gfxhook_lib,
|
||||
hooklib_lib,
|
||||
mai2io_lib,
|
||||
platform_lib,
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
'config.c',
|
||||
'config.h',
|
||||
'dllmain.c',
|
||||
'led.c',
|
||||
'led.h',
|
||||
'io4.c',
|
||||
'io4.h',
|
||||
'mai2-dll.c',
|
||||
'mai2-dll.h',
|
||||
'touch.c',
|
||||
'touch.h',
|
||||
'unity.h',
|
||||
'unity.c',
|
||||
],
|
||||
)
|
237
mai2hook/touch.c
237
mai2hook/touch.c
|
@ -1,237 +0,0 @@
|
|||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hooklib/reg.h"
|
||||
#include "hooklib/uart.h"
|
||||
#include "hooklib/fdshark.h"
|
||||
|
||||
#include "mai2hook/touch.h"
|
||||
#include "mai2hook/mai2-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
const char CMD_START = '{';
|
||||
const char CMD_END = '}';
|
||||
const char RESP_START = '(';
|
||||
const char RESP_END = ')';
|
||||
const char BLANK = '@';
|
||||
|
||||
// Commands with parameters
|
||||
const char CMD_RATIO[1] = "r";
|
||||
const char CMD_SENS[1] = "k";
|
||||
const char CMD_SENS_CHECK[2] = "th";
|
||||
|
||||
// Commands that never change
|
||||
const char CMD_RESET[7] = "{RSET}"; // Reset board to default state
|
||||
const char CMD_STAT[7] = "{STAT}"; // Start sending touch state
|
||||
const char CMD_HALT[7] = "{HALT}"; // Stop sending touch state
|
||||
const char RSP_ANY[6] = "(0000)"; // Stop sending touch state
|
||||
|
||||
static HRESULT read_fake_com0(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT read_fake_com1(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT read_fake_com2(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT touch_handle_irp(struct irp *irp);
|
||||
static HRESULT touch0_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT touch1_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT touch_cmd_dispatch(char* cmd, struct iobuf *dest, uint8_t side);
|
||||
|
||||
bool touch0_auto = false;
|
||||
bool touch1_auto = false;
|
||||
|
||||
static CRITICAL_SECTION touch0_lock;
|
||||
static struct uart touch0_uart;
|
||||
static uint8_t touch0_written_bytes[520];
|
||||
static uint8_t touch0_readable_bytes[520];
|
||||
|
||||
static CRITICAL_SECTION touch1_lock;
|
||||
static struct uart touch1_uart;
|
||||
static uint8_t touch1_written_bytes[520];
|
||||
static uint8_t touch1_readable_bytes[520];
|
||||
|
||||
static const struct reg_hook_val fake_com_keys[] = {
|
||||
{
|
||||
.name = L"\\Device\\RealTouchBoard0",
|
||||
.read = read_fake_com0,
|
||||
.type = REG_SZ,
|
||||
},{
|
||||
.name = L"\\Device\\RealTouchBoard1",
|
||||
.read = read_fake_com1,
|
||||
.type = REG_SZ,
|
||||
},{
|
||||
.name = L"\\Device\\RealLedBoard0",
|
||||
.read = read_fake_com2,
|
||||
.type = REG_SZ,
|
||||
},
|
||||
};
|
||||
|
||||
HRESULT touch_hook_init(const struct touch_config *cfg)
|
||||
{
|
||||
HRESULT hr;
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
dprintf("Mai2 touch: Init\n");
|
||||
InitializeCriticalSection(&touch0_lock);
|
||||
InitializeCriticalSection(&touch1_lock);
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"HARDWARE\\DEVICEMAP\\SERIALCOMM",
|
||||
fake_com_keys,
|
||||
_countof(fake_com_keys));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
uart_init(&touch0_uart, 3);
|
||||
touch0_uart.written.bytes = touch0_written_bytes;
|
||||
touch0_uart.written.nbytes = sizeof(touch0_written_bytes);
|
||||
touch0_uart.readable.bytes = touch0_readable_bytes;
|
||||
touch0_uart.readable.nbytes = sizeof(touch0_readable_bytes);
|
||||
|
||||
uart_init(&touch1_uart, 4);
|
||||
touch1_uart.written.bytes = touch1_written_bytes;
|
||||
touch1_uart.written.nbytes = sizeof(touch1_written_bytes);
|
||||
touch1_uart.readable.bytes = touch1_readable_bytes;
|
||||
touch1_uart.readable.nbytes = sizeof(touch1_readable_bytes);
|
||||
|
||||
return iohook_push_handler(touch_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT read_fake_com0(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
// dprintf("Mai2 Touch: Read COM3 reg val\n");
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"COM3");
|
||||
}
|
||||
|
||||
static HRESULT read_fake_com1(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
// dprintf("Mai2 Touch: Read COM4 reg val\n");
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"COM4");
|
||||
}
|
||||
|
||||
static HRESULT read_fake_com2(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
// dprintf("Mai2 LED: Read COM20 reg val\n");
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"COM20");
|
||||
}
|
||||
|
||||
static HRESULT touch_handle_irp(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(irp != NULL);
|
||||
|
||||
if (uart_match_irp(&touch0_uart, irp)) {
|
||||
EnterCriticalSection(&touch0_lock);
|
||||
hr = touch0_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&touch0_lock);
|
||||
}
|
||||
else if (uart_match_irp(&touch1_uart, irp)) {
|
||||
EnterCriticalSection(&touch1_lock);
|
||||
hr = touch1_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&touch1_lock);
|
||||
}
|
||||
else {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT touch0_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Mai2 touch0: Starting backend\n");
|
||||
//hr = mai2_dll.touch_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 touch0: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&touch0_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("touch0 Buffer:\n");
|
||||
dump_iobuf(&touch0_uart.written);
|
||||
#endif
|
||||
hr = touch_cmd_dispatch((char*)touch0_uart.written.bytes, &touch0_uart.readable, 0);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 touch0: Dispatch failed %08lX\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
touch0_uart.written.pos = 0;
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT touch1_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
dprintf("Mai2 touch1: Starting backend\n");
|
||||
//hr = mai2_dll.touch_init();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 touch1: Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&touch1_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
#if 0
|
||||
dprintf("touch1 Buffer:\n");
|
||||
dump_iobuf(&touch0_uart.written);
|
||||
#endif
|
||||
|
||||
hr = touch_cmd_dispatch((char*)touch1_uart.written.bytes, &touch1_uart.readable, 1);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Mai2 touch1: Dispatch failed %08lX\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
touch1_uart.written.pos = 0;
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT touch_cmd_dispatch(char* cmd, struct iobuf *dest, uint8_t side)
|
||||
{
|
||||
if (!strcmp(cmd, CMD_RESET)) {
|
||||
dprintf("Mai2 touch%d: Reset\n", side);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
else if (!strcmp(cmd, CMD_HALT)) {
|
||||
dprintf("Mai2 touch%d: Halt\n", side);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
dprintf("Mai2 touch%d: Unknow %s\n", side, cmd);
|
||||
return S_OK;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct touch_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
HRESULT touch_hook_init(const struct touch_config *cfg);
|
116
mai2hook/unity.c
116
mai2hook/unity.c
|
@ -1,116 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/reg.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "hooklib/serial.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target);
|
||||
|
||||
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
|
||||
static HMODULE WINAPI my_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags);
|
||||
static HMODULE (WINAPI *next_LoadLibraryExW)(const wchar_t *name, HANDLE hFile, DWORD dwFlags);
|
||||
|
||||
static const struct hook_symbol unity_kernel32_syms[] = {
|
||||
{
|
||||
.name = "LoadLibraryW",
|
||||
.patch = my_LoadLibraryW,
|
||||
.link = (void **) &next_LoadLibraryW,
|
||||
},{
|
||||
.name = "LoadLibraryExW",
|
||||
.patch = my_LoadLibraryExW,
|
||||
.link = (void **) &next_LoadLibraryExW,
|
||||
}
|
||||
};
|
||||
|
||||
static const wchar_t *target_modules[] = {
|
||||
L"mono-2.0-bdwgc.dll",
|
||||
L"cri_ware_unity.dll",
|
||||
};
|
||||
|
||||
static const size_t target_modules_len = _countof(target_modules);
|
||||
|
||||
void unity_hook_init(void)
|
||||
{
|
||||
dll_hook_insert_hooks(NULL);
|
||||
}
|
||||
|
||||
static void dll_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"kernel32.dll",
|
||||
unity_kernel32_syms,
|
||||
_countof(unity_kernel32_syms));
|
||||
}
|
||||
|
||||
static HMODULE WINAPI my_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags)
|
||||
{
|
||||
//dprintf("Unity: LoadLibraryExW %ls\n", name);
|
||||
return my_LoadLibraryW(name);
|
||||
}
|
||||
|
||||
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
|
||||
{
|
||||
const wchar_t *name_end;
|
||||
const wchar_t *target_module;
|
||||
bool already_loaded;
|
||||
HMODULE result;
|
||||
size_t name_len;
|
||||
size_t target_module_len;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if the module is already loaded
|
||||
already_loaded = GetModuleHandleW(name) != NULL;
|
||||
|
||||
// Must call the next handler so the DLL reference count is incremented
|
||||
result = next_LoadLibraryW(name);
|
||||
|
||||
if (!already_loaded && result != NULL) {
|
||||
name_len = wcslen(name);
|
||||
|
||||
for (size_t i = 0; i < target_modules_len; i++) {
|
||||
target_module = target_modules[i];
|
||||
target_module_len = wcslen(target_module);
|
||||
|
||||
// Check if the newly loaded library is at least the length of
|
||||
// the name of the target module
|
||||
if (name_len < target_module_len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
name_end = &name[name_len - target_module_len];
|
||||
|
||||
// Check if the name of the newly loaded library is one of the
|
||||
// modules the path hooks should be injected into
|
||||
if (_wcsicmp(name_end, target_module) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("Unity: Loaded %S\n", target_module);
|
||||
|
||||
dll_hook_insert_hooks(result);
|
||||
path_hook_insert_hooks(result);
|
||||
reg_hook_insert_hooks(result);
|
||||
proc_addr_insert_hooks(result);
|
||||
serial_hook_apply_hooks(result);
|
||||
iohook_apply_hooks(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void unity_hook_init(void);
|
|
@ -1,46 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mai2io/config.h"
|
||||
|
||||
static const int mai2_io_1p_default[] = {'W', 'E', 'D', 'C', 'X', 'Z', 'A', 'Q'};
|
||||
static const int mai2_io_2p_default[] = {0x68, 0x69, 0x66, 0x63, 0x62, 0x61, 0x64, 0x67};
|
||||
|
||||
void mai2_io_config_load(
|
||||
struct mai2_io_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
wchar_t key[240];
|
||||
int i;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_DELETE, filename);
|
||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_END, filename);
|
||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_INSERT, filename);
|
||||
cfg->vk_p1_start = GetPrivateProfileIntW(L"io4", L"p1_start", '1', filename);
|
||||
cfg->vk_p2_start = GetPrivateProfileIntW(L"io4", L"p2_start", '2', filename);
|
||||
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
swprintf_s(key, _countof(key), L"1p_btn%i", i + 1);
|
||||
cfg->vk_p1_btn[i] = GetPrivateProfileIntW(
|
||||
L"button",
|
||||
key,
|
||||
mai2_io_1p_default[i],
|
||||
filename);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
swprintf_s(key, _countof(key), L"2p_btn%i", i + 1);
|
||||
cfg->vk_p2_btn[i] = GetPrivateProfileIntW(
|
||||
L"button",
|
||||
key,
|
||||
mai2_io_2p_default[i],
|
||||
filename);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mai2_io_config {
|
||||
uint8_t vk_test;
|
||||
uint8_t vk_service;
|
||||
uint8_t vk_coin;
|
||||
uint8_t vk_p1_start;
|
||||
uint8_t vk_p2_start;
|
||||
uint8_t vk_p1_btn[8];
|
||||
uint8_t vk_p2_btn[8];
|
||||
};
|
||||
|
||||
void mai2_io_config_load(
|
||||
struct mai2_io_config *cfg,
|
||||
const wchar_t *filename);
|
|
@ -1,83 +0,0 @@
|
|||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mai2io/mai2io.h"
|
||||
#include "mai2io/config.h"
|
||||
|
||||
static struct mai2_io_config mai2_io_cfg;
|
||||
|
||||
uint16_t mai2_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT mai2_io_init(void)
|
||||
{
|
||||
mai2_io_config_load(&mai2_io_cfg, L".\\segatools.ini");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT mai2_io_poll(uint8_t *opbtn, uint8_t *player1, uint8_t *player2)
|
||||
{
|
||||
uint8_t opts = 0;
|
||||
uint8_t p1 = 0;
|
||||
uint8_t p2 = 0;
|
||||
|
||||
if (GetAsyncKeyState(mai2_io_cfg.vk_test) & 0x8000) {
|
||||
opts |= MAI2_IO_OPBTN_TEST;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_service) & 0x8000) {
|
||||
opts |= MAI2_IO_OPBTN_SERVICE;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_coin) & 0x8000) {
|
||||
opts |= MAI2_IO_OPBTN_COIN;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_start) & 0x8000) {
|
||||
opts |= MAI2_IO_P1_START;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_start) & 0x8000) {
|
||||
opts |= MAI2_IO_P2_START;
|
||||
}
|
||||
|
||||
*opbtn = opts;
|
||||
|
||||
if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[0]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_1;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[1]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_2;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[2]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_3;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[3]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_4;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[4]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_5;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[5]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_6;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[6]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_7;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p1_btn[7]) & 0x8000) {
|
||||
p1 |= MAI2_IO_GAMEBTN_8;
|
||||
}
|
||||
|
||||
*player1 = p1;
|
||||
|
||||
if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[0]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_1;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[1]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_2;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[2]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_3;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[3]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_4;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[4]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_5;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[5]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_6;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[6]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_7;
|
||||
}if (GetAsyncKeyState(mai2_io_cfg.vk_p2_btn[7]) & 0x8000) {
|
||||
p2 |= MAI2_IO_GAMEBTN_8;
|
||||
}
|
||||
|
||||
*player2 = p2;
|
||||
return S_OK;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
MAI2_IO_OPBTN_TEST = 0x01,
|
||||
MAI2_IO_OPBTN_SERVICE = 0x02,
|
||||
MAI2_IO_OPBTN_COIN = 0x04,
|
||||
MAI2_IO_P1_START = 0x08,
|
||||
MAI2_IO_P2_START = 0x10,
|
||||
};
|
||||
|
||||
enum {
|
||||
MAI2_IO_GAMEBTN_1 = 0x01,
|
||||
MAI2_IO_GAMEBTN_2 = 0x02,
|
||||
MAI2_IO_GAMEBTN_3 = 0x04,
|
||||
MAI2_IO_GAMEBTN_4 = 0x08,
|
||||
MAI2_IO_GAMEBTN_5 = 0x10,
|
||||
MAI2_IO_GAMEBTN_6 = 0x20,
|
||||
MAI2_IO_GAMEBTN_7 = 0x40,
|
||||
MAI2_IO_GAMEBTN_8 = 0x80,
|
||||
};
|
||||
|
||||
/* Get the version of the Mai2 IO API that this DLL supports. This
|
||||
function should return a positive 16-bit integer, where the high byte is
|
||||
the major version and the low byte is the minor version (as defined by the
|
||||
Semantic Versioning standard).
|
||||
|
||||
The latest API version as of this writing is 0x0100. */
|
||||
|
||||
uint16_t mai2_io_get_api_version(void);
|
||||
|
||||
/* Initialize the IO DLL. This is the second function that will be called on
|
||||
your DLL, after mai2_io_get_api_version.
|
||||
|
||||
All subsequent calls to this API may originate from arbitrary threads.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT mai2_io_init(void);
|
||||
|
||||
/* Send any queued outputs (of which there are currently none, though this may
|
||||
change in subsequent API versions) and retrieve any new inputs.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
HRESULT mai2_io_poll(uint8_t *opbtn, uint8_t *player1, uint8_t *player2);
|
|
@ -1,16 +0,0 @@
|
|||
mai2io_lib = static_library(
|
||||
'mai2io',
|
||||
name_prefix : '',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
c_pch : '../precompiled.h',
|
||||
dependencies : [
|
||||
xinput_lib,
|
||||
],
|
||||
sources : [
|
||||
'mai2io.c',
|
||||
'mai2io.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
],
|
||||
)
|
|
@ -13,7 +13,6 @@ add_project_arguments(
|
|||
'-DWIN32_LEAN_AND_MEAN',
|
||||
'-D_WIN32_WINNT=_WIN32_WINNT_WIN7',
|
||||
'-DMINGW_HAS_SECURE_API=1',
|
||||
'-Wno-unused',
|
||||
language: 'c',
|
||||
)
|
||||
|
||||
|
@ -61,7 +60,6 @@ subdir('idzio')
|
|||
subdir('mu3io')
|
||||
subdir('mercuryio')
|
||||
subdir('cxbio')
|
||||
subdir('mai2io')
|
||||
|
||||
subdir('chunihook')
|
||||
subdir('divahook')
|
||||
|
@ -71,4 +69,3 @@ subdir('minihook')
|
|||
subdir('mu3hook')
|
||||
subdir('mercuryhook')
|
||||
subdir('cxbhook')
|
||||
subdir('mai2hook')
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "platform/clock.h"
|
||||
#include "platform/config.h"
|
||||
#include "platform/dns.h"
|
||||
#include "platform/epay.h"
|
||||
#include "platform/hwmon.h"
|
||||
#include "platform/hwreset.h"
|
||||
#include "platform/misc.h"
|
||||
|
@ -31,7 +30,6 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
|||
amvideo_config_load(&cfg->amvideo, filename);
|
||||
clock_config_load(&cfg->clock, filename);
|
||||
dns_config_load(&cfg->dns, filename);
|
||||
epay_config_load(&cfg->epay, filename);
|
||||
hwmon_config_load(&cfg->hwmon, filename);
|
||||
hwreset_config_load(&cfg->hwreset, filename);
|
||||
misc_config_load(&cfg->misc, filename);
|
||||
|
@ -319,10 +317,3 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename)
|
|||
filename);
|
||||
}
|
||||
|
||||
void epay_config_load(struct epay_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"epay", L"enable", 1, filename);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "platform/amvideo.h"
|
||||
#include "platform/clock.h"
|
||||
#include "platform/dns.h"
|
||||
#include "platform/epay.h"
|
||||
#include "platform/hwmon.h"
|
||||
#include "platform/hwreset.h"
|
||||
#include "platform/misc.h"
|
||||
|
@ -26,7 +25,6 @@ void platform_config_load(
|
|||
void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename);
|
||||
void clock_config_load(struct clock_config *cfg, const wchar_t *filename);
|
||||
void dns_config_load(struct dns_config *cfg, const wchar_t *filename);
|
||||
void epay_config_load(struct epay_config *cfg, const wchar_t *filename);
|
||||
void hwmon_config_load(struct hwmon_config *cfg, const wchar_t *filename);
|
||||
void hwreset_config_load(struct hwreset_config *cfg, const wchar_t *filename);
|
||||
void misc_config_load(struct misc_config *cfg, const wchar_t *filename);
|
||||
|
|
|
@ -64,19 +64,6 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg)
|
|||
return hr;
|
||||
}
|
||||
|
||||
// Epay urls
|
||||
hr = dns_hook_push(L"api-aime.am-all.net", cfg->startup);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = dns_hook_push(L"tasms-api-basis.thincacloud.com", cfg->startup);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// if your ISP resolves bad domains, it will kill the network. These 2
|
||||
// *cannot* resolve
|
||||
|
||||
|
|
335
platform/epay.c
335
platform/epay.c
|
@ -1,335 +0,0 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/reg.h"
|
||||
|
||||
#include "platform/epay.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HRESULT misc_read_thinca_adapter(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_ca_loc(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_ca_client_loc(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_network_timeout(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_pattern0(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_network_timeout0(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_pattern1(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_network_timeout1(void *bytes, uint32_t *nbytes);
|
||||
|
||||
static uint64_t thinca_initialize(struct thinca_impl * self, uint64_t val);
|
||||
static uint64_t thinca_dispose(struct thinca_impl * self);
|
||||
static uint64_t thinca_set_resource(struct thinca_impl * self, char * res);
|
||||
static uint64_t thinca_set_pay_log(struct thinca_impl * self, uint64_t val, char * log, uint64_t val2, const char * size_lim);
|
||||
static uint64_t thinca_set_client_log(struct thinca_impl * self, uint64_t val, char * log);
|
||||
static uint64_t thinca_set_client_cfg(struct thinca_impl * self, char * log, uint64_t val);
|
||||
static uint64_t thinca_set_goods_code(struct thinca_impl * self, char * code);
|
||||
static uint64_t thinca_set_evt_handler(struct thinca_impl * self, void* handler);
|
||||
static uint64_t thinca_set_cert(struct thinca_impl * self, char * cert, uint64_t val);
|
||||
static uint64_t thinca_set_serial(struct thinca_impl * self, char * cert);
|
||||
static uint64_t thinca_check_deal(struct thinca_impl * self, void* deal);
|
||||
static uint64_t thinca_cancel(struct thinca_impl * self);
|
||||
static uint64_t thinca_select(struct thinca_impl * self);
|
||||
static uint64_t thinca_unk(struct thinca_impl * self, uint64_t val);
|
||||
static void thinca_unk8(struct thinca_impl * self);
|
||||
|
||||
static uint64_t my_ThincaPaymentGetVersion();
|
||||
static uint64_t (*next_ThincaPaymentGetVersion)();
|
||||
|
||||
static struct thinca_main* my_ThincaPaymentGetInstance(uint64_t ver);
|
||||
static struct thinca_main* (*next_ThincaPaymentGetInstance)(uint64_t ver);
|
||||
|
||||
static struct thinca_main* thinca_stub;
|
||||
|
||||
static const struct reg_hook_val epay_adapter_keys[] = {
|
||||
{
|
||||
.name = L"TfpsAimeRwAdapter",
|
||||
.read = misc_read_thinca_adapter,
|
||||
.type = REG_SZ,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct reg_hook_val epay_tcap_keys[] = {
|
||||
{
|
||||
.name = L"CaLocation",
|
||||
.read = misc_read_ca_loc,
|
||||
.type = REG_SZ,
|
||||
},
|
||||
{
|
||||
.name = L"ThincaTcapClientPath",
|
||||
.read = misc_read_ca_client_loc,
|
||||
.type = REG_SZ,
|
||||
},
|
||||
{
|
||||
.name = L"ClientNetworkTimeout",
|
||||
.read = misc_read_network_timeout,
|
||||
.type = REG_DWORD,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct reg_hook_val epay_tcap_url0_keys[] = {
|
||||
{
|
||||
.name = L"Pattern",
|
||||
.read = misc_read_pattern0,
|
||||
.type = REG_SZ,
|
||||
},
|
||||
{
|
||||
.name = L"ClientNetworkTimeout",
|
||||
.read = misc_read_network_timeout0,
|
||||
.type = REG_DWORD,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct reg_hook_val epay_tcap_url1_keys[] = {
|
||||
{
|
||||
.name = L"Pattern",
|
||||
.read = misc_read_pattern1,
|
||||
.type = REG_SZ,
|
||||
},
|
||||
{
|
||||
.name = L"ClientNetworkTimeout",
|
||||
.read = misc_read_network_timeout1,
|
||||
.type = REG_DWORD,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol epay_syms[] = {
|
||||
{
|
||||
.name = "ThincaPaymentGetVersion",
|
||||
.patch = my_ThincaPaymentGetVersion,
|
||||
.link = (void **) &next_ThincaPaymentGetVersion,
|
||||
.ordinal = 1,
|
||||
},
|
||||
{
|
||||
.name = "__imp_ThincaPaymentGetInstance",
|
||||
.patch = my_ThincaPaymentGetInstance,
|
||||
.link = (void **) &next_ThincaPaymentGetInstance,
|
||||
.ordinal = 2,
|
||||
},
|
||||
{
|
||||
.name = "ThincaPaymentGetInstance",
|
||||
.patch = my_ThincaPaymentGetInstance,
|
||||
.link = (void **) &next_ThincaPaymentGetInstance,
|
||||
.ordinal = 2,
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT epay_hook_init(const struct epay_config *cfg) {
|
||||
HRESULT hr;
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\TFPaymentService\\ThincaRwAdapter",
|
||||
epay_adapter_keys,
|
||||
_countof(epay_adapter_keys));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\TFPaymentService\\ThincaTcapClient",
|
||||
epay_tcap_keys,
|
||||
_countof(epay_tcap_keys));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\TFPaymentService\\ThincaTcapClient\\URL0",
|
||||
epay_tcap_url0_keys,
|
||||
_countof(epay_tcap_url0_keys));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\TFPaymentService\\ThincaTcapClient\\URL1",
|
||||
epay_tcap_url1_keys,
|
||||
_countof(epay_tcap_url1_keys));
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"ThincaPayment.dll",
|
||||
epay_syms,
|
||||
_countof(epay_syms));
|
||||
|
||||
thinca_stub = (struct thinca_main *)malloc(sizeof(struct thinca_main));
|
||||
thinca_stub->impl1 = (struct thinca_impl *)malloc(sizeof(struct thinca_impl));
|
||||
|
||||
thinca_stub->impl1->unk8 = thinca_unk8;
|
||||
thinca_stub->impl1->initialize = thinca_initialize;
|
||||
thinca_stub->impl1->dispose = thinca_dispose;
|
||||
thinca_stub->impl1->setResource = thinca_set_resource;
|
||||
thinca_stub->impl1->setThincaPaymentLog = thinca_set_pay_log;
|
||||
thinca_stub->impl1->setThincaEventInterface = thinca_set_evt_handler;
|
||||
thinca_stub->impl1->setIcasClientLog = thinca_set_client_log;
|
||||
thinca_stub->impl1->setIcasClientConfig = thinca_set_client_cfg;
|
||||
thinca_stub->impl1->setGoodsCode = thinca_set_goods_code;
|
||||
thinca_stub->impl1->setTerminalSerial = thinca_set_serial;
|
||||
thinca_stub->impl1->setClientCertificate = thinca_set_cert;
|
||||
thinca_stub->impl1->checkDeal = thinca_check_deal;
|
||||
thinca_stub->impl1->cancelRequest = thinca_cancel;
|
||||
thinca_stub->impl1->selectButton = thinca_select;
|
||||
thinca_stub->impl1->unk220 = thinca_unk;
|
||||
thinca_stub->impl1->unk228 = thinca_unk;
|
||||
|
||||
dprintf("Epay: Init\n");
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT misc_read_thinca_adapter(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"aime_rw_adapterMD.dll");
|
||||
}
|
||||
|
||||
static HRESULT misc_read_ca_loc(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"ca.pem");
|
||||
}
|
||||
|
||||
static HRESULT misc_read_ca_client_loc(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"thincatcapclient.dll");
|
||||
}
|
||||
|
||||
static HRESULT misc_read_network_timeout(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_u32(bytes, nbytes, 20000);
|
||||
}
|
||||
|
||||
static HRESULT misc_read_pattern0(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L".*\\.jsp");
|
||||
}
|
||||
|
||||
static HRESULT misc_read_network_timeout0(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_u32(bytes, nbytes, 5000);
|
||||
}
|
||||
|
||||
static HRESULT misc_read_pattern1(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L".*(closing|remove).*");
|
||||
}
|
||||
|
||||
static HRESULT misc_read_network_timeout1(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_u32(bytes, nbytes, 60000);
|
||||
}
|
||||
|
||||
static uint64_t thinca_initialize(struct thinca_impl * self, uint64_t val)
|
||||
{
|
||||
dprintf("Epay: Thinca Initialize v%I64X\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_dispose(struct thinca_impl * self)
|
||||
{
|
||||
dprintf("Epay: Thinca Dispose\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_resource(struct thinca_impl * self, char * res)
|
||||
{
|
||||
dprintf("Epay: Thinca Set Resource %s\n", res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_pay_log(struct thinca_impl * self, uint64_t val, char * log, uint64_t val2, const char * size_lim)
|
||||
{
|
||||
dprintf("Epay: Thinca Set Paylog %lld | %s | %lld | %s\n", val, log, val2, size_lim);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_client_log(struct thinca_impl * self, uint64_t val, char * log)
|
||||
{
|
||||
dprintf("Epay: Thinca Set ICAS Client log %lld | %s\n", val, log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_client_cfg(struct thinca_impl * self, char * log, uint64_t val)
|
||||
{
|
||||
dprintf("Epay: Thinca Set ICAS Client Config %s | %lld\n", log, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_goods_code(struct thinca_impl * self, char * code)
|
||||
{
|
||||
dprintf("Epay: Thinca Set Goods Code %s\n", code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_evt_handler(struct thinca_impl * self, void* handler)
|
||||
{
|
||||
dprintf("Epay: Thinca Set Event Handler %p\n", handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_cert(struct thinca_impl * self, char * cert, uint64_t val)
|
||||
{
|
||||
dprintf("Epay: Thinca Set Client Cert %s | %lld\n", cert, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_set_serial(struct thinca_impl * self, char * cert)
|
||||
{
|
||||
dprintf("Epay: Thinca Set Terminal Serial %s\n", cert);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_check_deal(struct thinca_impl * self, void* deal)
|
||||
{
|
||||
dprintf("Epay: Thinca Check Deal %p\n", deal);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_cancel(struct thinca_impl * self)
|
||||
{
|
||||
dprintf("Epay: Thinca Cancel\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_select(struct thinca_impl * self)
|
||||
{
|
||||
dprintf("Epay: Thinca Select\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t thinca_unk(struct thinca_impl * self, uint64_t val)
|
||||
{
|
||||
dprintf("Epay: Thinca Unknown 220/228 %lld\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thinca_unk8(struct thinca_impl * self)
|
||||
{
|
||||
dprintf("Epay: Thinca Unknown 8\n");
|
||||
}
|
||||
|
||||
static uint64_t my_ThincaPaymentGetVersion()
|
||||
{
|
||||
return 0x1040B00;
|
||||
}
|
||||
|
||||
static struct thinca_main* my_ThincaPaymentGetInstance(uint64_t ver)
|
||||
{
|
||||
dprintf("Epay: my_ThincaPaymentGetInstance hit!\n");
|
||||
return thinca_stub;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct epay_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
/* The functions in these structs are how clients like amdaemon interface
|
||||
* with thinca. We can simply replace these functions with our own stubs
|
||||
* to bypass errors and such. Currently this DOES NOT allow for epay, and
|
||||
* trying to do so will most likely just lead to misery. My goal isn't to
|
||||
* reimplement epay, just to give amdaemon SOMETHING so we can boot properly.
|
||||
*/
|
||||
struct thinca_impl {
|
||||
uint64_t* unk0;
|
||||
void (*unk8)(struct thinca_impl *);
|
||||
uint64_t (*initialize)(struct thinca_impl *, uint64_t);
|
||||
uint64_t (*dispose)(struct thinca_impl *);
|
||||
uint64_t (*setResource)(struct thinca_impl *, char *);
|
||||
uint64_t (*setThincaPaymentLog)(struct thinca_impl *, uint64_t, char *, uint64_t, const char *);
|
||||
uint64_t (*setIcasClientLog)(struct thinca_impl *, uint64_t, char *);
|
||||
uint64_t (*setIcasClientConfig)(struct thinca_impl *, char *, uint64_t);
|
||||
uint64_t* unk40;
|
||||
uint64_t* unk48;
|
||||
uint64_t (*setClientCertificate)(struct thinca_impl *, char *, uint64_t);
|
||||
uint64_t (*setTerminalSerial)(struct thinca_impl *, char *);
|
||||
uint64_t (*setGoodsCode)(struct thinca_impl *, char *);
|
||||
uint64_t unk68;
|
||||
uint64_t (*setThincaEventInterface)(struct thinca_impl *, void*); // probably a struct
|
||||
uint64_t unkGap78[7];
|
||||
uint64_t (*checkDeal)(struct thinca_impl *, void *); // probably a struct
|
||||
uint64_t unkGapB8[41];
|
||||
uint64_t (*cancelRequest)(struct thinca_impl *);
|
||||
uint64_t (*selectButton)(struct thinca_impl *);
|
||||
uint64_t unkGap210[2];
|
||||
uint64_t (*unk220)(struct thinca_impl *, uint64_t);
|
||||
uint64_t (*unk228)(struct thinca_impl *, uint64_t);
|
||||
};
|
||||
|
||||
/* I believe the actual struct is 0x310 bytes, so for now I'm just
|
||||
* implementing what I need and hoping the rest don't cause issues
|
||||
* later. AMDaemon seems to only care about impl1 and deal_thing,
|
||||
* at least from what I can tell
|
||||
*/
|
||||
struct thinca_main {
|
||||
struct thinca_impl* impl1;
|
||||
struct thinca_impl* impl2;
|
||||
HANDLE* mutex1;
|
||||
HANDLE* mutex2;
|
||||
HANDLE* mutex3;
|
||||
uint64_t* unk28;
|
||||
uint64_t* unk30;
|
||||
uint64_t* unk38;
|
||||
uint64_t* unk40;
|
||||
uint64_t* deal_thing;
|
||||
uint64_t filler[88];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
HRESULT epay_hook_init(const struct epay_config *cfg);
|
|
@ -16,8 +16,6 @@ platform_lib = static_library(
|
|||
'config.h',
|
||||
'dns.c',
|
||||
'dns.h',
|
||||
'epay.c',
|
||||
'epay.h',
|
||||
'hwmon.c',
|
||||
'hwmon.h',
|
||||
'hwreset.c',
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "util/dprintf.h"
|
||||
|
||||
static BOOL WINAPI misc_ExitWindowsEx(unsigned int flags, uint32_t reason);
|
||||
static int my_vsprintf(char *const buffer, const char *const format, va_list args);
|
||||
static int (*next_vsprintf)(char *const buffer, const char *const format, va_list args);
|
||||
|
||||
static HRESULT misc_read_os_version(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT misc_read_app_loader_count(void *bytes, uint32_t *nbytes);
|
||||
|
@ -31,14 +29,6 @@ static const struct hook_symbol misc_syms[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol logging_sym[] = {
|
||||
{
|
||||
.name = "vsprintf",
|
||||
.patch = my_vsprintf,
|
||||
.link = (void **) &next_vsprintf,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct reg_hook_val misc_root_keys[] = {
|
||||
{
|
||||
.name = L"OSVersion",
|
||||
|
@ -140,7 +130,6 @@ HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id)
|
|||
/* Apply function hooks */
|
||||
|
||||
hook_table_apply(NULL, "user32.dll", misc_syms, _countof(misc_syms));
|
||||
hook_table_apply(NULL, "msvcr110.dll", logging_sym, _countof(logging_sym));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -181,10 +170,3 @@ static HRESULT misc_read_platform_name(void *bytes, uint32_t *nbytes)
|
|||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"ALLS MX2.1"); // TODO: Dynamic
|
||||
}
|
||||
|
||||
static int my_vsprintf(char *const buffer, const char *const format, va_list args)
|
||||
{
|
||||
int ret = next_vsprintf(buffer, format, args);
|
||||
dprintf("%s\n", buffer);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -14,22 +14,21 @@
|
|||
#include "util/str.h"
|
||||
|
||||
enum {
|
||||
NUSEC_IOCTL_PING = CTL_CODE(0x22, 0x845, METHOD_BUFFERED, FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_PLAY_COUNT = CTL_CODE(0x22, 0x854, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_ADD_PLAY_COUNT = CTL_CODE(0x22, 0x855, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_ERASE_TRACE_LOG = CTL_CODE(0x22, 0x862, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_TD_ERASE_USED = CTL_CODE(0x22, 0x863, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_PUT_TRACE_LOG_DATA = CTL_CODE(0x22, 0x864, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_TRACE_LOG_DATA = CTL_CODE(0x22, 0x865, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_TRACE_LOG_STATE = CTL_CODE(0x22, 0x866, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_NVRAM_AVAILABLE = CTL_CODE(0x22, 0x867, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_BILLING_CA_CERT = CTL_CODE(0x22, 0x871, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_BILLING_PUBKEY = CTL_CODE(0x22, 0x872, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_PLAY_LIMIT = CTL_CODE(0x22, 0x881, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_PUT_PLAY_LIMIT = CTL_CODE(0x22, 0x882, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_NEARFULL = CTL_CODE(0x22, 0x883, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_PUT_NEARFULL = CTL_CODE(0x22, 0x884, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_GET_NVRAM_GEOMETRY = CTL_CODE(0x22, 0x893, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS),
|
||||
NUSEC_IOCTL_PING = 0x22A114,
|
||||
NUSEC_IOCTL_ERASE_TRACE_LOG = 0x22E188,
|
||||
NUSEC_IOCTL_ADD_PLAY_COUNT = 0x22E154,
|
||||
NUSEC_IOCTL_GET_BILLING_CA_CERT = 0x22E1C4,
|
||||
NUSEC_IOCTL_GET_BILLING_PUBKEY = 0x22E1C8,
|
||||
NUSEC_IOCTL_GET_NEARFULL = 0x22E20C,
|
||||
NUSEC_IOCTL_GET_NVRAM_AVAILABLE = 0x22E19C,
|
||||
NUSEC_IOCTL_GET_NVRAM_GEOMETRY = 0x22E24C,
|
||||
NUSEC_IOCTL_GET_PLAY_COUNT = 0x22E150,
|
||||
NUSEC_IOCTL_GET_PLAY_LIMIT = 0x22E204,
|
||||
NUSEC_IOCTL_GET_TRACE_LOG_DATA = 0x22E194,
|
||||
NUSEC_IOCTL_GET_TRACE_LOG_STATE = 0x22E198,
|
||||
NUSEC_IOCTL_PUT_NEARFULL = 0x22E210,
|
||||
NUSEC_IOCTL_PUT_PLAY_LIMIT = 0x22E208,
|
||||
NUSEC_IOCTL_PUT_TRACE_LOG_DATA = 0x22E190,
|
||||
};
|
||||
|
||||
struct nusec_log_record {
|
||||
|
@ -43,7 +42,6 @@ static HRESULT nusec_handle_ioctl(struct irp *irp);
|
|||
|
||||
static HRESULT nusec_ioctl_ping(struct irp *irp);
|
||||
static HRESULT nusec_ioctl_erase_trace_log(struct irp *irp);
|
||||
static HRESULT nusec_ioctl_td_erase_used(struct irp *irp);
|
||||
static HRESULT nusec_ioctl_add_play_count(struct irp *irp);
|
||||
static HRESULT nusec_ioctl_get_billing_ca_cert(struct irp *irp);
|
||||
static HRESULT nusec_ioctl_get_billing_pubkey(struct irp *irp);
|
||||
|
@ -211,9 +209,6 @@ static HRESULT nusec_handle_ioctl(struct irp *irp)
|
|||
case NUSEC_IOCTL_ERASE_TRACE_LOG:
|
||||
return nusec_ioctl_erase_trace_log(irp);
|
||||
|
||||
case NUSEC_IOCTL_TD_ERASE_USED:
|
||||
return nusec_ioctl_td_erase_used(irp);
|
||||
|
||||
case NUSEC_IOCTL_ADD_PLAY_COUNT:
|
||||
return nusec_ioctl_add_play_count(irp);
|
||||
|
||||
|
@ -293,13 +288,6 @@ static HRESULT nusec_ioctl_erase_trace_log(struct irp *irp)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT nusec_ioctl_td_erase_used(struct irp *irp)
|
||||
{
|
||||
dprintf("Security: %s\n", __func__);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT nusec_ioctl_add_play_count(struct irp *irp)
|
||||
{
|
||||
uint32_t delta;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "platform/amvideo.h"
|
||||
#include "platform/clock.h"
|
||||
#include "platform/dns.h"
|
||||
#include "platform/epay.h"
|
||||
#include "platform/hwmon.h"
|
||||
#include "platform/misc.h"
|
||||
#include "platform/netenv.h"
|
||||
|
@ -75,13 +74,7 @@ HRESULT platform_hook_init(
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = vfs_hook_init(&cfg->vfs, game_id);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = epay_hook_init(&cfg->epay);
|
||||
hr = vfs_hook_init(&cfg->vfs);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "platform/amvideo.h"
|
||||
#include "platform/clock.h"
|
||||
#include "platform/dns.h"
|
||||
#include "platform/epay.h"
|
||||
#include "platform/hwmon.h"
|
||||
#include "platform/hwreset.h"
|
||||
#include "platform/misc.h"
|
||||
|
@ -18,7 +17,6 @@ struct platform_config {
|
|||
struct amvideo_config amvideo;
|
||||
struct clock_config clock;
|
||||
struct dns_config dns;
|
||||
struct epay_config epay;
|
||||
struct hwmon_config hwmon;
|
||||
struct hwreset_config hwreset;
|
||||
struct misc_config misc;
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/reg.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "platform/vfs.h"
|
||||
|
||||
|
@ -22,10 +20,6 @@ static HRESULT vfs_path_hook_nthome(
|
|||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count);
|
||||
static HRESULT vfs_path_hook_w10home(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count);
|
||||
static HRESULT vfs_path_hook_option(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
|
@ -33,25 +27,10 @@ static HRESULT vfs_path_hook_option(
|
|||
static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes);
|
||||
|
||||
static wchar_t* my_System_getAppRootPath();
|
||||
static wchar_t* (*next_System_getAppRootPath)();
|
||||
|
||||
static const struct hook_symbol amdaemon_syms[] = {
|
||||
{
|
||||
.name = "System_getAppRootPath",
|
||||
.patch = my_System_getAppRootPath,
|
||||
.link = (void **) &next_System_getAppRootPath,
|
||||
},
|
||||
};
|
||||
|
||||
static wchar_t game[5] = {0};
|
||||
static wchar_t vfs_nthome_real[MAX_PATH];
|
||||
static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser";
|
||||
static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1;
|
||||
|
||||
static const wchar_t vfs_w10home[] = L"C:\\Users\\AppUser";
|
||||
static const size_t vfs_w10home_len = _countof(vfs_w10home) - 1;
|
||||
|
||||
static const wchar_t vfs_option[] = L"C:\\Mount\\Option";
|
||||
static const size_t vfs_option_len = _countof(vfs_option) - 1;
|
||||
|
||||
|
@ -69,7 +48,7 @@ static const struct reg_hook_val vfs_reg_vals[] = {
|
|||
|
||||
static struct vfs_config vfs_config;
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config)
|
||||
{
|
||||
wchar_t temp[MAX_PATH];
|
||||
size_t nthome_len;
|
||||
|
@ -82,8 +61,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
|||
return S_FALSE;
|
||||
}
|
||||
|
||||
mbstowcs(game, game_id, 4);
|
||||
|
||||
if (config->amfs[0] == L'\0') {
|
||||
dprintf("Vfs: FATAL: AMFS path not specified in INI file\n");
|
||||
|
||||
|
@ -167,12 +144,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = path_hook_push(vfs_path_hook_w10home);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (vfs_config.option[0] != L'\0') {
|
||||
hr = path_hook_push(vfs_path_hook_option);
|
||||
|
||||
|
@ -191,13 +162,6 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
|||
return hr;
|
||||
}
|
||||
|
||||
proc_addr_table_push(
|
||||
NULL,
|
||||
"amdaemon_api.dll",
|
||||
amdaemon_syms,
|
||||
_countof(amdaemon_syms)
|
||||
);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -309,8 +273,6 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count)
|
|||
}
|
||||
|
||||
switch (src[0]) {
|
||||
case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it
|
||||
case L'd':
|
||||
case L'e':
|
||||
case L'E':
|
||||
redir = vfs_config.amfs;
|
||||
|
@ -393,53 +355,6 @@ static HRESULT vfs_path_hook_nthome(
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT vfs_path_hook_w10home(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count)
|
||||
{
|
||||
size_t required;
|
||||
size_t redir_len;
|
||||
size_t shift;
|
||||
|
||||
assert(src != NULL);
|
||||
assert(count != NULL);
|
||||
|
||||
/* Case-insensitive check to see if src starts with vfs_w10home */
|
||||
|
||||
if (path_compare_w(src, vfs_w10home, vfs_w10home_len) != 0) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/* Check if the character after vfs_w10home is a separator or the end of
|
||||
the string */
|
||||
|
||||
if (!path_is_separator_w(src[vfs_w10home_len]) &&
|
||||
src[vfs_w10home_len] != L'\0')
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/* Cut off the matched <prefix>\, add the replaced prefix, count NUL */
|
||||
|
||||
shift = path_is_separator_w(src[vfs_w10home_len]) ? 1 : 0;
|
||||
redir_len = wcslen(vfs_nthome_real);
|
||||
required = wcslen(src) - vfs_w10home_len - shift + redir_len + 1;
|
||||
|
||||
if (dest != NULL) {
|
||||
if (required > *count) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
wcscpy_s(dest, *count, vfs_nthome_real);
|
||||
wcscpy_s(dest + redir_len, *count - redir_len, src + vfs_w10home_len + shift);
|
||||
}
|
||||
|
||||
*count = required;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT vfs_path_hook_option(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
|
@ -489,19 +404,10 @@ static HRESULT vfs_path_hook_option(
|
|||
|
||||
static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs); // seems to be busted?
|
||||
return reg_hook_read_wstr(bytes, nbytes, vfs_config.amfs);
|
||||
}
|
||||
|
||||
static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, vfs_config.appdata);
|
||||
}
|
||||
|
||||
static wchar_t* my_System_getAppRootPath()
|
||||
{
|
||||
wchar_t *path = malloc(sizeof(wchar_t) * MAX_PATH);
|
||||
wcscpy_s(path, MAX_PATH, vfs_config.appdata);
|
||||
wcscat_s(path, MAX_PATH, game);
|
||||
wcscat_s(path, MAX_PATH, L"\\");
|
||||
return path;
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ struct vfs_config {
|
|||
wchar_t option[MAX_PATH];
|
||||
};
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id);
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[wrap-git]
|
||||
directory = capnhook
|
||||
url = https://github.com/Hay1tsme/capnhook
|
||||
revision = dbdcd61b3a3043b08f86f959bd45df4967503a77
|
||||
url = https://github.com/decafcode/capnhook
|
||||
revision = 69f7e3b48c2e0ff5be1d7a83cdcc2597a458357b
|
||||
|
|
Loading…
Reference in New Issue