重要头文件:windows.h;
word 是字,占2个字节;
不会的函数可以去微软查出来,vs里选中F1;
链接器 子系统 选择 窗口;
windows是操作消息的,它有一个消息队列,可获取如鼠标键盘产生的消息;
数据类型
UINT unsigned int
DWORD double word
PDWORD pointer double word
BOOL bool
short short int
LRSULT 32 函数返回值
WPARAM LPARAM 32 消息参数
HANDLE 理解成windows对象,句柄
HWND 窗口句柄
HINSTANCE 实例句柄
主函数
1 | int WINAPI WinMain( |
参数一个不能少;
弹窗
1 | int MessageBox( |
选择不同的按键返回不同的值;
字符串处理
- ascii码对应普通字符串 CHAR -> char
- utf系列对应宽字符串 WCHAR -> wchar_t 输出是 %ls 用 L 修饰
- 通用字符串 TCHAR -> 类型随环境变化,引用 tchar.h 头 用_T()修饰;
由此引申出了三个版本的操作函数;
长度操作:
strlen wcslen _tcslen
字符串转数字:
atoi strtol
_wtoi wcstol
_ttoi tcstol
数字转字符串:
itoa _itow _itot
因为字符串,所以分三个版本:A W T;
如 MessageBoxA ,以及 MessageBoxW ,前者处理多字节,后者处理宽字节;
字节转换:
1 | //宽字节转多字节 (用的时候直接用宏定义) |
创建窗口
先创建WinMain函数
1 | { |
处理函数\回调:
1 | LRESULT CALLBACK WindowProc( |
简单说说回调函数机制:
每个窗口类会带有一个回调函数,用于处理这个类创建的窗口所获取的信息;
在无限循环的信息捕获中,当收到信息后(晃动鼠标,点击,按键),则使得 DispatchMessageW(&msg);
激活,调用指定窗口回调函数;
在这里指定窗口是 0 ,则是所有窗口;
回调函数中,为了当 点击叉掉 窗口时就 结束程序 就应该设置 退出信息 : WM_CLOSE
摧毁窗口,并退出 postmessage,此时就会退出在主函数里的循环;
回调函数的参数,第二个是信息,第三第四个是一些参数,这些参数有一定的作用,可以知道实际的状态:键盘按下但无弹起 / 鼠标处于窗口位置,等等;
消息处理
定义在 WINUSER.H 中, 以 WM_开头 (windows message);
类型
窗口消息,如之前遇到的
WM_CLOSE
;命令消息,特指
WM_COMMAND
,点击菜单,控件等会产生;WM_COMMAND LOW WPARAM HIGH WPARAM LPARAM 标准控件 id 响应码 控件句柄 快捷键 id 1 0 菜单 id 0 0 通知消息,特指
WM_NOTIFY
,只使用 用 windows 的公共控件,如列表,视图;WM_NOTIFY WPARAM LPARAM id NMHDR指针 NMHDR -> notify message header
控件消息,如:
BM_ 按钮
EM_ 编辑框
STM_ 静态文本
CM_ 组合框
LBM_ 列表
以及用户自定义消息,消息号大于 WM_USER
;
发送
PostMessage, SendMessage;
前者放到消息队列,后者主动调用 指定的回调函数;
变参函数
用于如printf输出宽字节;
1 | void func(LPCWSTR format, ...) |
窗口控件
使用控件引头文件: <CommCtrl.h>
窗口风格分两类:
窗口关系:
1 | WS_OVERLAPED 重叠 |
窗口外观:
1 | WS_BORDER |
它们之间可以用 | 运算结合使用;
控件的本质,还是窗口,在父窗口创建开始添加即可;
标准控件:
类名 | 名称 |
---|---|
WC_BUTTON | 按钮 |
WC_STATIC | 静态文本 |
WC_COMBOBOX | 复合框 |
WC_EDIT | 编辑框 |
WC_LISTBOX | 列表框 |
WC_SCROLLBAR | 滚动条 |
通用控件,如:
WC_LISTVIEW 列表框控件
WC_TREEVIEW 树控件
WC_TABCONTROL Tab控件
…
子控件响应父窗口,使用 命令消息 和 通知消息,标准控件使用前者,通用控件使用后者;
修改之后的回调函数:
1 | LRESULT CALLBACK WindowProc( |
如上可以实现一个按钮弹窗功能;
窗口操作函数
背景刷
1 | wnd.hbrBackground = CreateSolidBrush(RGB(255, 255, 255)); //白色背景 |
移动窗口位置
1 | RECT rect{ 0 }; |
获取和设置文本框内容
1 | HWND hedit = GetDlgItem(hwnd, 0x102); //获取文本框句柄,第一个是父窗口句柄,第二个是id |
根据窗口名获取句柄
1 | HWND hwnd = FindWindowW(ClassName, Name); //第一个窗口类名,第二个窗口名,不知道可以填0 |
设置父窗口
1 | SetParent((HWND)lParam, hwnd); //第一个是要被设置的,第二个是新的父窗口 |
资源操作
资源就是icon,光标,菜单一类的东西;
在VS里,代码下方可以创建资源,资源创建后,有资源本身,有.rc文件,以及resource.h头文件;
.rc保存了资源本身在文件中的宏命名,一般是int型,而头文件则是声明;
引入头后,使用 LoadXXX
函数获取资源句柄(XXX为资源类型,如图标是Icon);
1 | LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1)) |
参数类型第一个为实例句柄,第二个为资源宏,本质上是个指针,所以要强转,微软自带强转宏函数 MAKEINTRESOURCE()
;
使用如下代码设置类成员:
1 | //三个参数,第一个为窗口句柄,第二个为GCL_开头宏对应成员如GCL_ICON,第三个为设置的句柄,记得强转long |
菜单可以加载后给CreateWindow函数;
子菜单响应也是 WM_COMMAND;
使用以下函数获取子菜单以及弹出菜单:
1 | GetSubMenu(hMenu, 0); //第一个父菜单,第二个相对于父菜单位置 |
转换坐标当前窗口
1 | POINT point { 0 }; |
对话框
模态的会阻塞主窗口(无法点击主窗口),非模态不会;
创建非模态:
1 | CreateDialogW( |
创建模态:
它不需要捕获信息,也不需要显示
1 | DialogBoxW( /* same */) |
介绍一些简单的控件:
windowsx.h 头有定义操作控件信息的宏,可读性更高;
复选框,单选框,属于按钮类,其信息为 BM_打头;
图片,其信息 STM_打头;
滑块和进度条,其信息 TBM_ PBM_ 打头;
列表控件
任务管理器就是一个列表;
其重要的信息是 : LVM_INSERTCOLUMN
,插入索引;
其会用到一个结构:LVCOLUMN,其中标识了列表信息;
mask是掩码,说明了之后的成员有效性;
fmt是对齐方式,cx是大小,pszText为名字;
插入行: LVM_INSERTITEM
;
设置行: LVM_SETITEMTEXT
;
其结构和上面类似,叫 LVITEM;
item是第几行,subitem是第几列;
1 | BOOL InsertColum(HWND hwnd, int id, int nColum, int cx, LPWSTR name) |
添加样式:
1 | sendDlgItemMessageW(hwnd, id, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, style) |
常用style有:LVS_EX_FULLROWSELECT , 全行选中;
LVS_EX_GRIDLINES , 添加网格;
点击其成员触发notify信息,其有 NMHDR 结构:
1 | typedef struct _nmhdr { |
如果确认控件是list,则结构体为 NMLISTVIEW ,为 NMHDR 的继承;
捕获点击消息:
1 | case WM_NOTIFY: |
这种捕获类似于下拉表;
获取dll文件函数:
1 | HMODULE hModule = LoadLibraryW(L"./mydll.dll"); |
Lab
搓了个CPP的类粘合着窗口化编程使用做了个小程序,提取码 a333
;