Код:
#include
#include
#include "d3d9.h"
#include "kthook/kthook.hpp"
#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h"
#include "sampapi/CChat.h"
extern
IMGUI_IMPL_API LRESULT
ImGui_ImplWin32_WndProcHandler
(
HWND hWnd
,
UINT msg
,
WPARAM wParam
,
LPARAM lParam
)
;
// Сигнатуры функций
using
PresentSignature
=
HRESULT
(
__stdcall
*
)
(
IDirect3DDevice9
*
,
const
RECT
*
,
const
RECT
*
,
HWND
,
const
RGNDATA
*
)
;
using
ResetSignature
=
HRESULT
(
__stdcall
*
)
(
IDirect3DDevice9
*
,
D3DPRESENT_PARAMETERS
*
)
;
using
InitGameInstance
=
HWND
(
__cdecl
*
)
(
HINSTANCE
)
;
std
::
uintptr_t
find_device
(
std
::
uint32_t
Len
)
{
static
std
::
uintptr_t base
=
[
]
(
std
::
size_t Len
)
{
std
::
string
path_to
(
MAX_PATH
,
'\0'
)
;
if
(
auto
size
=
GetSystemDirectoryA
(
path_to
.
data
(
)
,
MAX_PATH
)
)
{
path_to
.
resize
(
size
)
;
path_to
+=
"\\d3d9.dll"
;
std
::
uintptr_t dwObjBase
=
reinterpret_cast
(
LoadLibraryA
(
path_to
.
c_str
(
)
)
)
;
while
(
dwObjBase
++
(
dwObjBase
+
0x00
)
==
0x06C7
&&
*
reinterpret_cast
(
dwObjBase
+
0x06
)
==
0x8689
&&
*
reinterpret_cast
(
dwObjBase
+
0x0C
)
==
0x8689
)
{
dwObjBase
+=
2
;
break
;
}
}
return
dwObjBase
;
}
return
std
::
uintptr_t
(
0
)
;
}
(
Len
)
;
return
base
;
}
void
*
get_function_address
(
int
VTableIndex
)
{
return
(
*
reinterpret_cast
(
find_device
(
0x128000
)
)
)
[
VTableIndex
]
;
}
kthook
::
kthook_signal
game_instance_init_hook
{
0x745560
}
;
HWND game_hwnd
=
[
]
(
)
{
// Указатель на HWND внутри движка игры
HWND
*
hwnd_ptr
=
*
reinterpret_cast
(
0xC17054
)
;
if
(
hwnd_ptr
!=
nullptr
)
{
return
*
hwnd_ptr
;
}
else
{
// Ставим коллбэк после выполенение оригинальной функции, т.к. нам нужен ее возврат
game_instance_init_hook
.
after
+=
[
]
(
const
auto
&
hook
,
HWND
&
return_value
,
HINSTANCE inst
)
{
// присваиваем нашей переменной значение, что вернула нам функция
game_hwnd
=
return_value
;
}
;
return
HWND
(
0
)
;
}
}
(
)
;
// Создаем хуки и сразу же инициализируем их на адреса в d3d9.dll
kthook
::
kthook_signal
present_hook
{
get_function_address
(
17
)
}
;
kthook
::
kthook_signal
reset_hook
{
get_function_address
(
16
)
}
;
kthook
::
kthook_simple
wndproc_hook
{
}
;
HRESULT __stdcall
on_wndproc
(
const
decltype
(
wndproc_hook
)
&
hook
,
HWND hwnd
,
UINT uMsg
,
WPARAM wParam
,
LPARAM lParam
)
{
switch
(
uMsg
)
{
// если событие - нажатие клавиши
case
WM_KEYDOWN
:
{
// если кнопка F11 и клавиша не повторялась до этого(нажата в первый раз)
if
(
wParam
==
VK_F11
&&
(
HIWORD
(
lParam
)
&
KF_REPEAT
)
!=
KF_REPEAT
)
{
sampapi
::
v037r3
::
RefChat
(
)
->
AddChatMessage
(
""
,
0xFFFFFFFF
,
"Привет из WNDPROC!"
)
;
}
break
;
}
}
if
(
uMsg
==
WM_CHAR
)
{
wchar_t
wch
;
MultiByteToWideChar
(
CP_ACP
,
MB_PRECOMPOSED
,
reinterpret_cast
(
&
wParam
)
,
1
,
&
wch
,
1
)
;
wParam
=
wch
;
}
ImGui_ImplWin32_WndProcHandler
(
hwnd
,
uMsg
,
wParam
,
lParam
)
;
auto
&
io
=
ImGui
::
GetIO
(
)
;
if
(
io
.
WantCaptureKeyboard
||
io
.
WantCaptureMouse
)
{
return
1
;
}
// вызываем оригинал
return
hook
.
get_trampoline
(
)
(
hwnd
,
uMsg
,
wParam
,
lParam
)
;
}
std
::
optional
on_present
(
const
decltype
(
present_hook
)
&
hook
,
IDirect3DDevice9
*
device_ptr
,
const
RECT
*
,
const
RECT
*
,
HWND
,
const
RGNDATA
*
)
{
static
bool
ImGui_inited
=
false
;
if
(
!
ImGui_inited
)
{
// Создаем имгуи контекст
ImGui
::
CreateContext
(
)
;
// Инициализируем OS зависимую часть(обрабатывает открытие шрифтов, обработку нажатия клавиш и т.д.)
ImGui_ImplWin32_Init
(
game_hwnd
)
;
// Инициализируем render framework зависимую часть(обрабатывает отрисовку на экране, создание текстур шрифтов и т.д.)
ImGui_ImplDX9_Init
(
device_ptr
)
;
auto
latest_wndproc_ptr
=
GetWindowLongPtrA
(
game_hwnd
,
GWLP_WNDPROC
)
;
wndproc_hook
.
set_dest
(
latest_wndproc_ptr
)
;
wndproc_hook
.
set_cb
(
&
on_wndproc
)
;
wndproc_hook
.
install
(
)
;
ImGui_inited
=
true
;
}
// Инициализируем render часть для нового кадра
ImGui_ImplDX9_NewFrame
(
)
;
// Инициализируем OS часть для нового кадра
ImGui_ImplWin32_NewFrame
(
)
;
// Создаем новый кадр внутри ImGui
ImGui
::
NewFrame
(
)
;
// получаем дравлист
auto
drawlist
=
ImGui
::
GetBackgroundDrawList
(
)
;
// Вычисляем размер текста
std
::
string text
{
"Hello from kin4!"
}
;
ImVec2 text_size
=
ImGui
::
CalcTextSize
(
text
.
c_str
(
)
)
;
// Рисуем прямоугольник с от 0;0 до text_size + 20; text_size + 20 белого цвета и закруглением 5 пикселей
drawlist
->
AddRectFilled
(
ImVec2
(
0
,
0
)
,
ImVec2
(
text_size
.
x
+
20.0f
,
text_size
.
y
+
20.0f
)
,
0xFFFFFFFF
,
5.0f
)
;
// Вычисляем позицию текста
ImVec2 pos
{
10.0f
,
10.0f
}
;
ImVec4 text_color
{
1.0f
,
0.0f
,
0.0f
,
1.0f
}
;
// Рисуем текст
drawlist
->
AddText
(
pos
,
ImGui
::
GetColorU32
(
text_color
)
,
text
.
c_str
(
)
)
;
ImGui
::
Begin
(
"Window"
)
;
if
(
ImGui
::
Button
(
"Click me!"
)
)
{
sampapi
::
v037r3
::
RefChat
(
)
->
AddChatMessage
(
""
,
0xFFFFFFFF
,
"Привет из ImGui!"
)
;
}
ImGui
::
End
(
)
;
// Завершаем кадр ImGui
ImGui
::
EndFrame
(
)
;
// Рендерим ImGuiв внутренний буффер
ImGui
::
Render
(
)
;
// Отдаем Directx внутренний буффер на рендер
ImGui_ImplDX9_RenderDrawData
(
ImGui
::
GetDrawData
(
)
)
;
return
std
::
nullopt
;
// не нужно прерывать выполнение
}
std
::
optional
on_lost
(
const
decltype
(
reset_hook
)
&
hook
,
IDirect3DDevice9
*
device_ptr
,
D3DPRESENT_PARAMETERS
*
parameters
)
{
ImGui_ImplDX9_InvalidateDeviceObjects
(
)
;
return
std
::
nullopt
;
// не нужно прерывать выполнение
}
void
on_reset
(
const
decltype
(
reset_hook
)
&
hook
,
HRESULT
&
return_value
,
IDirect3DDevice9
*
device_ptr
,
D3DPRESENT_PARAMETERS
*
parameters
)
{
}
BOOL APIENTRY
DllMain
(
HMODULE hModule
,
DWORD ul_reason_for_call
,
LPVOID lpReserved
)
{
switch
(
ul_reason_for_call
)
{
case
DLL_PROCESS_ATTACH
:
{
DisableThreadLibraryCalls
(
hModule
)
;
present_hook
.
before
+=
on_present
;
reset_hook
.
before
+=
on_lost
;
reset_hook
.
after
+=
on_reset
;
break
;
}
case
DLL_PROCESS_DETACH
:
break
;
}
return
TRUE
;
}