动态批注的替代方法

还有其他方法可为 UI 元素提供自定义 的 IAccessible 支持,在某些情况下,它们是正确的解决方案。 在动态批注之前,这些替代技术是开发人员唯一可用的选项。 它们包括实现所有 IAccessible 接口和编程技术。

实现所有 IAccessible 接口

另一种方法是实现所有 IAccessible 接口。 此方法通常是自定义控件或完全不同的 UI 元素所必需的;但是,开发和测试成本非常巨大,除非确实有必要,否则应避免这样做。 如果目标是修改单个属性,则成本难以证明。

编程技术

另一种选择是使用子类化和包装技术来修改为特定属性公开的信息。 这是动态批注旨在取代的技术。 若要使用子类化和包装替代单个属性,开发人员必须执行以下步骤:

  1. 子类 IAccessible 对象的 HWND。
  2. 截获正确的 IParam/OBJID 值的 WM_GETOBJECT 消息。
  3. 使用 CallWndProc 回调函数将WM_GETOBJECT消息转发到基类。 如果返回零,则调用 CreateStdAccessibleObject;否则,对返回的值调用 LresultFromObject 以获取控件的本机 IAccessible 接口指针。
  4. 创建一个包装类,该类实现 IAccessible 并包装上一步返回的 IAccessible 接口指针。 此包装类将所有方法和属性发送到原始 IAccessible 接口指针,但要重写的方法和属性除外。 这涉及到为所有 IAccessible 接口的 21 个属性和方法编写转发代码,而不管实际重写多少。

此外,开发人员必须验证以下条件:

  • 重写的方法或属性必须仅处理所需的子 ID,并将所有其他子 ID 转发到原始 IAccessible 接口指针。
  • 仅当原始对象支持 IEnumVARIANTIOleWindow 接口时,包装还必须转发它们。
  • 必须正确处理引用计数,尤其是在支持其他接口的情况下。
  • 必须正确处理 IDispatch 返回值,尤其是使用 ITypeInfo::Invoke 方法,必须使用指向包装器接口的接口指针(而不是指向原始 IAccessible 接口的指针)调用该方法。

即使只需要重写一个或两个属性,这些技术也需要大量的工作。 生成的大多数代码都与子类化和包装有关,实际上只有一小部分提供重写的信息。

但是,在某些情况下需要这些技术。 例如,如果要进行结构更改以创建占位符 UI 元素,则应使用这些技术,而不是动态批注。

修复从标签派生的名称

某些 Microsoft Win32 常用控件(如编辑框控件)几乎始终与标签 (资源文件) 中的 LTEXT 条目或资源文件) 中 GROUPBOX (GROUPBOX 的组框一起使用。 Microsoft Active Accessibility 会自动从其标签派生控件的名称属性。 对于此类控件,窗口文本 (Microsoft Visual Studio 中显示为 Name 或 ID 属性) 将被忽略,因为它通常是自动生成的,并且很少具有描述性;例如“IDC_EDIT1”。

如果应用程序的用户界面设计不正确,Microsoft Active Accessibility 可能无法正确设置名称。 若要与控件关联,标签或组框必须紧靠在 Tab 键顺序中的动态控件前面。

当资源编辑器) 打开时,可以使用 Visual Studio 中的工具 (“ 格式 ”菜单上的工具来更改 Tab 键顺序,也可以直接编辑资源文件。

以下示例显示了资源文件对包含两个标记编辑框的对话框的说明。

IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,179,35,30,11,WS_GROUP
    LTEXT           "First Name:",IDC_STATIC,8,16,43,8
    LTEXT           "Last Name:",IDC_STATIC,8,33,43,8
    EDITTEXT        IDC_EDITFIRSTNAME,53,15,120,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDITLASTNAME,53,34,120,12,ES_AUTOHSCROLL
END

在此示例中,标签和控件未按正确的 Tab 键顺序列出。 因此,Microsoft Active Accessibility 会将名称“姓氏”分配给名字编辑框,而姓氏编辑框根本没有名称。

以下示例显示了正确的资源列表。 另请注意,标签中已指定快捷键。

IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
    LTEXT           "&First Name:",IDC_STATIC,8,16,43,8
    EDITTEXT        IDC_EDITFIRSTNAME,53,15,120,12,ES_AUTOHSCROLL
    LTEXT           "&Last Name:",IDC_STATIC,8,33,43,8
    EDITTEXT        IDC_EDITLASTNAME,53,34,120,12,ES_AUTOHSCROLL
    DEFPUSHBUTTON   "OK",IDOK,179,35,30,11,WS_GROUP
END

当控件具有补充标签(例如跟踪条上的最小值和最大值)时,这些标签应按 Tab 键顺序放置在控件之后。 控件的main标签必须紧接在控件本身之前。

不带标签的命名控件

并非总是可能或需要为每个控件提供可见标签。 但是,仍可以通过添加不可见标签来为控件提供名称。 与往常一样,不可见标签必须紧接在 Tab 键顺序的控件前面。

如果在 Microsoft Visual Studio .NET 中使用资源编辑器,可以将 Visible 属性设置为 False。 若要使标签在编辑资源文件 (.rc) 时不可见,请将 NOT WS_VISIBLE 或 添加到标签控件的样式部分,如以下示例所示。

    LTEXT           "&FullName:",IDC_STATIC,111,23,44,8,NOT WS_VISIBLE

请注意,即使标签不可见,任何指定的快捷键也能正常工作。