day01
Windows 编程
1 Windows 编程基础
2 WIndows 字符
3 窗口处理
4 消息
5 绘图
6 对话框
7 控件
。。。
一Windows 编程基础
1 Windows 应用程序的类型
1.1 控制台程序Console
DOS 程序。本身没有窗口,通过Windows 的DOS
窗口执行。
1.2 窗口程序
拥有自己的窗口,可以与用户交互。
1.3 库程序
存放代码、数据的程序,执行文件可以从中
取出代码执行和获取数据。
1.3.1 动态库
扩展名DLL,在执行文件执行时从中获取代码
1.3.2 静态库
扩展名LIB,在编译链接程序时,将代码放入
到执行文件中。
1.4 对比
1.4.1 入口函数
控制台程序- main
窗口程序- WinMain
动态库程序- DllMain
静态库程序- 无入口函数
1.4.2 文件存在方式
控制台程序、窗口程序- EXE 文件
动态库程序- DLL 文件
静态库程序- LIB 文件
1.4.3 执行方式
控制台程序- 在DOS 窗口内执行。
窗口程序- 拥有自己的窗口的执行文件
动态库程序- 本身无法执行,由可执行程序
或其他的DLL 调用
静态库程序- 执行是不存在,代码会嵌入
到可执行文件或DLL 等中。
二Windows 开发环境
1 Visual Studio C++
VC1.5 - VC6.0 - VC2010( 10.0 )
2 VC 的编译工具
2.1 编译器
CL.EXE 将源代码编译成目标代码
2.2 链接器
LINK.EXE 将目标代码、库链接生成最终文件
2.3 资源编译器
RC.EXE 将资源编译,最终通过链接器存入
最终文件。
3 Windows 库和头文件
3.1 Windows 库
kernel32.dll - 提供了核心的API,例如
进程、线程、内存管理等。
user32.dll - 提供了窗口、消息等API
gdi32.dll - 绘图相关的API
3.2 头文件
Windows.h - 所有windows 头文件的集合
windef.h - windows 数据类型
winbase.h - kernel32 的API
wingdi.h - gdi32 的API
winuser.h - user32 的API
winnt.h - UNICODE 字符集支持
4 HelloWorld 程序
int WINAPI WinMain(
HINSTANCE hInstance,//当前程序的实例句柄
HINSTANCE hPrevInstance,
//当前程序前一个实例句柄
LPSTR lpCmdLine,//命令行参数字符串
int nCmdShow //窗口的显示方式
);
hPrevInstance - Win32 下,一般为NULL
int MessageBox(
HWND hWnd,//父窗口句柄
LPCTSTR lpText, //显示在消息框中的文字
LPCTSTR lpCaption,
//显示在标题栏中的文字
UINT uType //消息框中的按钮、图标显示类型
); 返回点击的按钮ID
5 编译环境准备
VC98\BIN\VCVARS32.BAT
6 编译程序- CL
CL.EXE -? 显示CL 的帮助
/c 只编译不链接
/Tc 编译C 文件
/Tp 编译C++文件
/I 头文件路径
7 链接程序- LINK
LINK.EXE xxx.obj xxx.lib
8 执行
三第一个窗口程序
1 WinMain 函数
2 定义窗口处理函数
3 注册窗口类
4 创建窗口
5 显示窗口
6 消息循环
7 消息处理
day02
一资源的使用
1 资源的文件
2 rc 资源脚本文件
3 编译rc 文件
RC.EXE
4 将资源链接到程序中
LINK.EXE
二NMAKE 和Makefile
1 NMAKE
Makefile 的一个解释执行的工具,根据Makefile 文件中的定义,
编译和链接程序,最终生成目标文件
2 Makefile
定义编译和链接等操作的脚本文件(把项目的处理命令写入),
一般对整个项目进行处理。
2.1 Makefile 语法
HELLO:依赖行
cl.exe hellownd.c /c//命令行
rc.exe hellownd.rc//命令行
link.exe hellownd.obj hellownd.res user32.lib//命令行
Makefile 文件中可以有多个依赖行。
2.2 执行方式
2.2.1 NMAKE 首先找到第一个依赖行
2.2.2 检查依赖行的依赖项,如果
发现依赖项,首先执行依赖项的
命令行
2.2.3 执行完所有依赖项命令后,再
执行自己的命令行。
A:B
B:C
C:D
D-〉C-〉B-〉A
一Windows 字符处理
1 字符的编码方式
1.1 DBCS 字符Double Byte Character Set
由1 个或2 个字节表示一个字符
A 我是程序员
01 0203 0405 0607 0809 0A0B
01 02030405060708090A0B
0102 030405060708090A0B
1.2 UNICODE 码
在Windows 平台下,采用2 字节表示一个字符
A 我是程序员
0001 0203 0405 0607 0809 0A0B
二字符集的使用
1 宽字节字符
wchar_t 每个字符占2 个字节
char 每个字符占1 个字节
wchar_t 实际是unsigned short 类型,
定义时,需要增加“L”,通知编译器按照
双字节编译字符串,采用UNICODE 编码。
需要使用支持wchar_t 函数操作宽字节
字符串。例如:
wchar_t * pwszText = L"Hello wchar";
wprintf( L"%s\n", pwszText );
2 TCHAR
#ifdef UNICODE // r_winnt
typedef WCHAR TCHAR, *PTCHAR;
#define __TEXT(quote) L##quote
#else
typedef char TCHAR, *PTCHAR;
#define __TEXT(quote) quote
#endif
5 UNICODE 字符打印
printf 对UNICODE 字符打印支持不完善。
在Windows 下使用WriteConsole
API 打印UNICODE 字符
三窗口的注册
1 窗口程序的创建过程
1.1 定义WinMain 入口函数
1.2 定义窗口处理函数WindowProc
1.3 注册窗口类
RegisterClass
1.4 创建窗口
CreateWindow
1.5 显示窗口
ShowWindow/UpdateWindow
1.6 消息循环
GetMessage
TranslateMessage
DisptachMessage
1.7 消息处理
2 窗口类
窗口类包含了窗口的各种参数信息的数据
结构。每个窗口都具有窗口类,基于窗口
类创建窗口。
每个窗口类都具有一个名称,使用前必须
注册到系统。
3 窗口类的分类
3.1 系统窗口类- 系统已经定义好的窗口
类,所有应用程序都可以直接使用。
3.2 应用程序全局窗口类- 由用户自己定
义,当前应用程序所有模块都可以使用。
3.3 应用程序局部窗口类- 由用户自己定
义,当前应用程序中本模块可以使用
4 系统窗口类的使用
不需要注册,直接使用窗口类即可。系统
已经定义好相应名称,例如
按钮- BUTTON
编辑框- EDIT
day03
一窗口的注册
5 应用程序全局窗口类
5.1 注册窗口类
RegisterClass/RegisterClassEx
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass
//窗口类的数据
); 注册成功后,返回一个数字标识。
ATOM RegisterClassEx(
CONST WNDCLASSEX *lpwcx
//窗口类的数据
);
typedef struct _WNDCLASSEX {
UINT cbSize; //结构体的大小
UINT style; //窗口类的风格
WNDPROC lpfnWndProc; //窗口处理函数
int cbClsExtra; //窗口类的附加数据
int cbWndExtra; //窗口的附加数据
HINSTANCE hInstance; //当前模块的实例句柄
HICON hIcon; //窗口图标句柄
HCURSOR hCursor; //鼠标的句柄
HBRUSH hbrBackground;
//绘制窗口背景的画刷句柄
LPCTSTR lpszMenuName;
//窗口菜单的资源ID 字符串
LPCTSTR lpszClassName;
//窗口类的名称
HICON hIconSm; //窗口的小图标句柄
} WNDCLASSEX, *PWNDCLASSEX;
应用程序全局窗口类的注册,需要在窗口类
的风格中增加CS_GLOBALCLASS,例如:
WNDCLASSEX wce = {0};
wce.style = CS_GLOBALCLASS;
5.2 创建窗口
6 应用程序局部窗口类
在注册窗口类时,不添加CS_GLOBALCLASS 风格。
7 窗口类的风格
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平
位置8 倍数对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置
8 倍数对齐
CS_HREDRAW - 当窗口水平变化时,窗口
重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口
重新绘制
CS_CLASSDC - 该类型的窗口,都是有同
一个绘图(DC)设备
CS_PARENTDC - 该类型的窗口,使用它的父
窗口的绘图(DC)设备
CS_OWNDC - 该类型的窗口,每个窗口都使用
自己的绘图(DC)设备
CS_SAVEBITS - 允许窗口保存成图(位图),
提高窗口的绘图效率,但是耗费内存资源
CS_DBLCLKS - 允许窗口接收鼠标左键双击
CS_NOCLOSE - 窗口没有关闭按钮
8 窗口类的查找过程
8.1 系统根据传入的窗口类名称,在应用
程序局部窗口类中查找,如果找到执行
8.2,如果未找到执行8.3。
8.2 比较局部窗口类与创建窗口时传入的
HINSTANCE 变量。如果发现相等,创建
和注册的窗口类在同一模块,创建窗口
返回。如果不相等,继续执行8.3。
8.3 在应用程序全局窗口类,如果找到,
执行8.4,如果未找到执行8.5
8.4 使用找到的窗口类的信息,创建窗口
返回。
8.5 在系统窗口类中查找,如果找到创建
窗口返回,否则创建窗口失败。
9 相关API
RegisterClass/Ex 注册
GetClassInfo 获取信息
UnregisterClass 卸载
...
二窗口的创建
1 创建窗口
CreateWindow/CreateWindowEx
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 //窗口创建时附加参数
); 创建成功返回窗口句柄
2 子窗口的创建
2.1 创建时要设置父窗口句柄
2.2 创建风格要增加WS_CHILD
3 窗口类和窗口的附加数据
3.1 作用
注册窗口时,可以设置这两个数据内存空间
的大小。
int cbClsExtra; //窗口类的附加数据大小
int cbWndExtra; //窗口的附加数据大小
可以提供窗口类和窗口存放自己的数据的
空间。
3.2 窗口类使用
3.2.1 定义数据空间的大小
int cbClsExtra - 一般定义为4 字节倍数
3.2.2 存入数据
DWORD SetClassLong(
HWND hWnd,//窗口句柄
int nIndex,//字节索引号
LONG dwNewLong //存入数据
);返回旧数据
3.2.3 读取数据
DWORD GetClassLong(
HWND hWnd, //窗口句柄
int nIndex //字节索引号
); 返回获取值
3.3 窗口使用
3.3.1 定义数据空间的大小
int cbWndExtra;
3.3.2 存入数据
LONG SetWindowLong(
HWND hWnd, // handle to window
int nIndex, // offset of value to set
LONG dwNewLong // new value
);
3.3.3 读取数据
LONG GetWindowLong(
HWND hWnd, // handle to window
int nIndex // offset of value to retrieve
);
3.4 不同点
窗口类的附加数据提供BUFF,是所有该类
窗口共享的BUFF。
窗口附加数据提供BUFF,只属于该窗口
所有,是窗口私有的BUFF。
一消息机制
1 程序执行机制
过程驱动- 程序的执行过程是按照预定好
的顺序执行,
事件驱动- 程序的执行是无序,用户可以
根据需要随机触发相应的事件。
Win32 窗口程序就是采用事件驱动方式
执行,也就是消息机制。
2 消息机制
2.1 消息定义
1) 消息
当系统通知窗口工作时,就采用消息的
方式派发给窗口。
2) 消息组成
窗口句柄
消息ID
消息的两个参数
消息产生的时间
消息产生时的鼠标位置
2.2 窗口处理函数
每个窗口都必须具有窗口处理函数。
函数原型为:
LRESULT CALLBACK WindowProc(
HWND hwnd, //窗口句柄
UINT uMsg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam //消息参数
);
当系统通知窗口时,会调用窗口处理函数
同时,将消息ID 和消息参数传递给窗口
处理函数。
在窗口处理函数中,不处理的消息,使用
缺省窗口处理函数,例如DefWindowProc。
2.3 消息相关函数
2.3.1 GetMessage - 获取消息。
BOOL GetMessage(
LPMSG lpMsg, //存放获取到的消息BUFF
HWND hWnd, //窗口句柄
UINT wMsgFilterMin,
//获取消息的最小ID
UINT wMsgFilterMax
//获取消息的最大ID
);
lpMsg - 当获取到消息后,将消息的参数
存放到MSG 结构中。
hWnd - 获取到hWnd 所指定窗口的消息。
wMsgFilterMin 和wMsgFilterMax -
只能获取到由它们指定的消息范围内
的消息,如果都为0,表示没有范围。
2.3.2 TranslateMessage - 翻译消息。
将按键消息,翻译成字符消息。
BOOL TranslateMessage(
CONST MSG *lpMsg //要翻译的消息地址
);
检查消息是否是按键的消息,如果不是
按键消息,不做任何处理,继续执行。
2.3.3 DispatchMessage - 派发消息。
将消息派发到该消息所属窗口的窗口
处理函数上。
LRESULT DispatchMessage(
CONST MSG *lpmsg //要派发的消息
);
3 常用的几个消息
3.1 WM_DESTROY - 窗口被销毁时的消息,
无消息参数。常用于在窗口被销毁之前,
做相应的善后处理,例如资源、内存等。
3.2 WM_SYSCOMMAND - 系统命令消息,当
点击窗口的最大化、最小化、关闭等
命令时,收到这个消息。
常用在窗口关闭时,提示用户处理。
wParam - 具体命令,例如关闭SC_CLOSE 等.
lParam - 鼠标位置
LOWORD 低字- 水平位置
HIWORD 高字- 垂直位置
3.3 WM_CREATE - 在窗口创建成功还未显示
之前,收到这个消息。
常用于初始化窗口的参数、资源等等,
包括创建子窗口等。
WPARAM - 不使用
LPARAM - 是CREATESTRUCT 结构的指针,
保存了CreatWindowEx 中的12 个参数。
3.4 WM_SIZE - 在窗口的大小发生变化后,
会收到WM_SIZE。
常用于窗口大小变化后,调整窗口内各个
部分的布局。
WPARAM - 窗口大小变化的原因。
LPARAM - 变化窗口客户区的大小
LOWORD - 变化后的宽度
HIOWORD- 变化后的高度
3.5 WM_QUIT - 用于结束消息循环处理。
wParam - PostQuitMessage 函数传递的参数。
lParam - 不使用
当GetMessage 收到这个消息后,会返回
FALSE,结束while 处理,退出消息循环。
3.6 WM_PAINT - 绘图消息
3.7 键盘消息
3.8 鼠标消息
3.9 定时器消息
Day04
4 消息的获取和发送
4.1 消息的获取
GetMessage - 从系统获取消息,将消息
从系统中移除,阻塞函数。
当系统无消息时,GetMessage 会等候
下一条消息。
PeekMessage - 以查看的方式从系统获取
消息,可以不将消息从系统移除,非
阻塞函数。
当系统无消息时,返回FALSE,继续执行
后续代码。
BOOL PeekMessage(
LPMSG lpMsg, // message information
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax, // last message
UINT wRemoveMsg //移除标识
);
4.2 消息的发送
4.2.1 SendMessage / PostMessage
BOOL SendMessage/PostMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam //消息参数
);
4.2.2 SendMessage - 发送消息,会等候
消息处理的结果。
4.2.3 PostMessage - 投递消息,消息发
出后立刻返回,不等候消息执行结果。
二消息的分类
1 系统消息- ID 范围0 - 0x03FF
由系统定义好的消息,可以在程序中直接
使用。
2 用户自定义消息- ID 范围0x0400 - 0x7FFF
由用户自己定义,满足用户自己的需求。
由用户自己发出消息,并响应处理。
自定义消息宏:WM_USER
3 应用程序消息- ID 范围0x8000 - 0xBFFF
程序之间通讯时使用的消息。
应用程序消息宏:WM_APP
4 系统注册消息- ID 范围0xC000 - 0xFFFF
在系统注册并生成相应消息,然后可以
在各个程序中使用这个消息。
三消息队列
1 消息队列
用于存放消息的一个队列,消息在队列
中先入先出。所有窗口程序都具有消息队列。
程序可以从队列中获取消息。
2 消息队列的类型
2.1 系统消息队列
由系统维护的消息队列。存放系统产生
的消息,例如鼠标、键盘等。
2.2 程序消息队列
属于每一个应用程序(线程)的消息队列。
由应用程序(线程)维护。
3 消息队列的关系
3.1 当鼠标、键盘产生消息时,会将消息
存放到系统消息队列
3.2 系统会根据存放的消息,找到对应窗口
的消息队列。
3.3 将消息投递到程序的消息队列中。
4 消息和消息队列
4.1 根据消息和消息队列之间使用关系,将
消息分成两类:
队列消息- 消息的发送和获取,都是通过
消息队列完成。
非队列消息- 消息的发送和获取,是直接
调用消息的窗口处理函数完成。
4.2 队列消息
消息发送后,首先放入队列,然后通过消息
循环,从队列当中获取。
GetMessage - 从消息队列中获取消息
PostMessage - 将消息投递到消息队列
常见队列消息:WM_PAINT、键盘、鼠标
定时器。
4.3 非队列消息
消息发送时,首先查找消息接收窗口的窗口
处理函数,直接调用处理函数,完成消息。
SendMessage - 直接将消息发送给窗口的
处理函数,并等候处理结果。
常见消息:WM_CREATE、WM_SIZE 等。
一消息的获取和发送
1 消息的获取
1.1 消息循环
1.1.1 GetMessage 从程序的消息队列当中,
获取到消息。
1.1.2 TranslateMessage 检查获取到的消息,
如果发现是按键消息,产生一个字符消息,
并放入程序的消息队列。
1.1.3 DispatchMessage 根据消息,找到
窗口处理函数,调用窗口处理函数,
完成消息的处理。
1.2 GetMessage/PeekMessage
1.2.1 在程序(线程)消息队列查找消息,
如果队列有消息,检查消息是否满足
指定条件(HWND,ID 范围),不满足条件就
不会取出消息,否则从队列取出消息返回。
1.2.2 如果程序(线程)消息队列没有消息,
向系统消息队列获取属于本程序的消息。
如果系统队列的当前消息属于本程序,
系统会将消息转发到程序队列,程序
获取消息返回,处理消息。
1.2.3 如果系统消息队列也没有消息,检查
当前窗口的需要重新绘制的区域,如果
发现有需要绘制的区域,产生WM_PAINT
消息,取得消息返回处理。
1.2.4 如果没有重新绘制区域,检查定时器
如果有到时的定时器,产生WM_TIMER,返回
处理执行。
1.2.5 如果没有到时的定时器,整理程序的
资源、内存等等。
1.2.6 GetMessage 会继续等候下一条消息。
PeekMessage 会返回FALSE,交出程序
的控制权。
注意:GetMessage 如果获取到是WM_QUIT,
函数会返回FALSE。
2 消息的发送
2.1 SendMessage
发送消息到指定的窗口,并等候对方将
消息处理,然后消息执行结果。
2.2 PostMessage
将消息放到消息队列中,立刻返回。
无法获知消息是否被对方处理。
二WM_PAINT
1 WM_PAINT
当窗口需要绘制的时候,会发送窗口处理函数。
2 窗口无效区域
被声明成需要重新绘制的区域。
BOOL InvalidateRect(
HWND hWnd, //窗口句柄
CONST RECT* lpRect, //区域的矩形坐标
BOOL bErase //重绘前是否先擦除
);
在程序中,如果需要绘制窗口,调用函数
声明窗口无效区域。
3 WM_PAINT 用法
3.1 参数
WPARAM - 不使用
LPARAM - 不使用
3.2 消息处理
3.2.1 开始绘图处理
HDC BeginPaint(
HWND hwnd, //绘图窗口
LPPAINTSTRUCT lpPaint
//绘图参数的BUFF
); 返回绘图设备句柄HDC
3.2.2 绘图
3.2.3 结束绘图处理
BOOL EndPaint(
HWND hWnd, //绘图窗口
CONST PAINTSTRUCT *lpPaint
//绘图参数的指针,即BeginPaint 返回
);
三键盘消息
1 键盘消息
WM_KEYDOWN - 按键被按下时产生
WM_KEYUP - 按键被放开时产生
WM_SYSKEYDOWN - 系统键按下时产生ALT、F10
WM_SYSKEYUP - 系统键放开时产生
WM_CHAR - 字符消息
2 消息参数
按键消息:WPARAM - 按键的Virtual Key
LPARAM - 按键的参数,例如按下次数
WM_CHAR 消息:WPARAM - 输入的字符
LPARAM - 按键的相关参数
3 消息的使用
3.1 KEYDOWN 可以重复出现,KEYUP 只能在
按键松开时出现1 次
3.2 TranslateMessage 在转换WM_KEYWODN 消息
时,对于可见字符可以产生WM_CHAR,
不可见字符无此消息。
3.3 WM_KEYWODN/UP 的wParam 是表示的按键,
WM_CHAR 是表示输入的字符。
Day05
四鼠标消息
1 鼠标消息
1.1 基本鼠标消息
WM_LBUTTONDOWN - 鼠标左键按下
WM_LBUTTONUP - 鼠标左键抬起
WM_RBUTTONDOWN - 鼠标右键按下
WM_RBUTTONUP - 鼠标右键抬起
WM_MOUSEMOVE - 鼠标移动消息
1.2 双击消息
WM_LBUTTONDBLCLK - 鼠标左键双击
WM_RBUTTONDBLCLK - 鼠标右键双击
1.3 滚轮消息
WM_MOUSEWHEEL - 鼠标滚轮消息
2 基本鼠标消息
2.1 消息参数
WPARAM - 其他按键的状态,例如
Ctrl/Shift 等
LPARAM - 鼠标的位置,窗口客户区坐标系。
LOWORD X 坐标位置
HIWORD Y 坐标位置
2.2 鼠标消息使用
一般情况鼠标按下/抬起成对出现。
在鼠标移动过程中,会根据移动速度产生
一系列的WM_MOUSEMOVE 消息。
3 双击鼠标消息
3.1 消息参数
WPARAM - 其他按键的状态,例如
Ctrl/Shift 等
LPARAM - 鼠标的位置,窗口客户区坐标系。
LOWORD X 坐标位置
HIWORD Y 坐标位置
3.2 使用
需要在注册窗口类的时候添加CS_DBLCLKS
风格。
3.3 消息产生顺序
以WM_LBUTTONDBLCLK 为例:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP
4 鼠标滚轮WM_MOUSEWHEEL
4.1 消息参数
WPARAM:
LOWORD - 其他按键的状态
HIWORD - 滚轮的偏移量,是120 的倍数
通过正负值表示表示滚动方向。
正:向前滚动
负:向后滚动
LPARAM:鼠标当前的位置,屏幕坐标系
LOWORD - X 坐标
HIWORD - Y 坐标
4.2 使用
通过偏移量,获取滚动的方向和倍数。
一定时器消息
1 定时器消息
可以在程序中设置定时器,当到达时间
间隔时,定时器会向程序发送一个
WM_TIMER 消息。
定时器的精度是毫秒,但是准确度很低。
例如设置时间间隔为1000ms,但是会在
非1000 毫秒到达。
2 消息的参数
WPARAM - 定时器ID
LPARAM - 定时器处理函数的指针
3 定时器使用
3.1 创建定时器
UINT_PTR SetTimer(
HWND hWnd,//定时器窗口句柄
UINT_PTR nIDEvent, //定时器ID
UINT uElapse,//时间间隔
TIMERPROC lpTimerFunc
//定时器处理函数指针
);创建成功,返回非0。
3.1.1 使用窗口处理函数,做为
定时器处理函数,lpTimerFunc 为NULL
3.1.2 使用定时器处理函数处理定时器
消息。
3.2 消息处理
WM_TIMER
3.3 关闭定时器
BOOL KillTimer(
HWND hWnd,//定时器窗口句柄
UINT_PTR uIDEvent //定时器ID
);
附:GetClientRect 获取窗口客户区大小
二菜单的使用
1 菜单的分类
1.1 窗口的顶层菜单
1.2 弹出式菜单
1.3 系统菜单
HMENU 类型表示菜单,菜单每一项有相应的ID。
2 窗口的顶层菜单
2.1 创建菜单
HMENU CreateMenu(VOID);
创建成功返回菜单句柄
2.2 增加菜单项
BOOL AppendMenu(
HMENU hMenu, //菜单句柄
UINT uFlags, //菜单项增加选项
UINT_PTR uIDNewItem, //菜单项ID
LPCTSTR lpNewItem //菜单项的名称
);
2.3 设置到窗口
BOOL SetMenu(
HWND hWnd, //窗口句柄
HMENU hMenu //菜单句柄
);
3 弹出式菜单Popup
3.1 菜单的创建
HMENU CreatePopupMenu(VOID);
创建成功返回菜单句柄
3.2 加入顶层菜单
BOOL AppendMenu(
HMENU hMenu, //菜单句柄
UINT uFlags,
//菜单项增加选项,MF_POPUP
UINT_PTR uIDNewItem,
//弹出式菜单的句柄
LPCTSTR lpNewItem //菜单项的名称
);
4 菜单命令处理
4.1 WM_COMMAND 消息
WPARAM:
HIWORD - 对于菜单为0
LOWORD - 菜单项的ID
LPARAM - 对于菜单为NULL
4.2 命令处理过程
获取WPARAM 菜单ID,根据ID 处理。
5 菜单项的状态
5.1 在增加菜单项可以设置菜单项的状态。
5.2 可以使用菜单API 修改状态
CheckMenuItem
EnableMenuItem
函数使用时,需要通过设置MF_BYPOSITION
或者MF_BYCOMMAND,确定使用菜单索引或
者菜单ID。
5.3 WM_INITMENUPOPUP
在菜单被激活但是未显示,窗口会收到这个
消息
WPARAM - 菜单句柄
LPARAM - LOWORD 是菜单索引
HIWORD 是窗口菜单标识
Day06
三系统菜单
1 系统菜单的使用
1.1 系统菜单的获取
HMENU GetSystemMenu(
HWND hWnd,//窗口句柄
BOOL bRevert //重置选项
); 返回获取到的系统菜单句柄
bRevert:
TRUE - 删除旧菜单,恢复到默认的
系统菜单
FALSE - 返回当前的系统菜单句柄。
1.2 系统菜单的修改
AppendMenu
DeleteMenu
...
1.3 系统菜单命令响应
通过WM_SYSCOMMAND 响应菜单命令。
WPARAM 的LOWORD 是命令ID
四右键菜单Context Menu
1 右键菜单使用
1.1 创建菜单
右键菜单是一个弹出式菜单,使用
CreatePopupMenu 创建。
1.2 显示菜单
BOOL TrackPopupMenu(
HMENU hMenu, //菜单句柄
UINT uFlags, //显示方式
int x,//水平位置,屏幕坐标系
int y,//垂直位置,屏幕坐标系
int nReserved, //保留,必须0
HWND hWnd, //处理菜单消息的窗口句柄
CONST RECT *prcRect //NULL,忽略
);
TrackPopupMenu 是阻塞函数
1.3 命令处理
1.3.1 WM_COMMAND,与窗口菜单一致
1.3.2 如果Track 设置了TPM_RETURNCMD 选项,
那么点击的菜单项ID 通过函数的返回值
获取。
1.4 菜单项的状态
WM_INITMENUPOPUP,按照弹出菜单处理
2 菜单处理位置
2.1 鼠标右键抬起
WM_RBUTTONUP 鼠标右键消息窗口坐标系
坐标,要使用需要转换成屏幕坐标系
ClientToScreen
ScreenToClient
2.2 WM_CONTEXTMENU
wParam - 右键点击的窗口句柄
LPARAM - LOWORD X 坐标,屏幕坐标系
HIWORD Y 坐标,屏幕坐标系
WM_CONTEXTMENU 消息是在WM_RBUTTONUP
消息之后产生。
一资源的使用
1 资源相关
资源脚本文件:*.rc 文件
编译器:RC.EXE
2 菜单资源的使用
2.1 添加菜单资源
2.2 加载菜单资源
2.2.1 在注册时设置菜单资源
2.2.3 加载菜单资源,设置到窗口
HMENU LoadMenu(
HINSTANCE hInstance, // handle to module
LPCTSTR lpMenuName // menu name or resource
identifier
);
CreateWindow/Ex
SetMenu
3 图标资源ICON
3.1 添加资源
注意图标的大小,一个图标文件中,
可以有多个不同大小的图标。
3.2 加载
HICON LoadIcon(
HINSTANCE hInstance, // handle to application instance
LPCTSTR lpIconName // name string or resource
identifier
); 成功返回HICON 句柄
3.3 设置
3.3.1 注册窗口类
3.3.2 WM_SETICON 消息
3.4 绘制
DrawIcon
4 光标资源
4.1 添加光标的资源
光标的大小默认是32X32 像素
每个光标有HotSpot,是当前鼠标的热点
4.2 使用资源
HCURSOR LoadCursor(
HINSTANCE hInstance, // handle to application instance
LPCTSTR lpCursorName // name or resource identifier
);
hInstance - 可以为NULL,获取系统默认的
Cursor
1.2.1 在注册窗口时,设置光标
1.2.2 使用SetCursor 设置光标
HCURSOR SetCursor(
HCURSOR hCursor // handle to cursor
);
4.3 WM_SETCURSOR 消息
1.3.1 参数
WPARAM - 当前使用的光标句柄
LPARAM -
LOWORD - 当前区域的代码(Hit-Test code )
HIWORD - 当前鼠标消息ID
1.3.2 使用
Day07
5 字符串资源
5.1 添加字符串资源
添加字符串表,在表中增加字符串
5.2 字符串资源的使用
int LoadString(
HINSTANCE hInstance, // handle to resource module
UINT uID, //字符串ID
LPTSTR lpBuffer, //存放字符串BUFF
int nBufferMax // 字符串BUFF 长度
); 成功返回字符串长度,失败0
6 加速键资源
6.1 添加
资源添加加速键表,增加命令ID 对应的加速键。
6.2 使用
6.2.1 加载加速键
HACCEL LoadAccelerators(
HINSTANCE hInstance, // handle to module
LPCTSTR lpTableName // accelerator table name
); 返回加速键句柄
6.2.2 处理加速键消息
int TranslateAccelerator(
HWND hWnd,//处理消息的窗口句柄
HACCEL hAccTable, //加速键句柄
LPMSG lpMsg //消息
); 如果是加速键,返回非零。
6.2.3 在WM_COMMAND 中相应消息,消息参数
WPARAM - HIWORD 为1,表示加速键
为0,表示菜单
LWORD 为命令ID
6.3 TranslateAccelerator 处理过程
6.3.1 检测消息是否是WM_KEYDOWN\WM_SYSKEYDOW,
获取按键状态
6.3.2 根据按键状态,从HACCEL 中查找对应
命令ID
6.3.3 找到对应ID,发送WM_COMMAND 消息,
处理ID 所对应的命令。
二绘图
1 绘图相关
绘图设备DC(Device Context),
HDC - DC 句柄,表示绘图设备
GDI - Windows graphics device interface
Win32 提供的绘图API
2 颜色
2.1 颜色的表示
电脑使用红、绿、蓝,
R - 0~255
G - 0~255
B - 0~255
每一个点颜色是3 个字节24 位保存0-2^24
16 位:5,5,6
32 位:8,8,8, 8 绘图或透明度
2.2 颜色的使用
COLORREF - 实际DWORD,例如:
COLORREF nColor = 0;
赋值使用RGB 宏,例如
nColor = RGB( 255, 0, 0 );
获取RGB 值,
GetRValue/GetGValue/GetBValue
例如:
BYTE nRed = GetRValue( nColor );
3 点的使用2011-5-16 15:42
GetPixel 获取指定点的颜色
COLORREF GetPixel(
HDC hdc, // handle to DC
int nXPos, // x-coordinate of pixel
int nYPos // y-coordinate of pixel
);
SetPixel 设置指定点的颜色
COLORREF SetPixel(
HDC hdc,//DC 句柄
int X,//X 坐标
int Y,//Y 坐标
COLORREF crColor //设置的颜色
); 返回点原来的颜色
4 线的使用(直线、圆形、弧线)
MoveTo - 移动当前点到指定点
LineTo - 从当前点到指定点绘制一条直线
当前点:上一次绘图时的最后一点,初始为
(0,0)点。
5 封闭图形
Rectangle
Ellipse
二绘图对象
2 GDI 绘图对象- 画笔
2.1 画笔相关
线的颜色、线型、线粗。
HPEN - 画笔句柄
2.2 画笔使用
2.2.1 创建画笔
HPEN CreatePen(
int fnPenStyle, //画笔的样式
int nWidth, //画笔的粗细
COLORREF crColor //画笔的颜色
);创建成功返回句柄
PS_SOILD - 实心线,可以支持多个像素宽
其他线型只能是一个像素宽。
2.2.2 将画笔应用到DC 中
HGDIOBJ SelectObject(
HDC hdc,//绘图设备句柄
HGDIOBJ hgdiobj
//GDI 绘图对象句柄,画笔句柄
);返回原来的GDI 绘图对象句柄
注意保存原来DC 当中画笔。
2.2.3 绘图
2.2.4 取出DC 中的画笔
将原来的画笔,使用SelectObject 函数,
放入到设备DC 中,就会将我们创建的
画笔取出。
2.2.5 释放画笔
BOOL DeleteObject(
HGDIOBJ hObject
//GDI 绘图对象句柄,画笔句柄
);
只能删除不被DC 使用的画笔,所以在释放
前,必须将画笔从DC 中取出。
3 GDI 绘图对象- 画刷
3.1 画刷相关
画刷- 封闭图形的填充的颜色、图案
HBRUSH - 画刷句柄
3.2 画刷的使用
3.2.1 创建画刷
CreateSolidBrush - 创建实心画刷
CreateHatchBrush - 创建填充画刷
CreatePatternBrush - 创建位图画刷
3.2.2 将画刷应用到DC 中
SelectObject
3.2.3 绘图
3.2.4 将画刷从DC 中取出
SelectObject
3.2.5 删除画刷
DeleteObject
3.3 其他
可以使用GetStockObject 函数获取系统
维护的画刷、画笔等。
如果不使用画刷填充,需要使用NULL_BRUSH
参数,获取不填充的画刷。
GetStockObject 返回的画刷不需要DeleteObject
Day08
4 GDI 绘图对象- 位图
4.1 位图相关
光栅图形- 记录图像中每一点的颜色等信息。
矢量图形- 记录图像算法、绘图指令等。
HBITMAP - 位图句柄
4.2 位图的使用
4.2.1 在资源中添加位图资源
4.2.2 从资源中加载位图
LoadBitmap
4.2.3 创建一个与当前DC 相匹配的DC
HDC CreateCompatibleDC(
HDC hdc
//当前DC 句柄,可以为NULL(使用屏幕DC)
); 返回创建好的DC 句柄
4.2.4 将位图放入匹配的DC 中
SelectObject
4.2.5 绘制位图
BOOL BitBlt(
HDC hdcDest, //目的DC
int nXDest, // 目的左上X 坐标
int nYDest, // 目的左上Y 坐标
int nWidth, // 目的宽度
int nHeight, // 目的高度
HDC hdcSrc, //源DC
int nXSrc, // 源左上X 坐标
int nYSrc, // 源左上Y 坐标
DWORD dwRop //绘制方法
);
缩放绘制
BOOL StretchBlt(
HDC hdcDest, // handle to destination DC
int nXOriginDest, // x-coord of destination upper-left corner
int nYOriginDest, // y-coord of destination upper-left corner
int nWidthDest, // width of destination rectangle
int nHeightDest, // height of destination rectangle
HDC hdcSrc, // handle to source DC
int nXOriginSrc, // x-coord of source upper-left corner
int nYOriginSrc, // y-coord of source upper-left corner
int nWidthSrc, // 源DC 宽
int nHeightSrc, // 源DC 高
DWORD dwRop // raster operation code
);
4.2.6 取出位图
SelectObject
4.2.7 释放位图
DeleteObject
4.2.8 释放匹配的DC
DeleteDC
4.3 其他
使用GetObject 获取位图信息。
三坐标系
1 坐标系分类
1.1 设备坐标系
以像素为单位,以设备左上角为原点,X 右为正,
Y 下为正的坐标系。
1.1.1 屏幕坐标系- 以当前屏幕左上角为原点坐标系。
1.1.2 窗口坐标系- 以窗口左上角为原点坐标系。
1.1.3 客户区坐标系- 以窗口的客户区左上角
为原点的坐标系。
1.2 逻辑坐标系
在GDI 绘图中,都是使用逻辑坐标绘图。
逻辑坐标系可以设置坐标系单位。
2 坐标系映射
2.1 映射模式
逻辑坐标系和设备坐标系单位之间映射关系。
设备坐标系的单位是由设备决定,大小固定。
逻辑坐标系的单位,可以通过程序设置,
int SetMapMode(
HDC hdc, //DC 句柄
int fnMapMode //映射模式
); 返回旧的映射模式
fnMapMode 映射模式:
MM_TEXT - 默认模式,1 个逻辑单位对应1 设备单位。
X 右为正,Y 下为正
MM_LOENGLISH - 1 个逻辑单位= 0.01 英寸
X 右为正,Y 上为正
MM_HIENGLISH - 1 个逻辑单位= 0.001 英寸
X 右为正,Y 上为正
MM_LOMETRIC - 1 个逻辑单位= 0.1 毫米
X 右为正,Y 上为正
MM_HIMETRIC - 1 个逻辑单位= 0.01 毫米
X 右为正,Y 上为正
MM_TWIPS - 1 个逻辑单位= 1/1440 英寸,打印机
使用单位。
MM_ISOTROPIC - 1 个逻辑单位= 自定义
X 和Y 正方向也可以自定义
MM_ANISOTROPIC -
X 的1 个逻辑单位= 自定义1
Y 的1 个逻辑单位= 自定义2
X 和Y 正方向也可以自定义
2.2 MM_ISOTROPIC / MM_ANISOTROPIC
通过函数设置逻辑单位与设备单位的对应关系
设备单位
BOOL SetViewportExtEx(
HDC hdc, //DC 句柄
int nXExtent, //设备单位的X 比例
int nYExtent, //设备单位的Y 比例
LPSIZE lpSize //旧比例
);
逻辑单位
BOOL SetWindowExtEx(
HDC hdc, //DC 句柄
int nXExtent, //逻辑单位的X 比例
int nYExtent, //逻辑单位的Y 比例
LPSIZE lpSize //旧比例
);
X 逻辑单位nWindowXExtent
―――――――――― =
――――――――――――――――――
X 设备单位nViewPortXExtent
Y 逻辑单位nWindowYExtent
―――――――――― =
――――――――――――――――――
Y 设备单位nViewPortYExtent
可以通过+/-,变换X 和Y 轴正方向
一文字和字体
1 文字的绘制
TextOut - 将文字绘制在指定坐标位置。
int DrawText(
HDC hDC, //DC 句柄
LPCTSTR lpString, //字符串
int nCount, //字符数量
LPRECT lpRect, //绘制文字的矩形框
UINT uFormat //绘制的方式
);BOOL ExtTextOut(
HDC hdc, //DC 句柄
int X, //输出X 位置
int Y, //输出Y 位置
UINT fuOptions, //输出选项
CONST RECT* lprc, //输出的矩形框
LPCTSTR lpString, //字符串
UINT cbCount, //字符数量
CONST INT* lpDx //字符间距的数组
);
2 文字颜色和背景
文字颜色
SetTextColor
文字背景色
SetBkColor
文件背景模式
SetBkMode
3 字体
3.1 字体相关
Window 常用的字体格式为TureType 字体
字体名- 标识字体类型
HFONT - 字体句柄
3.2 字体的使用
3.2.1 创建字体
HFONT CreateFont(
int nHeight, //字体高度
int nWidth, //字体宽度
int nEscapement, //字符串倾斜角度
int nOrientation,//字符旋转角度
int fnWeight, //字体的粗细
DWORD fdwItalic, //斜体
DWORD fdwUnderline, //字符下划线
DWORD fdwStrikeOut, //删除线
DWORD fdwCharSet, //字符集
DWORD fdwOutputPrecision,//输出精度
DWORD fdwClipPrecision,//剪切精度
DWORD fdwQuality,//输出质量
DWORD fdwPitchAndFamily,//匹配字体
LPCTSTR lpszFace //字体名称
);
3.2.2 应用字体到DC
3.2.3 绘制文字
3.2.4 取出字体
3.2.5 删除字体
二对话框
1 对话框窗口
对话框的分类
模式对话框- 当对话框显示时,会禁止其他窗口的
输入等用户交互操作。
无模式对话框- 在对话框显示后,其他窗口同样可
以接收输入等用户交互操作。
2 对话框基本使用
2.1 对话框窗口处理函数
2.2 注册窗口类(可选,基本不使用)
2.3 创建对话框
2.4 对话框的关闭
3 模式对话框的使用
3.1 对话框窗口处理函数
INT_PTR CALLBACK DialogProc(
HWND hwndDlg, //窗口句柄
UINT uMsg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam //消息参数
);
返回TRUE - 表示DialogProc 函数中处理了这个
消息,缺省处理函数不需要处理。
返回FALSE- 表示DialogProc 函数未处理这个消息,
交给缺省处理函数处理。
不需要调用缺省对话框窗口处理函数。
3.2 创建对话框
INT_PTR DialogBox(
HINSTANCE hInstance,//应用程序实例句柄
LPCTSTR lpTemplate, //对话框模板资源ID
HWND hWndParent, //对话框父窗口
DLGPROC lpDialogFunc //对话框窗口处理函数
);
需要添加对话框资源。
DialogBox 是一个阻塞函数,只有当对话框关闭后,
才会返回,继续执行后续代码。
返回值是通过EndDialog 设置。
3.3 对话框的关闭
BOOL EndDialog(
HWND hDlg,//关闭的对话框窗口句柄
INT_PTR nResult //关闭的返回值
);
关闭模式对话框,只能使用EndDialog,不能
使用DestroyWindow 等函数。
nResult 是DialogBox 函数退出时的返回值。
3.4 对话框的消息
WM_INITDIALOG - 对话框创建之后显示之前,
通知对话框窗口处理函数,可以完成自己
的初始化相关的操作。
Day09
4 无模式对话框
4.1 对话框窗口处理函数
DialogProc
4.2 创建对话框
HWND CreateDialog(
HINSTANCE hInstance, //应用程序实例句柄
LPCTSTR lpTemplate, //模板资源ID
HWND hWndParent, //父窗口
DLGPROC lpDialogFunc //窗口处理函数
);
非阻塞函数,创建成功返回窗口句柄,需要使用
ShowWindow 函数显示对话框。
4.3 对话框的关闭
关闭时使用DestroyWindow 销毁窗口,不能使用
EndDialog 关闭对话框。
4.4 对话框的消息
WM_INITDIALOG - 对话框创建之后显示之前,
通知对话框窗口处理函数,可以完成自己
的初始化相关的操作。
5 对话框/普通窗口
5.1 创建
模式对话框- DialogBox,阻塞函数
无模式对话框- CreateDialog
普通窗口- CreateWindow/Ex
5.2 窗口处理函数
对话框- DialogProc
普通窗口- WindowProc,需要调用缺省窗口
处理函数
5.3 窗口消息
普通窗口- WM_CREATE
对话框- WM_INITDIALOG
5.4 窗口关闭
模式对话框- EndDialog
无模式对话框/普通窗口- DestroyWindow
三子控件
1 子控件相关
1.1 子控件
系统已经定义窗口类型,相应窗口的处理函数等
都已经由系统完成。例如编辑框、按钮等等。
1.2 子控件的创建
不需要注册,直接使用CreateWindow/Ex
创建该类的窗口。子控件创建时,每个控件
都具有一个ID 号。
1.3 控件的消息
程序和子控件之间交互,都是通过消息完成。
控件的窗口消息- 程序可以使用SendMessage
向控件发送消息,获取控件的信息或设置控件。
控件的通知消息- 控件有相应的事件发生后,
会向所在的父窗口发送通知消息,父窗口
可以根据通知消息的ID,做相应的处理。
一静态框
1 静态框相关
常用于显示文字和图标等。窗口类名称“STATIC”。
文字静态框- 显示文字
图标静态框- 显示图标,设置SS_ICON/SS_BITMAP
2 静态框的使用
2.1 创建
2.1.1 CreateWindow
2.1.2 风格
图标静态框使用SS_ICON/SS_BITMAP 风格
如果创建图标静态框,那么窗口的名称要设置
成图标ID
例如:CreateWindowEx( 0, "STATIC", "#101"
...... );
2.2 窗口消息
SendMessage 发送到控件即可
例如:STM_SETICON
2.3 通知消息
需要在创建时增加SS_NOTIFY 风格。
通知消息通过WM_COMMAND 消息传递
附:WM_COMMAND
WPARAM:
LOWORD - 菜单项、加速键、控件的ID
HIWORD - 对于菜单项,为0
对于加速键,为1
对于控件,是Notify-Code
LPARAM:
对于菜单项、加速键为NULL
对于控件,为控件窗口句柄
二按钮
1 按钮相关
根据按钮的风格,将按钮分成4 类
1.1 下压式按钮
BS_PUSHBUTTON/BS_DEFPUSHBUTTON
1.2 分组框
BS_GROUPBOX
1.3 复选框
BS_CHECKBOX/BS_AUTOCHECKBOX
BS_3STATE/BS_AUTO3STATE
1.4 单选框
BS_RADIOBUTTON/BS_AUTORADIOBUTTON
窗口类名称BUTTON
2 下压式按钮
2.1 创建按钮
2.2 窗口消息
2.3 通知消息
3 分组框
常用于界面上的控件分组显示,提高界面友好性。
4 复选框
4.1 风格和创建
BS_CHECKBOX - 点击选择时,需要自己维护选择
状态
BS_AUTOCHECKBOX - 点击选择时,系统自动维护
选择状态
4.2 窗口消息
获取和设置选择状态
BM_SETCHECK
BM_GETCHECK
4.3 通知消息
BN_CLICKED 按钮被点击
5 单选按钮
5.1 风格和创建
BS_RADIOBUTTON - 自己维护状态
BS_AUTORADIOBUTTON - 系统自动维护状态
5.2 窗口消息
获取和设置选择状态
BM_SETCHECK
BM_GETCHECK
每组单选框中只能同时有1 个被选择。
5.3 通知消息
BN_CLICKED
5.4 其他
单选框分组,可以使用WS_GROUP 风格分组。
从当前具有WS_GROUP 风格的单选框,到下一个
WS_GROUP 风格单选框之前,为1 组单选框
例如: AB 为1 组CD 为1 组
CreateWindowEx( 0, "BUTTON", "A.",
WS_GROUP, .. )
CreateWindowEx( 0, "BUTTON", "B.",
... )
CreateWindowEx( 0, "BUTTON", "C.",
WS_GROUP, .. )
CreateWindowEx( 0, "BUTTON", "D.",
... )
三编辑框
1 编辑框相关
从风格可以将编辑框分成几类:
单行编辑框- 只能处理一行文字
多行编辑框- 可以显示多行文字
密码编辑框- 密码输入ES_PASSWORD
...
2 编辑框的使用
2.1 创建
窗口类名称EDIT
2.2 窗口消息
2.3 通知消息
EN_CHANGE 当编辑框内的文字被修改,通知
父窗口。
Day10
一组合框
1 组合框相关
组合框的分类
1.1 简单组合框- CBS_SIMPLE
1.2 下拉式组合框- 可以输入,CBS_DROPDOWN
1.3 下拉列表式组合框- 只能从选项中选择
CBS_DROPDOWNLIST
组合框窗口类- COMBOBOX
2 组合框的使用
2.1 创建组合框
2.2 选项的添加
CB_ADDSTRING - WPARAM 不使用
LPARAM 字符串指针
CB_INSERTSTRING
2.3 选项的删除
CB_DELETESTRING - 删除指定项
CB_RESETCONTENT - 清除所有项
2.4 获取和设置选择项
CB_GETCURSEL - 获取选择项
CB_SETCURSEL - 设置当前被选择项
2.5 查找选择项
CB_FINDSTRING - 根据字符串,查找选择项,
从选项的起始字符查找包含字符串
CB_FINDSTRINGEXACT - 匹配查找的字符串
CB_SELECTSTRING - 查找并设置成当前被选择项
2.6 获取选项的字符
CB_GETLBTEXTLEN - 获取选项的字符长度
CB_GETLBTEXT - 获取选项的字符内容
输入的字符串
WM_GETTEXT
2.7 目录的显示
CB_DIR - 在组合框中显示指定路径下的文件
和子目录
2.8 选项的附加数据
在每个选项中,可以保存自定义的数据
CB_SETITEMDATA - 将数据保存到指定选项
CB_GETITEMDATA - 从指定选项获取数据
3 通知消息
CBN_SELCHANGE - 当前被选择项发生变化后,
通知父窗口。
CBN_EDITCHANGE - 当输入发生变化后
Day11
三Windows 库程序
1 Windows 库程序
静态库程序- 运行时不独立存在,会被链接
到可执行文件或者动态库中,目标程序的归档。
文件扩展名:LIB
动态库程序- 运行时独立存在,不会被链接到
可执行文件或其他动态库中。
文件扩展名:DLL
2 静态库程序
2.1 静态库特点
1)运行时不独立存在
2)链接到可执行文件或者动态库中
3)目标程序的归档
2.2 C 语言静态库
2.2.1 静态库的使用
建立一个C 文件,可以在文件中直接
使用C 库函数,不需要头文件。
C 编译器只是根据库函数名称,在库中
找到对应的函数代码,进行链接。
2.2.2 静态库的创建
1)建项目
2)添加库程序,源文件使用C 文件
2.2.3 库的路径设置
1)项目的“Setting”中设置库的路径
2)可以使用pragma 关键字设置
#pragma comment( lib, "..\\lib\\clib.lib")
2.3 C++语言的静态库
2.3.1 静态库的建立
1)建立项目
2)添加库程序,源文件使用CPP 文件
2.3.2 库的导入
1)项目的“Setting”中设置库的路径
2)可以使用pragma 关键字设置
2.3.3 注意
在CPP 环境使用C 静态库,库中函数原型定义
要增加extern “C”, 例如:
extern "C" int Add(... );
一Windows 库程序
3 动态库程序
3.1 动态库特点
1)运行时独立存在
2)不会链接到执行程序
3)使用时加载
与静态库的比较:
1)由于静态库是将代码嵌入到使用程序中,
多个程序使用时,会有多份代码,所以
代码体积会增大。
动态库的代码只需要存在一份,其他程序
通过函数地址使用,所以代码体积小。
2)静态库发生变化后,新的代码需要重新
链接嵌入到执行程序中。
动态库发生变化后,如果库中函数的定义(或
地址)未变化,其他使用DLL 的程序不需重新
链接。
3.2 动态库的创建
3.2.1 建立项目
3.2.2 添加库程序
3.2.3 库程序导出
提供给使用者库中的函数等信息。
3.3 动态库的使用
3.3.1 隐式链接
3.3.2 显式链接
3.4 动态库的函数
3.4.1 实现动态库的函数
3.4.2 库函数的导出
1) C++的导出
使用_declspec(dllexport) 导出函数
注意:动态库编译链接后,也会有LIB 文件,
是作为动态库函数映射使用,与静态库
不完全相同。
2)C 的导出方式
extern “C” _declspec(dllexport) int Sub(...);
3)模块定义文件.def
例如:
LIBRARY DLLFunc //库
EXPORTS //库导出表
DLL_Mul @1//导出的函数
3.4.3 库函数的使用
3.4.3.1 隐式链接
1)头文件和函数原型
可以在函数原型的定义前,增加
_declspec(dllimport), 例如
_declspec(dllimport) int DLL_Add( ... );
如果库函数使用C 格式导出,需要在
函数定义增加extern “C”
2)导入动态库的LIB 文件
3)在程序中使用函数
4)隐式链接的情况,DLL 可以存放的路径:
(1)与执行文件中同一个目录下
(2)当前工作目录
(3)Windows 目录
(4)Windows/System32 目录
(5)Windows/System
(6)环境变量PATH 指定目录
注意:高版本VC 的配置文件
3.4.3.2 显式链接
1)定义函数指针类型
2)加载动态库
HMODULE LoadLibrary(
LPCTSTR lpFileName //动态库文件名或全路径
); 返回DLL 的实例句柄(HINSTANCE)
3)获取函数地址
FARPROC GetProcAddress(
HMODULE hModule, //DLL 句柄
LPCSTR lpProcName //函数名称
); 成功返回函数地址
4)使用函数
5)卸载动态库
BOOL FreeLibrary(
HMODULE hModule //DLL 的实例句柄
);
3.4.3.3 两种链接方式对比
1)在库函数的定义不变情况下:
隐式链接,由于库函数地址是在程序
编译链接时设置,所以当动态库变化后,
使用程序需要重新编译链接。
显式链接,由于库函数地址是在程序
执行时,动态的从库中查询,所以库变化
后,不需要重新编译链接。
2)动态库加载
隐式链接,动态库是在程序启动时就被
加载,当DLL 不存在,程序无法启动
显式链接,动态库只在使用LoadLibrary
函数,才会被加载。
4 DLL 中类的使用
1.1 DLL 中类的实现
1.2 DLL 中类的导出
在类名称前增加_declspec(dllexport) 定义,
例如:
class _declspec(dllexport) CMath
{
...
};
通常使用预编译开关切换类的导入导出定义,
例如:
#ifdef DLLCLASS_EXPORTS
#define EXT_CLASS _declspec(dllexport)//DLL
#else
#define EXT_CLASS _declspec(dllimport)//使用者
#endif
class EXT_CLASS CMath
{
...
};
2 使用DLL 中的类
2.1 导入DLL 的LIb
2.2 类的定义
2.3 使用类
3 动态库的程序入口
入口程序不是DLL 必须的。常用于DLL 内部
初始化或善后处理。
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, //动态库实例句柄
DWORD fdwReason, //被调用的原因
LPVOID lpvReserved //保留值
); 返回TRUE,表示动态库加载成功。
动态库的加载或卸载时会被调用。例如:使用
LoadLibrary 或FreeLibrary 时会被调用。
Day12
二Windows 文件
1 Windows 目录
1.1 Windows 相关的目录
程序当前工作目录
DWORD GetCurrentDirectory(
DWORD nBufferLength, // size of directory buffer
LPTSTR lpBuffer // directory buffer
);BOOL SetCurrentDirectory(
LPCTSTR lpPathName // new directory name
);
Windows 目录
UINT GetWindowsDirectory(
LPTSTR lpBuffer, // buffer for Windows directory
UINT uSize // size of directory buffer
);
Windows 的System 目录
UINT GetSystemDirectory(
LPTSTR lpBuffer, // buffer for system directory
UINT uSize // size of directory buffer
);
临时文件目录
DWORD GetTempPath(
DWORD nBufferLength, // size of buffer
LPTSTR lpBuffer // path buffer
);
2 Windows 文件
2.1 创建或打开Windows 文件
HANDLE CreateFile(
LPCTSTR lpFileName, //文件名称
DWORD dwDesiredAccess, //访问权限
DWORD dwShareMode, //共享方式
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
//安全属性,默认为NULL
DWORD dwCreationDisposition,
//创建方式
DWORD dwFlagsAndAttributes,
//文件属性
HANDLE hTemplateFile //文件句柄模板,默认为NULL
);
成功返回文件句柄。
2.2 写数据
BOOL WriteFile(
HANDLE hFile, //文件句柄
LPCVOID lpBuffer, //数据BUFF
DWORD nNumberOfBytesToWrite, //数据长度
LPDWORD lpNumberOfBytesWritten, //返回实际写入的数据
LPOVERLAPPED lpOverlapped //默认为NULL
);
2.3 读数据
BOOL ReadFile(
HANDLE hFile, //文件句柄
LPVOID lpBuffer, //数据BUFF
DWORD nNumberOfBytesToRead,
//要读的字节数
LPDWORD lpNumberOfBytesRead,
//实际读到字节数
LPOVERLAPPED lpOverlapped //默认为NULL
);
2.4 关闭文件
BOOL CloseHandle(
HANDLE hObject //文件句柄
);
2.5 文件长度
DWORD GetFileSize(
HANDLE hFile, //文件句柄
LPDWORD lpFileSizeHigh
//文件长度的高32 位
); 返回值是文件长度的低32 位
2.6 文件指针
DWORD SetFilePointer(
HANDLE hFile, //文件句柄
LONG lDistanceToMove, //偏移量的低32 位
PLONG lpDistanceToMoveHigh,
//偏移量的高32 位
DWORD dwMoveMethod
//偏移的相对位置
);
返回实际偏移量的低32 位,lpDistanceToMoveHigh
返回实际偏移量的高32 位
2.7 文件相关操作
CopyFile - 拷贝文件
DeleteFile - 删除文件
MoveFile - 移动文件
一文件查找
1 查找文件
HANDLE FindFirstFile(
LPCTSTR lpFileName, //查找路径
LPWIN32_FIND_DATA lpFindFileData
//查找的数据
);
返回查找句柄
2 获取下一个文件
BOOL FindNextFile(
HANDLE hFindFile, //查找句柄
LPWIN32_FIND_DATA lpFindFileData
//查找的数据
); 找到返回TRUE
3 关闭查找
BOOL FindClose(
HANDLE hFindFile //查找句柄
);
二Windows 内存管理
1 Windows 内存地址空间
1.1 地址空间
程序中可以寻址的最大范围。对于32 位操作系统,
地址空间范围为0-4G(2^32),地址空间越大,
相对程序的编写就会容易。
1.2 地址空间的划分
1.2.1 用户地址空间0 - 2G(7FFFFFFF )
存放用户的程序和数据。用户空间的代码是
不能访问内核空间的数据和代码。
1.2.1.1 空指针区(NULL 区,0-64K)
系统将地址小于64K 指针,都认为是空指针。
1.2.1.2 用户区
1.2.1.3 64K 禁入区(0x7FFEFFFF - 0x7FFFFFFF )
1.2.2 内核地址空间2G - 4G
存放内核的代码和数据,例如系统驱动。
内核空间代码是可以访问用户空间。
2 Windows 内存
2.1 区域
区域就是连续的一块内存。区域的大小一般为64K
或者64K 倍数。每个区域都有自己的状态:
1)空闲:没有被使用
2)私有:被预定的区域
3)映像:存放代码
4)映射:存放数据
2.2 物理内存
系统可以使用的实际内存。CPU 可以直接访问的内存。
2.3 虚拟内存
将硬盘文件虚拟成内存使用。(pagefile.sys 文件)
CPU 如果要访问虚拟内存数据,必须将虚拟内存数据
放到物理内存。
2.4 内存页
系统管理内存的最小单位。内存页大小为4K,每个
内存页有自己的权限。
2.5 页目表
指针地址
31 22 21 12 11 0
|-----------|------------|--------------|
10 位10 位12 位
2^10=1024 1024 4K
页目页表
2.6 从内存获取数据过程
2.6.1 根据地址在物理内存中查找相应的位置。
如果找到物理内存,取回数据。如果未找到,
执行2.6.2.
2.6.2 根据地址去虚拟内存中查找相应的位置。
如果未找到,那么该地址没有内存空间,
返回错误。如果找到,执行2.6.3.
2.6.3 将该地址所在内存页,置换到物理内存
中,同时将原物理内存数据,存入到虚拟内存
中。
2.6.4 将物理内存中的数据返回给使用者。
2.7 内存分配
2.7.1 虚拟内存分配
适合大内存分配,一般是1M 之上的内存。
2.7.2 堆内存分配
适合小内存分配,一般是1M 以下的内存。
malloc/new
2.7.3 栈内存分配
适合小内存分配,一般是1M 以下的内存。
3 虚拟内存分配
3.1 虚拟内存分配
速度快,大内存效率高。将内存和地址分配
分别执行,可以在需要的时候再提交内存。
常用字大型电子表格等处理。
3.2 虚拟内存使用
3.2.1 内存分配
LPVOID VirtualAlloc(
LPVOID lpAddress,// NULL 或提交地址
SIZE_T dwSize, //分配的大小
DWORD flAllocationType, //分配方式
DWORD flProtect //内存访问方式
);
分配成功返回地址
分配方式
MEM_COMMIT - 提交内存,分配之后返回
地址和内存空间
MEM_RESERVE- 保留地址,分配之后只
返回地址,内存空间不生成。要使用
内存必须再次提交。
3.2.2 使用
3.2.3 释放
BOOL VirtualFree(
LPVOID lpAddress,//释放地址
SIZE_T dwSize, //释放的大小
DWORD dwFreeType //释放方式
);
释放方式
MEM_DECOMMIT - 只释放内存
MEM_RELEASE - 地址和内存都释放
day13
4 堆内存Heap
4.1 堆内存分配
适合分配小内存,一般是小于1M 的内存。
一般每个程序都有自己的堆,默认大小为1M,
会根据使用情况进行调整。
4.2 堆的使用
4.2.1 堆的信息
GetProcessHeap - 获得程序的堆
GetProcessHeaps - 获取程序中所有的堆
4.2.2 创建堆
HANDLE HeapCreate(
DWORD flOptions,//创建选项
SIZE_T dwInitialSize, //初始化大小
SIZE_T dwMaximumSize //最大值
); 成功返回堆句柄
4.2.3 从堆中分配内存
LPVOID HeapAlloc(
HANDLE hHeap, //堆句柄
DWORD dwFlags, //分配方式
SIZE_T dwBytes //分配大小
); 成功返回地址
4.2.4 使用内存
4.2.5 释放内存
BOOL HeapFree(
HANDLE hHeap, // 堆句柄
DWORD dwFlags, // 释放方式
LPVOID lpMem // 释放地址
);
4.2.6 销毁堆
BOOL HeapDestroy(
HANDLE hHeap //堆句柄
);
当堆被销毁后,使用该堆分配内存全都被销毁。
4.3 VirtualAlloc/HeapAlloc/malloc/new
在Windows 平台上,函数调用关系:
new/malloc -> HeapAlloc -> VirtualAlloc
5 栈内存(简介)
5.1 栈内存
每个线程都具有自己的栈,默认大小1M。
5.2 一般是系统维护栈.
Windows 提供了_alloca, 可以在栈上分配内存。
一Windows 内存
6 内存映射文件
6.1 内存映射文件
将文件映射成内存来使用。当使用内存时,就是
在使用文件。
6.2 内存映射文件的使用
6.2.1 创建或打开文件
CreateFile
6.2.2 创建内存映射文件
HANDLE CreateFileMapping(
HANDLE hFile, //文件句柄
LPSECURITY_ATTRIBUTES lpAttributes,
//安全属性
DWORD flProtect,
//访问方式
DWORD dwMaximumSizeHigh,
//内存映射文件大小的高32
DWORD dwMaximumSizeLow,
//内存映射文件大小的低32
LPCTSTR lpName //命名,可以为NULL
);
创建成功返回句柄
6.2.3 加载内存映射文件
LPVOID MapViewOfFile(
HANDLE hFileMappingObject,
//内存映射文件句柄
DWORD dwDesiredAccess,
//访问模式
DWORD dwFileOffsetHigh,
//偏移量的高32 位
DWORD dwFileOffsetLow,
//偏移量的低32 位
SIZE_T dwNumberOfBytesToMap
//映射的字节数量
); 成功返回地址
dwFileOffsetHigh 和dwFileOffsetLow 合成
的偏移量,必须是区域粒度的整数倍
(64K 的整数倍)
6.2.4 使用内存
6.2.5 卸载内存映射文件
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress //卸载地址
);
6.2.6 关闭内存映射文件
CloseHandle
6.2.7 关闭文件
CloseHandle
二Windows 进程
1 Windows 进程
进程是一个容器,包含程序执行需要的代码、数据、
资源等等信息。Windows 是多任务操作系统,可以
同时执行多个进程。
Windows 进程的特点:
1)每个进程都有自己的ID 号
2)每个进程都有自己的地址空间,进程之间
无法访问对方的地址空间。
3)每个进程都有自己的安全属性
4)每个进程当中至少包含一个线程
2 进程环境信息(简介即可,不需要写代码)
2.1 获取环境信息
获取
LPVOID GetEnvironmentStrings(VOID);
释放
BOOL FreeEnvironmentStrings(
LPTSTR lpszEnvironmentBlock // environment strings
);
2.2 获取和设置环境变量
GetEnvironmentVariable
SetEnvironmentVariable
3 进程的信息
3.1 进程ID
GetCurrentProcessId
3.2 进程句柄
GetCurrentProcess
返回进程的伪句柄(-1),可以使用该句柄
访问该进程的所有操作。
4 进程的使用
4.1 创建进程
WinExec - 早期16 位
ShellExecute - Shell 操作
CreateProcess - 目前最多使用
BOOL CreateProcess(
LPCTSTR lpApplicationName,
//应用程序名称
LPTSTR lpCommandLine,
//命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes,
//进程安全属性SD
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//线程安全属性SD
BOOL bInheritHandles,
//进程的句柄继承
DWORD dwCreationFlags,
//创建方式
LPVOID lpEnvironment, //环境信息
LPCTSTR lpCurrentDirectory,//当前目录
LPSTARTUPINFO lpStartupInfo, //起始信息
LPPROCESS_INFORMATION lpProcessInformation
//返回进程和线程的句柄ID
);
4.2 结束进程
VOID ExitProcess(
UINT uExitCode // exit code for all threads
);
BOOL TerminateProcess(
HANDLE hProcess, // handle to the process
UINT uExitCode // exit code for the process
);
4.3 打开进程
HANDLE OpenProcess(
DWORD dwDesiredAccess, //访问权限
BOOL bInheritHandle, //继承标识
DWORD dwProcessId //进程ID
); 返回进程句柄
4.4 关闭进程句柄
CloseHandle
4.5 进程间的等候
等候可等候的句柄的信号
DWORD WaitForSingleObject(
HANDLE hHandle, //句柄
DWORD dwMilliseconds //等候时间
);
阻塞函数,等候句柄的信号,只在句柄有信号
或超出等候时间,才会结束等候。
三Windows 线程
1 Windows 线程
Windows 线程是可以执行的代码的实例。系统是以
线程为单位调度程序。一个程序当中可以有多个
线程,实现多任务的处理。
Windows 线程的特点:
1)线程都具有1 个ID
2)线程具有自己的安全属性
3)每个线程都具有自己的内存栈
4)每个线程都具有自己的寄存器信息
进程多任务和线程多任务:
进程多任务是每个进程都使用私有地址空间,
线程多任务是进程内的多个线程使用同一个
地址空间。
线程的调度:
将CPU 的执行时间划分成时间片,依次
根据时间片执行不同的线程。
线程轮询:
线程A -> 线程B -> 线程A......
2 线程的使用
2.1 定义线程处理函数
DWORD WINAPI ThreadProc(
LPVOID lpParameter
//创建线程时,传递给线程的参数
);
2.2 创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//安全属性
SIZE_T dwStackSize,
//线程栈的大小
LPTHREAD_START_ROUTINE lpStartAddress,
//线程处理函数的函数地址
LPVOID lpParameter,
//传递给线程处理函数的参数
DWORD dwCreationFlags,
//线程的创建方式,
LPDWORD lpThreadId
//创建成功,返回线程的ID
); 创建成功,返回线程句柄
dwCreationFlags:
0 - 创建之后线程立刻执行
CREATE_SUSPENDED - 创建之后线程处于挂起状态。
2.3 结束线程
结束指定线程
BOOL TerminateThread(
HANDLE hThread, // handle to thread
DWORD dwExitCode // exit code
);
结束函数所在的线程
VOID ExitThread(
DWORD dwExitCode // exit code for this thread
);
2.4 关闭线程句柄
CloseHandle
2.5 线程的挂起和执行
挂起
DWORD SuspendThread(
HANDLE hThread // handle to thread
);
执行
DWORD ResumeThread(
HANDLE hThread // handle to thread
);
2.6 线程的信息
GetCurrentThreadId - 获取当前线程的ID
GetCurrentThread - 获取当前线程的句柄
打开指定ID 的线程,获取其句柄
HANDLE OpenThread(
DWORD dwDesiredAccess, // access right
BOOL bInheritHandle, // handle inheritance option
DWORD dwThreadId // thread identifier
);
day14
二线程的同步
1 多线程的问题
线程A -> 线程B -> 线程A 。。。。。
当线程A 执行printf 输出时,如果线程A 的执行时间
结束,系统会将线程A 的相关信息(栈、寄存器)
压栈保护,同时将线程B 相关信息恢复,然后执行
线程B,线程B 继续输出字符。
由于线程A 正输出字符,线程B 会继续输出,
画面字符会产生混乱。
2 线程同步技术
2.1 原子锁
2.2 临界区(段)
2.3 事件
2.4 互斥
2.5 信号量
3 等候函数
WaitForSingleObject - 等候单个
WaitForMultipleObjects - 等候多个
DWORD WaitForMultipleObjects(
DWORD nCount, //句柄数量
CONST HANDLE *lpHandles,
//句柄BUFF 的地址
BOOL bWaitAll,//等候方式
DWORD dwMilliseconds
// 等候时间
);
bWaitAll - 等候方式
TRUE - 表示所有句柄都有信号,才结束等候
FASLE- 表示句柄中只要有1 个有信号,就结束等候。
三原子锁
1 相关问题
多个线程对同一个数据进行原子操作,会产生结果
丢失。
当线程A 执行g_nValue1++时,如果线程切换时间
正好是在线程A 将值保存到g_nValue1 之前,线程
B 继续执行g_nValue1++,那么当线程A 再次被切换
回来之后,会将原来线程A 保存的值保存到
g_nValue1 上,线程B 进行的加法操作被覆盖。
g_nValue1++;
ecx = &g_nValue1;
ecx = ecx+1
---------------------
*g_nValue1 = ecx
mov ecx,dword ptr [g_nValue1 (00423ba8)]
add ecx,1
mov dword ptr [g_nValue1 (00423ba8)],ecx
2 原子锁的使用
2.1 原子锁
对单条指令的操作。
2.2 API
InterlockedIncrement
InterlockedDecrement
InterlockedCompareExchange
InterlockedExchange
...
原子锁的实现:
直接对数据所在的内存操作,并且在任何一个
瞬间只能有一个线程访问。
加法举例
InterlockedIncrement( &g_nValue2 );
ecx = &g_nValue2;
---------------------
lock (*ecx) + 1
mov ecx,dword ptr [esp+4]
mov eax,1
lock xadd dword ptr [ecx],eax
四临界区
1 问题
printf 输出混乱,多线程情况下同时使用一段代码。
2 临界区
锁定一段代码,防止多个线程同时使用该段代码
3 使用
3.1 初始化一个临界区
VOID InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
//临界区变量
);
3.2 进入临界区
添加到被锁定的代码之前
VOID EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection // critical section
);
3.3 离开临界区
添加到被锁定的代码之后
VOID LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection // critical section
);
3.4 删除临近区
VOID DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
//临界区变量
);
4 原子锁和临界区
原子锁- 单条指令。
临界区- 单条或多行代码。
五事件
1 相关问题
程序之间的通知的问题。
2 事件的使用
2.1 创建事件
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
//安全属性
BOOL bManualReset,
//事件重置方式,TRUE 手动,FALSE 自动
BOOL bInitialState,
//事件初始状态,TRUE 有信号
LPCTSTR lpName
//事件命名
); 创建成功返回事件句柄
2.2 等候事件
WaitForSingleObject/
WaitForMultipleObjects
2.3 触发事件
将事件设置成有信号状态
BOOL SetEvent(
HANDLE hEvent // handle to event
);
将事件设置成无信号状态
BOOL ResetEvent(
HANDLE hEvent // handle to event
);
2.4 关闭事件
CloseHandle
事件的死锁。
六互斥Mutex
1 相关的问题
多线程下代码或资源的共享使用。
2 互斥的使用
2.1 创建互斥
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
//安全属性
BOOL bInitialOwner,
//初始的拥有者
LPCTSTR lpName
//命名
); 创建成功返回互斥句柄
bInitialOwner - 初始的拥有者
TRUE - 调用CreateMutex 的线程拥有互斥
FALSE - 创建的时没有线程拥有互斥
2.2 等候互斥
WaitFor....
互斥的等候遵循谁先等候谁先获取。
2.3 释放互斥
BOOL ReleaseMutex(
HANDLE hMutex // handle to mutex
);
2.4 关闭互斥句柄
CloseHandle
2.5 互斥和临界区的区别
临界区- 用户态,执行效率高,只能在同一个
进程中使用。
互斥- 内核态,执行效率低,可以通过命名的
方式跨进程使用。
七信号量
1 相关的问题
类似于事件,解决通知的相关问题。但是可以提供
一个计数器,可以设置次数。
2 信号量的使用
2.1 创建信号量
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
//安全属性
LONG lInitialCount,
//初始化信号量数量
LONG lMaximumCount,
//信号量的最大值
LPCTSTR lpName
//命名
); 创建成功返回信号量句柄
2.2 等候信号量
WaitFor...
每等候通过一次,信号量的信号减1,直到为0 阻塞
2.3 释放信号量
BOOL ReleaseSemaphore(
HANDLE hSemaphore, //信号量句柄
LONG lReleaseCount, //释放数量
LPLONG lpPreviousCount
//释放前原来信号量的数量,可以为NULL
);
2.4 关闭句柄
CloseHandle
本文出自 “日知其所无” 博客,谢绝转载!