QQ截图20200908082019.bmp

什么是子类化?

窗口子类化的目的是在不修改现有代码的前提下,扩展现有窗口、控件的功能。它的思路很简单,就是将窗口过程地址修改为一个新函数地址,新的窗口过程函数处理自己感兴趣的消息,将不感兴趣的消息丢给原窗口过程处理。

MFC框架将子类化方法应用得淋漓尽致,MFC将所有的窗口处理函数都注册成DefWndProc,那

么,是不是MFC将所有的消息都发送到DefWndProc中去了呢?答案是“不是”,而是都发送到

AfxWndProc函数中去了(您可以回想一下前面我们查看MSDN是提到的AfxWndProc)

窗口子类化的步骤如下:


(1)正常创建系统控件/窗口,得到控件/窗口的句柄。

(2)调用GetWindowLong()得到原来的系统的窗口函数OldWndProc

(3)调用SetWindowLong()设置控件新的窗口函数为我们的NewWndProc

(4)在NewWndProc处理感兴趣的消息

(5)不感兴趣的消息调用CallWindowProc()传递给原来的OldWndProc处理


注意:在调用旧的窗口函数时,不能直接调用OldWndProc(..),

而必须用函数CallWndProc调用,否则会出现堆栈错误。

相关函数解析

Long GetWindowLong(

HWND    hWnd,                //目标窗口句柄

int    nlndex                        // 要检索的值的基于零的偏移量

);

如果函数成功,返回值是所需的32位整型值

LONG SetWindowLong(

    HWND hWnd,                        // 目标窗口句柄

    int nlndex,                              // 要设置的值的基于零的偏移量

    LONG dwNewLong                // 新的值

);

如果函数成功,返回值是指定的32位整数的原来的值。如果函数失败,返回值为0。若想获得更多错误信息,请调用GetLastError函数。


nlndex可以为以下的值

GWL_EXSTYLE检索扩展窗口样式。
GWL_HINSTANCE检索应用程序实例的句柄。
GWL_HWNDPARENT检索父窗口的句柄(如果有的话)。
GWL_ID检索窗口的标识符。
GWL_STYLE检索窗口样式。
GWL_USERDATA检索与窗口关联的用户数据。
GWL_WNDPROC检索窗口过程的地址或表示窗口过程地址的句柄。您必须使用CallWindowProc函数调用窗口过程。
DWL_DLGPROC检索对话框过程的地址句柄,您必须使用CallWindowProc函数来调用对话框过程。
DWL_MSGRESULT检索在对话框过程中处理的消息的返回值。
DWL_USER检索应用程序专用的额外信息,例如句柄或指针。

//将消息信息传递给指定的窗口过程。

LRESULT CallWindowProc(            

WNDPROC lpPrevWndFunc,         //窗口过程

HWND hWnd,                                 //窗口句柄

UINT Msg,                                 //消息

WPARAM wParam,                         //额外的消息特定信息 

LPARAM IParam                         //额外的消息特定信息 

);


返回类型:LRESULT

返回值指定了消息处理的结果并取决于发送的消息。

备注

使用CallWindowProc函数进行窗口子类化,应用程序必须通过调用CallWindowProc将任何未由新窗口过程处理的消息传递给前一个窗口过程

实例代码

在主窗口过程中WM_CREATE消息中,创建控件时,将窗口过程改为我们自己的

case WM_CREATE:
{  

	LPCREATESTRUCT pcs = (LPCREATESTRUCT)LParam;
	HWND h3 = CreateWindow(L"edit", L"这是一个文本框", WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE, 5, 100, 100, 80, hwnd, (HMENU)10003, pcs->hInstance, NULL);
	
	
	//将控件的窗口过程处理函数改为自定义的,从而捕获控件消息
	//由于SetWindowLong会返回旧的过程,所以这里就不用GetWindowLong了
	编辑框旧过程 = (WNDPROC)SetWindowLong(h3, GWL_WNDPROC, (LONG)编辑框的窗口过程);
	break;
}

然后为编辑框写一个窗口过程

//创建一个全局变量 储存旧的过程
WNDPROC 编辑框旧过程 = NULL;


//为编辑框写一个窗口过程
LRESULT CALLBACK 编辑框的窗口过程(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM LParam){  //消息所处的窗口句柄,具体消息名称 WM_xxxx消息
	switch (uMsg)
	{	
		//处理了我们感兴趣的消息
		case WM_LBUTTONDOWN:
		{
			//MessageBox(hwnd, L"我们捕获了编辑框的左键消息", L"提示", MB_OK);
			SetWindowText(hwnd, L"我们捕获了编辑框的左键消息");
			//return 0;  返回0代表我们自己处理了  系统默认的点击事件就没有了 所以无法置焦点
			break;
		}
		
		
	}
	//其他的消息交给原来的处理过程函数去处理,保证控件原来的功能
	return CallWindowProc(编辑框旧过程, hwnd, uMsg, wParam, LParam);
}



相关推荐

wIndowsapI 高频窗口控件函数: 操作控件 创建 取句柄 取标题 取文本 置标题 置文本

Win32API提供了一系列的函数来操作控件高频常用控件函数:类型说明GetDlgItem根据控件ID,取控件句柄GetDlgItemText根据控件ID,取控件文本GetDlgItemInt根据控件

wIndowsapI创建窗口 并创建 标准控件

窗口的创建参考 http://qingzhouquanzi.com/269.html以下是windows 创建编辑框,文本框,标签,组合框,滚动条等头文件#include <windows.h&

wIndowsapI创建控件 或创建子窗口方法

创建按钮一般是在 WM_CREATE消息的响应中创建子窗口 创建控件 创建按钮,创建单选框,复选框 等等按钮的创建:创建按钮第一个参数(类名)必须是 button 不区分大小写case WM_CREA

wIndowsapI控件:创建超级列表框

超级列表框的类名是 WC_LISTVIEW样式是 LVS_ 开头的LVS_ICON图标视图LVS_SMALLICON小图标视图LVS_LIST列表视图LVS_REPORT报表视图可以向控件发送LVM_

wIndowsapI:公共控件

Windows中 分为标准控件 和 公共控件标准控件包括:标签,按钮,编辑框,组合框,滚动条,公共控件包括:动画框,日期框,热键框,日历,超级列表框,进度条,超链接,测量条,树形框,分页控件,工具条,

MFC(1):c语言/c++ apI 创建窗口 底层原理

Visual Studio直接创建一个空项目控件的创建请参考:http://qingzhouquanzi.com/287.html新建一个 后缀为 .c 或者 .cpp文件#include <w

C++ apI创建窗口与控件 包括窗口过程的写法

//纯API创建窗口 底层代码 #include <windows.h> //如果出现该符号在函数中被引用需要配置:项目-》属性->配置属性->连接器=》系统 子系统 设

wIndows apI数据型的命名规律 与常用的wIndows 数据

WindowsAPI数据类型的命名规律基本数据来袭包括:BYTE 字节CHAR 字符WORD 单字SHORT 短整型INT 整型指针的类型命名方式一般都在对象名前面加 LP 或者 P /*字

c++ char与wchar_t的区别 wIndowsapI函数后面带aw的区别

C++基本数据类型中表示字符的有两种: char、wchar_t。char叫多字节字符,一个char占1个字节,之所以叫多字节字符是因为它表示一个英文字符时是一个字节,而中文字符时是多个字节。wcha

LpsTR、LpwsTR、LpTsTR、LpCTsTR wIndowapI中的字符串数据

LP前缀 表示指针STR 表示字符串LPWSTR W代表Unicode版本LPTSTR T代表根据项目而定LPCTSTR C表示const T表示根据项目决定LPSTR 多字节变量类型使用自