<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Об указателе на метод класса в С++]]></title><description><![CDATA[<p dir="auto">Привет всем.<br />
Подскажите, нормально ли то, что я читаю указатель на метод класса с помощью ReadProcessMemory?<br />
Более подходящего способа идентифицировать метод класса я не нашел и не придумал.</p>
<p dir="auto">Я заметил при разных тестах, при использовании Cheat Engine и его memory view, что адрес в параметре method - (VOID connect(VOID(T::* method)(VOID), T* object)), в разных проектах имеет разную вложенность. Например, в одном проекте этот method указывает на jmp инструкцию, перейдя по которой, я попадаю на метод класса, в другом проекте, method указывает на адрес, который содержит этот же jmp . Я честно говоря не понял, почему там так, а здесь иначе.</p>
<p dir="auto">Вот псевдокод. Это самодельная система сигналов//слотов</p>
<pre><code>#include &lt;iostream&gt;
#include &lt;utility&gt;
#include &lt;type_traits&gt;
#include &lt;Windows.h&gt;
#include &lt;vector&gt;


class Button;
class Widget;


class Slot {
public:
    virtual VOID call() = 0;
    virtual BOOL isContain(DWORD_PTR methodAddress, DWORD_PTR objectAddress) = 0;
};


template &lt;typename T&gt;
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-&gt;methodAddress == methodAddress &amp;&amp; this-&gt;objectAddress == objectAddress);
    }
private:
    VOID(T::* method)(VOID);
    T* object;
    DWORD_PTR methodAddress{ 0 };
    DWORD_PTR objectAddress{ 0 };
};


class Event {
public:
    template &lt;class T&gt;
    requires (std::is_base_of_v&lt;Widget, std::remove_pointer_t&lt;T&gt;&gt;)
        VOID connect(VOID(T::* method)(VOID), T* object) {
        if (method &amp;&amp; object) {
            DWORD_PTR methodAddress{ 0 };
            ReadProcessMemory(GetCurrentProcess(), &amp;method, &amp;methodAddress, sizeof(methodAddress), NULL);
            DWORD_PTR objectAddress{ reinterpret_cast&lt;DWORD_PTR&gt;(object) };
            SlotMethod&lt;T&gt;* slotMethod{ new SlotMethod&lt;T&gt;{ method, object, methodAddress, objectAddress } };
            listeners.emplace_back(slotMethod);
        }
    }

    template &lt;class T&gt;
    requires (std::is_base_of_v&lt;Widget, std::remove_pointer_t&lt;T&gt;&gt;)
    VOID disconnect(VOID(T::* method)(VOID), T* object) {
        if (method &amp;&amp; object) {
            DWORD_PTR methodAddress{ 0 };
            ReadProcessMemory(GetCurrentProcess(), &amp;method, &amp;methodAddress, sizeof(methodAddress), NULL);
            DWORD_PTR objectAddress{ reinterpret_cast&lt;DWORD_PTR&gt;(object) };
            listeners.erase(std::remove_if(listeners.begin(), listeners.end(), [&amp;](auto&amp; listener) {
                Slot* slot{ listener };
                BOOL isContain{ slot-&gt;isContain(methodAddress, objectAddress) };
                if (isContain) {
                    delete slot;
                }
                return isContain;
                }), listeners.end());
        }
    }

    VOID callListeners() {
        for (auto&amp; listener : listeners) {
            listener-&gt;call();
        }
    }
private:
    std::vector&lt;Slot*&gt; listeners;
};


class Widget {};


class Button : public Widget {
public:
    VOID onLButtonDown(VOID) {
        std::cout &lt;&lt; "Button class - onLButtonDown method executed" &lt;&lt; std::endl;
        onLButtonDownEvent.callListeners();
    }
public:
    Event onLButtonDownEvent{};
};


class ButtonCustom : public Button {
public:
    VOID print(VOID) {
        std::cout &lt;&lt; "I am a ButtonCustom method print" &lt;&lt; std::endl;
    }
};


int main() {
    Button* button = new Button{};
    ButtonCustom* custom = new ButtonCustom{};
    button-&gt;onLButtonDownEvent.connect(&amp;ButtonCustom::print, custom);
    button-&gt;onLButtonDown();
    button-&gt;onLButtonDownEvent.disconnect(&amp;ButtonCustom::print, custom);
    return 0;
}
</code></pre>
]]></description><link>https://gamehacklab.ru/bb/topic/81/об-указателе-на-метод-класса-в-с</link><generator>RSS for Node</generator><lastBuildDate>Tue, 10 Mar 2026 12:54:31 GMT</lastBuildDate><atom:link href="https://gamehacklab.ru/bb/topic/81.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 06 Oct 2023 14:04:38 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Об указателе на метод класса в С++ on Fri, 15 Mar 2024 09:40:45 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="https://gamehacklab.ru/bb/uid/143">@Antonshka</a><br />
Можно без readProcessMemory так</p>
<pre><code>template &lt;typename T&gt; requires EventConnectConcept&lt;T&gt;
VOID Event::connect(EventStatus(T::* method)(EventMessage*), T* listener, BOOL mustSkipIfDuplicate) {
...
CONST auto* CONST methodAddress = *reinterpret_cast&lt;VOID**&gt;(&amp;method);
...
}

class MyWindow : public Window {
MyWindow () :
   openSomething(new SButton(TRUE, 0, 0, L"Open Something", 10, 10, 100, 30, this))
{
   openSomething-&gt;onLButtonUp-&gt;connect(&amp;MyWindow ::someMethod, this);
 ...
}
...
private:
EventStatus someMethod(EventMessage* message);
private:
SButton* CONST openSomething{};
}

</code></pre>
]]></description><link>https://gamehacklab.ru/bb/post/794</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/794</guid><dc:creator><![CDATA[Antonshka]]></dc:creator><pubDate>Fri, 15 Mar 2024 09:40:45 GMT</pubDate></item></channel></rss>