前段时间在自己用win32api封装一个进度条,做到后来的时候发现其中有一个重画界面的回调函数不能作为成员函数。不能够实时取得类中成员变量问题。后来经过一番探究以后终于找到了一个可行的方案,现将其发布在此方便后来者。
其中用到了部分汇编转换this指针地址。其中主要的代码如下:
Thunk.h
#include "stdafx.h"
template< typename TDst, typename TSrc >
TDst UnionCastType( TSrc src ) {
union {
TDst uDst;
TSrc uSrc;
} uMedia;
uMedia.uSrc = src;
return uMedia.uDst;
}
#pragma pack( push, 1 )
struct MemFunToStdCallThunk {
BYTE m_mov;
DWORD m_this; //mov ecx pThis
BYTE m_jmp;
DWORD m_relproc; //jmp
BOOL Init( DWORD_PTR proc, void* pThis ) {
m_mov = 0xB9; // mov ecx
m_this = PtrToUlong(pThis);
m_jmp = 0xe9; //jmp
m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(MemFunToStdCallThunk)));
::FlushInstructionCache( ::GetCurrentProcess(), this, sizeof(MemFunToStdCallThunk) );
return TRUE;
}
void* GetCodeAddress() {
return this;
}
};
#pragma pack( pop )
下面是需要回调的成员函数:
long ProcessBarProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
将thunk中的结构体声明为一个成员变量:
MemFunToStdCallThunk m_thunk;
设置系统钩子,也就是回调函数的设置:
m_thunk.Init(UnionCastType<DWORD_PTR>(&ProcessBar::ProcessBarProc), this);
SetWindowLongPtr(this->m_pbHwnd, GWL_WNDPROC, (LONG_PTR)m_thunk.GetCodeAddress());