窗口子类化:
窗口子类化,即重定向消息,也就是修改某个窗口消息执行函数,重定向
下面代码可以让你更好的理解窗口子类化:
先介绍三个函数:
1.GetWindowLong
函数原型:
Long GetWindowLong(HWND hWnd,int nlndex);
参数介绍:
HWND hWnd:目标窗口句柄
int nlndex:要获取的窗口类型信息:
宏定义 | 常量 | 描述 |
GWL_EXSTYLE | -20 | 获取扩展窗口样式 |
GWL_HINSTANCE | -6 | 获取应用实例句柄 |
GWL_HWNDPARENT | -8 | 获取所有者窗口句柄 |
GWL_ID | -12 | 获取窗口ID |
GWL_STYLE | -16 | 获得窗口样式 |
GWL_USERDATA | -21 | 获取用户设置的32位数据,其值默认为0 |
GWL_WNDPROC | -4 | 获取窗口过程地址或句柄。必须使用CallWindowProc函数调用获取的窗口过程。 |
返回值:
执行成功返回一个32位整形值,此值是获取到的风格的整数代码值,否则返回0,可以根据此标记来判断是否成功!
函数作用:用于获取指定窗口类型
2. SetWindowLong
函数原型:
LONG SetWindowLong(
HWND hWnd, // handle to window
int nlndex, // offset of value to set
LONG dwNewLong // new value
);
参数介绍:
HWND hWnd:目标窗口句柄
int nlndex:指定要设定的风格:
常量 | 常量值 | 意义 |
GWL_EXSTYLE | -20 | 设定一个新的扩展风格。 |
GWL_HINSTANCE | -6 | 设置一个新的应用程序实例句柄。 |
GWL_ID | -12 | 设置一个新的窗口标识符。 |
GWL_STYLE | -16 | 设定一个新的窗口风格。 |
GWL_USERDATA | -21 | 设置与窗口有关的32位值。每个窗口均有一个由创建该窗口的应用程序使用的32位值。 |
GWL_WNDPROC | -4 | 为窗口设定一个新的处理函数。 |
GWL_HWNDPARENT | -8 | 改变子窗口的父窗口,应使用SetParent函数。 |
当hWnd参数标识了一个对话框时,也可使用下列值:
常量 | 常量值 | 意义 |
DWL_DLGPROC | DWLP_MSGRESULT + sizeof(LRESULT) (值:4) | 设置对话框过程的新地址。 |
DWL_MSGRESULT | 0 | 设置在对话框过程中处理的消息的返回值。 |
DWL_USER | DWLP_DLGPROC + sizeof(DLGPROC) (值:8) | 设置的应用程序私有的新的额外信息,例如一个句柄或指针。 |
LONG dwNewLong
指定的替换值。
dwNewLong中可以使用以下一些列表控件的专用风格:
LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT
这四种风格决定控件的外观,同时只可以选择其中一种,分别对应:
大图标显示,小图标显示,列表显示,详细报表显示
LVS_EDITLABELS 结点的显示字符可以被编辑,对于报表风格来讲可编辑的只为第一列。
LVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点
LVS_SINGLESEL 同时只能选中列表中一项
返回值:
如果函数成功,返回值是指定的32位整数的原来的值。如果函数失败,返回值为0。若想获得更多错误信息,请调用GetLastError函数。
3.CallWindowProc
函数原型:
LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM IParam);
参数介绍:
lpPrevWndFunc:指向前一个窗口过程的指针。如果该值是通过调用GetWindowLong函数,并将该函数中的nlndex参数设为GWL_WNDPROC或DWL_DLGPROC而得到的,那么它实际上要么是窗口或者对话框的地址,要么就是代表该地址的句柄。
hWnd:指向接收消息的窗口过程的句柄。
Msg:指定消息类型。
wParam:指定其余的、消息特定的信息。该参数的内容与Msg参数值有关。
IParam:指定其余的、消息特定的信息。该参数的内容与Msg参数值有关。
返回值:返回消息处理结果
示列:
long OldWindowProc;
WNDPROC lpfnOldProc = 0;
LRESULT NewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_PAINT)
{
MessageBox(NULL, "dd", "绘图消息被触发了", 0);
}
return CallWindowProc(lpfnOldProc, hWnd, message, wParam, lParam);//交给旧的消息处理函数
}
// 入口函数
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
HWND hWnd = NULL;
LPCTSTR lpClassName = "MyWnd"; // 注册窗口的名称
RegisterWindow(lpClassName, hInstance);
hWnd = CreateMyWindow(lpClassName, hInstance);
OldWindowProc = GetWindowLong(hWnd, GWL_WNDPROC/* -4 */); //保存原窗口消息处理函数地址
lpfnOldProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)NewWndProc); //设置新的消息处理函数
DisplayMyWnd(hWnd);
doMessage();
return 0;
}
HWND hWnd = NULL;
LPCTSTR lpClassName = "MyWnd"; // 注册窗口的名称
RegisterWindow(lpClassName, hInstance);
hWnd = CreateMyWindow(lpClassName, hInstance);
OldWindowProc = GetWindowLong(hWnd, GWL_WNDPROC/* -4 */); //保存窗口原风格
WNDPROC lpfnOldProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)NewWndProc); //设置新的消息处理函数
DisplayMyWnd(hWnd);
doMessage();
return 0;
}
运行效果:
完整代码:
#include "stdafx.h"
#include <windows.h>
HWND hWnd; //progman
//消息函数
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//判断消息ID
switch (uMsg){
case WM_DESTROY: // 窗口销毁消息
PostQuitMessage(0); // 发送退出消息
return 0;
}
// 其他的消息调用缺省的消息处理程序
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// 3、注册窗口类型
BOOL RegisterWindow(LPCSTR lpcWndName, HINSTANCE hInstance)
{
ATOM nAtom = 0;
// 构造创建窗口参数
WNDCLASS wndClass = { 0 };
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WindowProc; // 指向窗口过程函数
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = NULL;
wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = lpcWndName; // 注册的窗口名称,并非标题,以后创建窗口根据此注册的名称创建
nAtom = RegisterClass(&wndClass);
return TRUE;
}
//创建窗口(lpClassName 一定是已经注册过的窗口类型)
HWND CreateMyWindow(LPCTSTR lpClassName, HINSTANCE hInstance)
{
HWND hWnd = NULL;
// 创建窗口
hWnd = CreateWindow(lpClassName, "test", WS_OVERLAPPEDWINDOW^WS_THICKFRAME, 0, 0, 1000, 800, NULL, NULL, hInstance, NULL);
return hWnd;
}
//显示窗口
void DisplayMyWnd(HWND hWnd)
{
//获得屏幕尺寸
int scrWidth = GetSystemMetrics(SM_CXSCREEN);
int scrHeight = GetSystemMetrics(SM_CYSCREEN);
RECT rect;
GetWindowRect(hWnd, &rect);
ShowWindow(hWnd, SW_SHOW);
//重新设置rect里的值
rect.left = (scrWidth - rect.right) / 2;
rect.top = (scrHeight - rect.bottom) / 2;
//移动窗口到指定的位置
SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
UpdateWindow(hWnd);
}
void doMessage() // 消息循环处理函数
{
MSG msg = { 0 };
// 获取消息
while (GetMessage(&msg, NULL, 0, 0)) // 当接收到WM_QIUT消息时,GetMessage函数返回0,结束循环
{
DispatchMessage(&msg); // 派发消息,到WindowPro函数处理
}
}
long OldWindowProc;
WNDPROC lpfnOldProc = 0;
LRESULT NewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_PAINT)
{
MessageBox(NULL, "dd", "绘图消息被触发了", 0);
}
return CallWindowProc(lpfnOldProc, hWnd, message, wParam, lParam);//交给旧的消息处理函数
}
// 入口函数
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
HWND hWnd = NULL;
LPCTSTR lpClassName = "MyWnd"; // 注册窗口的名称
RegisterWindow(lpClassName, hInstance);
hWnd = CreateMyWindow(lpClassName, hInstance);
OldWindowProc = GetWindowLong(hWnd, GWL_WNDPROC/* -4 */); //保存窗口原风格
lpfnOldProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)NewWndProc); //设置新的消息处理函数
DisplayMyWnd(hWnd);
doMessage();
return 0;
}