Здравствуйте diov, Вы писали:
D>Конечно, полученное решение далеко от совершенства, но оно работает. Вот во что это вылилось :
Начинаем в срочном порядке исправлять огрехи :
D>event_handler.h
D>template <class Hoster>
D>union TMethod
D>{
D>#define METHOD_ADDRESS(class_method) ((void *)(TMethod<CTest>(TMethod<CTest>::Ptr(class_method))))
Ошибка. Вместо этого должно было быть :
#define METHOD_ADDRESS(C, M) ((void *)(TMethod<C>(TMethod<C>::Ptr(M))))
и использовать надо бы так : METHOD_ADDRESS(CTest, MegaQ)
НО ! Все это не нужно теперь, поскольку оказалось возможным обойтись БЕЗ шаблонов.
Вот как должно быть :
//-------------------------------------------------------------------
class CEmpty {};
union UMethod
{
typedef HRESULT (STDCALL CEmpty::*Ptr)();
Ptr pMethod;
DWORD dwAddress;
void * pVoid;
inline UMethod() :
pVoid(0)
{}
inline UMethod(Ptr method) :
pMethod(method)
{}
inline operator DWORD () {
return dwAddress;
}
inline operator void * () {
return pVoid;
}
};
// Macro for retrieving method address
// Example : METHOD_ADDRESS(CTest::MegaQ)
// Returns (void *)
#undef METHOD_ADDRESS
#define METHOD_ADDRESS(class_method) ((void *)(UMethod(UMethod::Ptr(class_method))))
//-------------------------------------------------------------------
D>class CEventHandler {
В этом классе — без изменений
D>event_handler.cpp
Тут тоже ничего не менялось...
D>main.cpp
#include <windows.h> // в прошлый раз эта строчка потерялась
#include "event_handler.h"
class CTest
{
private :
public :
HRESULT STDCALL MegaQ(int a, int b, int * c) {
* c = a + b;
return S_OK;
}
HRESULT STDCALL MegaZ(char * psz, int b) {
* psz = char(b);
return S_OK;
}
};
//-------------------------------------------------------------------
int main(int argc, char * argv[])
{
CTest o;
CEventHandler h1(& o, METHOD_ADDRESS(CTest::MegaQ));
CEventHandler h2(& o, METHOD_ADDRESS(CTest::MegaZ));
int n;
h2.Raise(1, 2, & n);
h2.Raise("ssss", 2);
return 0;
}
//-------------------------------------------------------------------
D>Комментарии
D>Адрес метода получается 2мя способами — напрямую (для h1) и через макрос (для h2).
D>Передача события основана на __stdcall :
D>1) параметры в стек пихаются справа налево — this оказывается последним (esp + 4)
D>2) очистку стека делает вызывающая сторона
D>Это позволяет делать "слепое" делегирование. Более лучшее его описание ищите где то неподалеку.
Здесь следует добавить, что именно поэтому нельзя в параметрах использовать ссылки (int & n),
и не рекомендуется использовать const участки памяти.
D>Достоинства
D>1. "Слепое" делегирование позволяет передавать какие угодно параметры, т.е. подходит для всех случаев.
D>2. Простота в использовании.
D>3. Автоматическая проверка указателей на валидность при генерации события.
D>Недостатки
D>1. Появляется куча сгенеренных из шаблона TMethod классов.
Этот недостаток убран.
D>2. Замедлилась процедура установки обработчика : на вызов конструктора TMethod и вызов operator void * ().
D>3. Чууть замедлился вызов/делегирование события (но без этого никак).
D>4. Классы — обработчики обязаны для методов обработки ставить __stdcall.
D>5. Не поддерживается множественное наследование :-(((
D>P.S.
D>Если возникнет потребность, будет адаптировано для множественного наследования.