Win32编程API 基础篇 -- 3.消息处理 根据英文教程翻译
消息处理
例子:窗口点击
好的,现在我们已经得到一个窗口了,但我们什么也做不了除了DefWindowProc()允许窗口大小被调整,最大最小化等。。。这不是很激动人心啊
在接下来的一小节中我将向你展示如何修改现有的程序,让它做一些新的事情,这样我就可以告诉你,“处理消息然后这样做。。。”,我会明白我的意思是什么并且在不需要看完完整的栗子的基础上完成它。所以不管怎样,集中注意力
OK,对初学者来说拿最近的一个窗口程序的代码,保证编译通过并且正常运行,然后你就可以在这份代码的基础上进行一些小修改,或者把代码复制到新的一个项目中进行修改。
我们要添加一项功能,只要用户点击窗口,就显示我们程序的名字。这不是很激动人心,基本上是通过获取处理消息的句柄实现的,让我们看看WndProc()中有什么
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage();
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return ;
}
如果我们想处理鼠标点击事件,我们需要添加一个WM_LBUTTONDOWN的处理器(或者 WM_RBUTTONDOWN, WM_MBUTTONDOWN分别对应鼠标右击和中击)
如果我或其他人提到处理一个消息,意思是在窗口类的WndProc()中添加相应的处理消息处理程序,如下所示:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN: // <-
// <- 我们只是添加了这个东西
break; // <-
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage();
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return ;
}
你处理消息的顺序是很重要的,确保你有在每个case结尾加上break;,你可以看到我们在switch()中添加了另一个case,现在我们希望当代码跑到这个的时候有些事情发生。
首先我会展示我们要添加的代码(向用户显示我们程序的文件名),然后我会把这些代码集合到我们的程序中。接下来我可能只会向你展示这些代码并且让你自己集合到程序中去,这对我来说是好的因为不需要说太多废话,对你来说也是好的,这样你就可以把代码嵌入到任何你想加入的程序中去而不仅仅只是我呈现给大家的这个栗子。如果你不确定怎么做,看看ZIP样例代码文件中关于这一小节的内容。
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
现在这段代码不能代表它本身,它不能被插入我们旧代码中的任何位置。我们明确地想让它在用户点击窗口时运行,所以这就是我想整合进我们的骨骼程序中的一点代码。
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
// BEGIN NEW CODE
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL); GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
// END NEW CODE
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage();
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return ;
}
注意花括号,当我们在switch()中声明一个新的变量的时候就需要加上花括号,这应该是C语言的基础知识,但我想我应该指出你正在做的所有事情。
所以你添加那段代码,然后编译它,如果它正常运行,点击窗口,然后你会看到一个现实你可执行文件的消息盒。
你会注意到在这里添加了两个变量,hInstance和szFileName。查阅一下GetModuleFileName()函数,你会发现第一个参数是一个HINSTANCE跟可执行模块相关(我们的程序,.exe可执行文件),我们从哪里得到这个参数呢?答案是通过GetModuleHandle(),GetModuleHandle()的参考文献中指明当传入一个NULL时,会返回“创建调用进程的文件的句柄”,这恰好是我们所需要的,刚才提到的那个HINSTANCE。把这些信息都放在一起我们可以得到以下声明:
HINSTANCE hInstance = GetModuleHandle(NULL);
现在轮到二次个参数,再次转向我们可靠的参考手册,我们可以看到它是“一个指向接收指定的模块的路径和文件的缓冲区的指针”,数据类型是LPTSTR(或者LPSTR如果你的参考手册是老的)。因为LPSTR跟char*是相同的我们可以像下面那样声明一个字符数组:
char szFileName[MAX_PATH];
MAX_PATH是一个通过<windows.h>头文件中定义好的一个宏,这个宏用来定义存储一个win32下的文件名的缓冲区的最大长度,我们也把MAX_PATH传递给GetModuleFileName()这样它就会知道缓冲区的大小。
在GetModuleFileName()被调用之后,szFileName变量的缓存将会被填充,填充的内容就是我们可执行文件的文件名,我们把这个值传递给MessageBox(),通过这个简单的方式把它显示给用户。
如果你插入代码后不能正常地运行,这里是程序的完整的代码提供参考,跟它进行对比然后看看会你哪些地方犯了错误。
#include <windows.h> const char g_szClassName[] = "myWindowClass"; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL); GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage();
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return ;
} int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg; wc.cbSize = sizeof(WNDCLASSEX);
wc.style = ;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = ;
wc.cbWndExtra = ;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return ;
} hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, , ,
NULL, NULL, hInstance, NULL); if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return ;
} ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd); while(GetMessage(&Msg, NULL, , ) > )
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
PS.由于本人英文水平所限,只能翻译到这个程度了,有纰漏还望多多指出,附上本篇翻译的英文原版教程地址:http://www.winprog.org/tutorial/window_click.html
Win32编程API 基础篇 -- 3.消息处理 根据英文教程翻译的更多相关文章
- Win32编程API 基础篇 -- 1.入门指南 根据英文教程翻译
入门指南 本教程是关于什么的 本教程的目的是向你介绍使用win32 API编写程序的基础知识(和通用的写法).使用的语言是C,但大多数C++编译器也能成功编译,事实上,教程中的绝大多数内容都适用于任何 ...
- Win32编程API 基础篇 -- 4.消息循环
消息循环 理解消息循环 为了编写任何即使是最简单的程序,了解windows程序的消息循环和整个消息发送结构是非常有必要的.既然我们已经尝试了一点消息处理的东西,我们应该对整个程序有更深入的理解,如果你 ...
- Win32编程API 基础篇 -- 6.菜单和图标
菜单和按钮 例子:菜单1 本小节仅仅向你展示如果向你的窗口中加入一个基本的菜单,通常你会用到一个提前制作好的菜单资源,这会是一份.rc文件并且会被编译链接进你的.exe可执行程序中.这是具体的流程做法 ...
- Win32编程API 基础篇 -- 5.使用资源
使用资源 你可能想参考教程结尾的附近,为了获得跟VC++和BC++资源相关的信息. 在我们讲得更加深入之前,我将大致讲解一下资源的主题,这样在每个小节中我就不必再去重讲一遍了.在这一小节中,你不需要编 ...
- Win32编程API 基础篇 -- 2.一个简单的窗口 根据英文教程翻译
一个简单的窗口 例子:简单的窗口 有时人们在IRC提问,”我应该怎样制作一个窗口”...嗯,这恐怕不是完全这么简单好回答!其实这并不难一旦你明白你在做什么,但在你得到一个可展示的窗口之前还有一些事情需 ...
- ASP.NET Web API 基础篇1
ASP.NET Web API 直到我膝盖中了一箭[1]基础篇 无题 蓦然回首,那些年,我竟然一直很二. 小时候,读武侠小说的时候,看到那些猪脚,常常会产生一种代入感,幻想自己也会遭遇某种奇遇,遇到悬 ...
- 我拖拖拖--H5拖放API基础篇
不要搞错,本文不是讲如何拖地的.看过<javascript精粹>朋友应该知道,他实现拖放的过程比较复杂,现在时代不同了,我们用H5的新的拖放API就能非常方便的实现拖放效果了.最近在园子见 ...
- (转)Android高性能编程(1)--基础篇
关于专题 本专题将深入研究Android的高性能编程方面,其中涉及到的内容会有Android内存优化,算法优化,Android的界面优化,Android指令级优化,以及Android应用内存占 ...
- 【TCP/IP】之Java socket编程API基础
Socket是Java网络编程的基础,深入学习socket对于了解tcp/ip网络通信协议很有帮助, 此文讲解Socket的基础编程.Socket用法:①.主要用在进程间,网络间通信. 文章目录如下: ...
随机推荐
- C头文件中尖括号与双引号的区别及编译搜索顺序
这两天被问到一个很有意思的问题:C头文件中尖括号与双引号有什么区别,以前只大约知道 <> 常用在系统库文件,"" 常用在自定义的借口文件中,那具体在gcc编译搜索过程中 ...
- PHP的包依赖管理工具Composer简介
composer是一个基于项目的依赖管理器,负责将php项目的所依赖的包和库安装在项目的目录中,默认不会不会安装任何数据到全局.他用于取代之前pear工具 1 安装Composer curl -sS ...
- 状态压缩+枚举 UVA 11464 Even Parity
题目传送门 /* 题意:求最少改变多少个0成1,使得每一个元素四周的和为偶数 状态压缩+枚举:枚举第一行的所有可能(1<<n),下一行完全能够由上一行递推出来,b数组保存该位置需要填什么 ...
- 使用JS分页 <span> beta 3.0 完成封装的分页
<html> <head> <title>分页</title> <style> #titleDiv{ width:500px; backgr ...
- Windows 7上安装Microsoft Loopback Adapter(微软环回网卡)
Oracle 安装过程中,先决条件检查遇到如下错误: 正在检查网络配置要求... 检查完成.此次检查的总体结果为: 失败 <<<< 问题: 安装检测到系统的主 IP 地址是 ...
- [转]mysql update操作
转自:http://www.cnblogs.com/ggjucheng/archive/2012/11/06/2756392.html update语法 Single-table语法: UPDATE ...
- WEB-CSS实现单行(多行)文本溢出显示省略号
//单行文本溢出部分隐藏显示省略号...overflow: hidden; text-overflow:ellipsis; white-space: nowrap; /** n 行文本溢出部分隐藏显示 ...
- 60查找nanopim1plus的HDMI为720p输出的问题
60查找nanopim1plus的HDMI为720p输出的问题 大文实验室/大文哥 壹捌陆捌零陆捌捌陆捌贰 21504965 AT qq.com 完成时间:2017/12/5 17:51 版本:V1. ...
- Android学习笔记(五)Android框架
一.技术结构图 注:开发者最需要关注的是第三层“Application Framework” 二.基于组件的应用程序开发 1)Activity 一个Activity就是一个界面,负责和用户交互. 2) ...
- SVN的三种merge方式【转】
SVN的merge操作是为了保证主干(trunk)和分支(branch)同步,merge方式有: 1.Merge a range of revisions(合并一个范围的版本) 2.Reintegra ...