相比于MFC的消息机制,WTL/ATL的实现更加优雅。后者将win32 API与面向对象技术完美地结合起来,去掉了庞杂的MFC依赖,生成的软件体积更小,运行速度更快。在其中,如何将窗口函数转变为对窗口对象成员函数的调用,是WTL/ATL消息机制的核心。以下利用trunk技术模拟了这一过程,仅供参考:

#include <Windows.h>
#include <assert.h>
#include <tchar.h>
thread_local void* pWnd = nullptr;#pragma pack(push,1)
struct _StdCallThunk32//x86
{DWORD		m_mov;ULONG_PTR   m_this;BYTE		m_jmp;ULONG_PTR   m_relproc;void Init(ULONG_PTR wPtr, ULONG_PTR proc){m_mov = 0x042444C7;//mov dword ptr [esp+4], pThism_this = wPtr;m_jmp = 0xe9;//jmp pRelFuncm_relproc = proc;}
};struct _StdCallThunk64//x64
{unsigned char mov_rax_1[2];unsigned char object[sizeof(ULONG_PTR)];unsigned char mov_rax_to_rcx[3];unsigned char mov_rax_2[2];unsigned char procedure[sizeof(ULONG_PTR)];unsigned char jump_rax[3];void Init(ULONG_PTR wPtr, ULONG_PTR proc){mov_rax_1[0] = 0x48;//mov rax, pThismov_rax_1[1] = 0xb8;memcpy(object, &wPtr, sizeof(ULONG_PTR));mov_rax_to_rcx[0] = 0x48;//mov rcx,raxmov_rax_to_rcx[1] = 0x89;mov_rax_to_rcx[2] = 0xc1;mov_rax_2[0] = 0x48;//mov rax, pFuncmov_rax_2[1] = 0xb8;memcpy(procedure, &proc, sizeof(ULONG_PTR));jump_rax[0] = 0x48;//jmp raxjump_rax[1] = 0xff;jump_rax[2] = 0xe0;}
};#pragma pack(pop)#if defined(_WIN64)
typedef struct _StdCallThunk64 StdCallThunk;
#elif defined(_WIN32)
typedef struct _StdCallThunk32 StdCallThunk;
#endif
class Window
{
public:Window();~Window();public:BOOL Create();protected:LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);protected:HWND          m_hWnd;StdCallThunk* m_pThunk;protected:static LRESULT CALLBACK TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};Window::Window():m_hWnd(NULL),m_pThunk(nullptr)
{}Window::~Window()
{if(m_pThunk != nullptr)VirtualFree(m_pThunk, sizeof(StdCallThunk), MEM_RELEASE);
}BOOL Window::Create()
{LPCTSTR lpszClassName = _T("ClassName");HINSTANCE hInstance = GetModuleHandle(NULL);WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };wcex.lpfnWndProc = TempWndProc;wcex.hInstance = hInstance;wcex.lpszClassName = lpszClassName;wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);ATOM regRes = RegisterClassEx(&wcex);pWnd = this;m_pThunk = (StdCallThunk*)VirtualAlloc(NULL, sizeof(StdCallThunk), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);m_hWnd = CreateWindow(lpszClassName, NULL, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);if (m_hWnd == NULL){return FALSE;}ShowWindow(m_hWnd, SW_SHOW);UpdateWindow(m_hWnd);return TRUE;
}LRESULT Window::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_LBUTTONUP:MessageBox(m_hWnd, _T("LButtonUp"), _T("Message"), MB_OK | MB_ICONINFORMATION);break;case WM_RBUTTONUP:MessageBox(m_hWnd, _T("RButtonUp"), _T("Message"), MB_OK | MB_ICONINFORMATION);break;case WM_DESTROY:PostQuitMessage(0);break;default:break;}return DefWindowProc(m_hWnd, message, wParam, lParam);
}LRESULT CALLBACK Window::TempWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{Window* pThis = (Window*)pWnd;assert(pThis != nullptr);WNDPROC pWndProc = (WNDPROC)pThis->m_pThunk;
#if defined(_WIN64)ULONG_PTR rel = (LONG_PTR)&Window::StaticWndProc;auto ret = SetWindowLongPtr(hWnd, GWLP_WNDPROC, (ULONG_PTR)pWndProc);
#elif defined(_WIN32)ULONG_PTR rel = (DWORD)&Window::StaticWndProc - ((DWORD)pThis->m_pThunk + sizeof(StdCallThunk));auto ret = SetWindowLong(hWnd, GWLP_WNDPROC, (ULONG)pWndProc);
#endifpThis->m_pThunk->Init((ULONG_PTR)pThis, rel);//FlushInstructionCache(GetCurrentProcess(), pThis->m_pThunk, sizeof(StdCallThunk));pThis->m_hWnd = hWnd;return pWndProc(hWnd, message, wParam, lParam);
}LRESULT CALLBACK Window::StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{return ((Window*)hWnd)->WndProc(message, wParam, lParam);
}int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{Window wnd;wnd.Create();MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return (int)msg.wParam;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86981.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86981.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86981.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux——11.软件安装与包管理

Linux 与 Windows 系统在软件安装方式上的差异 Linux: Linux 通过 包管理系统(如 Debian 的 apt、Red Hat 的 yum/dnf)将软件打包为二进制安装包(如 .deb、.rpm),每个包包含程序文件、依赖关系和元数据。包管理系统负责统一管理软件的安装、更新、卸载,并自动处理依赖关…

无人机用shell远程登录机载电脑,每次需要环境配置原因

原因&#xff1a; 终端分为“登录 shell”和“非登录 shell”&#xff1a; - 登录 shell&#xff08;如开机登录、远程 SSH 连接&#xff09;会加载 .profile 或 .bash_profile 。 - 非登录 shell&#xff08;如打开新终端窗口&#xff09;会加载 .bashrc 。 - 如果环境变量…

HarmonyOS5 折叠屏适配测试:验证APP在展开/折叠状态下的界面自适应,以及会出现的问题

以下是HarmonyOS5折叠屏应用在展开/折叠状态下的UI自适应测试方案及技术实现要点&#xff1a; 一、核心测试维度 ‌状态连续性验证‌ 页面滚动位置保持&#xff08;需通过display.on(foldStatusChange)监听状态并保存/恢复滚动位置&#xff09;输入内容保留&#xff08;使用…

Introduction to Software Engineering(TE)

Program Design Language 也称为&#xff1a;伪代码语言&#xff08;Pseudo-code Language&#xff09; PDL 的同类&#xff08;或相关替代&#xff09; 名称简介是否代码结构化流程图 (Flowchart)用图形方式描述处理逻辑✅伪代码 (Pseudo-code)通用术语&#xff0c;PDL就是…

DM8数据库入门到熟练

1、部署 1.1、下载 用户在安装 DM 数据库之前需要检查或修改操作系统的配置&#xff0c;以保证 DM 数据库能够正确安装和运行。 操作系统CPU数据库CentOS7x86_64dm8_20250506_x86_rh7_64.zip 1.2、新建 dmdba 用户 安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户…

VUE3入门很简单(2)--- 计算属性

前言 重要提示&#xff1a;文章只适合初学者&#xff0c;不适合专家&#xff01;&#xff01;&#xff01; 为什么需要计算属性&#xff1f; 想象你在开发一个购物车功能。当用户选择商品时&#xff0c;你需要&#xff1a; 计算商品总价根据折扣码调整价格自动更新免运费状…

IPV6概述

1. 定义 IPv6&#xff08;Internet Protocol version 6&#xff09;是互联网协议的第六版&#xff0c;设计用于替代现有的 IPv4 协议。IPv6 提供了更大的地址空间、增强的路由效率、更好的安全性以及自动配置功能&#xff0c;以满足现代网络的需求。 1.1 地址空间 IPv6 地址长…

量子机器学习:AI算力突破量子优势临界点?

前言 前些天发现了一个巨牛的人工智能免费学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 以下是为您撰写的第六篇CSDN深度技术解析文章&#xff0c;围绕前沿命题 《量子机器学习&#xff1a;AI算力突破量子优势临界点&…

Kerberos 深入详解:原理、认证流程与应用场景

目录 什么是 KerberosKerberos 原理解析Kerberos 认证完整流程Kerberos 应用场景常见问题与最佳实践参考资料 什么是 Kerberos Kerberos 是一种广泛应用于计算机网络中的身份认证协议&#xff0c;它基于对称密钥加密思想&#xff0c;核心目标是在不安全的网络中实现安全的身份…

mac安装node 实测可行

进入nodejs官网&#xff0c;选择mac,选择安装方式&#xff0c;选择版本即可获得安装命令 直接执行即可 具体脚本 # Download and install nvm: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash# in lieu of restarting the shell \. "…

山石网科谈平凡对话中的咒语——提示词注入攻击与防御

现场 2026 年 4 月 25 日上午&#xff0c;A市 初春的街道&#xff0c;阳光普照&#xff0c;鸟语花香&#xff0c;V 君中午要与一个重要的客户见面&#xff0c; 特意预约了人气正旺的星际咖啡馆&#xff0c;他家主打未来科幻风&#xff0c;之前去过几次&#xff0c; 服务周到、…

SpringMVC系列(五)(响应实验以及Restful架构风格(上))

0 引言 作者正在学习SpringMVC相关内容&#xff0c;学到了一些知识&#xff0c;希望分享给需要短时间想要了解SpringMVC的读者朋友们&#xff0c;想用通俗的语言讲述其中的知识&#xff0c;希望与诸位共勉&#xff0c;共同进步&#xff01; 本系列会持续更新&#xff01;&…

Windows 环境下设置 RabbitMQ 的 consumer_timeout 参数

在 Windows 环境下设置 RabbitMQ 的 consumer_timeout 参数&#xff0c;可以通过临时修改或永久修改两种方式实现。以下是具体操作步骤&#xff1a; 一、临时修改&#xff08;无需重启服务&#xff0c;但重启后失效&#xff09; ‌通过命令行动态设置‌ 打开命令提示符&#xf…

Python 中切换镜像源

在 Python 中切换镜像源主要涉及 pip 包管理器 和 conda 环境&#xff08;如 Anaconda、Miniconda&#xff09; 的配置。国内访问 Python 官方源&#xff08;PyPI&#xff09;可能较慢&#xff0c;因此推荐使用国内镜像源&#xff08;如阿里云、清华大学、豆瓣等&#xff09;。…

深入解析拓扑排序算法:从原理到C++实现

一、拓扑排序概述 拓扑排序(Topological Sorting)是对有向无环图(Directed Acyclic Graph&#xff0c;简称DAG)的顶点进行排序&#xff0c;得到一个线性序列&#xff0c;使得对于图中的任意一对顶点u和v&#xff0c;若存在一条从u到v的路径&#xff0c;则u在排序结果中出现在v…

图像质量对比感悟

具体任务&#xff1a; 在本次任务中&#xff0c;我需要对比两张1080p的yuv图片的清晰度&#xff0c;那么如何判断呢&#xff1f;主要是进行了主观判断和客观psnr的判断。 psnr解释&#xff1a; 定义&#xff1a; PSNR 用于衡量 两幅图像之间的差异&#xff08;通常是原始图像和…

机器学习(ML)-Scikit-Learn--快速入门

专栏:机器学习 个人主页:云端筑梦狮 一.数据集读取方法&#xff08;常用功能用熟即可不用背下来&#xff09; 以例子代表需要的知识点和方法。 1. 导入必要的库 from sklearn.datasets import load_iris import numpy as npload_iris()&#xff1a;用于加载鸢尾花数据集的…

SQL语句四大分类详解:DDL、DML、DQL、DCL

前言 SQL&#xff08;Structured Query Language&#xff09;是用于管理和操作关系型数据库的标准语言。无论是开发人员还是数据库管理员&#xff0c;掌握 SQL 是必不可少的技能。 SQL 根据功能的不同&#xff0c;通常被划分为 四大类&#xff1a; ✅ DDL&#xff08;数据定义…

如何将Word里每页的行数设置成50行

https://www.zhihu.com/question/357856175 本文来自知乎林听晴 第一步&#xff1a;新建一个Word文档 打开“页面布局”&#xff0c;之后点击图片圈起来的小图标&#xff0c;即可出现“页面设置”页面。 ​ ​ 路径&#xff1a;页面设置—文档网络&#xff0c;可以看到默认行…

纯前端本地文件管理器(VSCode风格)(浏览器对本地文件增删改查)

纯前端本地文件管理器&#xff08;VSCode风格&#xff09;(浏览器对本地文件增删改查) 简介 本项目为一个纯前端实现的本地文件管理器网页&#xff08;index.html&#xff09;&#xff0c;可在 Chrome/Edge 浏览器中直接打开&#xff0c;具备类似 VSCode 的本地文件夹操作体验…