窗口子类化:
窗口子类化,即重定向消息,也就是修改某个窗口消息执行函数,重定向
下面代码可以让你更好的理解窗口子类化:
先介绍三个函数:
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; }