Windows编程

举报
御麟 发表于 2023/04/25 22:11:48 2023/04/25
【摘要】 Windows编程

 本文是介绍Windows编程的一篇博客

窗口是Windows应用程序的基本单位

山窗初曙,透纸黎光。                ——张岱

WINDOWS编程

控制台程序 Console

DOS程序,本身没有窗口,通过Windows DOS窗口执行

窗口程序

拥有自己的窗口,可以与用户交互

库程序

存放代码,数据的程序,执行文件可以从中取出代码执行和获取数据

静态库:扩展名LIB,在编译链接程序时,将代码放入执行文件中

动态库:扩展名DLL,在执行文件执行时从中获取代码

开发工具和库

编译工具

编译器 CL.EXE 将源代码编译成目标代码

链接器 LINK.EXE 将目标代码,库链接生成最终文件

资源编译器RC.EXE 将资源编译,最终通过链接器存入最终文件

C:\Program Files(x86)\Microsoft Visual Studio 10.0\VC\bin

库和头文件

Windows库

kernel32.dll 提供了核心的API,例如进程,线程,内存管理等

user32.dll 提供了窗口,消息等API

gdi32.dll 绘图相关的API

路径 C:\Windows\System32

头文件

windows.h 所有windows头文件的集合

windef.h windows数据类型

winbase.h kernel32的API

wingdi.h gdi32的API

winuser.h user32的API

winnt.h UNICODE字符集支持

相关函数

WinMain函数

int WINAPI WinMain(
​
•   HINSTANCE hInstance   //当前程序的实例句柄
​
•   HINSTANCE hPrevInstance  //当前程序的前一个实例句柄
​
•   LPSTR lpCmdLine  //命令行参数字符串
​
•   int nCmdShow  //窗口的显示方式
​
)
​
​
​
int MessageBox(
​
•   HWND hWnd //父窗口句柄
​
•   LPCTSTR lpText  //显示在消息框中的文字
​
•   LPCTSTR lpCaption   //显示在标题栏中的文字
​
•   UINT uType  //消息框中的按钮,图标显示类型
​
)  ;//返回点击的按钮ID

窗口创建过程

定义WInMain函数

定义窗口处理函数(自定义,处理消息)

注册窗口类(向操作系统写入一些数据)

创建窗口(内存中创建窗口)

显示窗口(绘制窗口的图像)

消息循环(获取/翻译/派发消息)

消息处理

字符编码

ASC

7位128个

ASCII

8位256个

DBCS

单双字节混合编码

UNICODE

几乎所有国家的字符

Ubuntu一般使用UTF-8,Windows使用的UTF-16

宽字节字符

wchar_t 每个字符占两个字节,不是基本的数据类型,实际上是unsigned short类型

定义时,需要加"L"

通知编译器按照双字节编译字符串

wchar_t* pwszText=L"Hello World";

TCHAR

定义Unicode宏的情况下是wchar_t

否则是char

#ifdef UNICODE
​
typedef wchar_t TCHAR;
​
#define __TEXT.(quote) L##quote
​
#else
​
typedef char TCHAR;
​
#define __TEXT(quote) quote
​
#endif

系统调用函数的参数类型

LPSTR===char

LPCSTR===const char*

LPWSTR===wchar_t*

LPCWSTR===const wchar_t*

LPTSTR===TCHAR*

LPCTSTR===const TCHAR*

注册窗口类

编辑

窗口类的概念

  • 窗口类就是包含了窗口各种参数信息的数据结构

  • 每个窗口都具有窗口类,基于窗口类创建窗口

  • 每个窗口类都有一个名称,使用前必须注册到系统

窗口类是操作系统内核的一堆数据

窗口类的分类

系统窗口类

系统已经定义好的窗口类,所有应用程序都可以直接使用

应用程序全局窗口类

由用户自己定义,当前应用程序所有模块都可以使用

应用程序局部窗口类

由用户自己定义,当前应用程序中本模块都可以使用

注册窗口类

typedef struct_WNDCLASS{
    int cbClsExtra;//窗口类的附加数据缓冲区字节大小
    int cbWndExtra;//窗口的附加数据缓冲区字节大小
    HBRUSH hbrBackground;//窗口背景画刷句柄
    HICON  hIcon;//窗口图标句柄
    HCURSOR  hCursor;//窗口光标句柄
    HINSTANCE  hInstance;//当前模块实例句柄
    WNDPROC lpfnWndProc;//窗口处理函数
    LPCTSTR lpszClassName;//窗口类名
    LPCTSTR lpszMenuName;//窗口菜单的资源ID字符串
    UINT style;//窗口类的风格
}WNDCLASS *PWNDCLASS;

style的几个参数:

CS_DBCLKS 允许窗口接收鼠标双击

CS_NOCLOSE 窗口没有关闭按钮

全局和局部窗口类

style窗口类风格

应用程序全局窗口类注册,需要在窗口类的风格中增加CS_GLOBALCLASS。

例如:

WNDCLASS wce={0};

wce.style=....|CS_GLOBALCLASS

不增加CS_GLOBALCLASS就是局部窗口类

不建议用全局窗口类,全局窗口类能完成的局部窗口类也能完成

创建窗口

HWND CreateWindowEx(          DWORD dwExStyle,
    LPCTSTR lpClassName,
    LPCTSTR lpWindowName,
    DWORD dwStyle,
    int x,
    int y,
    int nWidth,
    int nHeight,
    HWND hWndParent,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam
);

注册窗口类的两个重要成员

wc.hInstance=Ins;

wc.lpszClassName="Main";

CreateWindowEx

进入这个函数就进入内核态

CreateWindowEx(.."Main",...hIns..)

消息的概念和作用

系统根据传入窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3

比较局部窗口类和创建窗口传入的HINSTANCE变量。如果发现相等,创建和注册的窗口类在同一模块(进程),创建窗口返回。如果不相等,继续执行3

在应用程序全局窗口类,如果找到,执行4,如果没有找到执行5

使用找到的窗口类的信息,创建窗口返回

在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败

创建子窗口

创建时要设置父窗口句柄

创建风格要增加WS_CHILD|WS_VISIBLE

消息基础

消息的概念和作用

消息组成

窗口句柄

消息ID

消息的两个参数(两个附带信息)

消息的产生时间

消息产生时的鼠标位置

typedef struct tagMSG
{
HWND hwnd; // 消息所指窗口句柄
UINT message; //消息名称,形式如WM_SIZE
WPARAM wParam; //32位消息的特定附加信息
LPARAM lParam; //32位消息的特定附加信息
DWORD time; //消息创建时间
POINT pt; //消息创建时的鼠标位置
} MSG;

消息的作用

ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
MSG nMsg={0};
while(GetMessage(&nMsg,NULL,0,0)){
​	TranslateMessage(&nMsg);
​	DispatchMessage(&nMSg);
}

当系统通知窗口工作时,就采用消息的方式派发给窗口

每个窗口都必须有窗口处理函数

//窗口处理函数
LRESULT CALLBACK WindowProc(
    HWND hwnd;
    UNIT uMsg;
    WPARAM wParam;
    LPARAM IParam;
)

当系统通知窗口时,会调用窗口处理函数,同时将消息ID和消息参数传递给窗口处理函数。在窗口处理函数中,不处理消息,使用缺省窗口处理函数。例如:DefWindowProc

可以给各种消息做默认处理

三个消息处理函数

BOOL GetMessage(
    LPMSG lpMsg**,** // address of structure with message
    HWND hWnd**,** // handle of window
    UINT wMsgFilterMin**,** // first message
    UINT wMsgFilterMax // last message
);

lpMsg 当获取到消息后,将消息的参数存放到MSG结构中

hWnd 获取到hWnd所指定窗口的消息

BOOL TranslateMessage(
    CONST MSG **lpMsg* // address of structure with message
);

TranslateMessage将按键消息翻译成字符消息

检查消息是否是按键消息,如果不是按键消息,不做处理,继续执行

LONG DispatchMessage(
    CONST MSG *lpmsg
     // pointer to structure with message
);

将消息派发到该消息所属窗口的窗口处理函数上 


常见消息

一个消息需要掌握的三个方面

产生时间

附带的两个信息告诉我们什么

消息的一般用法(能拿来做什么)

常见的消息

WM_DESTROY

产生时间:窗口被销毁时的消息

附带信息:wParam 为0

lParam 为0

一般用法:常用于窗口被销毁之前,做相应的善后处理,例如资源,内存等

WM_SYSCOMMAND

产生时间:当点击窗口的最大化,最小化,关闭等

附带信息:wParam 具体点击的位置,例如关闭SC_CLOSE等

lParam 鼠标光标的位置

LOWORD(lParam)//水平位置

HIWORD(lParam)//垂直位置

一般用法:常用在窗口关闭时,提示用户处理

WM_CREATE

产生时间:在窗口创建成功但还未显示时

附带信息:wParam 为0

lParam 为CREATESTRUCT类型的指针

通过这个指针可知获取CreateWindowEx中的全部12个参数的信息

一般用法:常用于初始化窗口的参数,资源等等,包括创建子窗口

WM_SIZE

产生时间:在窗口大小发生变化后

附带信息:wParam 窗口大小变化的原因

lParam 窗口变化后的大小

LOWORD(lParam)//变化后的宽度

HIWORD(lParam)//变化后的高度

一般用法:常用于窗口大小变化后,调整窗口内各个部分的布局


消息循环原理

GetMessage从系统获取信息,将消息从系统中移除,阻塞函数。当系统无消息时,会阻塞等候下一条消息。

PeekMessage 以查看的方式从系统中获取消息,可以不将消息从系统中移除,非阻塞函数。当系统无消息时,返回False,继续执行后续代码

BOOL PeekMessage(

LPMSG lpMsg**,** // pointer to structure for message

HWND hWnd**,** // handle to window

UINT wMsgFilterMin**,** // first message

UINT wMsgFilterMax**,** // last message

UINT wRemoveMsg // removal flags

);

发送消息

SendMessage 发送消息,会等候消息处理结果

PostMessage 投递消息,消息发出之后立刻返回,不等候消息执行结果

LRESULT SendMessage(

HWND hWnd**,** // handle of destination window

UINT Msg**,** // message to send

WPARAM wParam**,** // first message parameter

LPARAM lParam // second message parameter

);

消息分类

系统消息-ID范围 0-0x03FF

由系统定义好的消息,可以在程序中直接使用

用户自定义消息 ID范围 0x0400-0x7FFF

由用户自己定义,满足用户自己的需求,由用户自己发出消息,并响应处理

自定义消息宏:WM_USER

消息队列

  • 用来存放消息的队列

  • 消息在队列中先入先出

  • 所有窗口程序都具有消息队列

  • 程序可以从队列中获取信息

消息队列的分类

  • 系统消息队列-由系统维护消息队列,存放系统产生的消息,例如鼠标,键盘

  • 程序消息队列-属于每一个应用程序的消息队列,由应用程序维护

消息和消息队列的关系

1.当鼠标,键盘产生消息时,会将消息存放到系统消息队列

2.系统会根据存放的消息,找到对应程序的消息队列

3.将消息投递到程序的消息队列

根据消息和消息队列的关系,将消息分为两类:

  • 队列消息

  • 非队列消息

常见的队列消息:键盘,鼠标,定时器,WM_PAINT

键盘消息

WM_KEYDOWN 按键被按下时产生

WM_KEYUP 按键被放开时产生

WM_SYSKEYDOWN 系统键按下时产生,比如ALT,F10

WM_SYSKEYDOWN 系统键放开时产生

附带信息

WPARAM 按键的Virtual Key

LPARAM 按键的参数,按下次数


鼠标消息

鼠标消息分类

基本鼠标消息

WM_LBUTTONDOWN 鼠标左键按下

WM_LBUTTONUP 鼠标左键抬起

WM_RBUTTONDOWN 鼠标右键按下

WM_RBUTTONUP 鼠标右键抬起

WM_MOUSEMOVE 鼠标移动消息

双击消息

WM_LBUTTONDBLOCK 鼠标左键双击

WM_RBUTTONDBLOCK 鼠标右键双击

滚轮消息

WM_MOUSEWHELL 鼠标滚轮消息

附带信息:

wPARAM 其他按键的状态,例如Ctrl/Shift等

lPARAM 鼠标的位置,窗口客户区坐标系

一般情况鼠标按下/抬起成对出现,在鼠标移动过程中,会根据移动速度产生一系列WM_MOUSEMOVE消息

定时器消息

定时器消息的介绍

在程序中创建定时器,当到达时间间隔时,定时器想程序发送一个WM_TIMER消息,定时器的精度是毫秒,但是准确度很低,例如设置时间间隔为1000ms,但是会在非1000ms到达消息

附带信息:wPARAM 定时器ID

lPARAM 定时器处理函数的指针

UINT SetTimer(  

​	**HWND** *hWnd***,** // handle of window for timer messages  

​	**UINT** *nIDEvent***,** // timer identifier  

​	**UINT** *uElapse***,** // time-out value  

​	**TIMERPROC** *lpTimerFunc* // address of timer procedure

  **);**
BOOL KillTimer(

    HWND hWnd,
     // handle of window that installed timer
    UINT uIDEvent
     // timer identifier
 
);
 

菜单资源

菜单分类

  • 窗口的顶层菜单

  • 弹出式菜单

  • 系统菜单

菜单资源的使用

添加菜单资源

加载菜单资源

  • 注册窗口类时设置菜单

  • 创建窗口传参设置菜单

  • 在主窗口WM_CREATE消息中利用SetMenu函数设置菜单

未完待续

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。