消息处理

  例子:窗口点击

  好的,现在我们已经得到一个窗口了,但我们什么也做不了除了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.消息处理 根据英文教程翻译的更多相关文章

  1. Win32编程API 基础篇 -- 1.入门指南 根据英文教程翻译

    入门指南 本教程是关于什么的 本教程的目的是向你介绍使用win32 API编写程序的基础知识(和通用的写法).使用的语言是C,但大多数C++编译器也能成功编译,事实上,教程中的绝大多数内容都适用于任何 ...

  2. Win32编程API 基础篇 -- 4.消息循环

    消息循环 理解消息循环 为了编写任何即使是最简单的程序,了解windows程序的消息循环和整个消息发送结构是非常有必要的.既然我们已经尝试了一点消息处理的东西,我们应该对整个程序有更深入的理解,如果你 ...

  3. Win32编程API 基础篇 -- 6.菜单和图标

    菜单和按钮 例子:菜单1 本小节仅仅向你展示如果向你的窗口中加入一个基本的菜单,通常你会用到一个提前制作好的菜单资源,这会是一份.rc文件并且会被编译链接进你的.exe可执行程序中.这是具体的流程做法 ...

  4. Win32编程API 基础篇 -- 5.使用资源

    使用资源 你可能想参考教程结尾的附近,为了获得跟VC++和BC++资源相关的信息. 在我们讲得更加深入之前,我将大致讲解一下资源的主题,这样在每个小节中我就不必再去重讲一遍了.在这一小节中,你不需要编 ...

  5. Win32编程API 基础篇 -- 2.一个简单的窗口 根据英文教程翻译

    一个简单的窗口 例子:简单的窗口 有时人们在IRC提问,”我应该怎样制作一个窗口”...嗯,这恐怕不是完全这么简单好回答!其实这并不难一旦你明白你在做什么,但在你得到一个可展示的窗口之前还有一些事情需 ...

  6. ASP.NET Web API 基础篇1

    ASP.NET Web API 直到我膝盖中了一箭[1]基础篇 无题 蓦然回首,那些年,我竟然一直很二. 小时候,读武侠小说的时候,看到那些猪脚,常常会产生一种代入感,幻想自己也会遭遇某种奇遇,遇到悬 ...

  7. 我拖拖拖--H5拖放API基础篇

    不要搞错,本文不是讲如何拖地的.看过<javascript精粹>朋友应该知道,他实现拖放的过程比较复杂,现在时代不同了,我们用H5的新的拖放API就能非常方便的实现拖放效果了.最近在园子见 ...

  8. (转)Android高性能编程(1)--基础篇

    关于专题     本专题将深入研究Android的高性能编程方面,其中涉及到的内容会有Android内存优化,算法优化,Android的界面优化,Android指令级优化,以及Android应用内存占 ...

  9. 【TCP/IP】之Java socket编程API基础

    Socket是Java网络编程的基础,深入学习socket对于了解tcp/ip网络通信协议很有帮助, 此文讲解Socket的基础编程.Socket用法:①.主要用在进程间,网络间通信. 文章目录如下: ...

随机推荐

  1. JAVA POI的使用

    最近开发遇到了要通过Java处理Excel文件的场景,于是乎在网上了解了一番,最后自己做了个demo,已上传gitee:https://gitee.com/github-26930945/JavaCo ...

  2. IDEA 激活方式

    最新的IDEA激活方式 使用网上传统的那种输入网址的方式激活不了,使用http://idea.lanyus.com/这个网站提供的工具进行 1.进入hosts文件中:C:\Windows\System ...

  3. ACM_求f(n)

    求f(n) Time Limit: 2000/1000ms (Java/Others) Problem Description: 设函数f(n)=1*1*1+2*2*2+3*3*3+...+n*n*n ...

  4. js易混API汇总

    一:slice()方法 ————————————http://www.w3school.com.cn/jsref/jsref_slice_string.asp ———————————————————— ...

  5. (三)Mybatis总结之动态sql

    动态sql 为何需要动态sql?因为简单的sql语句已经不能满足复杂的业务需求 动态sql相当于sql语句拼接 1.if语句 if语句:判断,如果执行多条件查询,如果中间某个条件变量为空,就跳过当前判 ...

  6. 2-2 列表推导同 filter 和 map 的比较

    列表推导同 filter 和 map 的比较 参考廖雪峰的文档: filter()函数:用于过滤序列. filter()接收一个函数和一个序列.把传入的函数依次作用于传入的序列的每个元素,根据返回值是 ...

  7. HDU_1232_畅通工程

    Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道 ...

  8. Handling unhandled exceptions and signals

    there are two ways to catch otherwise uncaught conditions that will lead to a crash: Use the functio ...

  9. blender_(uv应用)................http://digitalman.blog.163.com/blog/static/23874605620174172058299/

    轻松学习Blender基础入门之九:UV-1 2017-06-21 14:24:49|  分类: Blender |举报 |字号 订阅     下载LOFTER 我的照片书  |   [前言]     ...

  10. 百度地图API获取数据

    目前,大厂的服务范围越来越广,提供的数据信息也是比较全的,在生活服务,办公领域,人工智能等方面都全面覆盖,相对来说,他们的用户基数大,通过用户获取的信息也是巨大的.除了百度提供api,国内提供免费AP ...