Timers and Animation

theForger's Win32 API教程第二版(简体中文)

主页

基础
  1. 开始学习
  2. 一个简单的窗口
  3. 处理消息
  4. 理解消息循环
  5. 使用资源
  6. 菜单和图标
  7. 对话框
  8. 非模态对话框
  9. 标准控件
  10. 对话框常见问题
创建一个简单应用
  1. 在运行时创建控件
  2. 文件与常用对话框
  3. 工具栏与状态栏
  4. 多文档界面
图形设备接口
  1. 位图,设备上下文
  2. 透明位图
  3. 定时器与动画
  4. 文本,字体与顏色
工具与文档
  1. 参考
  2. 免费的Visual C++(最新更新)
附表
  1. 常见错误的解決方法
  2. API vs. MFC
  3. 关于资源文件的说明

处理消息

范例:window_click

[images/window_click.gif]  不错,我们有个窗口了,不过除了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;
}

Copyright © 1998-2008, Brook Miles (forgey). All rights reserved.