当前位置: 首页 > news >正文

第3章,[标签 Win32] :窗口类03,窗口过程函数字段

专栏导航

上一篇:第3章,[标签 Win32] :窗口类02,类风格字段

回到目录

下一篇:无

本节前言

有一段时间没去写文章和发表文章了。一点琐事缠身,导致了写文章的中断。现在,算是继续进行和了。

对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏之前的文章。真的遇到了需要参考之前的文章的知识点,请你自行查阅。

我呢,也会提到一部分的参考课节。但是呢,你不应该依赖于我的主动提及。最好呢,你自己能够多去了解和查看本专栏目录。

学习本节所讲的知识,需要你事先了解过本章的完整代码。完整的代码,请参考下述文章链接。

参考课节:第3章,[标签 Win32] :本章程序代码

在之前,我们有讲过窗口类的基本情况。

为了便于学习,我们还是再次贴出窗口类的各个成员变量,如下所示。

typedef struct {UINT      style;WNDPROC   lpfnWndProc;int       cbClsExtra;int       cbWndExtra;HINSTANCE hInstance;HICON     hIcon;HCURSOR   hCursor;HBRUSH    hbrBackground;LPCTSTR   lpszMenuName;LPCTSTR   lpszClassName;
} WNDCLASS, * PWNDCLASS;

本节,我们要去讲解的,是敞口过程函数指针字段,也是第 2 个字段,lpfnWndProc 。

下面,我们进入本节的正式学习。

一.    窗口过程函数

窗口过程函数,它可以说是 Windows API 程序设计的重点与核心了。Windows API 程序的运行的大部分工作,都在本函数中进行。我们来粗略地看一看这一函数的代码。

在本章程序代码的 60 行到 88 行,是本程序的窗口过程函数代码。

我将窗口过程函数代码摘录在下面。

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{HDC         hdc;PAINTSTRUCT ps;RECT        rect;switch (message){case WM_CREATE:PlaySound(TEXT("HelloWin.wav"), NULL, SND_FILENAME | SND_ASYNC);return 0;case WM_PAINT:hdc = BeginPaint(hwnd, &ps);GetClientRect(hwnd, &rect);DrawText(hdc, TEXT("Hello, Windows Program !"), -1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);EndPaint(hwnd, &ps);return 0;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc(hwnd, message, wParam, lParam);
}

对于这个函数,我们暂时不需要深究,因为后面我们会去正式讲解它。

此时,你有个印象就好了。

本节,我们需要关注的一段代码,如下图的红色框线所示。

图1

在窗口类中,有一个字段,名叫 lpfnWndProc,它用来保存程序的窗口过程函数指针。

由本章程序的窗口过程函数的头部可知,窗口过程函数名为 WndProc,我们将这个函数名赋给窗口类变量 wndclass 的 lpfnWndProc 成员就可以了。

二.    WNDPROC 类型

在窗口类中,lpfnWndProc 成员的类型为 WNDPROC 。

我们来看一看这一类型的定义情况。

typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);

这是 typedef 在定义函数指针类型时候的一种用法。

这一段代码,可能有些难度。

我们分解着来讲解。

首先呢,我们来讲解一个简单的情形。

我们来看一个函数代码。

int func_01(double a, int x)
{int res;res = a * a + 3 - x;return res;
}

对于上述的代码,如果你来写它的函数声明,要怎么来写呢?

我们可以将它的函数声明写成下面的样子。

int func_01(double a, int x);

也可以写成下面的样子。

int func_01(double, int);

函数名,标识的是一个函数的地址,也就是函数的指针。函数指针,也是一种指针类型。

下面,我们来声明一个变量,这个变量可以被赋值为一个函数指针。我们可以像下面这样子来做。

int (*func_pointer)(double, int);

在上面的示例代码里面,我们声明了一个函数指针变量,此变量的名字为 func_pointer 。这一函数指针变量所指向的函数,它的参数列表的类型为 (double, int),返回值为 int 类型。

与原来的函数声明代码【int func_01(double, int);】相比,声明函数指针变量的代码【int (*func_pointer)(double, int);】多了一个中间的括号和星号部分。括号和星号,正好可以用来区分普通的函数声明与函数指针变量的声明。

如果,我们将括号给去掉,变为下面的样子。

int *func_pointer(double, int);

在这种情况下,我们是声明了一个函数,函数名为 func_pointer,参数列表的类型为 (double, int),返回值为【int *】类型。

而加上了括号,成为【int (*func_pointer)(double, int);】以后,则我们所声明的,便不是一个函数,而是一个函数指针变量。

我们也可以将此函数指针变量的声明写成如下的样子。

int (*func_pointer)(double a, int x);

在一个普通的函数声明里,如果我们将函数名替换成一个新的组合,这个新组合的外面是一对括号,里面是一个星号加上右边的标识符,则总体来看,这个新的声明,就是声明了一个函数指针变量。

而一个函数指针变量声明中,我们若是将参数列表与返回值之间的括号组合部分,替换成一个普通的标识符,则形成的声明,便是一个普通的函数声明。

函数指针变量,是一个单独的变量。我们如果想要将这一变量类型提炼出来,我们可以这样子做。

typedef int (*FUNC_POINTER)(double, int);

或者也可以这样子写。

typedef int (*FUNC_POINTER)(double a, int x);

经过这样的处理以后,我们声明了一个新的类型。类型名为 FUNC_POINTER,这一类型可以用来声明一个函数指针变量,所声明的函数指针变量所指向的函数,它的参数列表为 (double, int) 或 (double a, int x),返回值为 int 。

我们可以用这个新的类型来声明函数指针变量,比如可以像下面这样子来声明变量。

FUNC_POINTER func_pointer_01;
FUNC_POINTER func_pointer_02;
FUNC_POINTER func_pointer_03;

当然了,如果你不厌其烦,你也可以像下面这样子来声明三个函数指针变量。

int (*func_pointer_01)(double, int);
int (*func_pointer_02)(double, int);
int (*func_pointer_03)(double, int);

相比之下,还是用 typedef 重新定义类型以后,再用新的类型名去声明变量,代码会更有层次感一些。

在原本的函数指针变量声明代码【int (*func_pointer)(double, int);】的基础上,左边再加上一个 typedef 关键字,形成【typedef int (*FUNC_POINTER)(double, int);】,就变成了定义新类型的代码。这一新类型可以用来声明函数指针变量。

函数除了函数名,返回值和参数列表之外,它也存在着调用约定这一要素。

关于调用约定,我们之前有讲过,你可以参考如下链接,来了解调用约定的知识。

参考课节:第1章 :第一个 WIn32 程序,程序入口

在上述文章链接的第七分节里面,有涉及调用约定。

我们平时所写的函数,一般都是采用 CDECL 调用约定。当不明确书写调用约定的名称的时候,我们所采用的,便是默认的 CDECL 调用约定。

调用约定有很多种,一种常用的调用约定,叫做标准调用,其标识符为 __stdcall 。

在 Windows 程序设计中,有很多的重定义的标识符,都是 __stdcall 的别名。

我们之前学过的 WINAPI 是 __stdcall 的别名,CALLBACK 也是它的别名。

我们再来看一看本章程序的窗口过程函数的头部。

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

在这段函数头部里面,LRESULT 是返回值类型,一般情况下它等价于 long 型。而WndProc及其后的东西,为函数名与参数列表。

在返回值类型 LRESULT 与函数名 WndProc 之间的东西,为 CALLBACK 。

CALLBACK 为 __stdcall 的别名,表示标准调用。

有了 CALLBACK,表明本章程序代码中的窗口过程函数 WndProc,采用的调用约定是标准调用 __stdcall 。

对于此窗口过程函数,本章程序代码给出的函数声明代码如下。

图2

图2 中的红色框线所示的部分,为窗口过程函数的声明代码。

我们将其摘录在下面的代码块中。

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

如果我们来声明一个函数指针变量,这个变量可以指向此窗口过程函数,那么,我们可以像下面这样子来声明。

LRESULT (CALLBACK * FuncPointer_WndProc)(HWND, UINT, WPARAM, LPARAM);

或者呢,换一个变量名,将上面的声明代码变为下面这样子。

LRESULT (CALLBACK * lpfnWndProc)(HWND, UINT, WPARAM, LPARAM);

如果,我们想要定义一个新的类型,此新的类型所声明的变量,可以用来指向本章程序的窗口过程函数,我们可以像下面这样子来做。

typedef LRESULT (CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM);

定义了这一新的类型之后,我们可以用它来声明函数指针变量,并将此函数指针变量赋值为本章程序的窗口过程函数。代码如下。

WNDPROC lpfnWndProc;
lpfnWndProc = WndProc;

而函数指针变量类型 WNDPROC 及其声明的函数指针变量 lpfnWndProc 都被封装在了窗口类 WNDCLASS 里面了,而本章程序代码中的窗口类变量为 wndclass,所以,就有了下面的代码。

图3

到了这里,窗口过程函数字段,及其类型 WNDPROC,我们就算是讲完了。

在这一过程中,我们还讲解了 typedef 在定义函数指针变量类型的用法。

typedef,对我来讲,当初学习它的时候,也算是稍微耗费了一些思考。

typedef 的用法,可能不是很直观。大家在学习它的时候,如果有困难,建议你多看看,多学学。

结束语

关于窗口过程函数,本节就先讲这么多了。

下一节,我们接着来讲窗口过程函数。

专栏导航

上一篇:第3章,[标签 Win32] :窗口类02,类风格字段

回到目录

下一篇:无

http://www.dtcms.com/a/497024.html

相关文章:

  • 软件开发网站开发公司工作组赴平凉事故现场
  • 友情链接如何选择网站工程招标信息网
  • 现在建设的网站有什么劣势网站建设公司盈利分析
  • 广西网站设计服务代码优化网站排名
  • django 网站开发视频杭州品牌网站建设
  • 白银市建设局网站首页包头微网站开发
  • 做网站维护是什么岗位浅谈你对大学校园网站建设的建议
  • seo整站优化建网站能干嘛
  • 企业网站推广建议考试报名费悦生活建设银行网站
  • 所得税 网站建设费北京网站建设公司华网制作作
  • Java核心概念:抽象类、接口、Object类深度剖析
  • 广西城乡与住房建设厅网站昆山网站建设公司哪家好
  • 正规网站制作价格跨境电商平台建设方案
  • 网站seo优化排名红河网页设计
  • Linux osq_lock(二)
  • 烟台电商网站建设济宁百度网站建设
  • wordpress图片添加标签无锡seo公司
  • 革吉网站建设网站开发建
  • 科研新手如何建立规范的图片处理习惯?
  • Swift中.gesture的用法
  • 厦门企业自助建站系统建站软件可以不通过网络建设吗
  • 电商建网站运营襄阳网站建设公司哪家好
  • 网站建设的培训心得万维网网站注册
  • 网站左侧边栏导航代码企业计划书
  • 歙县建设银行网站成都行业网站
  • 整体设计 逻辑系统程序 之33 程序定稿 PIN 语言工具设计需求与交付方案
  • 江门网站推广技巧wordpress获取tag名称
  • 湘潭哪里做网站 电话阿里巴巴的电子商务网站建设
  • Qwen3VL源码侧改进点及DeepStack核心思想概述
  • 设计一个商务网站专做ppt的网站