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 Crontab 使用(转)
cron用法说明 cron的用法老是记不住,索性写下来备忘.下文内容大部分是根据<Cron Help Guide>翻译而来,有些部分是自己加上的. 全文如下: cron来源于希腊单词chr ...
- PHP面向对象之旅:模板模式(转)
抽象类的应用就是典型的模版模式 抽象类的应用就是典型的模版模式,先声明一个不能被实例化的模版,在子类中去依照模版实现具体的应用. 我们写这样一个应用: 银行计算利息,都是利率乘以本金和存款时间,但各种 ...
- Android制作粒子爆炸特效
简介 最近在闲逛的时候,发现了一款粒子爆炸特效的控件,觉得比较有意思,效果也不错. 但是代码不好扩展,也就是说如果要提供不同的爆炸效果,需要修改的地方比较多.于是我对源代码进行了一些重构,将爆炸流程和 ...
- Winform 程序中dll程序集嵌入exe可执行文件
关于这方面,Google一下有很多方法,参考: http://blog.csdn.net/astonqa/article/details/7300856 但按照以上的方法我并没有成功,于是继续找到了一 ...
- 织梦dede编辑器ckeditor如何添加中文字体不乱码
dedecms内容编辑器ckeditor没有中文字体,找了很多教程都是千篇一律,而且都是错的,终于找到了一篇,结合自己的实际操作,来教您如何添加中文字体,并且解决乱码问题. 工具/原料 dedec ...
- CSS3 变形小结
为原始大小 b:纵向扭曲,0为不变 c :横向扭曲,0不变 d:垂直伸缩量,1为原始大小 e:水平偏移量,0为初始位置 f :垂直偏移向,0是初始位置 Ø原点 transform-origin() ...
- <html:text> Id属性
可能 会遇到这样 的问题,需要通过document.getElementById得到<html:text>标签的id, 可是据说ie设置property后id就是一样的了,不过具体没有去测 ...
- 判断浏览器是否支持FileReader
1.js代码: //判断浏览器是否支持FileReader if (typeof FileReader == "undefined") { document.write(" ...
- 不用Google Adsense的84个赚钱方法
这是一个关于网络广告商和网络销售的汇总列表,可以用来为您的网站或博客赚点钱.广告商都是英文的,加入广告请确认其是否支持中国地区支持,不支持的话就不必加入了. Chitika : 购物中心旗帜广告. ( ...
- javascript的选项卡
主要用的索引值 首先 写三个按钮 <input type="button" > <input type="button" > <i ...