ATL Windowing中的汇编:_stdcallthunk分析

C++中的Thunk技术和它的使用场景 阅读详情

1. 指令指针寄存器与正在执行指令指针关系:


I:                      CPU正在执行指令;

xIP:                  CPU指令指针寄存器内容;

xIP(I):              CPU正在执行的指令I的指针;

LEN(I):            指令I的长度。


1)顺序执行:xIP = xIP(I) + LEN(I);

2)相对跳转:xIP = xIP(I) + LEN(I) + REL_DISPLACEMENT_CONST;

3)绝对跳转:xIP = Target_CONST;

 

2. ATL:: _stdcallthunk 代码片断(节选自atlstdthunk.h)


struct _stdcallthunk

{

        DWORD   m_mov;          // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd)

        DWORD   m_this;         //

        BYTE    m_jmp;          // jmp WndProc

        DWORD   m_relproc;      // relative jmp

        BOOL Init(DWORD_PTR proc, void* pThis)

        {

                m_mov = 0x042444C7;  //C7 44 24 0C

                m_this = PtrToUlong(pThis);

                m_jmp = 0xe9;

                m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk)));

                // write block from data cache and

                //  flush from instruction cache

                FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));

                return TRUE;

        }

        //some thunks will dynamically allocate the memory for the code

        void* GetCodeAddress()

        {

                return this;

        }

// code ignored ……

};

 

3. 数据作为代码运行


实际使用时,_stdcallthunk结构作为代码使用。经过Init()后,被解释为以下两条指令(X86机器):

            Mov dword ptr[esp+4], pThis_CONST;

            Jmp REL_DISPLACEMENT_CONST;

其中 pThis_CONST是CWindowXXX的指针;

REL_DISPLACEMENT_CONST是跳转到实际WndProc的相对偏移量。那为什么 REL_DISPLACEMENT_CONST是 “_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk))); ”呢?稍候解释。

           

下面是一个可能的伪码例子:

WNDPROC pWndProc = (WNDPROC)( _stdcallthunkOBJ. GetCodeAddress() );

SetWindowLongPtr( hwnd, GWLP_WNDPROC, pWndProc);


4. 两条指令的解释


当WndProc被调用时,程序堆栈如下:(地址约定:高地址在上,低地址在下)


LPARAM

WPARAM

UINT

HWND                                    ß esp+4

RetAddr( from WNdProc)       ß esp


所以当第一条指令Mov dword ptr[esp+4], pThis_CONST 执行后,程序堆栈如下:

LPARAM

WPARAM

UINT

pThis_CONST             ß esp+4

RetAddr( from WNdProc)       ß esp

 

当第二条指令Jmp REL_DISPLACEMENT_CONST 执行时,xIP和xIP(I)的关系如下(重复地址约定:高地址在上,低地址在下):


Others ….                                ß_stdcallthunk结构的基址+_stdcallthunk结构大小

Jmp ….. (第二条指令)           ß xIP(I)

Mov ….. (第一条指令)          ß_stdcallthunk结构的基址


由于xIP = xIP(I) + LEN(I) + REL_DISPLACEMENT_CONST;

显然 xIP(I) + LEN(I) = _stdcallthunk结构的基址+_stdcallthunk结构大小;

又因为 REL_DISPLACEMENT_CONST = _relproc = DWORD((INT_PTR)proc - (_stdcallthunk结构的基址+_stdcallthunk结构大小);


所以 xIP = xIP(I) + LEN(I) + REL_DISPLACEMENT_CONST

            =  (_stdcallthunk结构的基址+_stdcallthunk结构大小)+ (DWORD((INT_PTR)proc - (_stdcallthunk结构的基址+_stdcallthunk结构大小))

= proc;

既下一条将要执行的指令是实际WndProc的首条指令。


如果使用绝对寻址,要好理解的多,可能是基于性能考虑,使用相对寻址。X64使用寄存器绝对寻址(rcx rax),好理解一些,但显然须符合调用约定。

 

5.总结

1)      数据被解释为代码;

2)      相对跳转正好跳到实际WndProc。

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/benny5609/archive/2008/06/30/2597419.aspx

深入构建加密货币价格预测系统:从数据获取到模型优化的完整指南! 🏆本文收录于「编程与技术实战」专栏,此专栏涵盖了C/C++编程、人工智能、数据结构、机器学习等技术领域的内容,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 阅读详情

相关推荐

Mac新手必看:为什么你的终端找不到Python命令?5分钟搞定zsh报错

本文针对Mac用户在终端遇到“zsh: command not found: python”报错的问题,提供了深度解析与实战修复指南。文章解释了macOS系统因历史原因默认使用`python3`而非`python`命令,并详细介绍了四种解决方案:养成使用`python3`的习惯、创建别名、通过Homebrew安装链接以及修改PATH环境变量,帮助新手快速解决zsh报错,顺利开始Python开发。

weixin_29248653的博客 594

C++ Thunk技术

一. 使用回调函数时遇到的问题 在使用Win32 API(如CreateThread等)时我们经常需要传入回调函数,这个回调函数不能是类的成员函数,只能是友元函数或静态函数。为了在回调函数中访问某个类的成员变量或函数,我们通常不得不通过某种方式将该类的This指针传入到回调函数中,从而实现在回调函数中访问类的公有的成员变量或函数。 如果有一种方式可以实现将类的成员函数作为回调函数来使用,那么就...

while(1) { smile(); } 5万+

Cocos Creator发布微信小游戏:深度定制与去除默认加载页面的实践指南

本文详细介绍了如何使用Cocos Creator发布微信小游戏时去除默认加载页面的实践方法。通过修改构建配置和重写启动逻辑,开发者可以自定义加载体验,提升品牌一致性。文章还提供了进阶优化方案和常见问题解决方案,帮助开发者实现更专业的微信小游戏发布流程。

weixin_27972919的博客 568

Thunk 回调函数实现面向对象

回调函数实现面向对象 什么是回调函数? 通常,Windows均要求我们将消息处理函数定义为一个全局函数,或者是一个类中的静态成员函数。并且该函数必须采用__stdcall的调用约定(Calling Convention) 在VC中函数前有callback,就认为是回调函数,回调函数是__stdcall调用约定,参数是从右边开始压入栈的,所以第一个参数就在栈的最上层 在使用VC开发的时候,回

嬴政 2262

DRAM架构演进与HBM技术在高性能计算中的应用

DRAM(动态随机存取存储器)是现代计算系统中关键的内存技术,其架构优化直接影响数据供给能力。随着AI训练和科学计算等数据密集型负载的普及,传统DDR架构面临带宽墙、能效比和访问粒度等挑战。HBM(高带宽内存)通过3D堆叠技术(如TSV硅通孔)和异构集成(如PIM存内计算)显著提升了带宽和能效比。这些技术在高性能计算、AI推理和大模型训练等场景中展现出巨大潜力,例如HBM3的带宽可达819GB/s,能效比低至0.95pJ/b。未来,DRAM技术将继续向更高密度、更低功耗和更智能的内存计算方向发展。

weixin_35757191的博客 400

ECU-TEST笔记&使用技巧01

说明 1)所述均基于如下环境:ECU-TEST 8.0、Win10系统、NI Veristand 2018(HIL测试)。不排除因为版本及软件环境问题,所述方法不奏效或有更好的方法,欢迎交流,一起提高。 2)本博客以问答形式进行,所述问题均来自于实际测试(包括MIL、HIL测试)遇到的问题及需求,目的是提高测试效率和自动化测试序列的可维护性。 3)本博客尽量从测试方法及ECU-TEST原...

Eigrl的博客 1万+

ATL Thunk机制学习

      ATL模板类库使用Thunk技术来实现与窗口消息相关联的HWND和负责处理消息的对象的this指针之间的映射。    ATL中窗口类注册时,窗口过程函数缺省值都是StartWindowProc,当创建窗口产生第一条消息时将调用此函数。StartWindowProc是CWindowImplBase的一个静态成员函数,它的工作是建立CWindowImpl派生对象的HWND与对象

热爱工作,快乐生活 4743

HFSS本征模求解:谐振特性分析与工程实践

本征模求解是电磁仿真中的基础技术,用于分析无源谐振系统的固有特性。其核心原理是通过求解麦克斯韦方程组的特征值问题,获得谐振频率、品质因数(Q值)及电磁场分布等关键参数。在5G滤波器设计、雷达谐振腔优化等高频场景中,精确的本征模分析能有效避免模式干扰,提升器件性能。HFSS作为行业标准工具,提供了完整的本征模求解工作流,涵盖边界条件设置、模式识别、场分布可视化等关键环节。针对多模耦合、模式纯度评估等工程难题,结合参数化扫描和场重叠积分等高级技巧,可显著提升微波器件设计效率。

weixin_27918373的博客 328

ATL之thunk技术

<br /><br /><br />学习下 ATL 的 thunk<br />由于 C++ 成员函数的调用机制问题,对C语言回调函数的 C++ 封装是件比较棘手的事。为了保持C++对象的独立性,理想情况是将回调函数设置到成员函数,而一般的回调函数格式通常是普通的C函数,尤其是 Windows API 中的。好在有些回调函数中留出了一个额外参数,这样便可以由这个通道将 this 指针传入。比如线程函数的定义为:<br />typedef DWORD (WINAPI *PTHREAD_START_ROUTINE

xsh_123321的专栏 4790

IIS - 会话cookie中缺少HttpOnly属性

不啰嗦,我们直接开始! 先进行常规设置 打开配置编辑器 选中图中节点,将httpOnlyCookies设置为true 然后。。。不起作用。。。 换种方式 通过配置出站规则getcookie添加HttpOnly 在Web.config中添加如下出站规则 <rewrite> <outboundRules> <rule name="Add HttpOnly"> <match serverVa.

。 21万+

OpenGL纹理贴图

OpenGL纹理1. 基本概念2. 纹理环绕方式3. 纹理过滤3.1 GL_NEAREST3.2 GL_LINEAR3.3 多级渐远纹理 (Mipmap)4. 纹理加载与创建4.1 纹理加载4.2 纹理创建4.3 纹理的使用 1. 基本概念 纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来表示物体的细节特征,希望绘制一个有足够多细节的物体,当然可以用足够多的顶点颜色来描述,但是无疑也增加了许多额外的开销;另一种办法就是使用纹理。 学习之前先展示一张实现的纹理图以更好理解纹理! 还是这张图为了将纹

牵LV小猪精的博客 8922

利用Thunk让C++成员函数变回调函数

Windows API经常需要回调函数,而在C++开发中面向对象当行其道,若能让C++类的成员函数成为回调函数,简直就是大善!但是C++成员函数都隐含了一个this指针用于指向当前的对象.要实现回调确实不容易. 我大约一年前就接触到Thunk技术,甚至也看过利用Thunk实现将成员函数变成回调函数的例子.但是我实在没了解过C++汇编后的样子,很容易钻了牛角尖,看都看不懂,直接用他们的程序又不敢,...

weixin_30794851的博客 273

YOLOv8自定义训练:车牌识别全流程(从标注到推理,附可视化代码)

车牌检测全流程实践指南 摘要:本文详细介绍了基于YOLOv8的车牌检测完整实现方案。针对车牌检测中的三大难点(小目标、多角度、光照变化),提供了从数据准备到模型部署的全流程解决方案。重点包括:1)数据采集与标注规范;2)针对小目标的YOLOv8模型优化配置;3)K-means锚框聚类方法;4)训练参数调优策略。通过实际验证,该方法可获得95%以上的检测准确率,并附有完整的代码实现和可视化工具,便于开发者快速复现应用。 (字数:149字)

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 849

Thunk技术的一些理解(一)

Thunk技术的一些理解(一) 首先我们需要搞清楚一个问题,为什么我们要用Thunk技术?Thunk技术可以解决神马难题? 在探寻上面的问题之前先讲述一下线程从面向过程到面相对象编程所面临的问题和解决的方法,因为Thunk也是为了解决这些问题而产生的 我们知道用Window的API来开发程序的话实际上是用的C语言的面向过程的方式来开发的。 而在我们使用C++开发程序的时候通常都是用的OOP(面向对...

weixin_30342827的博客 297

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++中的Thunk技术 / 非静态类成员函数作为回调函数 的实现方法

  原文:https://blog.twofei.com/616/   用我的理解通俗地解释一下什么是C++中的Thunk技术吧!  Thunk技术就是申请一段可执行的内存, 并通过手动构造CPU指令的形式来生成一个小巧的, 具有明确作用的代码块.  小巧? 具有明确作用? 你曾经初学C++时, 如果我没猜错的话, 肯定尝试过用C++封装一个窗口类(因为我也尝试过 :-) ),在封装窗口类的时候...

weixin_34144450的博客 640

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

atl thunk源码

atlstdthunk.h // This is a part of the Active Template Library. // Copyright (C) Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // A...

晓晓梦 334

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

ATL thunk机制

起初在DECLARE_WND_CLASS宏中可以知道,窗口类的窗口过程是CWindowImplBaseT的静态成员函数StartWindowProc,在StartWindowProc第一次被调用的时候,它把CWindowImplBaseT的非静态成员函数通过thunk机制设置为窗口过程。 template LRESULT CALLBACK CWindowImplBaseT::Start

w的专栏 1906

ATL Thunk技术简单解析

Thunk的基本原理是分配一段内存,然后将窗口过程设置为这段内存。这段内存的作用是将窗口过程的第一个参数(窗口句柄)替换成类的This指针,并jump到类的WinProc函数中。这样就完成了窗口过程到类的成员函数的一个转换。 ATL采用一种称为thunk的机制,简单来说,公共的窗口过程依然是类的一个静态函数,但只负责窗口的第一个消息WM_NCCREATE,其目的是在堆上开辟一小块数据区,

jdzfjfhnui的专栏 1379

ATL7窗口类剖析

目录:ATL7窗口类剖析... 1目录:... 1前言:... 1第一章              HWND和CWindow类... 1Create成员函数:... 2使用CWindow类... 3第二章              CWindowImpl类... 4ProcessWindowMessage与消息映射宏... 4窗口创建与消息路由... 6窗口风格... 9修改WNDCLASSE

feimashenhua的专栏 1008

thunk技术

Thunk : 将一段机器码对应的字节保存在一个连续内存结构里, 然后将其指针强制转换成函数. 即用作函数来执行,通常用来将对象的成员函数作为回调函数. #include "stdafx.h" #include namespace pri{ typedef unsigned char u1byte; typedef unsigned short u2byte; typedef uns

dc11223344的专栏 1682

ATL Thunk机制的一个例子

转自:http://blog.youkuaiyun.com/tttyd/article/details/4562233 //涂远东 2009 09 17 深圳 //声明函数类型。 typedef void (*TESTFUN)(void*); //定义修改代码的结构。 #pragma pack(push,1) struct Thunk { DWORD m_mov; // 修改参数指令

天道酬勤 2293
上一篇: 成员函数指针与高性能的C++委托
下一篇: 微软的COM中GUID和UUID、CLSID、IID
killcpp
博客等级 码龄20年 13粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值