重温WIN32 API ------ Window消息跟踪

Windows操作系统的名称本身就是其核心概念--窗口。与窗口密不可分的就是消息了,本文建立一个最简单的Windows窗口程序,然后增加跟踪代码,把所有的Windows消息打印到文件中。我们知道,Windows处理消息的时候是序列化处理的,只有一个线程来完成,所以消息的处理具有严格的顺序,这也便于我们分析消息处理过程。项目代码如下:#include #include "LogWriter.h"
摘要由CSDN通过智能技术生成

1 探索消息处理过程的必要性与可能性

Windows操作系统的名称本身就是其核心概念--窗口。与窗口密不可分的就是消息了,本文建立一个最简单的Windows窗口程序,然后增加跟踪代码,把所有的Windows消息打印到文件中。我们知道,Windows处理消息的时候是序列化处理的,只有一个线程来完成,所以消息的处理具有严格的顺序,这也便于我们分析消息处理过程。

运行环境: Windows8.1

编译环境:VS2013

项目源码:见附录

2 消息跟踪结果与分析

2.1 结果文件

由于结果文件太大了,请读者自己编译此项目运行查看,项目源码已放到了文后的附录里。

2.2 分析结论

USER32.dll中的代码和我们编写的代码彼此调用,下面是几个具体的小结论。

(1)当我们调用CreateWindow()创建窗口的时候,这个函数的内部却在以不同参数多次调用我们编写的窗口过程WndProc了;

(2)当我们调用ShowWindow()显示窗口的时候,这个函数内部疯狂地多次以不同参数调用WndProc();

(3)当我们调用UpdateWindow()更新窗口时,这个函数内部以WM_PAINT参数调用WndProc();

(4)当我们调用GetMessage()从消息队列取消息时,这个函数内部可能会多次调用WndProc()来处理Send到消息队列中的消息,处理完sent的消息后,才返回一个posted的消息;

(5)我们在WndProc()里调用了DefWindowProc(),而这个函数内部也会根据处理消息的类型,反过来调用WndProc(),有点像递归调用了,不过每次使用的参数值不同,不会出现死循环;

(6)窗口被销毁后,User32模块内部以WM_DESTROY参数调用WndProc()。

(7)应用程序必须自己主动调用PostQuitMessage()来把WM_QUIT放入消息队列中结束消息循环。

附录 项目源代码

main.cpp

 

#include <Windows.h>
#include "LogWriter.h"
#include "WindowsMessages.h"

LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t* szCmdLine, int iCmdShow)
{
	LOG(L"程序开始");
	wchar_t szClassName[] = L"MyWindowClass";
	// 注册窗口类
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = NULL;
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = szClassName;
	wcex.hIconSm = NULL;
	LOG(L"RegisterClassEx()开始");
	::RegisterClassEx(&wcex);
	LOG(L"RegisterClassEx()返回");

	// 创建窗口
	LOG(L"CreateWindow()开始");
	HWND hWnd = CreateWindow(szClassName, L"Windows 消息测试", WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
	LOG(L"CreateWindow()返回");

	LOG(L"ShowWindow()开始");
	::ShowWindow(hWnd, SW_SHOW);
	LOG(L"ShowWindow()返回");

	LOG(L"UpdateWindow()开始");
	::UpdateWindow(hWnd);
	LOG(L"UpdateWindow()返回");

	// 开启消息循环, 直到取回WM_QUIT消息,GetMessage()返回0,退出循环
	MSG msg;
	BOOL bRet = 0;
	wchar_t str[256];
	while (1)
	{
		LOG(L"GetMessage()开始");
		bRet = GetMessage(&msg, NULL, 0, 0);
		::wsprintf(str, L"GetMessage()返回,取回消息:%s,对应窗口:%X", get_msg_name(msg.message), msg.hwnd);
		LOG(str);

		if (bRet == 0)
		{
			// 收到了WM_QUIT,退出循环
			break;
		}
		else if (bRet == -1)
		{
			// 处理错误
		}
		else
		{
			TranslateMessage(&msg);
			LOG(L"DispatchMessage()开始");
			DispatchMessage(&msg);   // 根据msg.hwnd调用指定窗口过程
			LOG(L"DispatchMessage()返回");
		}
	}

	// 程序结束
	LOG(L"程序结束");
	ENDLOG
	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	wchar_t str[128];
	::wsprintf(str, L"WndProc被调用开始,消息参数: %s", get_msg_name(message));
	LOG(str);
	int r = 0;
	switch (message)
	{
	case WM_CREATE:
		break;
	case WM_DESTROY:
		::PostQuitMessage(0);   // 窗口销毁后,指示退出消息循环
		break;
	default:
		LOG(L"DefWindowProc()开始");
		r = ::DefWindowProc(hWnd, message, wParam, lParam);
		LOG(L"DefWindowProc()返回");

		LOG(L"WndProc返回");
		return r;
	}
	LOG(L"WndProc返回");
	return 0;
}

 


其他辅助文件的功能包括:打印到文件和根据消息号获得消息名称。这些辅助文件一并列到下面:

LogWriter.h

#pragma once
/*
日志记录类
功能描述:
根据当前时间自动生成日志文件名,自动记录日志到日志文件。

日志文件名格式(样例):
20141219211252255.log

日志内容格式(样例):
2014年12月19日11时52分55秒,源文件:e:\work\udptest\udptestdlg.cpp,第109行, 这里是要写的日志内容

使用方式:
此类采用单例模式设计,为使用方便,定义了两个宏供用户调用。样例代码:
LOG(L"这里是要写的日志内容");  // 记录日志到文件
ENDLOG  // 程序退出之前调用,关闭日志文件
*/
#include <stdio.h>
class LogWriter
{
protected:
	LogWriter();
	~LogWriter();
private:
	wchar_t fileName[1024];
	FILE* fp;
public:
	void Log(wchar_t* log);
public:
	static LogWriter* GetLogWriter();
	static void DeleteLogWriter();
private:
	static LogWriter* theOnlyLogWriter;
};

#define LOG(x) \
{ \
	wchar_t buffer[2048]; \
	SYSTEMTIME st; \
	::GetLocalTime(&st); \
	swprintf_s(buffer, L"%04d年%0
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值