win32应用程序消息机制(窗口的建立过程)

来源:互联网 发布:.tv域名前景 编辑:程序博客网 时间:2024/05/16 23:40

窗口创建过程


注册窗口类

  • win32中通过调用RegisterClassEx API来注册窗口样式,相当于指定一个窗口模板.
  • 通过WNDCLASSEX结构体来指定窗口类的样式,WNDCLASSEX 是一个窗口风格样式的设置结构体.

具体代码如下

//由入口函数WinMain调用此函数ATOM MyRegisterClass(HINSTANCE hInstance){    //指定窗口类的样式的结构体    WNDCLASSEXW wcex;     wcex.cbSize = sizeof(WNDCLASSEX);    wcex.style          = CS_HREDRAW | CS_VREDRAW;    wcex.lpfnWndProc    = WndProc;    wcex.cbClsExtra     = 0;    wcex.cbWndExtra     = 0;    wcex.hInstance      = hInstance;    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32DEMO));    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WIN32DEMO);    wcex.lpszClassName  = szWindowClass;    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));    //RegisterClassExW函数的功能就是根据给定窗口类的样式的结构体wcex注册窗口类    return RegisterClassExW(&wcex);}

cbSize

存储表示该结构大小的字节数,通常以sizeof(WNDCLASSEX)的形式对该域进行设置 一定要确保在调用

一定要在 GetClassInfoEx 前设置该值

style

存储表示窗口类风格的整数,它决定了该窗口的外观和内在特征。

可以使用’|‘进行多个选项绑定
具体绑定原理参见:枚举值的组合使用

lpfnWndProc

  • lp :ong point 指针。
  • fn :Function 函数。
  • wnd :window 窗口
  • proc :process 过程,步骤

    所以lpfnWndProc就是指向窗口处理过程的函数指针

  • 必须使用 CallWindowProc 函数去调用窗口过程

cbClsExtra

为窗口类的额外信息做记录,初始化为0。

一般用得很少

cbWndExtra

记录窗口实例的额外信息,系统初始为0

如果应用程序使用WNDCLASSEX注册在资源文件中使用CLASS指令创建的对话框, 则必须将此成员设置为DLGWINDOWEXTRA

hInstance

该窗口类的窗口过程所属的应用实例

hIcon

存储该类窗口的图标的句柄

如果设置为NULL, 系统将提供默认图标

hCursor

存储该窗口光标的句柄

  • 该域必须是一个光标资源的句柄。
  • 如果为NULL, 则只要鼠标移动到应用程序的窗口中, 应用程序就必须显式设置光标形状

hbrBackground

窗口类的背景刷.

为背景刷句柄,也可以为系统颜色值

lpszMenuName

存储以空结尾的指定类菜单资源名的字符串指针

  • 类菜单资源名已经在资源文件中进行了定义。
  • 如果使用整数来标识菜单, 请使用MAKEINTRESOURCE宏
  • 如果此成员为NULL, 属于此类的Windows没有默认菜单

lpszClassName

当前窗口类的名称

使用当前窗口类的唯一标识符

hIconSm

存储该类窗口小图标的句柄。


创建窗口

注册窗口类后,就可以创建窗口了,创建窗口的有关语句如下:

////由入口函数WinMain调用此函数BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){   hInst = hInstance; // 将实例句柄存储在全局变量中 // 通过调用CreateWindowW来创建窗口   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);   if (!hWnd)   {      return FALSE;   }   ShowWindow(hWnd, nCmdShow);   UpdateWindow(hWnd);   return TRUE;}

参数说明

  • 参数1:登记的窗口类名,这个类名刚才咱们在注册窗口时已经定义过了。

  • 参数2:用来表明窗口的标题。

  • 参数3: 用来表明窗口的风格,如有无最大化,最小化按纽啊什么的。

  • 参数4,5: 用来表明程序运行后窗口在屏幕中的坐标值。

  • 参数6,7: 用来表明窗口初始化时(即程序初运行时)窗口的大小,即宽度与高度。

  • 参数8: 在创建窗口时可以指定其父窗口,这里没有父窗口则参数值为0。

  • 参数9: 用以指明窗口的菜单,菜单以后会讲,这里暂时为0。

  • 参数10:该窗口类的窗口过程所属的应用实例

  • 最后一个参数是附加数据,会被传递到窗口过程中。一般都是0。


显示和更新窗口

API函数CreateWindow创建完窗口后,要想把它显示出现,还必须调用另一个API函数ShowWindows.形式为:ShowWindow (hWnd, nCmdShow);

  • hwnd: 窗口句柄,告诉ShowWindow()显示哪一个窗口
  • nCmdShow:告诉它如何显示这个窗口.
    • 最小化(SW_MINIMIZE)
    • 普通(SW_SHOWNORMAL)
    • 最大化(SW_SHOWMAXIMIZED)

WinMain在创建完窗口后就调用ShowWindow函数,并把iCmdShow参数传送给这个窗口。
WinMain()调用完ShowWindow后,还需要调用函数UpdateWindow使窗口得到更新.


创建消息循环

Windows为每个正在运行的应用程序都保持一个消息队列。
息响应机制是在Win32子系统中实现的.

  • 为什么不在内核中实现?
    • 因为内核越简单越好
    • 如果在内核中实现, 则会使内核占用大量资源
    • 可能会引起不稳定

过程

  1. 当按下鼠标或者键盘时,Windows并不是把这个输入事件直接送给应用程序,
  2. 而是将输入的事件先翻译成一个消息,
  3. 然后把这个消息放入到这个应用程序的消息队列中去。
  4. 应用程序的WinMain函数通过执行一段代码(主消息循环)从她的队列中来检索Windows送往她的消息。
  5. 然后WinMain就把这些消息分配给相应的窗口函数以便处理它们,
    这段代码是一段循环代码,故称为”消息循环”

具体代码如下

 // 主消息循环:  //通过GetMessage函数获取当前应用程序的消息队列的消息    while (GetMessage(&msg, nullptr, 0, 0))    {        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))        {            //消息翻译            TranslateMessage(&msg);            //消息分发            DispatchMessage(&msg);        }    }//MSG的定义 在WinUser.h中typedef struct tagMSG {    HWND        hwnd;     UINT        message;    WPARAM      wParam;    LPARAM      lParam;    DWORD       time;    POINT       pt;#ifdef _MAC    DWORD       lPrivate;#endif} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

MSG结构体参数解析

  • hwnd
    • 消息要发送到的那个窗口的句柄,
    • 这个窗口就是用CreateWindows函数创建的那一个。
    • 如果是在一个有多个窗口的应用程序中,用这个参数就可决定让哪个窗口接收消息。
  • message
    • 消息值, UINT类型,它唯一标识了一种消息类型。
    • 每种消息类型都在Windows文件中定义了,这些常量都以WM_开始后面带一些描述了消息特性的名称。
  • wParam,lParam
    • 一个32位的附加信息,UINT类型,这个值的意义由message决定
    • wParam,lParam和message一起决定要进行怎样的操作
    • 通常作为指针来使用
  • time
    • 消息创建的时间
    • 在这个域中写入的并不是日期,而是从Windows启动后所测量的时间值
    • Windows用这个域来使用消息保持正确的顺序。
  • pt
    • 消息创建时鼠标所在屏幕当中的位置

GetMessage

GetMessage(    _Out_ LPMSG lpMsg,    _In_opt_ HWND hWnd,    _In_ UINT wMsgFilterMin,    _In_ UINT wMsgFilterMax);


  • 第一个参数是要接收消息的MSG结构的地址,
  • 第二个参数表示窗口句柄,NULL则表示要获取该应用程序创建的所有窗口的消息;
  • 第三,四参数指定消息范围。

在接收到除WM_QUIT之外的任何一个消息后,GetMessage()都返回TRUE。
如果GetMessage收到一个WM_QUIT消息,则返回FALSE,结束消息循环,从而终止应用程序。

TranslateMessage

将用GetMessage读入的消息翻译成一些键盘消息

对大多数消息来说它并不起什么作用

DispatchMessage

在注册窗口类时曾提到过,注册窗口类时,指定Windows把函数WindosProc作为窗口处理过程。就是说,Windows会调用函数WindowsProc()来处理这个消息。在WindowProc()处理完消息后,代码又循环到开始去接收另一个消息,这样就完成了一个消息循环。

1 0
原创粉丝点击