d3d9(32位)

dllmain.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <windows.h>
#include <d3d9.h>
#include <iostream>

// ImGui 头文件
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_dx9.h"
#include "MinHook.h"

// 链接 D3D9 库
#pragma comment(lib, "d3d9.lib")

// --- 类型定义 ---
typedef HRESULT(STDMETHODCALLTYPE* EndScene_t)(IDirect3DDevice9*);
typedef HRESULT(STDMETHODCALLTYPE* Reset_t)(IDirect3DDevice9*, D3DPRESENT_PARAMETERS*);

EndScene_t oEndScene = nullptr;
Reset_t oReset = nullptr;

// --- 全局变量 ---
bool g_Initialized = false;

// 消息处理声明
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// --- Hook 函数:EndScene ---
// D3D9 的 EndScene 在每一帧渲染结束时调用,是画 UI 的绝佳时机
HRESULT STDMETHODCALLTYPE hkEndScene(IDirect3DDevice9* pDevice) {
if (!g_Initialized) {
D3DDEVICE_CREATION_PARAMETERS cp;
pDevice->GetCreationParameters(&cp);

ImGui::CreateContext();
ImGui_ImplWin32_Init(cp.hFocusWindow);
ImGui_ImplDX9_Init(pDevice);

g_Initialized = true;
}

// 开始 ImGui 帧
ImGui_ImplDX9_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();

// 绘制方框和菜单
ImGui::GetBackgroundDrawList()->AddRect(ImVec2(100, 100), ImVec2(300, 300), IM_COL32(255, 0, 0, 255), 0, 0, 2.0f);

ImGui::Begin("D3D9 Hook Menu");
ImGui::Text("Hello from D3D9!");
if (ImGui::Button("Unload DLL")) {
// 可以在这里设置退出标志
}
ImGui::End();

ImGui::EndFrame();
ImGui::Render();
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());

return oEndScene(pDevice);
}

// --- Hook 函数:Reset ---
// 当窗口改变大小或切换全屏时,D3D9 设备会丢失,必须在此处理资源释放
HRESULT STDMETHODCALLTYPE hkReset(IDirect3DDevice9* pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters) {
ImGui_ImplDX9_InvalidateDeviceObjects();
HRESULT hr = oReset(pDevice, pPresentationParameters);
if (SUCCEEDED(hr)) {
ImGui_ImplDX9_CreateDeviceObjects();
}
return hr;
}

// --- 寻找 VTable 并执行 Hook ---
DWORD WINAPI MainThread(LPVOID lpReserved) {
// 1. 创建一个临时的 D3D9 接口
IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!pD3D) return FALSE;

// 2. 准备创建虚拟设备的参数
D3DPRESENT_PARAMETERS d3dpp = { 0 };
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = GetForegroundWindow(); // 借用当前前台窗口

IDirect3DDevice9* pDummyDevice = nullptr;
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice))) {
pD3D->Release();
return FALSE;
}

// 3. 获取虚函数表地址
// IDirect3DDevice9 的内存布局:[vtable_ptr] -> [Function Pointers]
void** vTable = *(void***)pDummyDevice;

// 4. 初始化 MinHook 并挂钩
// Index 42: EndScene
// Index 16: Reset
if (MH_Initialize() == MH_OK) {
MH_CreateHook(vTable[42], &hkEndScene, reinterpret_cast<LPVOID*>(&oEndScene));
MH_CreateHook(vTable[16], &hkReset, reinterpret_cast<LPVOID*>(&oReset));
MH_EnableHook(MH_ALL_HOOKS);
}

// 5. 销毁虚拟设备
pDummyDevice->Release();
pD3D->Release();

return TRUE;
}

BOOL WINAPI DllMain(HMODULE hMod, DWORD dwReason, LPVOID lpReserved) {
if (dwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hMod);
CreateThread(nullptr, 0, MainThread, hMod, 0, nullptr);
}
return TRUE;
}

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 【核心】禁用 vcpkg 所有的自动集成行为
set(VCPKG_MANIFEST_MODE OFF CACHE BOOL "Disable vcpkg manifest" FORCE)
set(X_VCPKG_APPLOCAL_DEPS_INSTALL OFF CACHE BOOL "Disable applocal copy" FORCE)

project(GLBoxHook LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)

# 1. 统一输出目录到 bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 2. ImGui 路径 (保持不变)
set(IMGUI_DIR "C:/D/test/CCpp/ccpplib/imgui")
include_directories(${IMGUI_DIR} ${IMGUI_DIR}/backends)

# 1. 更新 ImGui 源码搜集(换成 D3D11 后端)
# 搜集 DX11 后端文件
set(IMGUI_SOURCES
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_widgets.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/backends/imgui_impl_win32.cpp
${IMGUI_DIR}/backends/imgui_impl_dx9.cpp # 关键:换成 DX9
)

# 3. 手动链接 vcpkg 下的 MinHook (硬路径)
set(VCPKG_BASE "C:/D/test/CCpp/ccpplib/vcpkg/vcpkg/installed/x86-windows-static")
include_directories("${VCPKG_BASE}/include")
link_directories("${VCPKG_BASE}/lib")

# 4. 生成 DLL
add_library(${PROJECT_NAME} SHARED "dllmain.cpp" ${IMGUI_SOURCES})

# 5. 链接系统库和 minhook
# 注意:如果链接报错,请检查 lib 目录下是否叫 minhook.lib 还是 libMinHook.x64.lib
# 2. 链接 D3D 核心库
# 链接 D3D11 必备库
# 1. 更新 ImGui 源码搜集(换成 D3D9 后端)

# 2. 链接 D3D9 核心库
target_link_libraries(${PROJECT_NAME} PRIVATE
minhook.x32.lib
d3d9 # D3D9 核心
dwmapi
)
add_definitions(-DUNICODE -D_UNICODE -D_CRT_SECURE_NO_WARNINGS)
if(MSVC)
add_compile_options("/utf-8")
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)