Windows and Messages

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?

其他

(完)

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可以创建一个新的窗口消息。

其他参考

(更新完)