处理消息
范例:window_click
不错,我们有个窗口了,不过除了DefWindowProc()允许它做的,如拉抻,最大化等等之外沒有別的什的功能了,并不是很令人激动.
下一章节我将演示如何修改你已有的代码来加点新东西.现在我只来告诉你”处理这个消息,在这里处
理...”你就知道我的意思,知道怎样做且不用看一整个例子.希望如此,所以注意看:P
对于初学者,请把我们最后那个窗口编译好并确信它能工作.然后你要么就在这个例子上修改要么拷到另外一个新工程中来修改.
我们準备加个使用戶点击我们的窗口时候能夠显示出我们程序的名称的功能.不是很酷,就是基本的一个消息的处理.让我们看看我们的WndProc()中有些什么:LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
如果我们想处理鼠标的点击,我们需要添加一个WM_LBUTTONDOWN的处理部分(对于右键与中间键,分別是WM_RBUTTONDOWN与WM_MBUTTONDOWN).
如果你听到我或其它人提到处理消息,就是说在窗口的类的WndProc()中加上如下代码:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN: // <-
// <- we just added this stuff
break; // <-
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
不同消息处理的代码的顺序基本上沒有什么关系.要记住的是一定不要忘了在每个消息处理代码后写上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(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
注意那对新的花括号{}.当你在switch()中定义变量时需要它.这本来是基础的C语言知识,但我认为我应该在此指出来,为那些理解有困难的读者著想.
如果你已经加进了代码,现在就编译它.如果正常的话,你点击窗口你就应该看到一个有.exe字样的对话框弹出来.
你可能已经注意到我们加了两个变量,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将包括一个我们的.exe文件名的字符串,以null结尾.我们把它传递给MessageBox()以一个简单的方法向用戶显示.
所以如果你加了代码,编译了.如果正常,点击窗口你就会看到一个有.exe文件名的对话框弹出来.
如果不是这样,这里是完整的代码.跟你的比较一下,看错误在哪里.
#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(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
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 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
|