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函数设置菜单
未完待续