消息处理

  例子:窗口点击

  好的,现在我们已经得到一个窗口了,但我们什么也做不了除了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. RabbitMQ学习之Work Queues(2)

    目录: 轮询调度(Round-robin dispatching):即依次分配分配任务给worker. 消息答复(Message acknowledgement):在consumer处理完之后,进行消 ...

  2. Spring 侵入式和非侵入式

    1.非侵入式的技术体现 允许在应用系统中自由选择和组装Spring框架的各个功能模块,并且不强制要求应用系统的类必须从Spring框架的系统API的某个类来继承或者实现某个接口. 2.如何实现非侵入式 ...

  3. 365 Water and Jug Problem 水壶问题

    有两个容量分别为 x升 和 y升 的水壶以及无限多的水.请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?如果可以,最后请用以上水壶中的一或两个来盛放取得的 z升 水.你允许:    装满任 ...

  4. [转]oracle 同义词 synonym

    本文转自:http://blog.csdn.net/generalfu/article/details/7906561 同义词定义 当一个用户想访问另外一个用户的表时, 需要在表前加用户名,总加表名不 ...

  5. LN : leetcode 515 Find Largest Value in Each Tree Row

    lc 515 Find Largest Value in Each Tree Row 515 Find Largest Value in Each Tree Row You need to find ...

  6. LN : leetcode 207 Course Schedule

    lc 207 Course Schedule 207 Course Schedule There are a total of n courses you have to take, labeled ...

  7. redis学习-sds数据类型

    今天开始了redis的学习,本来想直接从源码看起的,不过看到有篇对redis介绍的基础教程 <Redis 设计与实现(第一版)> 于是决定从这个开始入门. 1.数据类型定义 typedef ...

  8. Meta标签 h5

    一  PC端meta标签 1 页面关键词 <meta name="keywords" content="your tags"> 2 页面描述 < ...

  9. (转) 淘淘商城系列——使用SolrJ查询索引库

    http://blog.csdn.net/yerenyuan_pku/article/details/72908538 我们有必要在工程中写查询索引库的代码前先进行必要的测试.我们先到Solr服务页面 ...

  10. CAD由一个自定义实体事件中的id得到自定义实体对象(com接口VB语言)

    由一个自定义实体事件中的id得到自定义实体对象.该函数只能在自定义实体事件中调用. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2 ...