這段時間用VC封裝Windows類庫,沒有MakeObjectInstance處理窗口消息確實不爽,又不想使用MFC的消息映射,這玩意的效率和美觀只能呵呵。函數
至於MakeObjectInstance是什麼,Delphi轉過來的同窗必然很瞭解這個方便的功能,就是動態構造一個函數把普通函數轉到一個類的成員函數。spa
VC X86實現起來沒問題,可是X64實現起來的麻煩在於不能內嵌彙編了,X64必須結合ASM文件編譯的obj(這一點仍是感激Delphi的編譯器,X86和X64均可之內聯彙編)。代理
個人實現方案是經過構造一段ShellCode來達到目的。指針
SIZE_T
PageSize = 4096;
template
<
typename
T>
//產生一個代理函數
WNDPROC MakeObjectInstance(
LPVOID
AObject, T AMethod)
{
union
{
T MethodAddr;
//成員函數指針
LPVOID
NomralAddr;
//正常指針
}ut;
//由於VC不容許成員函數指針轉換到普通指針。只能變通的經過union來實現
const
unsigned
char
BlockCode[] = {
#ifdef _WIN64
0x55,
//{ push rbp }
0x48, 0x83, 0xEC, 0x40,
//{ sub rsp,0x40 }
0x48, 0x8B, 0xEC,
//{ mov rbp,rsp }
0x48, 0x89, 0x4D, 0x50,
//{ mov[rbp + 0x50],rcx }
0x89, 0x55, 0x58,
//{ mov[rbp + 0x58],edx }
0x4C, 0x89, 0x45, 0x60,
//{ mov[rbp + 0x60],r8 }
0x4C, 0x89, 0x4D, 0x68,
//{ mov[rbp + 0x68],r9 }
0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//{ mov rcx,AObject }
0x48, 0x8B, 0x55, 0x50,
//{ mov rdx,[rbp + 0x50] }
0x44, 0x8B, 0x45, 0x58,
//{ mov r8,[rbp + 0x58] }
0x4C, 0x8B, 0x4D, 0x60,
//{ mov r9,[rbp + 0x60] }
0x48, 0x8B, 0x45, 0x68,
//{ mov rax,[rbp + 0x68] }
0x48, 0x89, 0x44, 0x24, 0x20,
//{ mov[rsp + 0x20],rax }
0x49, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//{ mov r11, AMethod }
0x49, 0xFF, 0xD3,
//{ call r11 }
0x48, 0x8D, 0x65, 0x40,
//{ lea rsp,[rbp + 0x40] }
0x5D,
//{ pop rbp }
0xC3
//{ ret }
#else
0x58,
//{ pop eax }
0x68, 0x00, 0x00, 0x00, 0x00,
//{ push AObject }
0x50,
//{ push eax }
0xB8, 0x00, 0x00, 0x00, 0x00,
//{ mov eax, AMethod }
0xFF, 0xE0
//{ jmp eax }
#endif // endif
};
size_t
CodeBytes =
sizeof
(BlockCode);
LPVOID
Block = VirtualAlloc(
nullptr
, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy
(Block, BlockCode, CodeBytes);
unsigned
char
* bBlock = (unsigned
char
*)Block;
ut.MethodAddr = AMethod;
#ifdef _WIN64
*
PLONG64
(&bBlock[25])=
LONG64
(AObject);
*
PLONG64
(&bBlock[0x38]) =
LONG64
(ut.NomralAddr);
#else
*
PLONG32
(&bBlock[2]) =
LONG32
(AObject);
*
PLONG32
(&bBlock[8]) =
LONG32
(ut.NomralAddr);
#endif
return
(WNDPROC)Block;
}
//釋放代理函數
void
FreeObjectInstance(WNDPROC wndProc)
{
VirtualFree(wndProc, PageSize, MEM_RELEASE);
}
|
用法相似的以下code
class
MyClass{
LRESULT
CALLBACK WndProc(
HWND
hWnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParam);
}
MyClass c;
WNDCLASSEXW wcex;
wcex.cbSize =
sizeof
(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = MakeObjectInstance(&c, &MyClass::WndProc);
//使用MyClass::WndProc做爲創消息處理函數
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WNDPROCTEST));
wcex.hCursor = LoadCursor(
nullptr
, IDC_ARROW);
wcex.hbrBackground = (
HBRUSH
)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WNDPROCTEST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
|
再例如ci
class
MyClass{
LRESULT
CALLBACK WndProc(
HWND
hWnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParam);
}
MyClass c;
SetWindowLongPtr(hWnd, GWL_WNDPROC, (
LONG_PTR
)MakeObjectInstance(&c, &MyClass::WndProc));
|
http://www.raysoftware.cn/?p=552編譯器