动态批注的替代项

可通过其他方法为 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 接口时,包装还必须转发 IEnumVARIANT 和 IOleWindow 接口。
  • 必须正确处理引用计数,尤其是在支持其他接口时。
  • 必须正确处理 IDispatch 返回值,尤其是使用 ITypeInfo::Invoke 方法(必须使用指向包装接口的接口指针调用)而不是指向原始 IAccessible 接口的指针。

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

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

修复派生自标签的名称

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

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

当资源编辑器) 打开或直接编辑资源文件时,可以使用“格式”菜单上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

在此示例中,标签和控件未按正确的制表符顺序列出。 因此,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 键顺序放置这些标签。 控件的主标签必须立即显示在控件本身之前。

不带标签的命名控件

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

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

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

请注意,即使标签不可见,任何指定的快捷键都有效。