WinSDK

一、概述

Windows程序具有相对固定的结构,对编写者而言,不需要书写整个过程,大部分过程由系统完成。
程序中只要按一定的格式填写系统留给客户的那一小部分。
所需要完成的有:
窗口类的定义、窗口的建立、消息函数的书写、消息循环。


二、消息处理函数

Windows程序是事件驱动的,对于一个窗口,它的大部分例行维护是由系统维护的。没个窗口都有一个消息处理函数。
在消息处理函数中,对传入的消息进行处理。系统内还有它自己的缺省消息处理函数。

客户写一个消息处理函数,在窗口建立前,将消息处理函数与窗口关联。这样,每当有消息产生时,就会去调用这个消息处理函数。
通常情况下,客户都不会处理全部的消息,而是只处理自己感兴趣的消息,其他的,则送回到系统的缺省消息处理函数中去。

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
      switch (message)
      {
      case ...
       ...
      case ...
       ...

      }
      return DefWindowProc (hwnd, message, wParam, lParam) ;
}
三、窗口的建立

客户需要自己建立窗口,建立后会得到系统返回的窗口句柄(HWND),后继的针对窗口的操作都针对句柄进行。
1.注册窗口类
建立窗口前,需要制定好这个窗口的相关属性,最主要的就是将自己定义的消息处理函数与窗口关联,其他的属性还包括:菜单、图标等等。
这个属性指定步骤是通过指定"窗口类"来完成的。
对于自己建立的窗口,这个"窗口类"需要自己制定,也即自己填充一个WNDCLASS结构,然后向系统注册。
对于一些特殊窗口,如按钮等控件,他们的行为是系统制定好了的,所以不需要自己注册,直接使用对应的“窗口类”名称就行了。
2.建立窗口
建立窗口时,注册的"窗口类"名称作为参数传入。
这样,当有针对该窗口的消息时,将调用“窗口类”中指定的消息处理函数,在其中得到处理。

四、消息循环

系统会将针对这个程序的消息依次放到程序的“消息队列”中,由程序自己依次取出消息,在分发到对应的窗口中去。
因此,建立窗口后,将进入一个循环。
在循环中,取出消息、派发消息,循环往复,直到取得的消息是退出消息。
循环退出后,程序即结束。
#include "stdafx.h"
#include <windows.h>

//一、消息处理函数
//参数:窗口句柄,消息,消息参数,消息参数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 //处理感兴趣的消息
 switch (message)
 {
 case WM_DESTROY:
  //当用户关闭窗口,窗口销毁,程序需结束,发退出消息,以退出消息循环
  PostQuitMessage (0) ;
  return 0 ;
 }
 //其他消息交给由系统提供的缺省处理函数
 return ::DefWindowProc (hwnd, message, wParam, lParam) ;
}

//二、应用程序主函数
//参数:实例句柄、前一个实例的句柄、命令行参数、窗口显示方式
#include "stdafx.h"
#include<windows.h>
BOOL InitApplication(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance ,int nCmdShow);
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
static TCHAR szAppName[]=TEXT("HelloWin");//窗口类名称
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  // TODO: Place code here.
 MSG msg;
 if(!hPrevInstance)
  if(!InitApplication(hInstance))
  {
   MessageBox(NULL,TEXT("RegisterClass Fail!"),szAppName,MB_ICONERROR);
   return false;
  }
 if(!InitInstance(hInstance,nCmdShow))
  return false;
 //消息循环
 while(GetMessage(&msg,NULL,0,0))//从消息队列中取消息
 {
  TranslateMessage(&msg);//转换消息
  DispatchMessage(&msg);//派发消息
 }
// return 0;
 return (msg.wParam);
}
BOOL InitApplication(HINSTANCE hInstance)
{
// static TCHAR szAppName[]=TEXT("HelloWin");//窗口类名称
 //定制"窗口类"结构
 WNDCLASS wc;
 wc.style=CS_HREDRAW|CS_VREDRAW;
 wc.lpfnWndProc=(WNDPROC) WndProc;  //关联消息处理函数
 wc.cbWndExtra=0;
 wc.cbClsExtra=0;
 wc.hInstance=hInstance;   //实例句柄
// wc.hIcon=LoadIcon(hInstance,"jjhouricon");  //图标
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);  //图标
 wc.hCursor=LoadCursor(NULL,IDC_ARROW);  //光标
 wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);//画刷
 wc.lpszMenuName="GenericMenu";
// wc.lpszClassName="MyWindow";//类名称
 wc.lpszClassName=szAppName; //类名称
 return (RegisterClass(&wc));
}
BOOL InitInstance(HINSTANCE hInstance ,int nCmdShow)
{
 //建立窗口
 HWND hWnd;
// hWnd=CreateWindow("MyWindow",  //窗口类名称
 hWnd=CreateWindow(szAppName,  //窗口类名称
  "This is Windows SDK", //窗口标题
  WS_OVERLAPPEDWINDOW,   //窗口风格
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  CW_USEDEFAULT,
  NULL,
  NULL,
  hInstance,      //实例句柄
  NULL);
 if(hWnd==NULL)
  return false;
 ShowWindow(hWnd,nCmdShow);
 UpdateWindow(hWnd);
 return true;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
 switch(message)
 {
 case WM_DESTROY:
  PostQuitMessage(0);
  break;
 default:
  return DefWindowProc(hWnd,message,wParam,lParam);
 }
 return 0;
}
首先,在C语言中的入口函数是main函数,在Win32程序中则是WinMain。其原型是
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int CmdShow)
第一个参数是hInstance,是所传进来的值是此程序的当前程序实例句柄。什么叫实例呢?当你运行两次同一个Windows程序时,屏幕上会出现两个一模一样的窗口;这时我们就说这个程序就被生成了两个实例。再举一个例子,在你眼前搁仨苹果,其时这个仨苹果就是苹果这一大类的三个实例。按照这个思路说实例就是一个抽象概念中的实体存在。那么严格来说其时我们所编写的并不是这个程序,而是这个程序的逻辑。而程序实例则是按照这个我们编写的逻辑所生成的实体结果。而句柄就是用来代表实例的,它是一个32位的值。每一个实例都对就着一个32位的值,而这个值就被称为句柄。不知道我说明白没有。这里的Instance就是当前程序被实例化后的句柄。而且属于同一个实例中的资源是共享的。第二个参数hPreInstance则代表上一个(前一个)程序实例句柄,在Win32程序中这个值总为空(为零),第三个参数是lpCmdLine,这是一个字符串,记录着启动程序时的命令行,起着C中main函数的(argc,argv)的作用.最后nCmdShow则表示这个程序的窗口是否被显示出来。

在主函数中,第一个要执行的函数就是InitApplication(),语句如下:

if (!InitApplication(hInstance))
return (FALSE);
这个函数所起的作用是注册窗口类。注册窗口类的意思就是告诉系统将我们的提供的图标,菜单,消息处理函数,光标联系起来成为一个窗口类,为后面的显示窗口作准备。在InitApplication()函数中使用RegisterClass()来注册窗口。如果成功则返回true,否则返回false。其唯一的参数是一个WNDCLASS结构。其中各字段功能如下:(关于具体值请查看MSDN)
style 指定窗口风格,譬如例子所举的CS_HREDRAW表示当水平长度发生改变时,重画整个窗口。 LpfnWndProc 指定窗口的消息处理函数,其函数的原型必须是
LRESULT CALLBACK WndProcName(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
WndProcName这一名字是随便起的.
hInstance 标识该窗口属于哪个程序实例.
hIcon 标识该窗口图标的图标句柄
hCurosr 标识该窗口光标的光标句柄
hbrBackground 标识该窗口的背景画笔.
lpszClassName 为这个窗口类所起的名字,为后来建立窗口引用窗口类所用。

当注册窗口类成功后就可以建立窗口了。主函数调用InitInstance()来建立窗口.在InitInstance()函数中使用CreateWindow();来建立窗口,其中第一个参数就是窗口类的名称,则注册窗口类时lpszClassName字段中的内容。如果成功则返回句柄,句柄代表刚刚建立好的窗口(实例)。否则的话返回的句柄为空。当建立好窗口的并不立即显示,还需用ShowWindow来使系统显示窗口,其参数就是一个窗口句柄(HWND)。看吧,在WinSDK中都是句柄来标识任何东西的(程序,窗口,图标,光标,文件等等)。然后再使用UpdateWindow()让窗口在屏幕上重绘一遍,使其真正显示出来。最后返回true.
接着就是WinSDK中重要一节消息循环:
while (GetMessage(&msg, NULL, 0, 0)) 
{
 TranslateMessage(&msg);
 DispatchMessage (&msg);
}
在每个程序实例中系统都会给配置了一个消息队列,当消息产生后(譬如:刷新WM_PAINT,鼠标移动WM_MOUSEMOVE,键盘某个键被按下WM_KEYDOWN等等),就会将其放入队列尾部。程序这里用了一个while循环,这就是著名的消息循环了。GetMessage()在队列头部取出一条消息放入第一参数msg中,如果不是WM_QUIT (退出程序消息)消息则返回true,如果是WM_QUIT则返回false,结束循环。循环中第一个函数TranslateMessage()是键盘转换函数,其功能是将虚拟键消息转换成字符消息:

*WM_KEYDOWN/WM_KEYUP组合成一个WM_CHAR或WM_DEADCHAR消息
*WM_SYSKEYDOWN/WM_SYSKEYUP组合成一个WM_SYSCHAR或WM_SYSDEADCHAR消息。
并将组合成的消息放到队列当中去,等以后处理。

DispatchMessage()函数是将消息传送给相应的窗口消息处理函数中去。在MSG结构中有一个HWND字段它记录着产生消息的窗口,DispatchMessage会查找这个HWND句柄属于哪个窗口类,并将消息传入这个窗口类所联系的消息处理函数(在WNDCLASS结构中LpfnWndProc字段所指向的函数)中去。这样它就完成了它的消息分配工作。在上面示例程序中,只注册了一个窗口类。所以所有消息都是由这个窗口类的窗口实例所产生的,因此所有的消息都会被传入WinProc中去了。

在消息处理函数的入口参数中,是标识一条消息的主要信息,hWnd发生消息的源窗口,message消息的类型表示发生了什么消息,wParam,lParam与消息捆绑来的信息。因为在C/C++中类型是可以自由转换的,所以根据不同消息,其里面的内容是不一致。在消息处理函数中一般上是用switch/case语句来实现不同消息不同处理的。相信大家一看就明白怎么回事了。

关于message中的信息在VC98/Include/WinUSER.h(参考行数1292)中有详细的定义,各个消息的涵义可在MSDN中查到。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值