Об указателе на метод класса в С++
-
Привет всем.
Подскажите, нормально ли то, что я читаю указатель на метод класса с помощью ReadProcessMemory?
Более подходящего способа идентифицировать метод класса я не нашел и не придумал.Я заметил при разных тестах, при использовании Cheat Engine и его memory view, что адрес в параметре method - (VOID connect(VOID(T::* method)(VOID), T* object)), в разных проектах имеет разную вложенность. Например, в одном проекте этот method указывает на jmp инструкцию, перейдя по которой, я попадаю на метод класса, в другом проекте, method указывает на адрес, который содержит этот же jmp . Я честно говоря не понял, почему там так, а здесь иначе.
Вот псевдокод. Это самодельная система сигналов//слотов
#include <iostream> #include <utility> #include <type_traits> #include <Windows.h> #include <vector> class Button; class Widget; class Slot { public: virtual VOID call() = 0; virtual BOOL isContain(DWORD_PTR methodAddress, DWORD_PTR objectAddress) = 0; }; template <typename T> class SlotMethod : public Slot { public: SlotMethod(VOID(T::* method)(VOID), T* object, DWORD_PTR methodAddress, DWORD_PTR objectAddress) : method(method), object(object), methodAddress(methodAddress), objectAddress(objectAddress) {} public: virtual VOID call() override { ((*object).*method)(); } virtual BOOL isContain(DWORD_PTR methodAddress, DWORD_PTR objectAddress) { return (this->methodAddress == methodAddress && this->objectAddress == objectAddress); } private: VOID(T::* method)(VOID); T* object; DWORD_PTR methodAddress{ 0 }; DWORD_PTR objectAddress{ 0 }; }; class Event { public: template <class T> requires (std::is_base_of_v<Widget, std::remove_pointer_t<T>>) VOID connect(VOID(T::* method)(VOID), T* object) { if (method && object) { DWORD_PTR methodAddress{ 0 }; ReadProcessMemory(GetCurrentProcess(), &method, &methodAddress, sizeof(methodAddress), NULL); DWORD_PTR objectAddress{ reinterpret_cast<DWORD_PTR>(object) }; SlotMethod<T>* slotMethod{ new SlotMethod<T>{ method, object, methodAddress, objectAddress } }; listeners.emplace_back(slotMethod); } } template <class T> requires (std::is_base_of_v<Widget, std::remove_pointer_t<T>>) VOID disconnect(VOID(T::* method)(VOID), T* object) { if (method && object) { DWORD_PTR methodAddress{ 0 }; ReadProcessMemory(GetCurrentProcess(), &method, &methodAddress, sizeof(methodAddress), NULL); DWORD_PTR objectAddress{ reinterpret_cast<DWORD_PTR>(object) }; listeners.erase(std::remove_if(listeners.begin(), listeners.end(), [&](auto& listener) { Slot* slot{ listener }; BOOL isContain{ slot->isContain(methodAddress, objectAddress) }; if (isContain) { delete slot; } return isContain; }), listeners.end()); } } VOID callListeners() { for (auto& listener : listeners) { listener->call(); } } private: std::vector<Slot*> listeners; }; class Widget {}; class Button : public Widget { public: VOID onLButtonDown(VOID) { std::cout << "Button class - onLButtonDown method executed" << std::endl; onLButtonDownEvent.callListeners(); } public: Event onLButtonDownEvent{}; }; class ButtonCustom : public Button { public: VOID print(VOID) { std::cout << "I am a ButtonCustom method print" << std::endl; } }; int main() { Button* button = new Button{}; ButtonCustom* custom = new ButtonCustom{}; button->onLButtonDownEvent.connect(&ButtonCustom::print, custom); button->onLButtonDown(); button->onLButtonDownEvent.disconnect(&ButtonCustom::print, custom); return 0; }
-
@Antonshka
Можно без readProcessMemory такtemplate <typename T> requires EventConnectConcept<T> VOID Event::connect(EventStatus(T::* method)(EventMessage*), T* listener, BOOL mustSkipIfDuplicate) { ... CONST auto* CONST methodAddress = *reinterpret_cast<VOID**>(&method); ... } class MyWindow : public Window { MyWindow () : openSomething(new SButton(TRUE, 0, 0, L"Open Something", 10, 10, 100, 30, this)) { openSomething->onLButtonUp->connect(&MyWindow ::someMethod, this); ... } ... private: EventStatus someMethod(EventMessage* message); private: SButton* CONST openSomething{}; }