HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ПРОГРАММИРОВАНИЕ > С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 05.01.2022, 06:54
kin4stat
Флудер
Регистрация: 06.11.2017
Сообщений: 2,759
С нами: 4483143

Репутация: 183


По умолчанию

  1. Создание ASI-плагина с нуля
  2. Хуки – что это такое и как с ними работать
  3. Безопасная инициализация и работа с SAMP
  4. Работа с рендером и Directx9
  5. Обработка событий окна + ImGui
В этом гайде будет рассказано про работу с событиями окна, а также их передачей в ImGui

При использовании на других ресурсах необходимо указание авторства и ссылки на оригинальную темы!

Все действия производились на Visual Studio 2019 с параметром /std:c++17, в других версиях интерфейс может отличаться.

И так, начнем:

Для этого гайда нам не нужно никаким образом настраивать проект и что-то в него добавлять. Можно воспользоваться готовым из гайда [4]

В Windows существует множество различных возможностей по работе с окнами(на то она и Windows). И чтобы все было максимально гибко, Windows может отдавать высокоуровневые события окон, и низкоуровневые. Про низкоуровневые события сегодня и пойдет речь.

Все события окна Windows присылает в коллбэк WindowProc. Сюда входят нажатия мышкой, нажатиян на клавиатуру, перемещение окна, изменение его размера, сворачивание, разворачивание и еще куча других событий(около 2000, если не ошибаюсь).

У каждого приложения должен быть создан коллбэк на события окна, иначе вы не сможете создать окно. Т.к. мы работаем внутри готового окна, нам нужно перехватывать уже существующий обработчик событий.

Делать это можно несколькими способами:
  1. Штатными средствами Windows
  2. Перехват самого первого коллбэка(нужно знать его адрес)
  3. Перехват самого последнего зарегистрированного коллбэка
В этом гайде я покажу все три способа.

Начнем с того, что для всех способов, кроме 2 нам нужен хендл окна. В общем случае нам придется получать его через "костыли" поиском по имени окна(FindWindow)

Начнем с того, что нам нужно получить HWND нашего окна. В GTA:SA его можно вытащить из внутренней структуры движка игры. Но просто вытаскивать HWND из структуры игры не всегда хорошая затея, особенно если мы хотим перехватывать события еще до полного запуска игры. Поэтому мы перехватим функцию, создающую окно игры и будем вытаскивать HWND оттуда.

Перейдем к созданию хука

Чтобы не гонять в холостую код, мы сделаем проверку на то, существует ли уже окно игры, и если оно уже создано - будем брать hwnd оттуда.

(На самом деле показанное - почти бесполезно. Но я все же посчитал нужным показать это, лишним точно не будет)

Также можно перехватывать CreateWindow, но там чуть больше заморочек, но зато способ универсальный, и будет работать везде

C++:





Код:
// Сигнатура
using
InitGameInstance
=
HWND
(
__cdecl
*
)
(
HINSTANCE
)
;
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
)
;
}
}
(
)
;


Наверное вы спросите, что произошло

game_hwnd - глобальная переменная. Все глобальные переменные инициализируются до перехода к основной функции программы(DllMain в нашем случае). А чтобы при инициализации переменной выполнился наш код с условиями - мы создаем лямбду, и сразу же ее вызываем, в итоге результат вызова нашей лямбды будет записан в переменную.

Теперь game_hwnd сама инициализируется, как только окно игры будет создано.

И уже сейчас мы можем перехватывать обработчик событий окна.

Начнем с самого простого способа - 3

Перехватывать текущий обработчик событий можно где угодно, но я буду делать это внутри хука Present. Это можно было бы сделать даже внутри game_instance_init_hook.

Чтобы получить текущий обработчик - воспользуемся функцией GetWindowLongPtr.

И так, создадим хук и воспользуемся сигнатурой, объявленной внутри WINAPI:

C++:





Код:
kthook
::
kthook_simple

wndproc_hook
{
}
;


Теперь, в инициализации directx9 мы будем устанавливать наш хук на последний зарегистрированный обработчик и повесим свой обработчик on_wndproc:

C++:





Код:
HRESULT __stdcall
on_wndproc
(
const
decltype
(
wndproc_hook
)
&
hook
,
HWND hwnd
,
UINT uMsg
,
WPARAM wParam
,
LPARAM lParam
)
{
// вызываем оригинал
return
hook
.
get_trampoline
(
)
(
hwnd
,
uMsg
,
wParam
,
lParam
)
;
}


C++:





Код:
auto
latest_wndproc_ptr
=
GetWindowLongPtrW
(
game_hwnd
,
GWLP_WNDPROC
)
;
wndproc_hook
.
set_dest
(
latest_wndproc_ptr
)
;
wndproc_hook
.
set_cb
(
&
on_wndproc
)
;
wndproc_hook
.
install
(
)
;


В данном случае важно использовать функцию с постфиксом W. Сломать что-то своим кодом будет сложно, а вот править ImGui в будущем - не лучшая идея.

Перехват функции игры примерно такой же, и т.к. мне лень писать 1 строку кода - попробуйте сделать это сами, адрес игровой функции -
Код:
0x747EB0
Также нужно учитывать, что функция игры будет самой последней в цепочке, и поэтому если кто-то зарегистрирует свой обработчик позже - вы можете не получить событие.

Ну и последний способ - зарегистрировать свой обработчик средствами Windows.

Код:
kthook::kthook_simple wndproc_hook{};
- Эту строку и все связанные с ней нужно будет удалить.

Добавляем переменную для хранения прошлого обработчика.

C++:





Код:
WNDPROC old_wndproc
{
}
;
HRESULT __stdcall
on_wndproc
(
const
decltype
(
wndproc_hook
)
&
hook
,
HWND hwnd
,
UINT uMsg
,
WPARAM wParam
,
LPARAM lParam
)
{
// вызываем оригинал
return
CallWindowProcA
(
old_wndproc
,
hwnd
,
uMsg
,
wParam
,
lParam
)
;
}


Ну и теперь вместо кода с установкой хука на основе kthook, пишем что-то такое:

C++:





Код:
old_wndproc
=
reinterpret_cast

(
SetWindowLongPtrA
(
game_hwnd
,
GWLP_WNDPROC
,
reinterpret_cast

(
&
on_wndproc
)
)
)
;


Внимательнее на строке возврата, код ниже показан на примере первого примера(да, тавтология)

Теперь попробуем обработать нажатие клавиши и вывести сообщение в чат.

C++:





Код:
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
;
}
}
// вызываем оригинал
return
hook
.
get_trampoline
(
)
(
hwnd
,
uMsg
,
wParam
,
lParam
)
;
}


Компилируем, запускаем, жмякаем F11 и видим сообщение в чате:

Цитата:
Сообщение от Спойлер  




Но у нас все еще осталась проблема - ImGui не будет обрабатывать наши нажатия.

Чтобы это сделать - нужно объявить обработчик ImGui, добавив где-нибудь такую строку:

C++:





Код:
extern
IMGUI_IMPL_API LRESULT
ImGui_ImplWin32_WndProcHandler
(
HWND hWnd
,
UINT msg
,
WPARAM wParam
,
LPARAM lParam
)
;


Ну, а теперь, чтобы все верно работало, нам нужно вызвать эту функцию внутри обработчика событий окон, и блокировать дальнейшую обработку клавиш, если ImGui хочет этого. Пример показан только ради показа, как это делать, в случае когда будут окна зависящие от булевой переменной - нужно будет обернуть это в
Код:
if (window_opened)
C++:





Код:
ImGui_ImplWin32_WndProcHandler
(
hwnd
,
uMsg
,
wParam
,
lParam
)
;
auto
&
io
=
ImGui
::
GetIO
(
)
;
if
(
io
.
WantCaptureKeyboard
||
io
.
WantCaptureMouse
)
{
return
1
;
}


Ну и теперь можем сделать тестовый пример:

C++:





Код:
ImGui
::
Begin
(
"Window"
)
;
if
(
ImGui
::
Button
(
"Click me!"
)
)
{
sampapi
::
v037r3
::
RefChat
(
)
->
AddChatMessage
(
""
,
0xFFFFFFFF
,
"Привет из ImGui!"
)
;
}
ImGui
::
End
(
)
;


Конпелируем, запускаем, жмякаем по кнопочкам, и видим что все работает:

Цитата:
Сообщение от Спойлер  




Но осталась одна проблема - ImGui расчитан на работу с wchar_t, который используется для UTF16 на windows, а обработчик событий нашего окна работает в CP_ACP кодировке. Чтобы это исправить, нам нужно конвертировать CP_ACP в UTF16 перед передачей в ImGui чтобы не видеть каракули при вводе.

Для этого, перед вызовом ImGui_ImplWin32_WndProcHandler, добавим такой код:

C++:





Код:
if
(
uMsg
==
WM_CHAR
)
{
wchar_t
wch
;
MultiByteToWideChar
(
CP_ACP
,
MB_PRECOMPOSED
,
reinterpret_cast

(
&
wParam
)
,
1
,
&
wch
,
1
)
;
wParam
=
wch
;
}


Цитата:
Сообщение от Спойлер  


C++:





Код:
#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
;
}


 
Ответить с цитированием

  #2  
Старый 31.08.2022, 00:35
loganhackerdff
Постоянный
Регистрация: 24.07.2017
Сообщений: 867
С нами: 4633764

Репутация: 148


По умолчанию

если хукать по 0x747EB0, то не приходят WM_SETFOCUS и WM_KILLFOCUS, мб ещё что-то, но гайд топовый

ну хукать типо onBefore, я urmem oм хукал

Зато есть хороший способ, он ещё позволяет при отгрузке dllки убрать хук, это Subclass -> https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-setwindowsubclass
 
Ответить с цитированием

  #3  
Старый 15.11.2022, 18:17
SADFI2259X
Познающий
Регистрация: 05.09.2021
Сообщений: 92
С нами: 2468408

Репутация: 18
По умолчанию

can anyone release this guide source code for me please
 
Ответить с цитированием

  #4  
Старый 15.11.2022, 18:34
AugustTN
Познавший АНТИЧАТ
Регистрация: 14.06.2021
Сообщений: 1,354
С нами: 2587494

Репутация: 88


По умолчанию

Цитата:
Сообщение от SADFI2259X  

can anyone release this guide source code for me please
C++:





Код:
#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
;
}


??
 
Ответить с цитированием

  #5  
Старый 17.11.2022, 15:28
SADFI2259X
Познающий
Регистрация: 05.09.2021
Сообщений: 92
С нами: 2468408

Репутация: 18
По умолчанию

Цитата:
Сообщение от Loocking  

C++:





Код:
#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
;
}


??
no i mean in visual studio can you send me the project in zip or rar file please ?
 
Ответить с цитированием

  #6  
Старый 07.01.2023, 23:57
AnWu
Флудер
Регистрация: 08.11.2017
Сообщений: 4,787
С нами: 4480376

Репутация: 183


По умолчанию

@kin4stat

C++:





Код:
case
DLL_PROCESS_DETACH
:
{
ImGui_ImplDX9_Shutdown
(
)
;
ImGui_ImplWin32_Shutdown
(
)
;
ImGui
::
DestroyContext
(
)
;
break
;
}
 
Ответить с цитированием

  #7  
Старый 29.06.2023, 16:57
SADFI2259X
Познающий
Регистрация: 05.09.2021
Сообщений: 92
С нами: 2468408

Репутация: 18
По умолчанию

how to see if the game is inited ?
 
Ответить с цитированием

  #8  
Старый 11.07.2025, 02:39
Smeruxa
Познавший АНТИЧАТ
Регистрация: 27.11.2020
Сообщений: 1,431
С нами: 2874035

Репутация: 183


По умолчанию

Цитата:
Сообщение от AnWu  

@kin4stat

C++:





Код:
case
DLL_PROCESS_DETACH
:
{
ImGui_ImplDX9_Shutdown
(
)
;
ImGui_ImplWin32_Shutdown
(
)
;
ImGui
::
DestroyContext
(
)
;
break
;
}

Это помогает отгрузить без краша? У меня нет
 
Ответить с цитированием

  #9  
Старый 11.07.2025, 04:00
ARMOR
Флудер
Регистрация: 02.02.2019
Сообщений: 5,070
С нами: 3831395

Репутация: 183


По умолчанию

Цитата:
Сообщение от Smeruxa  

Это помогает отгрузить без краша? У меня нет
ImGui_ImplDX9_InvalidateDeviceObjects в детач плагина вставь. Должно помочь
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.