VC版本的MakeObjectInstance把WNDPROC映射到类的成员函数
这段时间用VC封装Windows类库,没有MakeObjectInstance处理窗口消息确实不爽,又不想使用MFC的消息映射,这玩意的效率和美观只能呵呵。
至于MakeObjectInstance是什么,Delphi转过来的同学必然很了解这个方便的功能,就是动态构造一个函数把普通函数转到一个类的成员函数。
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); } |
用法类似的如下
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); |
再例如
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
VC版本的MakeObjectInstance把WNDPROC映射到类的成员函数的更多相关文章
- VC.VS版本&VC版本&OpenCV版本
1.VS版本 与 VC版本 的对应关系,以及opencv 对 VC版本 的支持情况 - 魔法学徒 - CSDN博客.html(https://blog.csdn.net/yefcion/article ...
- 直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)
在C++中,成员函数的指针是个比较特殊的东西.对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用.但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法. ...
- VS2013 VC++的.cpp文件调用CUDA的.cu文件中的函数
CUDA 8.0在函数的调用中方便的让人感动.以下是从网上学到的VC++的.cpp文件调用CUDA的.cu文件中的函数方法,和一般的VC++函数调用的方法基本没差别. 使用的CUDA版本为CUDA 8 ...
- MyBatis-Spring 学习笔记一 SqlSessionFactoryBean以及映射器类
MyBatis-Spring 是一个用来整合 MyBatis 和 Spring 框架的小类库,通过这个jar包可以将 MyBatis 代码地整合到 Spring 中. 使用这个类库中的类, Sprin ...
- Hibernate框架学习之注解映射实体类
前面的相关文章中,我们已经介绍了使用XML配置文件映射实体类及其各种类型的属性的相关知识.然而不论是时代的潮流还是臃肿繁杂的配置代码告诉我们,注解配置才是更人性化的设计,于是学习了基本的映射 ...
- MyBatis Spring整合配置映射接口类与映射xml文件
本文转自http://blog.csdn.net/zht666/article/details/38706083 Spring整合MyBatis使用到了mybatis-spring,在配置mybati ...
- vc MFC 通过IDispatch调用默认成员函数
CComPtr<IDispatch> spDisp(IDispatch *); if(!spDisp) return; DISPPARAMS dispParam={0}; //没有参数 V ...
- SMACH(五)----用户数据UserData类和重映射Remapper类的原理和例子
用户数据UserData类和重映射Remapper类包含在smach中的user_data.py文件中实现,该博文主要介绍其原理和例子 UserData主要用于状态之间的数据传递,包括数据的输入inp ...
- c++类成员函数重载常量与非常量版本时避免代码重复的一种方法
c++有时候需要为类的某个成员函数重载常量与非常量的版本,定义常量版本是为了保证该函数可作用于常量类对象上,并防止函数改动对象内容.但有时两个版本的函数仅仅是在返回的类型不同,而在返回前做了大量相同的 ...
随机推荐
- linux 命令c语言代码实现
自己学习<APUE>时写的linux下一些命令(大概40个左右)实现,仅当学习使用,这些命令包含cat cp echo head ls paste rmdir tail umask who ...
- mybatis0208 缓存
查询缓存 1.1缓存的意义 数据在磁盘会有一个IO,高并发读取效率就很低,将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效 ...
- WebLogic Server的Identity Assertion--转载
在一些典型的公司Web应用程序安全部署中,访问受保护应用程序的用户通过企业身份/访问管理产品,如Netegrity 的 SiteMinder,IBM 的WebSEAL 和Oblix 的 Oblix C ...
- Struts2 ValueStack
一.作用 可以作为一个数据中转站,用在前台和后台数据传递 二.生命周期 ValueStack的生命周期是随着request的创建而创建,随request的销毁而销毁. 三.结构 OgnlValueSt ...
- Block之变量作用域
在使用block的过程中经常会调用不同类型.不同作用域的变量,如果对这些变量作用域的理解稍有偏差,就会出现问题.故此特意整理出block中会经常使用到的几种变量,如有补充,欢迎指出. 1. 局部变量 ...
- oracle 字符串切割成结果集方法
oracle字符串切割几种方式 方法一: SELECT COLUMN_VALUE FROM TABLE(SYS.ODCIVARCHAR2LIST('1','2','3','4','5')); 方法二: ...
- CSS3伪类nth-child结合transiton动画实现文字若影若现
css3伪类nth-child结合transiton动画实现文字若影若现收先创建一个div盒子,然后包裹在div中的有10个span标签每个span标签填上内容一次为A,B,C,D,E,F,G,H,I ...
- PHP 正则表达式匹配 preg_match 与 preg_match_all 函数
--http://www.5idev.com/p-php_preg_match.shtml 正则表达式在 PHP 中的应用 在 PHP 应用中,正则表达式主要用于: 正则匹配:根据正则表达式匹配相应的 ...
- jquery---点击弹出层
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 解决vim不能使用方向键和退格键问题
1.使用vi命令时,不能正常编辑文件,使用方向键时老是出现很多字母,或者退格键却变成方向键的功能 只要重装一下vi的依赖包即可完美解决vi编辑器方向键变字母的问题.rpm -e vim-enhance ...