背景
许多库需要我们提供一个函数作为回调,这使得使用 “面向对象编程”(OOP) 出现了麻烦。因为普通的C函数没有成员函数需要的this指针。Thunk技术是一种快速但是平台相关的解决此问题的方法。我最近研究过许多有关thunk技术的文章,我认为许多解决方案都是针对于特定问题的。我设计了一组类,来提供一种通用的解决方案。
环境
开发环境 : IA32,Windows Xp SP2,Visual Studio 2005
用法
源代码提供了5(实际上4)个类(全都在 Thunk 名字空间中)。它们的每一个对象都有2个属性,对象和方法。它们可以动态的创建一些机器码。执行这些机器码将在逻辑上和调用 Obj.Method(…); 举例来说,如果我们想要设计一个类来进行窗口子类化的工作,我们可以按下面5个步骤使用通用Thunk
class CSubClassing {
这5个类(class)都有相同的界面和使用方式。一旦你依据成员函数与回调函数的调用约定选定好了一个Thunk类,就可以按照上面的步骤做一些有用的事情 : 如WNDPROC,THREADPROC,hooking,等等
private:
Thunk::ThisToStd m_thunk;
//1.选择一个合适的Thunk类
// ThisToStd 类使一个使用__thiscall 约定的成员函数 (LRESULT SubProc(…) )
//成为一个使用_stdcall 约定的回调函数WNDPROC)
//2.实例化一个对象.
public:
CSubClassing() {
m_thunk.Attach(this);
//3.附加到想要回调的对象上
m_thunk.AttachMethod(&CSubClassing::SubProc);
// 4.附加成员函数
// to do
}
void Attach(HWND hWnd) {
m_oldProc = (WNDPROC)SetWindowLong(hWnd,GWL_PROC
,m_thunk.MakeCallback<LONG>());
// 5.转化到回调函数指针
//SetWindowLong函数使用一个LONG值来表示WNDPROC
// to do
}
private:
//这个非静态成员函数将被Windows回调
LRESULT SubProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
if (msg!=WE_NEEDED)
return CallWndProc(m_oldProc,hWnd,msg,wParam,lParam);
// to do
}
WNDPROC m_oldProc;
}
更多详细信息 见 Thunk.h和 示例(sample)工程(project)
示例工程包含5个程序的源代码,但是没有可执行文件,否则会太庞大。工程可以在Visual Studio 2005上顺利编译,只要工程的目录结构维持原样。5个程序使用一份相同的测试代码——TestClass.h TestClass.cpp main.cpp。不同之处在预处理器的定义。这样,它们分别测试了 ThisToStd,ThisToCdecl,StdToStd,StdToCdecl和CdeclToCdecl的功能。除了这些,你还可以从中得知使用一个Thunk类,需要包含和加入到工程中的最少文件。(只包含Thunk.h 并把Thunk.cpp 加入工程中也能工作,但不是最好方法)