Support pop'n music 15-18

* popnhook1 for pop'n 15 - 18 has been added
* popnio has been added
* inject.exe has new syntax for loading hook DLLs, `real.dll=hook.dll`. This will trigger an early IAT hook where it will load the EXE suspended without resolving imports, replace the reference to real.dll in the import table with hook.dll, and then resolve everything before launching. This allows for ezusb.dll to be hooked properly.
* launcher.exe also has a new early IAT hook feature now. Use `-I real.dll=hook.dll`. The idea is the same as described above for inject.exe.
* Updated ezusb constant namings based on what is visible in ezusb.dll's debug statements.

The launcher.exe implementation of early IAT hooking means that someone can implement popnhook2.dll for 19 and above. I have tried pop'n music Sunny Park using a modified version of popnhook1 and it seems to work to some degree: the I/O check and security check returns OK which means the ezusb hooking used in popnhook1 is also working for the later games using `launcher.exe -I ezusb.dll=ezusb2-popn-shim.dll ...`. The process is rather invasive (manually resolving all imports means more chances to fail) so it has been implemented in such a way that the launcher will work the same as it has before as long as `-I` isn't specified.

One questionable thing I am not confident about is the `texture_usage_fix` hack flag I added in the conf. As the comment says, pop'n music 16 will work in Windows XP without the flag being set, but the game will immediately crash on later OSes without the flag being set in my experience. No other games had this issue in my experience. Enabling it in other games doesn't seem to have any negative effects.
This commit is contained in:
QCDLZCLW3K
2022-06-10 22:46:59 +00:00
committed by icex2
parent 6e06685551
commit f8a09580ea
66 changed files with 3732 additions and 159 deletions
+15
View File
@@ -0,0 +1,15 @@
libs += popnhook-util
libs_popnhook-util := \
iidxhook-util \
ezusb-iidx-emu \
ezusb2-popn-emu \
ezusb2-emu \
acioemu \
hook \
hooklib \
util \
src_popnhook-util := \
acio.c \
mixer.c \
+115
View File
@@ -0,0 +1,115 @@
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <devioctl.h>
#include <ntdef.h>
#include <ntddser.h>
// clang-format on
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "acioemu/addr.h"
#include "acioemu/emu.h"
#include "acioemu/icca.h"
#include "hook/iohook.h"
#include "hooklib/rs232.h"
#include "popnhook-util/acio.h"
#include "imports/avs.h"
#include "util/defs.h"
#include "util/iobuf.h"
#include "util/log.h"
#include "util/str.h"
static struct ac_io_emu popnhook_acio_emu;
static struct ac_io_emu_icca popnhook_acio_emu_icca;
static bool popnhook_icca_override_version;
static enum ac_io_emu_icca_version popnhook_icca_override_version_value;
void popnhook_acio_override_version(enum ac_io_emu_icca_version version)
{
popnhook_icca_override_version = true;
popnhook_icca_override_version_value = version;
}
void popnhook_acio_init(bool legacy_mode)
{
if (legacy_mode) {
ac_io_legacy_mode();
}
ac_io_emu_init(&popnhook_acio_emu, L"COM1");
ac_io_emu_icca_init(
&popnhook_acio_emu_icca, &popnhook_acio_emu, 0);
if (popnhook_icca_override_version) {
ac_io_emu_icca_set_version(
&popnhook_acio_emu_icca,
popnhook_icca_override_version_value
);
}
rs232_hook_add_fd(popnhook_acio_emu.fd);
}
void popnhook_acio_fini(void)
{
ac_io_emu_fini(&popnhook_acio_emu);
}
HRESULT
popnhook_acio_dispatch_irp(struct irp *irp)
{
const struct ac_io_message *msg;
HRESULT hr;
log_assert(irp != NULL);
if (!ac_io_emu_match_irp(&popnhook_acio_emu, irp)) {
return iohook_invoke_next(irp);
}
for (;;) {
hr = ac_io_emu_dispatch_irp(&popnhook_acio_emu, irp);
if (hr != S_OK) {
return hr;
}
msg = ac_io_emu_request_peek(&popnhook_acio_emu);
switch (msg->addr) {
case 0:
ac_io_emu_cmd_assign_addrs(&popnhook_acio_emu, msg, 1);
break;
case 1:
ac_io_emu_icca_dispatch_request(
&popnhook_acio_emu_icca, msg);
break;
case AC_IO_BROADCAST:
log_warning("Broadcast(?) message on pop'n ACIO bus?");
break;
default:
log_warning(
"ACIO message on unhandled bus address: %d", msg->addr);
break;
}
ac_io_emu_request_pop(&popnhook_acio_emu);
}
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef POPNHOOK_UTIL_ACIO_H
#define POPNHOOK_UTIL_ACIO_H
#include <windows.h>
#include <stdbool.h>
#include "acioemu/icca.h"
#include "hook/iohook.h"
/**
* Initialize an emulated ACIO on COM1 for pop'n music.
*
* @param legacy_mode Set to true if running on slotted readers on pop'n 15-18.
*/
void popnhook_acio_init(bool legacy_mode);
/**
* Use the specified ICCA emulation version
*/
void popnhook_acio_override_version(enum ac_io_emu_icca_version version);
/**
* Cleanup the ACIO emulation layer.
*/
void popnhook_acio_fini(void);
/**
* iohook dispatch function. Needs to be installed.
*/
HRESULT popnhook_acio_dispatch_irp(struct irp *irp);
#endif
+71
View File
@@ -0,0 +1,71 @@
#define LOG_MODULE "jbhook-mixer"
#include <windows.h>
#include <mmsystem.h>
#include "hook/table.h"
#include "util/defs.h"
#include "util/log.h"
MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls);
MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps);
MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);
MMRESULT STDCALL hook_mixerClose(HMIXER hmx);
MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo);
static const struct hook_symbol mixer_hook_syms[] = {
{.name = "mixerGetLineControlsA",
.patch = hook_mixerGetLineControlsA},
{.name = "mixerGetDevCapsA",
.patch = hook_mixerGetDevCapsA},
{.name = "mixerOpen",
.patch = hook_mixerOpen},
{.name = "mixerSetControlDetails",
.patch = hook_mixerSetControlDetails},
{.name = "mixerGetControlDetailsA",
.patch = hook_mixerGetControlDetailsA},
{.name = "mixerClose",
.patch = hook_mixerClose},
{.name = "mixerGetLineInfoA",
.patch = hook_mixerGetLineInfoA},
};
MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen) {
*(DWORD*)phmx = 1234; // any non-zero value is fine
return MMSYSERR_NOERROR;
}
MMRESULT STDCALL hook_mixerClose(HMIXER hmx) {
return MMSYSERR_NOERROR;
}
MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls) {
return MMSYSERR_NOERROR;
}
MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps) {
return MMSYSERR_NOERROR;
}
MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
return MMSYSERR_NOERROR;
}
MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo) {
return MMSYSERR_NOERROR;
}
MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
return MMSYSERR_NOERROR;
}
void popnhook_mixer_hook_init(void)
{
hook_table_apply(NULL, "winmm.dll", mixer_hook_syms, lengthof(mixer_hook_syms));
log_info("Inserted mixer hooks");
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef POPNHOOK_UTIL_MIXER_H
#define POPNHOOK_UTIL_MIXER_H
/**
* Hook some mixer related functions and stub out attempts to change the volume.
* In addition to being annoying, this can fail on Vista+ on some outputs,
* despite not actually preventing sound from playing.
*/
void popnhook_mixer_hook_init(void);
#endif