Skip to content

Commit ad5e524

Browse files
author
StArray
committed
feat: integrate kiero2 for D3D11 vtable detection
- Add kiero2 as git submodule for graphics API method location - Replace manual dummy-device vtable extraction with kiero2::locate() - Integrate kiero2 with CMake build (D3D11 only, MinGW WIN32 fix)
1 parent 9a0008f commit ad5e524

5 files changed

Lines changed: 103 additions & 60 deletions

File tree

‎.gitmodules‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "StArray.ModManager.Windows/Native/minhook"]
22
path = StArray.ModManager.Windows/Native/minhook
33
url = https://github.com/TsudaKageyu/minhook
4+
[submodule "StArray.ModManager.Windows/Native/kiero2"]
5+
path = StArray.ModManager.Windows/Native/kiero2
6+
url = https://github.com/kirchesz/kiero2

‎StArray.ModManager.Windows/Managed.cs‎

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,51 @@ public static int Entry(int argc, IntPtr argv)
8282
Writer.AutoFlush = true;
8383
Logger.Info($"{nameof(Managed)}-Benchmark", $"Path resolve: {Benchmark.End():F3}s");
8484

85-
Il2CppFunctions.SetIl2CppLibraryPath(Path.Combine(new DirectoryInfo(modsPath).Parent.Parent.FullName,"GameAssembly.dll"));
86-
// 检测运行时后端 + 图形设备类型
87-
//RuntimeManager.Detect();
85+
Il2CppFunctions.SetIl2CppLibraryPath(Path.Combine(AppContext.BaseDirectory,"..","..", "GameAssembly.dll"));
86+
// 检测运行时后端 (IL2CPP / Mono)
87+
RuntimeManager.Detect();
8888
Logger.Info("Runtime", $"Detected backend: {RuntimeManager.Backend}");
8989

90-
ModManagerUI modManagerUI = new(new ModLoader(modsPath), managedDir);
91-
92-
// Detect backend and pick renderer
93-
var renderer = Renderer.D3D11;
90+
// 检测图形设备类型
91+
var renderer = GetGameRenderer();
9492
Logger.Info("Backend", $"Detected renderer: {renderer}");
9593

96-
if ((renderer & Renderer.D3D11) != 0)
94+
ModManagerUI modManagerUI = new(new ModLoader(modsPath), managedDir);
95+
96+
NativeApi.SetBackend(1); // D3D11
97+
ImGuiDXRenderer.OnRender += modManagerUI.Render;
98+
ImGuiDXRenderer.Install();
99+
/*if ((renderer & Renderer.D3D11) != 0)
97100
{
98101
NativeApi.SetBackend(1); // D3D11
99-
ImGuiDXRenderer.OnRender += modManagerUI.Render;
100-
ImGuiDXRenderer.Install();
101-
return 0;
102+
ImGuiRenderer.OnRender += modManagerUI.Render;
103+
ImGuiRenderer.Install();
104+
}
105+
else if ((renderer & Renderer.D3D12) != 0)
106+
{
107+
NativeApi.SetBackend(0); // D3D12
108+
ImGuiRenderer.OnRender += modManagerUI.Render;
109+
ImGuiRenderer.Install();
102110
}
111+
else if ((renderer & Renderer.D3D9) != 0)
112+
{
113+
NativeApi.SetBackend(2); // D3D9
114+
ImGuiRenderer.OnRender += modManagerUI.Render;
115+
ImGuiRenderer.Install();
116+
}
117+
else if ((renderer & Renderer.Vulkan) != 0 ||
118+
(renderer & Renderer.OpenGL) != 0)
119+
{
120+
// GL/VK: native handles Win32 init only, C# handles ImGui backend
121+
ImGuiRenderer.OnRender += modManagerUI.Render;
122+
ImGuiRenderer.Install();
123+
}
124+
else
125+
{
126+
Logger.Error("Backend", "No supported renderer found");
127+
return 1;
128+
}*/
129+
103130
totalSw.Stop();
104131
Logger.Info($"{nameof(Managed)}-Benchmark", $"=== Startup total: {totalSw.Elapsed.TotalSeconds:F3}s ===");
105132
return 0;

‎StArray.ModManager.Windows/Native/CMakeLists.txt‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ add_library(MinHook STATIC
2525
target_include_directories(MinHook PUBLIC minhook/include)
2626
target_compile_definitions(MinHook PRIVATE _CRT_SECURE_NO_WARNINGS)
2727

28+
# ---- kiero2: locate graphics API methods at runtime ----
29+
set(KIERO_BUILD_D3D9 OFF CACHE BOOL "" FORCE)
30+
set(KIERO_BUILD_D3D10 OFF CACHE BOOL "" FORCE)
31+
set(KIERO_BUILD_D3D11 ON CACHE BOOL "" FORCE)
32+
set(KIERO_BUILD_D3D12 OFF CACHE BOOL "" FORCE)
33+
set(KIERO_BUILD_OPENGL OFF CACHE BOOL "" FORCE)
34+
set(KIERO_BUILD_VULKAN OFF CACHE BOOL "" FORCE)
35+
add_subdirectory(kiero2)
36+
# MinGW in C++17 strict mode doesn't define the bare `WIN32` macro,
37+
# but kiero headers rely on it to enable Win32 code paths.
38+
if(MINGW)
39+
target_compile_definitions(kiero PRIVATE WIN32)
40+
endif()
41+
2842
# ---- cimgui: build from source as static library ----
2943
set(IMGUI_STATIC ON CACHE BOOL "" FORCE)
3044
set(CIMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cimgui)
@@ -40,11 +54,13 @@ add_library(${PROJECT_NAME} SHARED
4054
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
4155
target_include_directories(${PROJECT_NAME} PRIVATE
4256
minhook/include
57+
${CMAKE_CURRENT_SOURCE_DIR}/kiero2
58+
${CMAKE_CURRENT_BINARY_DIR}/kiero2
4359
${CIMGUI_DIR}
4460
${CIMGUI_DIR}/imgui
4561
${CIMGUI_DIR}/imgui/backends
4662
)
47-
target_link_libraries(${PROJECT_NAME} PRIVATE MinHook d3d11 d3dcompiler dxgi dwmapi gdi32 cimgui)
63+
target_link_libraries(${PROJECT_NAME} PRIVATE MinHook kiero d3d11 d3dcompiler dxgi dwmapi gdi32 cimgui)
4864

4965
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
5066
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}/net10.0"
Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// DX11 Present hook — cimgui-based ImGui overlay
22
#include "hook_common.h"
3+
#include "cimgui.h"
4+
#include "kiero.hpp"
5+
#include "kiero_d3d11.hpp"
36

47
typedef HRESULT(APIENTRY* PresentFn)(IDXGISwapChain*, UINT, UINT);
58

@@ -38,6 +41,8 @@ namespace DX11Hook {
3841
return CallWindowProcW(g_OriginalWndProc, h, m, w, l);
3942
}
4043

44+
ID3D11RenderTargetView *MainRTV = nullptr;
45+
4146
HRESULT HookPresent(IDXGISwapChain* swapChain, UINT syncInterval, UINT flags) {
4247
if (!Initialised) {
4348
DXGI_SWAP_CHAIN_DESC desc;
@@ -48,6 +53,7 @@ namespace DX11Hook {
4853
swapChain->GetDevice(__uuidof(ID3D11Device), (void**)&device);
4954
device->GetImmediateContext(&DeviceContext);
5055
if (imgui_callbacks.init_callback) imgui_callbacks.init_callback();
56+
5157
if (ImGui_ImplWin32_Init(g_GameWindow) && ImGui_ImplDX11_Init(device, DeviceContext)) {
5258
SwapChain = swapChain;
5359
g_OriginalWndProc = (WNDPROC)SetWindowLongPtrW(g_GameWindow,
@@ -56,68 +62,59 @@ namespace DX11Hook {
5662
ImGui_Initialised = true;
5763
DEBUG_LOG("DX11Hook: ImGui initialised, hwnd=%p", g_GameWindow);
5864
}
59-
60-
device->Release();
6165
}
6266

6367
if (Initialised) {
68+
/*if (MainRTV) { MainRTV->Release(); MainRTV = nullptr; }
69+
ID3D11Texture2D* bb = nullptr;
70+
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&bb);
71+
ID3D11Device* device = nullptr;
72+
swapChain->GetDevice(__uuidof(ID3D11Device), (void**)&device);
73+
if (bb) { device->CreateRenderTargetView(bb, nullptr, &MainRTV); bb->Release(); }
74+
*/
75+
6476
ImGui_ImplDX11_NewFrame();
6577
ImGui_ImplWin32_NewFrame();
78+
auto io = igGetIO();
79+
DXGI_SWAP_CHAIN_DESC desc;
80+
swapChain->GetDesc(&desc);
81+
io->DisplaySize.x = desc.BufferDesc.Width;
82+
io->DisplaySize.y = desc.BufferDesc.Height;
6683
if (imgui_callbacks.render_callback) imgui_callbacks.render_callback();
6784
ImGui_ImplDX11_RenderDrawData(igGetDrawData());
85+
86+
//if (MainRTV) DeviceContext->OMSetRenderTargets(1, &MainRTV, nullptr);
6887
}
6988

7089
return OriginalPresent(swapChain, syncInterval, flags);
7190
}
7291

7392
bool InstallHook() {
74-
DEBUG_LOG("DX11Hook::InstallHook: creating dummy device...");
75-
76-
WNDCLASSEXW wc = {};
77-
wc.cbSize = sizeof(wc);
78-
wc.lpfnWndProc = DefWindowProcW;
79-
wc.hInstance = GetModuleHandleW(nullptr);
80-
wc.lpszClassName = L"DX11HookDummy";
81-
RegisterClassExW(&wc);
82-
83-
HWND dummy = CreateWindowExW(0, L"DX11HookDummy", L"", WS_POPUP,
84-
0, 0, 1, 1, nullptr, nullptr, wc.hInstance, nullptr);
85-
86-
DXGI_SWAP_CHAIN_DESC scd = {};
87-
scd.BufferCount = 1;
88-
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
89-
scd.BufferDesc.Width = 1;
90-
scd.BufferDesc.Height = 1;
91-
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
92-
scd.OutputWindow = dummy;
93-
scd.SampleDesc.Count = 1;
94-
scd.Windowed = TRUE;
95-
96-
ID3D11Device* tmpDevice = nullptr;
97-
IDXGISwapChain* tmpSwapChain = nullptr;
98-
ID3D11DeviceContext* tmpContext = nullptr;
99-
100-
bool ok = false;
101-
if (SUCCEEDED(D3D11CreateDeviceAndSwapChain(
102-
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0,
103-
nullptr, 0, D3D11_SDK_VERSION,
104-
&scd, &tmpSwapChain, &tmpDevice, nullptr, &tmpContext))) {
105-
106-
MH_Initialize();
107-
void** vt = *(void***)tmpSwapChain;
108-
ok = (MH_CreateHook(vt[8], (void*)HookPresent, (void**)&OriginalPresent) == MH_OK)
109-
&& (MH_EnableHook(vt[8]) == MH_OK);
110-
DEBUG_LOG("DX11Hook::InstallHook: Present hook %s", ok ? "OK" : "FAILED");
111-
112-
tmpSwapChain->Release();
113-
tmpContext->Release();
114-
tmpDevice->Release();
115-
} else {
116-
DEBUG_LOG("DX11Hook::InstallHook: D3D11CreateDeviceAndSwapChain FAILED");
93+
DEBUG_LOG("DX11Hook::InstallHook: locating D3D11 methods via kiero...");
94+
95+
kiero::D3D11Output output;
96+
auto err = kiero::locate<kiero::Implementation_D3D11>(nullptr, &output);
97+
if (err != kiero::Error_Nil) {
98+
DEBUG_LOG("DX11Hook::InstallHook: kiero locate failed (err=%d)", err);
99+
return false;
100+
}
101+
102+
if (output.swapchain_methods.size() <= 8 || !output.swapchain_methods[8]) {
103+
DEBUG_LOG("DX11Hook::InstallHook: Present method not found in vtable");
104+
return false;
105+
}
106+
107+
auto presentAddr = output.swapchain_methods[8];
108+
DEBUG_LOG("DX11Hook::InstallHook: Present found at %p", presentAddr);
109+
110+
MH_Initialize();
111+
if (MH_CreateHook(presentAddr, (void*)HookPresent, (void**)&OriginalPresent) != MH_OK
112+
|| MH_EnableHook(presentAddr) != MH_OK) {
113+
DEBUG_LOG("DX11Hook::InstallHook: MinHook failed");
114+
return false;
117115
}
118116

119-
DestroyWindow(dummy);
120-
UnregisterClassW(L"DX11HookDummy", wc.hInstance);
121-
return ok;
117+
DEBUG_LOG("DX11Hook::InstallHook: hook installed successfully");
118+
return true;
122119
}
123120
}
-314 KB
Binary file not shown.

0 commit comments

Comments
 (0)