API部分在Windows and Messages。
Windows (Windows and Messages)
窗口是屏幕上的一块矩形区域。窗口和窗口之间共享屏幕。
Window Overviews
About Windows
DeskopWindow是系统定义的窗口,用于绘制屏幕背景(wallapper),以及作为其他所有窗口的基准。
GetDesktopWindow
返回DesktopWindow的控把。
可以通过SystemParametersInfo来改变桌面窗口的墙纸。
每个图形化应用创建最少一个窗口,即主窗口。可以有其他多个辅助窗口。 每个应用在任务栏上会有一个按钮。
应用窗口上的元素包括标题栏、菜单栏、窗口菜单(系统菜单),最小/最大/还原按键等,边框,客户区,横向和纵向滚动栏。
应用可以在客户区自主绘制,客户区以外需要跟系统协商管理。对于客户区,应用需要提供一个窗口执行诀来处理丢给客户区的消息。
一个控件是一个特殊的窗口,用于从用户处获取特定的信息,参考https://docs.microsoft.com/en-us/windows/desktop/Controls/window-controls。控件一定是和其他窗口配合使用的。比如一个对话框窗口上可以包含若干控件。(对话框的非客户区域通常是简化的,参考https://docs.microsoft.com/en-us/windows/desktop/dlgbox/dialog-boxes)。
一个消息框是一种特殊对话框,用于展示一些信息给用户,参考https://docs.microsoft.com/en-us/windows/desktop/dlgbox/about-dialog-boxes。
窗口有若干属性需要应用来提供:
- 类名
- 主要是将窗口和窗口过程关联起来,这样系统知道输入事件应该发给谁
- 窗口名
- 一串文本,用于向用户标识一个窗口
- 对于已创建窗口
- SetWindowText设置
- GetWindowTextLength和GetWindowText获取
- 窗口样式
- 设置有限的几种样式
- 对于已创建窗口
- 使用SetWindowLong设置
- 扩展的窗口样式
- CreateWindowEx
- 定位
- 左上角的坐标用于定位窗口
- WindowFromPoint获取某像素点上的窗口
- ChildWindowFromPoint和ChildWindowFromPointEx 获取子窗口
- 大小
- 以像素为单位
- 系统默认值可以通过GetSystemMetrics获取
- 此函数也可以获取屏幕大小
- 创建时可以通过CreateWindowEx设置
- 对于已创建窗口
- AdjustWindowRect 和 AdjustWindowRectEx调整窗口大小
- 上级或所属窗口控把
- 子窗口,或者下级窗口,其坐标基于上级窗口
- 绘制区域无法超过上级窗口
- 没有上级窗口,或者上级窗口是桌面窗口的,叫做顶级窗口
- 可以通过EnumWindows枚举顶级窗口
- 可以通过EnumWindowsProc枚举顶级窗口的执行诀
- 菜单控把或子窗口标识
- 可以通过SetWindowLong和GetWindowLong进行设置和获取
- 应用例现控把
- 应用可以有多个例现,所以需要有办法区分不同例现的窗口
- 创建时囊括的数据
- 会传给窗口执行诀
- 窗口控把
- 用于把控所创建窗口
- 应用程序可以通过FindWindow/FindWindowEx来查找具有特定类名和窗口名的窗口
- IsWindow函数用于判断窗口控把是否有效
- 有特定作用的控把
- SendMessage/SendMessageTimeout所用的HWND_BROADCAST
- MapWindowPoints 所用的HWND_DESKTOP
CreateWindow或CreateWindowEx 可以创建窗口,Ex款可以指定扩展样式。
基于窗口的应用程序必须用WinMain作为入口点。文中讲述了WinMain中应该处理的一些事情。
RegisterClassW创建的窗口只接受Unicode信息。相关函数:IsWindowUnicode。
窗口创建中涉及一系列窗口消息的处理
- WM_NCCREATE, 在创建完非客户区之后发送
- WM_CREATE,在创建完客户区之后发送
- 上述两个消息会在系统绘制窗口之前接收,可用于初始化
- WM_PARENTNOTIFY ,在创建子窗口之后发送
基于窗口的应用可以是多线程执行的,每个线程都可以创建窗口。窗口执行诀必须和所创建窗口在同一个线程上。 可以通过EnumThreadWindows获取特定线程上的窗口,对应的还有EnumThreadWndProc。
GetWindowThreadProcessId返回窗口对应的线程。ShowWindowAsync可以显示另一个线程上创建的窗口。
Window Features
暂略。
Using Windows
有一些参考示例。
Messages and Message Queues
暂略。
Does a win32 application have one message loop? Or is it one message loop per window?
其他
- Window Reference
- Design basics for Desktop applications
- Layout in Win32 GUI program
- Get Started with Win32 and C++
- How can I make a WNDPROC or DLGPROC a member of my C++ class?
(完)
2022-04-09更新
根据Creating a win32 modal window with CreateWindow,若要某窗口成为另一个窗口的模态窗口,不使用对话框的话,可以
- 将用作模态窗口的窗口创建时,在hwndParent处输入上级窗口的hwnd
- 在模态窗口弹出时使用
EnableWindow(hwndParent, FALSE)
禁用上级窗口 - 在模态窗口关闭时使用
EnableWindow(hwndParent, TRUE)
恢复上级窗口
The correct order for disabling and enabling windows说到,
- 不能销毁模态对话框之后再恢复主管窗口,否则其他意料外窗口会被启用
所以正确的做法是恢复主管窗口,然后再销毁对话框。
Modality, part 1: UI-modality vs code-modality说到,模态其实就是本该由主管窗口处理的消息,被模态窗口处理了,是一种嵌套的消息处理。这个跟图形界面上,模态窗口叠加在主管窗口上面,有类似关系,但不一定完全照应。
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerwindowmessagew可以创建一个新的窗口消息。
其他参考
- How to display a modal dialog window from another process?
- 一种采用 Win32 CreateWindow 方式的模态窗口
- [Win32]创建模态窗口
- (Win32)如何手动实现模态对话框 —— 你应该知道的父子窗口与拥有者与被拥有者窗口之间的关系
(更新完)