1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2024-11-28 00:10:51 +01:00

test/hook: Add tests for d3d9 hook module

Creates a simple d3d9 context and render loop allowing us to run
quick and easy integration tests of the hooking infrastructure.
This commit is contained in:
icex2 2019-10-06 21:17:56 +02:00
parent 60050d0d09
commit d169ee84b3
7 changed files with 501 additions and 1 deletions

View File

@ -54,11 +54,12 @@ libs :=
avsdlls :=
avsexes :=
testdlls :=
testexes :=
include Module.mk
modules := $(dlls) $(exes) $(libs) $(avsdlls) $(avsexes) $(testexes)
modules := $(dlls) $(exes) $(libs) $(avsdlls) $(avsexes) $(testdlls) $(testexes)
#
# $1: Bitness
@ -94,6 +95,7 @@ $$(eval $$(foreach lib,$(libs),$$(call t_archive,$1,indep,$$(lib))))
$$(eval $$(foreach avsver,$$(avsvers_$1),$$(call t_avsver,$1,$$(avsver))))
$$(eval $$(foreach dll,$(testdlls),$$(call t_linkdll,$1,indep,$$(dll))))
$$(eval $$(foreach exe,$(testexes),$$(call t_linkexe,$1,indep,$$(exe))))
endef

View File

@ -137,6 +137,7 @@ include src/main/util/Module.mk
include src/main/vefxio/Module.mk
include src/test/cconfig/Module.mk
include src/test/d3d9hook/Module.mk
include src/test/iidxhook-util/Module.mk
include src/test/security/Module.mk
include src/test/test/Module.mk
@ -458,6 +459,8 @@ $(BUILDDIR)/tests.zip: \
build/bin/indep-32/cconfig-test.exe \
build/bin/indep-32/cconfig-util-test.exe \
build/bin/indep-32/cconfig-cmd-test.exe \
build/bin/indep-32/d3d9hook.dll \
build/bin/indep-32/d3d9hook-test.exe \
build/bin/indep-32/iidxhook-util-config-eamuse-test.exe \
build/bin/indep-32/iidxhook-util-config-gfx-test.exe \
build/bin/indep-32/iidxhook-util-config-misc-test.exe \

View File

@ -25,4 +25,6 @@ wine ./security-rp2-test.exe
wine ./security-rp3-test.exe
wine ./util-net-test.exe
wine ./inject.exe d3d9hook.dll d3d9hook-test.exe
echo "All tests successful."

View File

@ -0,0 +1,32 @@
testdlls += d3d9hook
srcdir_d3d9hook := src/test/d3d9hook
ldflags_d3d9hook := \
libs_d3d9hook := \
hook \
test \
util \
src_d3d9hook := \
dllmain.c \
################################################################################
testexes += d3d9hook-test
srcdir_d3d9hook-test := src/test/d3d9hook
ldflags_d3d9hook-test := \
-ld3d9
libs_d3d9hook-test := \
hook \
test \
util \
src_d3d9hook-test := \
main.c \
################################################################################

View File

@ -0,0 +1,5 @@
LIBRARY d3d9hook
EXPORTS
DllMain@12 @1 NONAME

289
src/test/d3d9hook/dllmain.c Normal file
View File

@ -0,0 +1,289 @@
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "hook/d3d9.h"
#include "test/check.h"
#include "util/log.h"
#define debug_print(...) fprintf(stderr, __VA_ARGS__)
static HRESULT my_d3d9_handler(struct hook_d3d9_irp* irp);
static const hook_d3d9_irp_handler_t d3d9_handlers[] = {
my_d3d9_handler
};
static HRESULT my_d3d9_handler(struct hook_d3d9_irp* irp)
{
HRESULT hr;
enum hook_d3d9_irp_op pre_op;
debug_print("my_d3d9_handler dispatch: %d\n", irp->op);
// Important: All parameter checks must align with the parameters from the test executable
// Pre-real invoke checks
switch (irp->op) {
case HOOK_D3D9_IRP_OP_INVALID:
exit(EXIT_FAILURE);
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE:
debug_print("Pre HOOK_D3D9_IRP_OP_CTX_CREATE\n");
check_int_eq(irp->args.ctx_create.sdk_ver, D3D_SDK_VERSION);
check_null(irp->args.ctx_create.ctx);
break;
case HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES:
debug_print("Pre HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES\n");
check_null(irp->args.enum_display_devices.dev_name);
check_int_eq(irp->args.enum_display_devices.dev_num, 0);
check_non_null(irp->args.enum_display_devices.info);
check_int_eq(irp->args.enum_display_devices.flags, EDD_GET_DEVICE_INTERFACE_NAME);
break;
case HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX:
debug_print("Pre HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX\n");
// Cannot test because wine is also using this call causing the tests to fail
// check_int_eq(irp->args.create_window_ex.ex_style, 0);
// check_str_eq(irp->args.create_window_ex.class_name, "d3d9hook");
// check_str_eq(irp->args.create_window_ex.window_name, "d3d9hook test");
// check_int_eq(irp->args.create_window_ex.style, WS_OVERLAPPEDWINDOW);
// check_int_eq(irp->args.create_window_ex.x, 0);
// check_int_eq(irp->args.create_window_ex.y, 0);
// check_int_eq(irp->args.create_window_ex.width, 640);
// check_int_eq(irp->args.create_window_ex.height, 480);
// check_null(irp->args.create_window_ex.wnd_parent);
// check_null(irp->args.create_window_ex.menu);
// check_null(irp->args.create_window_ex.instance);
// check_null(irp->args.create_window_ex.param);
// check_null(irp->args.create_window_ex.result);
break;
case HOOK_D3D9_IRP_OP_GET_CLIENT_RECT:
debug_print("Pre HOOK_D3D9_IRP_OP_GET_CLIENT_RECT\n");
// Cannot test because wine is also using this call causing the tests to fail
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE:
debug_print("Pre HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE\n");
check_non_null(irp->args.ctx_create_device.self);
check_int_eq(irp->args.ctx_create_device.adapter, D3DADAPTER_DEFAULT);
check_int_eq(irp->args.ctx_create_device.type, D3DDEVTYPE_HAL);
check_non_null(irp->args.ctx_create_device.hwnd);
check_int_eq(irp->args.ctx_create_device.flags, D3DCREATE_HARDWARE_VERTEXPROCESSING);
check_non_null(irp->args.ctx_create_device.pp);
check_non_null(irp->args.ctx_create_device.pdev);
break;
case HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE\n");
check_non_null(irp->args.dev_create_texture.self);
check_int_eq(irp->args.dev_create_texture.width, 320);
check_int_eq(irp->args.dev_create_texture.height, 240);
check_int_eq(irp->args.dev_create_texture.levels, 0);
check_int_eq(irp->args.dev_create_texture.usage, 0);
check_int_eq(irp->args.dev_create_texture.format, D3DFMT_A8R8G8B8);
check_int_eq(irp->args.dev_create_texture.pool, D3DPOOL_DEFAULT);
check_non_null(irp->args.dev_create_texture.texture);
check_null(irp->args.dev_create_texture.shared_handle);
break;
case HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE\n");
check_non_null(irp->args.dev_begin_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_END_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_END_SCENE\n");
check_non_null(irp->args.dev_end_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_PRESENT:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_PRESENT\n");
check_non_null(irp->args.dev_present.self);
check_null(irp->args.dev_present.source_rect);
check_null(irp->args.dev_present.dest_rect);
check_null(irp->args.dev_present.dest_window_override);
check_null(irp->args.dev_present.dirty_region);
break;
case HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE\n");
check_non_null(irp->args.dev_set_render_state.self);
check_int_eq(irp->args.dev_set_render_state.state, D3DRS_FILLMODE);
check_int_eq(irp->args.dev_set_render_state.value, D3DFILL_POINT);
break;
default:
debug_print("Unhandled op code: %d\n", irp->op);
check_fail_msg("Unhandled op code.");
break;
}
pre_op = irp->op;
hr = hook_d3d9_irp_invoke_next(irp);
if (hr != S_OK) {
debug_print("HRESULT of op %d: %lX\n", irp->op, hr);
} else {
check_int_eq(irp->op, pre_op);
// Post real invoke checks
switch (irp->op) {
case HOOK_D3D9_IRP_OP_INVALID:
exit(EXIT_FAILURE);
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE:
debug_print("Post HOOK_D3D9_IRP_OP_CTX_CREATE\n");
check_int_eq(irp->args.ctx_create.sdk_ver, D3D_SDK_VERSION);
check_non_null(irp->args.ctx_create.ctx);
break;
case HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES:
debug_print("Post HOOK_D3D9_IRP_OP_ENUM_DISPLAY_DEVICES\n");
check_null(irp->args.enum_display_devices.dev_name);
check_int_eq(irp->args.enum_display_devices.dev_num, 0);
check_non_null(irp->args.enum_display_devices.info);
check_int_eq(irp->args.enum_display_devices.flags, EDD_GET_DEVICE_INTERFACE_NAME);
break;
case HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX:
debug_print("Post HOOK_D3D9_IRP_OP_CREATE_WINDOW_EX\n");
// Cannot test because wine is also using this call causing the tests to fail
// check_int_eq(irp->args.create_window_ex.ex_style, 0);
// check_str_eq(irp->args.create_window_ex.class_name, "d3d9hook");
// check_str_eq(irp->args.create_window_ex.window_name, "d3d9hook test");
// check_int_eq(irp->args.create_window_ex.style, WS_OVERLAPPEDWINDOW);
// check_int_eq(irp->args.create_window_ex.x, 0);
// check_int_eq(irp->args.create_window_ex.y, 0);
// check_int_eq(irp->args.create_window_ex.width, 640);
// check_int_eq(irp->args.create_window_ex.height, 480);
// check_null(irp->args.create_window_ex.wnd_parent);
// check_null(irp->args.create_window_ex.menu);
// check_null(irp->args.create_window_ex.instance);
// check_null(irp->args.create_window_ex.param);
// check_non_null(irp->args.create_window_ex.result);
break;
case HOOK_D3D9_IRP_OP_GET_CLIENT_RECT:
debug_print("Post HOOK_D3D9_IRP_OP_GET_CLIENT_RECT\n");
// Cannot test because wine is also using this call causing the tests to fail
break;
case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE:
debug_print("Post HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE\n");
check_non_null(irp->args.ctx_create_device.self);
check_int_eq(irp->args.ctx_create_device.adapter, D3DADAPTER_DEFAULT);
check_int_eq(irp->args.ctx_create_device.type, D3DDEVTYPE_HAL);
check_non_null(irp->args.ctx_create_device.hwnd);
check_int_eq(irp->args.ctx_create_device.flags, D3DCREATE_HARDWARE_VERTEXPROCESSING);
check_non_null(irp->args.ctx_create_device.pp);
check_non_null(irp->args.ctx_create_device.pdev);
break;
case HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE:
debug_print("Post HOOK_D3D9_IRP_OP_DEV_CREATE_TEXTURE\n");
check_non_null(irp->args.dev_create_texture.self);
check_int_eq(irp->args.dev_create_texture.width, 320);
check_int_eq(irp->args.dev_create_texture.height, 240);
check_int_eq(irp->args.dev_create_texture.levels, 0);
check_int_eq(irp->args.dev_create_texture.usage, 0);
check_int_eq(irp->args.dev_create_texture.format, D3DFMT_A8R8G8B8);
check_int_eq(irp->args.dev_create_texture.pool, D3DPOOL_DEFAULT);
check_non_null(irp->args.dev_create_texture.texture);
check_null(irp->args.dev_create_texture.shared_handle);
break;
case HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE\n");
check_non_null(irp->args.dev_begin_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_END_SCENE:
debug_print("Pre HOOK_D3D9_IRP_OP_DEV_END_SCENE\n");
check_non_null(irp->args.dev_end_scene.self);
break;
case HOOK_D3D9_IRP_OP_DEV_PRESENT:
debug_print("Post HOOK_D3D9_IRP_OP_DEV_PRESENT\n");
check_non_null(irp->args.dev_present.self);
check_null(irp->args.dev_present.source_rect);
check_null(irp->args.dev_present.dest_rect);
check_null(irp->args.dev_present.dest_window_override);
check_null(irp->args.dev_present.dirty_region);
break;
case HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE:
debug_print("Post HOOK_D3D9_IRP_OP_DEV_SET_RENDER_STATE\n");
check_non_null(irp->args.dev_set_render_state.self);
check_int_eq(irp->args.dev_set_render_state.state, D3DRS_FILLMODE);
check_int_eq(irp->args.dev_set_render_state.value, D3DFILL_POINT);
break;
default:
debug_print("Unhandled op code: %d\n", irp->op);
check_fail_msg("Unhandled op code.");
break;
}
}
return hr;
}
BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
{
if (reason == DLL_PROCESS_ATTACH) {
log_to_writer(log_writer_stderr, NULL);
debug_print("Initializing d3d9 hook module...\n");
hook_d3d9_init(d3d9_handlers, lengthof(d3d9_handlers));
}
return TRUE;
}

167
src/test/d3d9hook/main.c Normal file
View File

@ -0,0 +1,167 @@
#include <d3d9.h>
#include <stdio.h>
#include <windows.h>
#include <winuser.h>
#include "test/check.h"
#define debug_print(...) fprintf(stderr, __VA_ARGS__)
static const int render_loop_iterations = 100;
static LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param);
static HWND create_window()
{
WNDCLASS wc;
HRESULT hr;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = (WNDPROC) wnd_proc;
wc.hInstance = NULL;
wc.lpszClassName = "d3d9hook";
hr = RegisterClass(&wc);
check_int_neq(hr, 0);
return CreateWindow("d3d9hook", "d3d9hook test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, NULL, NULL, NULL, 0);
}
static D3DPRESENT_PARAMETERS create_presenter_params(HWND window)
{
D3DPRESENT_PARAMETERS pp;
memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
pp.BackBufferWidth = 640;
pp.BackBufferHeight = 480;
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
pp.BackBufferCount = 1;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = 0;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = window;
pp.Windowed = TRUE;
pp.EnableAutoDepthStencil = TRUE;
pp.AutoDepthStencilFormat = D3DFMT_D24S8;
pp.Flags = 0;
pp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
return pp;
}
static IDirect3DTexture9* create_texture(IDirect3DDevice9* dev)
{
HRESULT hr;
IDirect3DTexture9* texture;
hr = IDirect3DDevice9_CreateTexture(dev, 320, 240, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, NULL);
check_int_eq(hr, S_OK);
return texture;
}
int main(int argc, char** argv)
{
DISPLAY_DEVICEA display_device;
BOOL res;
HWND window;
RECT rect;
MSG msg;
IDirect3D9* d3d9;
HRESULT hr;
D3DPRESENT_PARAMETERS pp;
IDirect3DDevice9* dev;
int loop_count;
IDirect3DTexture9* texture;
res = EnumDisplayDevicesA(NULL, 0, &display_device, EDD_GET_DEVICE_INTERFACE_NAME);
check_int_eq(res, TRUE);
window = create_window();
check_non_null(window);
res = GetClientRect(window, &rect);
check_int_eq(res, TRUE);
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
check_non_null(d3d9);
pp = create_presenter_params(window);
hr = IDirect3D9_CreateDevice(
d3d9,
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
window,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&pp,
&dev);
check_int_eq(hr, S_OK);
IDirect3DDevice9_Release(d3d9);
d3d9 = NULL;
texture = create_texture(dev);
ShowWindow(window, SW_SHOW);
UpdateWindow(window);
memset(&msg, 0, sizeof(MSG));
loop_count = 0;
// TODO create vertex buffer, upload and render
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
hr = IDirect3DDevice9_Clear(dev, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff, 1.0f, 0);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_SetRenderState(dev, D3DRS_FILLMODE, D3DFILL_POINT);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_BeginScene(dev);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_EndScene(dev);
check_int_eq(hr, S_OK);
hr = IDirect3DDevice9_Present(dev, NULL, NULL, NULL, NULL);
check_int_eq(hr, S_OK);
loop_count++;
if (loop_count > render_loop_iterations) {
PostQuitMessage(0);
}
}
}
IDirect3DTexture9_Release(texture);
IDirect3DDevice9_Release(dev);
return 0;
}
LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
switch(msg) {
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(wnd, msg, w_param, l_param);
}