Другое С/С++ Вопрос - Ответ

sc6ut

неизвестный
Модератор
382
1,075
Тим, напиши пожалуйста как можно заменить эти 11 строк твоими 2
C++:
void add_chat_message(DWORD dwColor, LPCSTR szString, ...)
{
    va_list ap;

    char msg[/* SAMP_MAX_CHAT_MESSAGE*/ 144] = { 0 };
    va_start(ap, szString);
    vsprintf_s(msg, szString, ap);
    va_end(ap);

    DWORD base = reinterpret_cast<DWORD>(GetModuleHandleW(L"samp.dll"));
    typedef void(__thiscall* CChat__AddEntry)(void*, int, char*, char*, DWORD, DWORD);
    reinterpret_cast<CChat__AddEntry>(base + /* SAMP_PTR_FUNC_ADDTOCHATWND */ 0x64010)(*reinterpret_cast<void**>(base + /* SAMP_PTR_CHAT_INFO */ 0x21A0E4), 8, msg, 0, dwColor, 0);
}
11 строк вместо 2х
почему 2? можно и 1 😀
 
Последнее редактирование:
  • Нравится
Реакции: Vintik и bottom_text

Sana_Minotazaki

Участник
75
2
Почему не работает? Вроде же все норм делаю или нет? Когда нажимаю H игра просто виснет @SC6UT @KiN4StAt help pls
вот это:
#include <Windows.h>
#include "main.h"

SAMPFUNCS *SF = new SAMPFUNCS();

void __stdcall mainloop()
{
    static bool initialized = false;
    static bool activated = false;
    if (!initialized)
    {
        if (GAME && GAME->GetSystemState() == eSystemState::GS_PLAYING_GAME && SF->getSAMP()->IsInitialized())
        {
            initialized = true;
            SF->getSAMP()->getChat()->AddChatMessage(D3DCOLOR_XRGB(0, 0xAA, 0), "SAMPFUNCS Plugin loaded.");
        }
    }
    if (SF->getGame()->isKeyPressed('H'))
    {
        activated = true;
    }
    while (activated)
    {
        SF->getSAMP()->getPlayers()->pLocalPlayer->Say("/edit");
        Sleep(2500);
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
    if (dwReasonForCall == DLL_PROCESS_ATTACH)
        SF->initPlugin(mainloop, hModule);
    return TRUE;
}
 
Последнее редактирование:

sc6ut

неизвестный
Модератор
382
1,075
игра просто виснет
нельзя делать Sleep в mainloop, ты останавливаешь всю игру, а не только свой плагин. так же нельзя делать while в mainloop, да и нет смысла, так как mainloop вызывается постоянно. используй if и GetTickCount (функция которая берет текущее количество пройденых милисекунд с запуска системы, 1000 милисекунд = 1 секунда), вот так:
C++:
#include "main.h"

SAMPFUNCS *SF = new SAMPFUNCS();

void __stdcall mainloop()
{
    static bool initialized = false;
    static bool activated = false;
    static DWORD dwTime = 0;
    if (!initialized)
    {
        if (GAME && GAME->GetSystemState() == eSystemState::GS_PLAYING_GAME && SF->getSAMP()->IsInitialized())
        {
            initialized = true;
            SF->getSAMP()->getChat()->AddChatMessage(D3DCOLOR_XRGB(0, 0xAA, 0), "SAMPFUNCS Plugin loaded.");
        }
    }
    else
    {
        if (SF->getGame()->isKeyPressed('H'))
        {
            // активирует и деактивирует на ту же кнопку
            activated = !activated;
        }
        if (activated && GetTickCount() - dwTime >= /* время ожидания */ 2500)
        {
            SF->getSAMP()->getPlayers()->pLocalPlayer->Say("/edit");
            dwTime = GetTickCount();
        }
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
    if (dwReasonForCall == DLL_PROCESS_ATTACH)
        SF->initPlugin(mainloop, hModule);
    return TRUE;
}
 
Последнее редактирование:

Sana_Minotazaki

Участник
75
2
нельзя делать Sleep в mainloop, ты останавливаешь всю игру, а не только свой плагин. так же нельзя делать while в mainloop, да и нет смысла, так как mainloop вызывается постоянно. используй if и GetTickCount (функция которая берет текущее количество пройденых милисекунд с запуска системы, 1000 милисекунд = 1 секунда), вот так:
C++:
#include "main.h"

SAMPFUNCS *SF = new SAMPFUNCS();

void __stdcall mainloop()
{
    static bool initialized = false;
    static bool activated = false;
    static DWORD dwTime = 0;
    if (!initialized)
    {
        if (GAME && GAME->GetSystemState() == eSystemState::GS_PLAYING_GAME && SF->getSAMP()->IsInitialized())
        {
            initialized = true;
            SF->getSAMP()->getChat()->AddChatMessage(D3DCOLOR_XRGB(0, 0xAA, 0), "SAMPFUNCS Plugin loaded.");
        }
    }
    else
    {
        if (SF->getGame()->isKeyPressed('H'))
        {
            // активирует и деактивирует на ту же кнопку
            activated = !activated;
        }
        if (activated && GetTickCount() - dwTime > /* время ожидания */2500)
        {
            SF->getSAMP()->getPlayers()->pLocalPlayer->Say("/edit");
            dwTime = GetTickCount();
        }
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
    if (dwReasonForCall == DLL_PROCESS_ATTACH)
        SF->initPlugin(mainloop, hModule);
    return TRUE;
}
Игра уже не виснет, но команда отправляется только тогда когда я жму H а не циклически как хотелось
 

sc6ut

неизвестный
Модератор
382
1,075
Игра уже не виснет, но команда отправляется только тогда когда я жму H а не циклически как хотелось
команда отправляется каждые 2.5 секунды, можешь проверить это добавлением логгированием в месте отправления команды
1610554444624.png

решил добавить фикс краша по адрессу 0x0072CD14 в сф плагин. заметил, что при отгрузке плагина через pfree или просто выходе из игры, то функция хука пропадает быстрее, чем сам хук снимается и игра крашится. когда я делал тоже самое в проекте с аси плагином, то всё было окей. как можно это исправить?
хук я ставлю в DLL_PROCESS_ATTACH, а снимаю в DLL_PROCESS_DETACH.
 

SR_team

like pancake
BH Team
4,720
6,365
решил добавить фикс краша по адрессу 0x0072CD14 в сф плагин. заметил, что при отгрузке плагина через pfree или просто выходе из игры, то функция хука пропадает быстрее, чем сам хук снимается и игра крашится. когда я делал тоже самое в проекте с аси плагином, то всё было окей. как можно это исправить?
хук я ставлю в DLL_PROCESS_ATTACH, а снимаю в DLL_PROCESS_DETACH.
У SF плагинов есть специальный коллбек, который выполняется перед выгрузкой
 
  • Нравится
Реакции: sc6ut

sc6ut

неизвестный
Модератор
382
1,075
специальный коллбек
не нахожу, можешь ткнуть пальцем пожалуйста

Как мне в сф сделать onServerMessage как в луа?
регистрируешь в mainloop коллбек на приходящие rpc, читаешь данные, взаимодействуешь:
C++:
// регистрируем коллбек в mainloop
SF->getRakNet()->registerRakNetCallback(RAKHOOK_TYPE_INCOMING_RPC, incomingRPC);

bool CALLBACK incomingRPC(stRakNetHookParams* params)
{
    // проверяем что пришло рпц сообщения в чат по id
    if (params->packetId == RPC_ScrClientMessage)
    {
        DWORD color; // цвет
        DWORD length; // длинна сообщения
        char message[256]; // сообщение

        // читаем данные
        params->bitStream->ResetReadPointer();
        params->bitStream->Read(color);
        params->bitStream->Read(length);
        params->bitStream->Read(message, length);
        message[length] = '\0'; // ставим в конце массава NULL чтобы превратить наш массив символов в стринг

        // взаимодействуем
    }
    return true; // возвращаем true чтобы рпц принимались
}
 
  • Нравится
Реакции: frit

ishi

Известный
493
110
Пытаюсь реализовать класс с функцией, способной вызывать другие функции по адресам, но компилятор ругается:
Код:
результатом вычисления фрагмента не является функция, принимающая 4 аргументов
Вот, что я пытался ему впарить:
C++:
class user32
{
    char* base_address;

    template <typename function>
    void call(function func, int a,const char* b, const char* c, long d)
    {
        func(a, b, c, d)();
    }
public:
    user32()
    {
        base_address = (char*)GetModuleHandleA("user32.dll");
    }
    void MessageBoxA(int a, const char* b, const char* c, long d)
    {

        call((base_address + 0x77B30),a,b,c,d);
    }
};

Копаясь в интернете, я понял, что можно как-то сделать, чтобы функция объявлялась как обычная статическая и перекидывала аргументы через fastcall, stdcall и т.д., типа ты её объявил в переменной, но аргументы перекинул как в статическую и всё на ок сработало, но в тех громоздких конструкциях я так и не нашёл минималистичного примера, который смог бы понять. Всё как-то слишком уж перегружено
Отчаянно нуждаюсь в помощи в понимании этого механизма

то, что я уже написал, это попытка сделать прямой вызов MessageBoxA, не используя исходники, но зная оффсет в библиотеке (для чего и нужна эта функция в принципе)
 

memir

🇷🇺
Всефорумный модератор
333
597

Пытаюсь реализовать класс с функцией, способной вызывать другие функции по адресам, но компилятор ругается:
Код:
результатом вычисления фрагмента не является функция, принимающая 4 аргументов
Вот, что я пытался ему впарить:
C++:
class user32
{
    char* base_address;

    template <typename function>
    void call(function func, int a,const char* b, const char* c, long d)
    {
        func(a, b, c, d)();
    }
public:
    user32()
    {
        base_address = (char*)GetModuleHandleA("user32.dll");
    }
    void MessageBoxA(int a, const char* b, const char* c, long d)
    {

        call((base_address + 0x77B30),a,b,c,d);
    }
};

Копаясь в интернете, я понял, что можно как-то сделать, чтобы функция объявлялась как обычная статическая и перекидывала аргументы через fastcall, stdcall и т.д., типа ты её объявил в переменной, но аргументы перекинул как в статическую и всё на ок сработало, но в тех громоздких конструкциях я так и не нашёл минималистичного примера, который смог бы понять. Всё как-то слишком уж перегружено
Отчаянно нуждаюсь в помощи в понимании этого механизма

то, что я уже написал, это попытка сделать прямой вызов MessageBoxA, не используя исходники, но зная оффсет в библиотеке (для чего и нужна эта функция в принципе)
C++:
#include <Windows.h>

class user32
{
    using TypeMessageBoxA = int(__stdcall *)(HWND, LPCSTR, LPCSTR, UINT);
    TypeMessageBoxA messageBoxA;
  
    template <typename F, typename... Args>
    void call(F f, Args... args)
    {
        f(args...);
    }
public:
    user32()
    {
        auto user32Module = LoadLibraryA("user32.dll");
        messageBoxA = reinterpret_cast<TypeMessageBoxA>(
            GetProcAddress(user32Module, "MessageBoxA"));
    }
    void MessageBoxA(HWND a, LPCSTR b, LPCSTR c, UINT d)
    {

        call(messageBoxA, a, b, c, d);
    }
};

int main()
{
    user32 obj;
    obj.MessageBoxA(NULL,
                    "Resource not available\nDo you want to try again?",
                    "Account details",
                    MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
    return 0;
}
Компилятор вычисляет тип (base_address + 0x77B30) и получает char *, а затем пытается вызвать его с четырьмя аргументами. Это приводит к ошибке.
Ты должен кастить base_address + 0x77B30, в void(__stdcall *)(int a, const char* b, const char* c, long d) чтобы всё заработало.
А ещё я бы посоветовал заменить a b c d в user32::call на вариативный шаблон с аргументами.
И у тебя скобочки в вызове лишние...
 
  • Нравится
Реакции: 4el0ve4ik и ishi

nomio

Известный
551
208
Охх как я люблю имуги,решил на плюсах пощупать имгуи,вставил рабочий код,имуги в папку с проектом,настройки для компиляции выставил.Компилирую - ошибки.Ставил старые,новые имуги,тыкал все что надо и все что не надо и в итоге пишу сюда

Visual Studio 2019
Imgui последней версии(на 1.63 такая же хуйня)
Найстроки проекта для компиляции стоят нормальные,компилил без имуги и все работало

Ошибки:
Папка с имуги файлами:
Код:

C++:
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS 1
#include "main.h"
#include "imgui/imgui.h"
#include "imgui/imgui_impl_dx9.h"
#include "imgui/imgui_impl_win32.h"
#include <d3d9.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <tchar.h>
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

SAMPFUNCS* SF = new SAMPFUNCS();

void CALLBACK PluginFree()
{
    ImGui_ImplDX9_Shutdown();
    ImGui_ImplWin32_Shutdown();
    ImGui::DestroyContext();
}

bool CALLBACK WndProcHandler(HWND hwd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    ImGui_ImplWin32_WndProcHandler(hwd, msg, wParam, lParam);
    return true;
}

HRESULT CALLBACK Reset(D3DPRESENT_PARAMETERS* pPresentationParameters)
{
    ImGui_ImplDX9_InvalidateDeviceObjects();
    return true;
}

bool CALLBACK Present(CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
{
    if (SUCCEEDED(SF->getRender()->BeginRender()))
    {
        static bool menu = true, checkbox;
        ImGui_ImplDX9_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();
        ImGui::SetNextWindowSize(ImVec2(228, 228));
        ImGui::Begin("123", &menu, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
        {
            ImGui::Checkbox("111", &checkbox);
        }
        ImGui::End();
        ImGui::EndFrame();
        ImGui::Render();
        ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
        SF->getRender()->EndRender();
    }
    return true;
}


void CALLBACK mainloop()
{
    static bool init = false;
    if (!init)
    {
        if (GAME == nullptr)
            return;
        if (GAME->GetSystemState() != eSystemState::GS_PLAYING_GAME)
            return;
        if (!SF->getSAMP()->IsInitialized())
            return;
        ImGui::CreateContext();
        ImGui_ImplWin32_Init(GetActiveWindow());
        ImGui_ImplDX9_Init(SF->getRender()->getD3DDevice());
        SF->getRender()->registerD3DCallback(eDirect3DDeviceMethods::D3DMETHOD_PRESENT, Present);
        SF->getRender()->registerD3DCallback(eDirect3DDeviceMethods::D3DMETHOD_RESET, Reset);
        SF->getGame()->registerWndProcCallback(SFGame::MEDIUM_CB_PRIORITY, WndProcHandler);
        SF->getGame()->registerGameDestructorCallback(PluginFree);
        init = true;
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
    if (dwReasonForCall == DLL_PROCESS_ATTACH)
        SF->initPlugin(mainloop, hModule);

    return TRUE;
}