Windows编程基础
Windows
系统级开发,简称Win32
应用程序分类
- 在
Windows
这个操作系统平台上,共有三类应用程序 - 控制台程序Console
Dos
程序,本身没有窗口,通过Windows DOS
窗口执行
- 窗口程序
- 拥有自己的窗口,可以与用户交互
- 库程序
- 存放代码、数据的程序,执行程序时可以从中取出代码执行和获取数据
- 静态库程序:扩展名
LIB
,在编译链接程序时,将代码放入到执行文件中 - 动态库程序:扩展名
DLL
,在程序执行时从中获取代码
应用程序对比
-
入口函数
- 控制台程序 -
main
- 窗口程序 -
WinMain
- 动态库程序 -
DllMain
- 静态库程序 - 无入口函数
- 控制台程序 -
-
文件存在方式
- 控制台程序、窗口程序 -
EXE
文件 - 动态库程序 -
DLL
文件 - 静态库程序 -
LIB
文件
- 控制台程序、窗口程序 -
开发工具和库
编译工具
-
编译器
CL.EXE
将源代码编译成目标代码.obj
-
链接器
LINK.EXE
将目标代码、库链接生成最终文件 -
资源编译器
RC.EXE
(.rc
)将资源编译,最终通过链接器存入最终文件 -
路径 :
C:\Program Files (x86)\Microsoft Visual Studio \VC\bin
库和头文件
-
Windows库(动态库)
kernel32.dll
- 提供了核心的API,例如进程、线程、内存管理等user32.dll
- 提供了窗口、消息等APIgdi32.dll
- 绘图相关的API- 路径:
C:\Windows\System32
-
头文件
windows.h
- 所有windows
头文件的集合windef.h
-windows
数据类型winbase.h
-kernel32
的APIwingdi.h
-gdi32
的APIwinuser.h
-user32
的APIwinnt.h
-UNICODE
字符集支持- 路径:
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include
相关函数
|
|
- 句柄是用来找到内存的东西,但不是指针
- 当前程序的实例句柄能够找到当前进程所占据的那块内存
程序编译过程
-
编译环境准备
VCVARS32.BAT
-
编译程序 - CL
CL.EXE –c xxx.c
-
链接程序 - LINK
LINK.EXE xxx.obj xxx.lib
-
执行
-
编写资源的文件 -
.rc
资源脚本文件 -
编译
rc
文件 -RC.EXE
-
将资源链接到程序中 -
LINK.EXE
第一个windows窗口
窗口创建过程
- 定义
WinMain
函数 - 定义窗口处理函数 (自定义,处理消息)
- 注册窗口类(向操作系统写入一些数据)
- 创建窗口( 内存中创建窗口 )
- 显示窗口( 绘制窗口的图像 )
- 消息循环(获取/翻译/派发消息)
- 消息处理
代码示例
|
|
字符编码
- 宽字节字符
wchar_t
每个字符占2个字节char
每个字符占1个字节wchar_t
实际是unsigned short
类型,定义时,需要增加L
,通知编译器按照双字节编译字符串,采用UNICODE
编码- 需要使用支持
wchar_t
函数操作宽字节字符串。例如:
|
|
TCHAR
|
|
UNICODE
字符打印wprintf
对UNICODE
字符打印支持不完善- 在
Windows
下使用WriteConsole
API打印UNICODE
字符GetStdHandle
Windows窗口
注册窗口类
窗口类的概念
- 窗口类包含了窗口的各种参数信息的数据结构(在程序中体现为结构体)
- 每个窗口都具有窗口类,基于窗口类创建窗口
- 每个窗口类都具有一个名称,使用前必须注册到系统
窗口类的分类
- 系统窗口类
- 系统已经定义好的窗口类,所有应用程序都可以直接使用
- 应用程序全局窗口类
- 由用户自己定义,当前应用程序所有模块都可以使用
- 应用程序局部窗口类
- 由用户自己定义,当前应用程序中本模块可以使用
系统窗口类
- 不需要注册,直接使用窗口类即可。系统已经注册好了
- 例如:
- 按钮 -
BUTTON
- 编辑框 -
EDIT
- 按钮 -
全局及局部窗口类
- 注册窗口类的函数
|
|
- 注册窗口类的结构体
|
|
style
窗口类风格- 应用程序全局窗口类的注册,需要在窗口类的风格中增加
CS_GLOBALCLASS
- 应用程序全局窗口类的注册,需要在窗口类的风格中增加
- 例如:
|
|
- 应用程序局部窗口类:在注册窗口类时,不添加
CS_GLOBALCLASS
风格(推荐使用局部窗口类)CS_HREDRAW
- 当窗口水平变化时,窗口重新绘制CS_VREDRAW
- 当窗口垂直变化时,窗口重新绘制CS_DBLCLKS
- 允许窗口接收鼠标双击CS_NOCLOSE
- 窗口没有关闭按钮
窗口创建
创建窗口的函数
|
|
窗口创建原理
-
系统(
CreateWindow
内部)根据传入的窗口类名称,在应用程序局部窗口类中查找,如果找到执行2,如果未找到执行3 -
比较局部窗口类与创建窗口时传入的
HINSTANCE
变量。如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回。如果不相等,继续执行3 -
在应用程序全局窗口类,如果找到,执行4,如果未找到执行5
-
使用找到的窗口类的信息,创建窗口返回
-
在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败
子窗口创建
-
创建时要设置父窗口句柄
-
创建风格要增加
WS_CHILD|WS_VISIBLE
消息基础
消息的概念和作用
- 消息组成(windows平台下)
- 窗口句柄
- 消息ID
- 消息的两个参数(两个附带信息)
- 消息产生的时间
- 消息产生时的鼠标位置
- 消息的作用
- 当系统通知窗口工作时,就采用消息的方式派发(
DispatchMessage
)给窗口的窗口处理函数
- 当系统通知窗口工作时,就采用消息的方式派发(
窗口处理函数
- 每个窗口都必须具有窗口处理函数
|
|
- 当系统通知窗口时,会调用窗口处理函数,同时将消息ID和消息参数传递给窗口处理函数
- 在窗口处理函数中,不想处理的消息,使用缺省窗口处理函数,例如:
DefWindowProc
浅谈消息相关函数
GetMessage
- 获取消息(本进程)
|
|
-
lpMsg
- 当获取到消息后,将消息的参数存放到MSG
结构中 -
hWnd
- 获取到hWnd
所指定窗口的消息 -
wMsgFilterMin
和wMsgFilterMax
-只能获取到由它们指定的消息范围内的消息,如果都为0,表示没有范围 -
TranslateMessage
- 翻译消息。将按键消息,翻译成字符消息
|
|
-
检查消息是否是按键的消息,如果不是按键消息,不做任何处理,继续执行
-
DispatchMessage
- 派发消息
|
|
- 将消息派发到该消息所属窗口的窗口处理函数上。
常见消息
WM_DESTORY
-
产生时间:窗口被销毁时的消息
-
附带信息:
wParam
:为0lParam
:为0
-
一般用法:常用于在窗口被销毁之前,做相应的善后处理,例如资源、内存等
WM_SYSCOMMAND
-
产生时间:当点击窗口的最大化、最小化、关闭等
-
附带信息:
wParam
: 具体点击的位置,例如关闭是SC_CLOSE
lParam
: 鼠标光标的位置
|
|
- 一般用法:常用在窗口关闭时,提示用户处理
WM_CREATE
-
产生时间:在窗口创建成功但还未显示时
-
附带信息:
wParam
: 为0lParam
: 为CREATESTRUCT
类型的指针- 通过这个指针可以获取
CreatWindowEx
中的全部12个参数的信息
-
一般用法:常用于初始化窗口的参数、资源等等,包括创建子窗口等
WM_SIZE
-
产生时间:在窗口的大小发生变化后
-
附带信息:
wParam
: 窗口大小变化的原因lParam
: 窗口变化后的大小
|
|
- 一般用法:常用于窗口大小变化后,调整窗口内各个部分的布局
WM_QUIT
-
产生时间:程序员发送
-
附带信息:
wParam
:PostQuitMessage
函数传递的参数lParam
: 0- 一般用法:用于结束消息循环,当
GetMessage
收到这个消息后,会返回FALSE
,结束while
处理,退出消息循环
消息循环的原理
消息循环的阻塞
GetMessage
- 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,会等候下一条消息PeekMessage
- 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE
,继续执行后续代码
|
|
发送消息
SendMessage
- 发送消息,会等候消息处理的结果PostMessage
- 投递消息,消息发出后立刻返回,不等候消息执行结果
|
|
消息分类
- 系统消息 - ID范围
0 - 0x03FF
- 由系统定义好的消息,可以在程序中直接使用。
- 用户自定义消息 - ID范围
0x0400 - 0x7FFF(31743)
- 由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理。
- 自定义消息宏:
WM_USER
Windows消息
消息队列
消息队列概念
-
消息队列是用于存放消息的队列
-
消息在队列中先入先出
-
所有窗口程序都具有消息队列
-
程序(
GetMessage
)可以从队列中获取消息
消息队列分类
- 系统消息队列-由系统维护的消息队列。存放系统产生的消息,例如鼠标、键盘等
- 程序消息队列-属于每一个应用程序(线程)的消息队列。由应用程序(线程)维护
消息和队列关系
- 消息和消息队列的关系
- 当鼠标、键盘产生消息时,会将消息存放到系统消息队列
- 系统会根据存放的消息,找到对应的程序消息队列
- 将消息投递到对应的程序消息队列中
- 根据消息和消息队列之间使用关系,将消息分成两类:
- 队列消息 - 消息的发送和获取,都是通过消息队列完成
- 非队列消息 - 消息的发送和获取,是直接调用消息的窗口处理函数完成
- 队列消息-消息发送后,首先放入队列,然后通过消息循环,从队列当中获取
GetMessage
- 从消息队列中获取消息PostMessage
- 将消息投递到消息队列- 常见队列消息:
WM_PAINT
、键盘、鼠标、定时器
- 非队列消息-消息发送时,首先查找消息接收窗口的窗口处理函数,直接调用窗口处理函数,完成消息
SendMessage
- 直接将消息发送给窗口的处理函数,并等候处理结果- 常见消息:
WM_CREATE
、WM_SIZE
等
深谈GetMessage原理
- 在程序(线程)消息队列查找消息,如果队列有消息,检查消息是否满足指定条件(
HWND
,ID
范围),不满足条件就不会取出消息,否则从队列取出消息返回 - 如果程序(线程)消息队列没有消息,向系统消息队列获取属于本程序的消息。如果系统队列的当前消息属于本程序,系统会将消息转发到程序消息队列中
- 如果系统消息队列也没有消息,检查当前进程的所有窗口的需要重新绘制的区域,如果发现有需要绘制的区域,产生
WM_PAINT
消息,取得消息返回处理 - 如果没有重新绘制区域,检查定时器如果有到时的定时器,产生
WM_TIMER
,返回处理执行 - 如果没有到时的定时器,整理程序的资源、内存等等
GetMessage
会继续等候下一条消息。PeekMessage
会返回FALSE
,交出程序的控制权- 注意:
GetMessage
如果获取到是WM_QUIT
,函数会返回FALSE
WM_PAINT消息
- 产生时间:当窗口需要绘制的时候
- 附带信息:
wParam
: 0lParam
: 0
- 专职用法:用于绘图
- 窗口无效区域 :需要重新绘制的区域
|
|
消息处理步骤
- 开始绘图
|
|
-
正式绘图
-
结束绘图
|
|
键盘消息
键盘消息分类
WM_KEYDOWN
- 按键被按下时产生WM_KEYUP
- 按键被放开时产生WM_SYSKEYDOWN
- 系统键按下时产生 比如ALT
、F10
WM_SYSKEYUP
- 系统键放开时产生
附带信息:
WPARAM
- 按键的Virtual Key
LPARAM
- 按键的参数,例如按下次数
字符消息(WM_CHAR)
TranslateMessage
在转换WM_KEYDOWN
消息时,对于可见字符可以产生WM_CHAR
,不可见字符无此消息
附带信息:
WPARAM
- 输入的字符的ASCII
字符编码值LPARAM
- 按键的相关参数
WM_KEYDOWN
不能区分大小写;WM_CHAR
能够区分大小写
鼠标消息
鼠标消息分类
- 基本鼠标消息
WM_LBUTTONDOWN
- 鼠标左键按下WM_LBUTTONUP
- 鼠标左键抬起WM_RBUTTONDOWN
- 鼠标右键按下WM_RBUTTONUP
- 鼠标右键抬起WM_MOUSEMOVE
- 鼠标移动消息
- 双击消息
WM_LBUTTONDBLCLK
- 鼠标左键双击WM_RBUTTONDBLCLK
- 鼠标右键双击
- 滚轮消息
WM_MOUSEWHEEL
- 鼠标滚轮消息
鼠标基本消息
- 附带信息:
wPARAM
: 其他按键的状态,例如Ctrl/Shift
等lPARAM
: 鼠标的位置,窗口客户区坐标系LOWORD
:X
坐标位置HIWORD
:Y
坐标位置
- 一般情况鼠标按下/抬起成对出现。在鼠标移动过程中,会根据移动速度产生一系列的
WM_MOUSEMOVE
消息
鼠标双击消息
-
附带信息:
-
wPARAM
- 其他按键的状态,例如Ctrl/Shift
等 -
lPARAM
- 鼠标的位置,窗口客户区坐标系LOWORD(lParam)
:X
坐标位置HIWORD(lParam)
:Y
坐标位置
-
-
消息产生顺序
-
以左键双击为例:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
-
使用时需要在注册窗口类的时候添加
CS_DBLCLKS
风格
-
鼠标滚轮消息
- 附带信息:
wPARAM
:LOWORD
- 其他按键的状态HIWORD
- 滚轮的偏移量,通过正负值表示表示滚动方向- 正:向前滚动 负:向后滚动
lPARAM
:鼠标当前的位置,屏幕坐标系LOWORD
-X
坐标HIWORD
-Y
坐标
- 使用:
- 通过偏移量,获取滚动的方向和距离
定时器消息
定时器消息介绍
- 产生时间:
- 在程序中创建定时器,当到达时间间隔时,定时器(
GetMessage
)会向程序发送一个WM_TIMER
消息 - 定时器的精度是毫秒,但是准确度很低。例如设置时间间隔为1000ms,但是会在非1000毫秒到达消息
- 在程序中创建定时器,当到达时间间隔时,定时器(
- 附带信息:
wPARAM
: 定时器IDlPARAM
: 定时器处理函数的指针
创建销毁定时器
- 创建定时器
|
|
- 关闭定时器
|
|
菜单资源
菜单分类
- 窗口的顶层菜单
- 弹出式菜单
- 系统菜单
HMENU
:菜单句柄,类型表示菜单,ID
表示菜单项
资源相关
菜单资源使用
-
添加菜单资源
-
加载菜单资源的三种方法
- 注册窗口类时设置菜单
- 创建窗口传参设置菜单
- 在主窗口
WM_CREATE
消息中利用SetMenu
函数设置菜单
-
加载菜单资源
|
|
命令消息处理
- 附带信息:
wPARAM
:HIWORD
- 对于菜单为0LOWORD
- 菜单项的ID
lPARAM
- 对于菜单为0
上下文菜单
- 显示上下文菜单
|
|
WM_RBUTTONUP
- 鼠标右键弹起消息为窗口坐标系坐标,要使用需将其转换成屏幕坐标系坐标
ClientToScreen
- 鼠标右键弹起消息为窗口坐标系坐标,要使用需将其转换成屏幕坐标系坐标
WM_CONTEXTMENU
wParam
:右键点击的窗口句柄lPARAM
:LOWORD
:X
坐标,屏幕坐标系HIWORD
:Y
坐标,屏幕坐标系
WM_CONTEXTMENU
消息是WM_RBUTTONUP
消息之后产生
Windows资源
图标资源、光标资源、字符串资源
图标资源
- 添加资源
- 注意图标的大小,一个图标文件中,可以有多个不同大小的图标
- 加载
|
|
- 设置
- 注册窗口类
光标资源
- 添加光标的资源
- 光标的大小默认是
32X32
像素,每个光标有HotSpot
,是当前鼠标的热点
- 光标的大小默认是
- 加载资源
|
|
- 设置资源
- 在注册窗口时,设置光标使用
SetCursor
函数设置光标
- 在注册窗口时,设置光标使用
|
|
WM_SETCURSOR
消息参数wPARAM
- 当前使用的光标句柄lPARAM
LOWORD
当前区域的代码(Hit-Test code
)HTCLIENT / HTCAPTION…
HIWORD
- 当前鼠标消息ID
字符串资源
- 添加字符串资源
- 添加字符串表,在表中增加字符串
- 字符串资源的使用
|
|
加速键资源
- 添加
- 资源添加加速键表,增加命令ID对应的加速键。
- 使用
- 加载加速键表
|
|
- 在
WM_COMMAND
中相应消息,消息参数 wPARAM
:HIWORD
为1
表示加速键,为0
表示菜单LOWORD
为命令ID。
lParam
:为0
绘图编程
绘图基础
-
绘图设备
DC
(Device Context
),绘图上下文/绘图描述表 -
HDC
-DC
句柄,表示绘图设备 -
GDI
-Windows graphics device interface
(Win32
提供的绘图API
) -
颜色
- 计算机使用红、绿、蓝,
R
-0~255
G
-0~255
B
-0~255
- 计算机使用红、绿、蓝,
-
每一个点颜色是3个字节24位保存
0-2^24-1
- 16位:5,5,6
- 32位:8,8,8, 8绘图或透明度
-
颜色的使用
COLORREF
- 实际DWORD
- 例如:
COLORREF nColor = 0;
-
赋值使用RGB宏
- 例如 :
nColor = RGB( 0, 0, 255);
- 例如 :
-
获取RGB值,
GetRValue/GetGValue/GetBValue
- 例如 :
BYTE nRed = GetRValue( nColor );
基本图形绘制
SetPixel
设置指定点的颜色
|
|
- 线的使用(直线、弧线)
MoveToEx
– 指名窗口当前点LineTo
- 从窗口当前点到指定点绘制一条直线- 当前点:上一次绘图时的最后一点,初始为
(0,0)
点
- 封闭图形:能够用画刷填充的图形
Rectangle / Ellipse
GDI绘图对象
画笔
- 画笔的作用
- 线的颜色、线型、线粗
HPEN
- 画笔句柄
- 画笔的使用
- 创建画笔
|
|
PS_SOILD
- 实心线,可以支持多个像素宽其他线型只能是一个像素宽- 将画笔应用到DC中
|
|
-
注意保存原来DC当中画笔
-
绘图
-
取出DC中的画笔
- 将原来的画笔,使用
SelectObject
函数,放入到设备DC中,就会将我们创建的画笔取出
- 将原来的画笔,使用
-
释放画笔
|
|
- 只能删除不被DC使用的画笔,所以在释放前,必须将画笔从DC中取出
画刷
- 画刷相关
- 画刷 - 封闭图形的填充的颜色、图案
HBRUSH
- 画刷句柄
- 画刷的使用
- 创建画刷
CreateSolidBrush
- 创建实心画刷CreateHatchBrush
- 创建纹理画刷
- 将画刷应用到DC中
SelectObject
- 绘图
- 将画刷从DC中取出
SelectObject
- 删除画刷
DeleteObject
- 创建画刷
位图绘制
- 位图相关
- 光栅图形 - 记录图像中每一点的颜色等信息
- 矢量图形 - 记录图像算法、绘图指令等
HBITMAP
- 位图句柄
- 位图的使用
- 在资源中添加位图资源
- 从资源中加载位图
LoadBitmap
- 创建一个与当前
DC
相匹配的DC
(内存DC
)
|
|
- 将位图放入匹配的
DC
中SelectObject
- 成像(
1:1
)
|
|
- 缩放成像
|
|
- 取出位图
SelectObject
- 释放位图
DeleteObject
- 释放匹配的DC
DeleteDC
文本绘制
绘制字符串
- 文字的绘制
TextOut
- 将文字绘制在指定坐标位置。
|
|
- 文字颜色和背景
- 文字颜色 :
SetTextColor
- 文字背景色:
SetBkColor
- 文字背景模式:
SetBkMode
(OPAQUE
/TRANSPARENT
)
- 文字颜色 :
字体
-
字体相关
Windows
常用的字体为TrueType
格式的字体文件- 字体名 - 标识字体类型
HFONT
- 字体句柄
-
字体的使用
- 创建字体
|
|
- 应用字体到DC
SelectObject
- 绘制文字
DrawText/TextOut
- 取出字体
SelectObject
- 删除字体
DeleteObject
Windows内核开发
对话框
- 普通窗口:自定义函数调用缺省函数
- 对话框窗口:缺省函数调用自定义函数
对话框原理
- 对话框的分类
- 模式对话框 - 当对话框显示时,会禁止其他窗口和用户交互操作
- 无模式对话框 - 在对话框显示后,其他窗口仍然可以和用户交互操作
- 对话框基本使用
- 对话框窗口处理函数
- 注册窗口类(不使用)
- 创建对话框
- 对话框的关闭
- 对话框窗口处理函数(并非真正的对话框窗口处理函数)
|
|
- 返回
TRUE
- 缺省处理函数不需要处理 - 返回
FALSE
- 交给缺省处理函数处理 - 不需要调用缺省对话框窗口处理函数
模式对话框
- 创建对话框
|
|
DialogBox
是一个阻塞函数,只有当对话框关闭后,才会返回,继续执行后续代码- 返回值是通过
EndDialog
设置 - 对话框的关闭
|
|
- 关闭模式对话框,只能使用
EndDialog
,不能使用DestroyWindow
等函数 nResult
是DialogBox
函数退出时的返回值- 对话框的消息
WM_INITDIALOG
- 对话框创建之后显示之前,通知对话框窗口处理函数,可以完成自己的初始化相关的操作
无模式对话框
- 创建对话框
|
|
- 非阻塞函数,创建成功返回窗口句柄,需要使用ShowWindow函数显示对话框
- 对话框的关闭
- 关闭时使用DestroyWindow销毁窗口,不能使用EndDialog关闭对话框
- 对话框的消息
WM_INITDIALOG
- 对话框创建之后显示之前,通知对话框窗口处理函数,可以完成自己的初始化相关的操作
静态库
静态库特点
-
运行不存在
-
静态库源码被链接到调用程序中
-
目标程序的归档
C语言静态库
- C静态库的创建
- 创建一个静态库项目
- 添加库程序,源文件使用C文件
- C静态库的使用
- 库路径设置:可以使用
pragma
关键字设置 #pragma comment( lib, “../lib/clib.lib”)
- 库路径设置:可以使用
C++语言静态库
- C++静态库的创建
- 创建一个静态库项目。
- 添加库程序,源文件使用
CPP
文件。
- C++静态库的使用
- 库路径设置:可以使用
pragma
关键字设置 #pragma comment( lib, “../lib/cpplib.lib”)
- 库路径设置:可以使用
动态库
动态库特点
-
动态库特点
- 运行时独立存在
- 源码不会链接到执行程序
- 使用时加载(使用动态库必须使动态库执行)
-
与静态库的比较:
- 由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,所以代码体积会增大。动态库的代码只需要存在一份,其他程序通过函数地址使用,所以代码体积小
- 静态库发生变化后,新的代码需要重新链接嵌入到执行程序中。动态库发生变化后,如果库中函数的定义(或地址)未变化,其他使用DLL的程序不需重新链接
动态库创建
- 创建动态库项目
- 添加库程序
- 库程序导出 - 提供给使用者库中的函数等信息
- 声明导出 : 使用
_declspec(dllexport)
导出函数- 注意:动态库编译链接后,也会有
LIB
文件,是作为动态库函数映射使用,与静态库不完全相同
- 注意:动态库编译链接后,也会有
- 模块定义文件
.def
- 例如:
- 声明导出 : 使用
|
|
动态库的使用
隐式链接
- 隐式链接(操作系统负责使动态库执行)
- 头文件和函数原型
- 可以在函数原型的声明前,增加
_declspec(dllimport)
- 可以在函数原型的声明前,增加
- 导入动态库的
LIB
文件 - 在程序中使用函数
- 隐式链接的情况,
dll
文件可以存放的路径:- 与执行文件中同一个目录下(推荐)
- 当前工作目录
Windows
目录Windows/System32
目录Windows/System
- 环境变量
PATH
指定目录
- 头文件和函数原型
显式链接
- 显式链接(程序员自己负责使动态库执行)
- 定义函数指针类型
typedef
- 加载动态库
|
|
- 获取函数地址
|
|
- 使用函数
- 卸载动态库
|
|
动态库中封装类
- 在类名称前增加
_declspec(dllexport)
定义,例如:
|
|
- 通常使用预编译开关切换类的导入导出定义,例如:
|
|
- 使用
dll
中封装的类- 导入
DLL
的LIb
- 类的定义
- 使用类
- 导入
Windows线程开发
线程
线程基础
- Windows线程是可以执行的代码的实例。系统是以线程为单位调度程序
- 一个程序当中可以有多个线程,实现多任务的处理
- Windows线程的特点:
- 线程都具有1个ID
- 每个线程都具有自己的内存栈
- 同一进程中的线程使用同一个地址空间。
- 线程的调度:
- 将CPU的执行时间划分成时间片,依次根据时间片执行不同的线程
- 线程轮询:线程A -> 线程B -> 线程A……
创建线程
- 创建线程
|
|
- 定义线程处理函数
|
|
线程挂起/销毁
- 挂起
|
|
- 唤醒
|
|
- 结束指定线程
|
|
- 结束函数所在的线程
|
|
线程相关操作
- 获取当前线程的ID
GetCurrentThreadId
- 获取当前线程的句柄
GetCurrentThread
- 等候单个句柄有信号
|
|
- 同时等候多个句柄有信号
|
|
bWaitAll
- 等候方式TRUE
- 表示所有句柄都有信号,才结束等候FASLE
- 表示句柄中只要有1个有信号,就结束等候
线程同步
原子锁
- 相关问题
- 多个线程对同一个数据进行原子操作,会产生结果丢失。比如执行
++
运算时
- 多个线程对同一个数据进行原子操作,会产生结果丢失。比如执行
- 错误代码分析:
- 当线程A执行
g_value++
时,如果线程切换时间正好是在线程A将值保存到g_value
之前,线程B继续执行g_value++
,那么当线程A再次被切换回来之后,会将原来线程A保存的值保存到g_value
上,线程B进行的加法操作被覆盖
- 当线程A执行
- 使用原子锁函数
|
|
- 原子锁的实现:直接对数据所在的内存操作,并且在任何一个瞬间只能有一个线程访问
互斥
- 相关的问题
- 多线程下代码或资源的共享使用。
- 互斥的使用
- 创建互斥
|
|
- 等候互斥
WaitFor....
互斥的等候遵循谁先等候谁先获取
- 释放互斥
|
|
- 关闭互斥句柄
CloseHandle
事件
- 相关问题
- 程序之间的通知的问题。
- 事件的使用
- 创建事件
|
|
- 等候事件
WaitForSingleObject
/WaitForMultipleObjects
- 触发事件(将事件设置成有信号状态)
|
|
- 复位事件(将事件设置成无信号状态)
|
|
- 关闭事件
CloseHandle
- 小心事件的死锁
信号量
- 相关的问题
- 类似于事件,解决通知的相关问题。但提供一个计数器,可以设置次数。
- 信号量的使用
- 创建信号量
|
|
- 等候信号量
WaitFor...
每等候通过一次,信号量的信号减1,直到为0阻塞
- 给信号量指定计数值
|
|
- 关闭句柄
CloseHandle