Windows核心编程_窗口子类化

窗口子类化:

窗口子类化,即重定向消息,也就是修改某个窗口消息执行函数,重定向

下面代码可以让你更好的理解窗口子类化:

先介绍三个函数:

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_WNDPROCDWL_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;

}


猜你喜欢

转载自blog.csdn.net/bjbz_cxy/article/details/80762692