sanxcoo

做一个耐得住寂寞的人
posts - 1, comments - 8, trackbacks - 0, articles - 0

将成员函数作为回调函数

Posted on 2010-04-01 14:25 Sanxcoo 阅读(1105) 评论(8)  编辑 收藏 引用

在网上查了一些资料,做了一个Thunk模板,能够正确调用成员函数。但是在做取成员函数地址操作时比较麻烦,需要用到汇编。
//取成员函数地址
DWORD_PTR off = 0;
_asm
{
   mov eax, Class::MemFunc
   mov DWORD PTR [off], eax
}
每指定一个成员函数作为一个回调函数就要做如上操作。本想将Class和MemFunc作为两个参数定义一个宏包含汇编语言部分,
但不知道怎样编写汇编部分。如果有知道怎么编写的,希望能不吝赐教^_^

// Thunk 具体实现
#pragma pack( push, 1 )
struct Thunk_struct
{
 BYTE  op_movecx;  // as operation "mov" in asm
 DWORD_PTR val_ecx;
 BYTE  op_call;  // as operation "jmp" in asm
 DWORD_PTR val_address;
};
#pragma pack( pop )

template < class TCallback, class TClass >
class Thunk
{
public:
 TCallback MemFuncToCallback( TClass* pObject, DWORD_PTR pMemFuncAddress )
 {
  // 0xB9是“mov ecx, 数值”的机器码
  m_thunk.op_movecx = 0xB9;
  // 将对象指针pObject赋值给ecx
  m_thunk.val_ecx = (DWORD_PTR)pObject;
  // 0xE9是“jmp 相对地址”的机器码
  m_thunk.op_call = 0xE9;
  // 利用成员函数的具体地址pMemFuncAddress计算jmp的相对地址
  m_thunk.val_address = pMemFuncAddress - ((DWORD_PTR)(&m_thunk.val_address) + sizeof(DWORD_PTR));

  return (TCallback)&m_thunk;
 };

protected:
 Thunk_struct m_thunk;
};

Feedback

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-01 17:36 by OwnWaterloo
取成员指针地址:

template<typename D,typename S>
D cast_union(S src)
{
union
{
S src;
D dst;
} u = {src};
return u.dst;
}

uintptr_t address = cast_union<uintptr_t>(&C::F);

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-01 17:41 by OwnWaterloo
注意, 成员指针并不一定仅仅是地址。
所以最安全的作法是实现一个转发函数, 而不是去取地址:

void forwarding(void* o, int i, double d)
{
static_cast<C*>(o)->F(i, d);

}

然后将forwarding绑定到一个object上:
C o;
void (*f)(int, double ) = bind(forwarding, &o);

然后将f传递给需要回调的地方:
f(1212, 3.26);

等效于:
o.f(1212, 326);

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-01 18:26 by Sanxcoo
@OwnWaterloo
谢谢。
成员指针如果不是地址的话,还有其他哪些情况?希望能举个例子

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-01 18:31 by OwnWaterloo
@Sanxcoo
gcc下有继承关系。
msvc下有多继承关系。

指向成员的指针就可能不仅仅是一个地址。

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-02 11:24 by 陈梓瀚(vczh)
使用std::function完美解决这个问题

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-02 15:56 by OwnWaterloo
@陈梓瀚(vczh)
std::function?
那是什么东西?

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-02 22:56 by Sanxcoo
应该是std::tr1::function

# re: 将成员函数作为回调函数  回复  更多评论   

2010-04-03 19:49 by OwnWaterloo
@Sanxcoo
哈, 既然你已经找了这么复杂的方案, 相信你是清楚tr1::function这种东西是无效的~_~

tr1::function对象或者std::binder1st, std::bind2nder对象的接受者都是template。
而当接收者只能接受pointer to function时, tr1::function, binder这种东西都是无效的~


这里有一个类似的, 不过不需要写汇编。
http://code.google.com/p/callback-currying/source/browse/trunk/src/stdcall2stdcall.c

项目新的地址在
http://github.com/OwnWaterloo/callback-currying

不过目前是空的……

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理