Skip to content

Commit fd0c01a

Browse files
committed
feat(windows): multi-backend D3D hook with CMake + kiero2
- Replace vcxproj with CMake + MinGW build for native DLL - Add kiero2 & minhook as git submodules (D3D9/11/12/GL/VK support) - Implement C# bridge via ImGuiRenderer + NativeApi with P/Invoke callbacks - Use cimgui.dll for ImGui backend calls (no ImGui .cpp compiled in) - D3D12: descriptor heap + cmdList rendering - D3D11: Device + Context rendering - D3D9: Device rendering - GL/VK: detection only, C# render without GPU submit - CI: switch to windows-latest + MSYS2 MinGW, single dotnet build step - csproj: auto-invoke CMake before build, remove test copy targets - Remove all debug Log() calls, cleanup unused typedefs - Update README with multi-backend arch, third-party libs, Corehold guide - Update GET_STARTED with Windows DLL hijack instructions via Corehold
1 parent 50b1698 commit fd0c01a

20 files changed

Lines changed: 5760 additions & 28 deletions

‎.github/workflows/build.yml‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,38 @@ jobs:
4343
name: library-release.aar
4444
path: Android/library/build/outputs/aar/library-release.aar
4545

46-
# ──── Windows .NET DLL ────
46+
# ──── Windows Native + .NET DLL ────
4747
windows:
48-
name: Windows DLL
49-
runs-on: ubuntu-latest
48+
name: Windows
49+
runs-on: windows-latest
50+
defaults:
51+
run:
52+
shell: bash
5053
steps:
5154
- uses: actions/checkout@v4
5255
with:
5356
submodules: recursive
5457

58+
- name: Set up MSYS2 (MinGW)
59+
uses: msys2/setup-msys2@v2
60+
with:
61+
msystem: mingw64
62+
update: true
63+
install: >-
64+
mingw-w64-x86_64-gcc
65+
mingw-w64-x86_64-cmake
66+
mingw-w64-x86_64-toolchain
67+
5568
- name: Set up .NET 10
5669
uses: actions/setup-dotnet@v4
5770
with:
5871
dotnet-version: '10.0.x'
5972

60-
- name: Build Windows
73+
- name: Build (native + C#)
74+
shell: msys2 {0}
6175
run: dotnet build StArray.ModManager.Windows/StArray.ModManager.Windows.csproj -c Release
6276

63-
- name: Package output (exclude runtimes)
77+
- name: Package
6478
run: |
6579
src="StArray.ModManager.Windows/bin/Release/net10.0"
6680
dst="artifacts"
@@ -69,7 +83,7 @@ jobs:
6983
rm -rf "$dst/runtimes"
7084
cd "$dst" && zip -r ../windows-dll.zip . && cd ..
7185
72-
- name: Upload Windows DLL
86+
- name: Upload
7387
uses: actions/upload-artifact@v4
7488
with:
7589
name: windows-dll.zip

‎.gitignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
*.aab
99
*.ap_
1010

11+
# Native generated
12+
StArray.ModManager.Windows/Native/build/
13+
StArray.ModManager.Windows/Native/cimgui.def
14+
StArray.ModManager.Windows/Native/libcimgui.a
15+
1116
# Release artifacts
1217
/release/
1318

‎.gitmodules‎

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

‎GET_STARTED.md‎

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,58 @@
11
# Getting Started / 快速开始
22

3-
## 1. Inject into APK / 注入 APK
3+
## Windows / Windows 注入
4+
5+
通过 [Corehold](https://github.com/StArraySharp/Corehold) 的 `winmm.dll` 代理劫持自动加载 CoreCLR。
6+
7+
### 构建
8+
9+
```bash
10+
git clone --recurse-submodules https://github.com/StArraySharp/StArray.ModManager.git
11+
dotnet build StArray.ModManager.Windows -c Release
12+
```
13+
14+
### 部署
15+
16+
```bash
17+
# 1. 下载 Corehold 的 winmm.dll + Corehold/ 模板
18+
# https://github.com/StArraySharp/Corehold/releases
19+
20+
# 2. 放入游戏 .exe 同目录
21+
GameFolder/
22+
├── Game.exe
23+
├── winmm.dll # Corehold 代理 DLL
24+
└── Corehold/
25+
├── corehold.json
26+
├── managed/ # 放入我们的 DLL
27+
│ ├── StArray.ModManager.dll
28+
│ ├── StArray.ModManager.Windows.dll
29+
│ ├── StArray.ModManager.Windows.Native.dll
30+
│ ├── cimgui.dll
31+
│ └── ImGui.NET.dll
32+
└── runtime/ # 首次启动自动下载 .NET
33+
```
34+
35+
### corehold.json
36+
37+
```json
38+
{
39+
"enabled": true,
40+
"console_enabled": true,
41+
"runtime_path": "Corehold/runtime/",
42+
"coreclr_path": "Corehold/runtime/coreclr.dll",
43+
"target_assembly_path": "Corehold/managed/StArray.ModManager.Windows.dll",
44+
"entry_point_method": "StArray.ModManager.Windows.Managed.Entry",
45+
"entrypoint_string_args": ["Corehold/mods"]
46+
}
47+
```
48+
49+
### 运行
50+
51+
启动游戏 → `winmm.dll` 被加载 → Corehold 初始化 CoreCLR →
52+
`Managed.Entry` 调用 `NativeApi.Init` → kiero 检测 D3D9/11/12 →
53+
MinHook 钩 `Present` → C# 回调渲染 ImGui → 按 `INSERT` 打开菜单
54+
55+
## Android (IL2CPP Unity) / Android 注入
456

557
Download `library-release.aar` from [Releases](https://github.com/StArraySharp/StArray.ModManager/releases).
658
从 [Releases](https://github.com/StArraySharp/StArray.ModManager/releases) 下载 `library-release.aar`。
@@ -40,7 +92,7 @@ apktool b target_src -o repacked.apk
4092
uber-apk-signer --apks repacked.apk
4193
```
4294

43-
## 2. Deploy Manager / 部署管理器
95+
## 2. Deploy Manager (Android) / 部署管理器
4496

4597
Place manager DLL and dependencies in `/sdcard/ModManager/manager/`.
4698
将管理器 DLL 及依赖放入 `/sdcard/ModManager/manager/`。
@@ -66,7 +118,7 @@ Final layout / 最终目录:
66118
└── ...
67119
```
68120

69-
## 3. Write a Mod / 写一个 Mod
121+
## 3. Write a Mod / 写 Mod (跨平台)
70122

71123
Reference `StArray.ModManager.dll` → implement `IModPlugin` → build DLL → drop into `mods/{ModName}/`.
72124
引用 `StArray.ModManager.dll` → 实现 `IModPlugin` → 编译 DLL → 放入 `mods/{ModName}/`。

‎README.md‎

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,28 +56,70 @@ Android/library/ 原生库 (libmodmanager.so)
5656
- **IImGuiRenderer** interface — swap between EGL, Vulkan backends
5757
- **CoreCLR args** — pass `string[]` from Java to managed `Entry(int, IntPtr)`
5858

59+
## Third-Party Libraries
60+
61+
| Library | License | Used In |
62+
|---------|---------|---------|
63+
| [Dear ImGui](https://github.com/ocornut/imgui) | MIT | UI rendering |
64+
| [cimgui](https://github.com/cimgui/cimgui) | MIT | ImGui C API bindings |
65+
| [ImGui.NET](https://github.com/ImGuiNET/ImGui.NET) | MIT | C# ImGui bindings |
66+
| [kiero2](https://github.com/kirchesz/kiero2) | MIT | Graphics API detection (D3D9/11/12/GL/VK) |
67+
| [MinHook](https://github.com/TsudaKageyu/minhook) | BSD-2 | API hooking |
68+
| [Corehold](https://github.com/StArraySharp/Corehold) | MIT | winmm proxy DLL + CoreCLR hosting |
69+
| [Dobby](https://github.com/jmpews/Dobby) | Apache-2.0 | Android inline hook |
70+
| [CoreCLR](https://github.com/dotnet/runtime) | MIT | .NET runtime |
71+
| [FontAwesome 7](https://fontawesome.com) | OFL/SIL | Icon font |
72+
5973
## Build
6074

61-
Requires .NET 10 SDK and Android NDK 27+.
75+
Requires .NET 10 SDK + MinGW (gcc/cmake on PATH).
6276

6377
```bash
64-
# Build C# mod manager
65-
cd StArray.ModManager
66-
dotnet build -c Release
78+
# Windows (native + C#, one command)
79+
dotnet build StArray.ModManager.Windows -c Release
80+
81+
# Android
82+
cd Android && ./gradlew :library:assembleRelease
83+
```
6784

68-
# Build Android native library
69-
cd Android
70-
./gradlew :library:assembleRelease
85+
## Windows Architecture
86+
87+
The Windows native DLL (`StArray.ModManager.Windows.Native.dll`) uses
88+
[kiero2](https://github.com/kirchesz/kiero2) + [MinHook](https://github.com/TsudaKageyu/minhook) to
89+
detect and hook the game's graphics API at runtime.
90+
91+
| Backend | Support |
92+
|---------|---------|
93+
| D3D12 | Descriptor heap + Command list |
94+
| D3D11 | Device + Context |
95+
| D3D9 | Device |
96+
| OpenGL / Vulkan | Detected only |
97+
98+
The C# side (`ImGuiRenderer`) is backend-agnostic — it provides init/shutdown/render callbacks and
99+
the native DLL handles all platform-specific `ImGui_Impl*` setup.
100+
101+
```mermaid
102+
flowchart LR
103+
CSharp[C# ImGuiRenderer] -->|P/Invoke Init| Native[Native DLL]
104+
Native -->|kiero| API[D3D9/11/12]
105+
API -->|MinHook| Present[Present Hook]
106+
Present -->|callback| CSharp
107+
CSharp -->|ImGui.NET| cimgui[cimgui.dll]
71108
```
72109

73110
## Target
74111

75-
- Android arm64-v8a
76-
- IL2CPP Unity games (API 26+)
112+
- Windows x64 (D3D9/11/12) — DLL injection or CoreCLR hosting
113+
- Android arm64-v8a (OpenGL ES) — IL2CPP Unity games (API 26+)
77114
- CoreCLR .NET 10 runtime
78115

79116
## Getting Started
80117

118+
```bash
119+
git clone --recurse-submodules https://github.com/StArraySharp/StArray.ModManager.git
120+
dotnet build StArray.ModManager.Windows -c Release
121+
```
122+
81123
See [GET_STARTED.md](GET_STARTED.md) for injection and build instructions.
82124

83125
Runtime assemblies can be downloaded from the [runtime-references release](https://github.com/StArraySharp/StArray.ModManager/releases/tag/0).

‎StArray.ModManager.Windows/Managed.cs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ public static int Entry(int argc, IntPtr argv)
6666
Logger.Info($"{nameof(Managed)}-Benchmark", $"Path resolve: {Benchmark.End():F3}s");
6767
Il2CppFunctions.SetIl2CppLibraryPath(Path.Combine(new DirectoryInfo(modsPath).Parent.Parent.FullName,"GameAssembly.dll"));
6868
ModManagerUI modManagerUI = new(new ModLoader(modsPath), Path.GetDirectoryName(AssemblyPath));
69-
ImGUIGLRenderer.OnRender += modManagerUI.Render;
70-
ImGUIGLRenderer.Install();
69+
70+
// Use DX12 renderer — hooks IDXGISwapChain::Present via vtable + MinHook
71+
ImGuiRenderer.OnRender += modManagerUI.Render;
72+
ImGuiRenderer.Install();
7173
totalSw.Stop();
7274
Logger.Info($"{nameof(Managed)}-Benchmark", $"=== Startup total: {totalSw.Elapsed.TotalSeconds:F3}s ===");
7375
return 0;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
project(StArray.ModManager.Windows.Native LANGUAGES C CXX)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
7+
if(MSVC)
8+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
9+
endif()
10+
11+
# ---- MinHook (submodule, static lib) ----
12+
add_library(MinHook STATIC
13+
minhook/src/buffer.c
14+
minhook/src/hook.c
15+
minhook/src/trampoline.c
16+
minhook/src/hde/hde32.c
17+
minhook/src/hde/hde64.c
18+
)
19+
target_include_directories(MinHook PUBLIC minhook/include)
20+
target_compile_definitions(MinHook PRIVATE _CRT_SECURE_NO_WARNINGS)
21+
22+
# ---- kiero2 (submodule, static lib, all backends except D3D10) ----
23+
add_library(kiero STATIC
24+
kiero2/kiero_intern.cpp
25+
kiero2/kiero_d3d9.cpp
26+
kiero2/kiero_d3d11.cpp
27+
kiero2/kiero_d3d12.cpp
28+
kiero2/kiero_opengl.cpp
29+
kiero2/kiero_vulkan.cpp
30+
)
31+
target_include_directories(kiero PUBLIC kiero2)
32+
target_compile_definitions(kiero PRIVATE KIERO_BUILD_D3D9 KIERO_BUILD_D3D11 KIERO_BUILD_D3D12 KIERO_BUILD_OPENGL KIERO_BUILD_VULKAN)
33+
34+
# ---- Main hook DLL ----
35+
add_library(${PROJECT_NAME} SHARED main.cpp)
36+
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") # no "lib" prefix
37+
target_include_directories(${PROJECT_NAME} PRIVATE . kiero2 minhook/include)
38+
target_link_libraries(${PROJECT_NAME} PRIVATE kiero MinHook d3d12 dxgi ${CMAKE_CURRENT_SOURCE_DIR}/libcimgui.a)
39+
40+
# Copy DLL to C# build output
41+
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
42+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
43+
"$<TARGET_FILE:${PROJECT_NAME}>"
44+
"${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}/net10.0/"
45+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#undef NDEBUG

0 commit comments

Comments
 (0)