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 _WIN640x55,//{ 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 }#else0x58,//{ 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);#endifreturn (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++有时候需要为类的某个成员函数重载常量与非常量的版本,定义常量版本是为了保证该函数可作用于常量类对象上,并防止函数改动对象内容.但有时两个版本的函数仅仅是在返回的类型不同,而在返回前做了大量相同的 ...
随机推荐
- iOS-UICollectionView自定义布局
UICollectionView自定义布局 转载: http://answerhuang.duapp.com/index.php/2013/11/20/custom_collection_view_l ...
- iOS 使用Charts框架 折线,柱状,K线,饼状,雷达全攻略
我是前言: 大约几个月前我在某平台写了一篇文章, 文中简单地介绍了Charts两种图表的样式的使用, 不过有种意犹未尽的感觉, 利用周末的空闲时间再次看了看, 有了新的收获, 今天发出来,分享给大家, ...
- Android开发:最详细的 Toolbar 开发实践总结
最详细的 Toolbar 开发实践总结 过年前发了一篇介绍 Translucent System Bar 特性的文章 Translucent System Bar 的最佳实践,收到很多开发者的关注和反 ...
- Android中你应该知道的设计模式
建造者模式 建造者模式最明显的标志就是Build类,而在Android中最常用的就是Dialog的构建,Notification的构建也是标准的建造者模式. 建造者模式很好理解,如果一个类的构造需要很 ...
- Java 原始数据类型转换
在开发中经常遇到数据类型转换的问题,大多数都是拿来强制转换,强制转换可能会出现你意想不到的问题: int a = -1; 我们经过多重转换之后:int b = (int)(char)(byte) a ...
- 10.18 noip模拟试题
分火腿 (hdogs.pas/.c/.cpp) 时间限制:1s:内存限制 64MB 题目描述: 小月言要过四岁生日了,她的妈妈为她准备了n根火腿,她想将这些火腿均分给m位小朋友,所以她可能需要切火腿. ...
- 关于pv的那些事!!
遗留问题:whid=1969的日志记录是什么意思? 网站站点信息未分配的时候,会用1969去代替站点信息. PV:页面浏览量(page view),用户每次打开或刷新一次网页即被计算一次. 关于pv的 ...
- Android 四大组件之service与Broadcast
Android 四大组件之一:service: Service有五个生命周期:onCreat,onStartCommand, onBind,onUnbind, onDestroy 主要有绑定和非绑定两 ...
- JAVA package与import机制
JAVA package与import机制 http://files.cnblogs.com/files/misybing/JAVA-package-and-import.pdf import org ...
- jQuery - 获取内容和属性
jQuery 拥有可操作 HTML 元素和属性的强大方法. jQuery DOM 操作 jQuery 中非常重要的部分,就是操作 DOM 的能力. jQuery 提供一系列与 DOM 相关的方法,这使 ...