初级Windows API C++语言版 编程(4)

在介绍了Windows API的基本结构以后,我给大家介绍一下Windows下的消息机制。

我们知道,大多数Windows的应用程序都有自己的窗口,我们拖动鼠标,就能够改变窗口的大小、位置,而这一结果的实现过程,正是Windows的消息机制的体现。这一过程中,当用户改变窗口大小时,Windows给程序发送一条消息指出新窗口的大小。然后程序根据这条消息,适当调整窗口的大小,以反映大小变化。所谓的“Windows给程序发送消息”,是指Windows调用程序中的一个函数,该函数的参数描述了这个特定消息。这种位于Windows程序中的函数被称为“窗口过程”。

程序创建的每一个窗口都会有相关的窗口过程。这个窗口过程是一个函数,Windows是通过调用窗口过程来给应用程序发送消息的,应用程序就根据这一消息进行相应的处理,然后将控制反给Windows。Windows程序开始执行后,Windows为该程序建立一个“消息队列”。这个消息队列用来存放应用程序可能遇到的各种消息。程序中有一段代码,叫做“消息循环”,用来从“消息队列”中取出消息,并发送给相应的窗口过程。

下面我们看一个简单的例子,有助于大家更好的体会窗口消息:  

/*------------------------------------------------------------
HELLOWIN.C -- Displays "Hello, Windows 2000!" in client area
(c) onefi, 2002
------------------------------------------------------------*/

#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;//声明函数

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
  static TCHAR szAppName[] = TEXT ("HelloWin") ;
  HWND hwnd ;
  MSG msg ;
  WNDCLASS wndclass ;
  //下面这一部分前面给大家介绍过
  wndclass.style = CS_HREDRAW | CS_VREDRAW ; 
  wndclass.lpfnWndProc = WndProc ;
  wndclass.cbClsExtra = 0 ;
  wndclass.cbWndExtra = 0 ;
  wndclass.hInstance = hInstance ;
  wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
  wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  wndclass.lpszMenuName = NULL ;
  wndclass.lpszClassName = szAppName ;

  if (!RegisterClass (&wndclass))  //注册窗口类
  {
    MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
      szAppName, MB_ICONERROR) ;       //如果不是NT内核的系统,出现错误信息。
    return 0 ;
  }

  hwnd = CreateWindow (szAppName,      //程序的名称
    TEXT ("The Hello Program"),        //程序的标题
    WS_OVERLAPPEDWINDOW,               //程序的样式
    CW_USEDEFAULT,                     //默认初始X的坐标
    CW_USEDEFAULT,                     //默认初始Y的坐标
    CW_USEDEFAULT,                     //默认下窗口的宽度
    CW_USEDEFAULT,                     //默认下窗口的长度
    NULL,                              //父窗口句柄
    NULL,                              //菜单句柄
    hInstance,                         //本程序的实例句柄
    NULL) ;                            //附加项

  ShowWindow (hwnd, iCmdShow) ;
  UpdateWindow (hwnd) ;

  while (GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage (&msg) ;
    DispatchMessage (&msg) ;
  }
  return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  HDC hdc ;
  PAINTSTRUCT ps ;
  RECT rect ;

  switch (message)
  {
    case WM_PAINT:
      hdc = BeginPaint (hwnd, &ps) ;

      GetClientRect (hwnd, &rect) ;

      DrawText (hdc,
        TEXT ("Hello, Windows 2000!"),
        -1,
        &rect,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER); //在客户区绘制“Hello,Windows2000!”的标志

      EndPaint (hwnd, &ps) ;
      return 0 ;

    case WM_DESTROY:
      PostQuitMessage (0) ;
      return 0 ;
  }
  return DefWindowProc (hwnd, message, wParam, lParam) ;
}

下面具体说明消息循环的那段代码:

while (GetMessage (&msg, NULL, 0, 0))
{
  TranslateMessage (&msg) ;
  DispatchMessage (&msg) ;
}

msg变量是类型为MSG结构,在第一章中给大家介绍过,其中的POINT也是一种结构,定义如下:

typedef struct tagPOINT{
  LONG x;
  LONG y;
} POINT , *POINT;

消息循环以GetMessage调用开始,它从消息队列中提取一个消息:

GetMessage(&msg,NULL,0,0);

这一调用传给Windows一个指向名字为msg的MSG结构的指针,然后用所接收来的消息填充到msg的各个域中。

WM_PAINT消息

当客户区的一部分或者全部变为无效时,以至于必须将客户区重新绘制时,发送此消息。

在最初建立的客户区内,整个区域都是无效的,所以必须要画一些东西才行。而在移动或者改变大小时,客户区也变得无效,所以还是需要绘制整个区域。对于这个消息的处理,一般来讲,都是从 hdc = BeginPaint (hwnd, &ps) 开始的,又是以 EndPaint (hwnd, &ps) 结束的。在这两个函数中,第一个参数是客户区的句柄,第二个是指向结构为POINT类型的指针。在调用完BeginPaint函数后,需要调用 GetClientRect(hwnd,&rect) ,同样,第一个参数是窗口句柄,第二个参数是指向RECT结构的指针。这个函数的作用是将 rect 结构内所指的区域设置为客户区,自然大家就会想到,客户区是我们可以执行操作的地方。那么,我们就调用 DrawText 函数,在客户区内“绘制”一句话。

WM_DESTROY消息

 当用户单击Close按钮或者执行任意可以关闭程序的操作时,发送此消息。

本程序通过调用 PostQuitMessage 一标准的方式响应 WM_DESTROY 消息: PostQuitMessage(0); 这个函数在程序的消息队列中插入一个 WM_QUIT 消息,而 GetMessage 函数对于除 WM_QUIT 之外的所有消息均返回非0,所以只要接收到 WM_QUIT 消息,将退出 switch 循环。然后执行 return msg.wParam; ,msg是MSG结构的一个指针,其 wParam 域是传递给 PostQuitMessage 函数的值(这里通常是0)。最后返回语句退出 WinMain。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值