Windows (Win32) Accessibility for Developers
Welcome to the Win32 for Developers course. As a developer, you are responsible for implementing accessible solutions for end users, and a little work up front on your part goes a long way towards integrated accessible code in the final product. This course is tailored for Win32 developers and will give you specific tools and skills to create more accessible, user-friendly products.
As a result of this course, you will be able to:
Win32 has been around since 1985 and is widely used in many programs around the world, which means creating accessible products in Win32 is essential to the continued success of a wide range of users. This course assumes you have a working knowledge of Win32 common controls, and how to customize them. As a developer working with Win32, you face unique challenges when developing for accessibility.
This course is organized to help you locate information quickly when you need it, and is laid out in the following manner:
In order to create accessible products, you need to be aware of the accessibility-related Application Programming Interfaces (APIs) used for Win32 product development. Programmatic exposure for Win32 has historically been provided through Microsoft Active Accessibility (MSAA), but newer implementations are now using UI Automation (UIA). Understanding these two accessibility APIs will assist you in making the best choice for implementing programmatic access, which ensures that all UI elements are programmatically exposed to assistive technology (AT).
In the Windows operating system, there are two APIs that provide programmatic access for Win32 controls:
If you need to modify the default accessibility properties of a control, you can use two different techniques:
Use the table below to determine the best approach for implementing your control(s).
In most cases, a common control implemented correctly will provide all the necessary default programmatic access without additional work on your part. For example, when implementing a “button” common control the MSAA information, such as the role, will automatically be provided.
If you use common controls that do not have the name provided on the control (such as button) or lack a label, it is possible to insert a hidden text label preceding the control in the .rc file with a proper label. This will allow the accessibility frameworks to correctly set the name without you customizing it.
Common Mistakes: The most common mistake made in providing programmatic access to W32 controls is not specifying the controls in the correct order. When using common controls, the .rc file should always have the controls listed in the logical order in which they appear on the UI. For example, text labels should always precede the controls they label in the .rc file. This allows MSAA or UI Automation to create the tree correctly and set the elements' names correctly.
Test Your Control: You must test your implementation to ensure the programmatic access is provided correctly. If information is missing or incorrect, check your control's implementation, and use dynamic annotation, if needed, to override basic properties both in MSAA and UI Automation (see the Dynamic Annotation section of this course for more information).
Modifying Common Controls
When using common controls for your application, the default programmatic access for correctly coded controls is usually adequate.
You will need to modify the properties for the control in cases where you:
It is possible to change the MSAA properties of the controls but this should only be done if you are able to describe the functionality of the control with MSAA. Otherwise you will have to use a UIA solution.
Before you are able to make the necessary changes, you need to understand if MSAA can describe your controls completely; you need to understand the MSAA architecture. This section will give you an overview of the MSAA architecture and introduce you to the concepts of Dynamic Annotation and IAccessibleEx, both of which can be used to describe your controls and their functionality.
The IAccessible interface is the heart of MSAA. Applications implement this COM interface to represent their custom user interface elements, which can include their client area as accessible objects, if necessary. Client applications call IAccessible methods and properties to obtain information about an application's user interface and data.
Providing programmatic access using MSAA requires that you address the following issues:
Include initguid.h: As with any COM interface, the system file initguid.h should be included in any source code that requires MSAA.
Bridge/Proxy Communication: What happens when an application implements UI Automation and tries to communicate with an AT that uses MSAA, or vice versa?
What happens when an application implements UI Automation and tries to communicate with an AT that uses MSAA, or vice versa? UIA has a built-in technique to connect clients (AT applications, such as a screen reader application) with your application, regardless of which API is implemented.
The UI Automation to MSAA Bridge (MSAA Bridge) enables client applications that use MSAA to access applications that implement UIA. By bridging MSAA and UIA together, MSAA-based clients, such as screen reader on Windows XP, can programmatically interact with UIA-based providers of UI Automation elements, patterns, properties and events to MSAA accessible objects and properties. It is part of the UIA (Proxy) to treat the enhanced accessible MSAA object as an automation element of the UIA object.
UIA providers can supply information to MSAA clients, and MSAA servers can provide information to UIA client applications. However, because MSAA does not expose as much information as UIA, the two models are not fully compatible. Custom controls built using an MSAA server do not make use of the Proxy, and require additional implementation for cross-communication and correct translation for the navigation tree between APIs.
Dynamic Annotation vs. IAccessibleEx
If your current common control has properties which need to be adjusted, Dynamic Annotation or IAccessibleEx may be good choices for you. New controls that will need additional functionality, or the flexibility to change functionality in the future, should implement UIA.
How do you determine whether IAccessibleEx or a type of Dynamic Annotation is the correct option for your control? The answer is based on what properties need to be changed or added. The table below lays out what each option will do, and when to use it.
What would be the best option for each scenario? Review these scenarios to learn more about how to select which option works best for your situation.
A custom control has some IAccessible information implemented, but also needs to report custom properties such as the range or step values of the progress bar.
Which is the best option to handle this situation?
Answer: IAccessibleEx-- IAccessibleEx is the best option when you seek to expose complex UIA or MSAA properties from a control.
An edit box is missing its Name, and there is no ability to place a label (either visible or invisible) preceding the control.
Which is the best option to handle this situation?
Answer: Dynamic Annotation (Direct Annotation)--Direct Annotation is useful when the Name property needs to be corrected or changed.
You have an existing MSAA slider control that you want to make into a slider that programmatically exposes resolution information as you move the slider up and down.
Which is the best option to handle this situation?
Answer: Dynamic Annotation (Value Map Annotation)--Value Map Annotation is used to correct and change the properties exposed by MSAA slider controls.
Dynamic Annotation is a technology introduced with MSAA version 2.0. Its purpose is to enable a customized common control to expose accessibility information without the need to fully implement the IAccessibleinterface. Dynamic Annotation works by overriding the default properties that are created for standard Windows controls. If you are changing a control, you can use Dynamic Annotation to modify MSAA, or add some UIA properties. Four examples of MSAA properties you may need to modify are: Name, Role, State, and Value.
Name & Role
The Name for elements in an application is assigned in the code by the developer. Many objects such as icons, menus, check boxes, combo boxes, and other controls have labels that are displayed to users. Any label that is displayed to users on or before a control, such as a button, should be the default for the object's name property. Ensure that the Name of the object makes sense to a user, describes the control properly, and does not duplicate the name of a nearby control. For example, if a button is called “Button” and the button next to it is also called “Button,” a user of AT will not be able to identify the function of either button, nor understand the differences between them. A better Name for them might be “Previous page” and “Next page.”
Label as a Default Name: When using common controls, the text label that precedes the control needs to be specified directly before the control in the “.rc” file. Without this, the label will not default as the Name property for the object.
Name Localization: When you annotate the Name, the string should be localized. This allows users to receive information in their native language when using your product.
The Role information is based on the type of control you choose. Select the correct Role to implement based on the desired function of the control. For example the classic confirmation push button “OK” in most dialogues would have an MSAA role of ROLE_SYSTEM_PUSHBUTTON.
A list of windows controls and their functions can be found on MSDN.
Choose the Correct Role: Choosing the incorrect Role for your control may result in impaired or completely inaccessible control functionality. When you change the MSAA role, many of the other properties must be changed as well. For example, do not annotate a button as a slider because the baseline Win32 button control does not offer all of the functionality of a slider control. A slider has “values” and by only changing the Role to “slider” you will not expose your control correctly.
State & Value
The State property describes an object's status at a moment in time. MSAA provides object state constants, defined in oleacc.h, that are combined to identify an object's state. It is required that server developers use these predefined state values. If predefined state values are returned, clients use GetStateText to retrieve a localized string that describes the state. All objects support the State property. Implementation for a button can include the following constants:
Value is returned for objects where percentages, integers and non-integers, textual or visual information are contained in the object. For example, numeric values returned from scroll bar and track bar accessible objects indicate percentages. In this case, the Value returned is an integer between zero and one hundred. Objects that don’t use percentages might use a limited range, such as between one and sixteen. Some objects return strings that correspond to settings. For example, screen size or Internet security levels might be mapped to the Value in place of an integer or percentage. Another example is an editable text field. The Value for the text field is the text typed into and contained by the field. A push button, however, does not have a value.
Value: Not all objects have a Value assigned to them.
There are other MSAA properties that should be implemented depending on your control’s role and functionality. You can find out more about other MSAA properties and their implementations on MSDN.
Using Dynamic Annotation
Dynamic Annotation provides two different mechanisms for handling annotations:
Sample code for Dynamic Annotation of a button taken from MSDN
Affecting Expected Behavior: Dynamic Annotation can affect the expected behavior of a control. For example, if you annotate the Role from “pushbutton” to “entry” (creates editable text) it may cause the AT to interpret the control as an unreadable control.
Adding Event Support: Dynamic Annotation does not provide event support. Developers must add event support manually.
Community Promise Dynamic Annotation Section: The properties supported by dynamic annotations are present in the Common Infrastructure section of the Community Promise.
Direct Annotation is used to override default values for properties such as the string for a Name. It can also be used to add UI Automation properties, including the Automation ID (see the Automation ID section in this course for more information).
More information about Direct Annotation is available on MSDN.
Value Map Annotation
Value Map Annotation is used to specify strings for slider values and specify roles, states, and descriptions for icons in list and tree views for a control. This type of annotation is only supported for the limited controls that require a Value, such as checkbox or sliders. With value map annotation, you can use a mapping string to indicate how the image index of an item in a list view or tree view corresponds to its role or state. For example, a mapping string may indicate that a list view's image index 0 maps to a role of check box, while image index 1 maps to a role of radio button.
Another example is the Internet Explorer “Security” tab in the Internet Options window, which has a slider on it for level of security on the local intranet. Sliders use numbers by default, but a security of “25” or “63” doesn’t give the user very much information about their level of allowed security. Value Map Annotation can map values to a string, such as “25” being equal to “Medium-low” in order to make the control more comprehensible to a user.
More information about Value Map Annotation is available on MSDN.
The IAccessibleEx interface enables legacy MSAA applications to add support for specific UI Automation patterns and properties without creating a native UI Automation solution. With IAccessibleEx, you can implement richer information about your control using the UIA control patterns and properties.
When to Use IAccessibleEx
IAccessibleEx is a bridging technique that allows some UIA information to be implemented. On the whole, however, any new application or control could be more effective when created using UIA, which provides the best flexibility to support new UI behaviors for accessibility.
While IAccessibleEx can be a cost effective way of supporting UIA, your application should meet the following two criteria if you are to consider using it:
If either of these baseline requirements is not met, you should implement UIA natively instead of IAccessibleEx. You may choose to keep legacy MSAA implementations for backward compatibility, if necessary.
Should IAccessibleEx be the better choice for your situation, follow these steps to implement it:
1. Implement IAccessibleEx. Here is an implementation of the GetObjectForChild and GetIAccessiblePair methods so UI Automation can map an IAccessible and ChildId pair to a corresponding IAccessibleEx instance.
2. Expose IAccessibleEx with IServiceProvider::QueryService.
3. Implement IRawElementProviderSimple to provide property values and pattern providers for your control.
4. Implement control patterns and properties that describe your control.
5. Implement WinEvents for your control.
For more information on IAccessibleEx, see the Microsoft Community Promise.
You must plan for effective keyboard interactions in your product. Think through the navigation for the product, which items should receive focus, and how non-text items will be labeled in order to provide the best experience for users. All applications must be navigable using only a keyboard. Tab order and shortcut keys should all be provided in the spec. Further keyboard navigation information can be found on MSDN.
Writing a DPI-aware application is the key to making a UI look consistently good across a wide variety of high DPI display settings. An application that is not DPI-aware but is running on a high DPI display setting can suffer from many visual artifacts, including incorrect scaling of UI elements, clipped text, and blurry images. By adding support in your application for DPI-awareness, your application’s UI is more predictable, making it more visually appealing to users.
As more manufacturers ship greater numbers of high-resolution displays, the default 96 DPI setting can no longer be assumed by applications.
While the Win32 API provides a function declaring an application as dpi-aware, its use is discouraged, except in very specific circumstances. In general, using an application manifest is the recommended process for declaring an application to be dpi-aware.
Supporting high contrast is an important part of making your application accessible. A high contrast mode must remove flashing animations, and remove or reduce transition animations. It should also be set to omit non-functional images, gradients or patterns behind text. When creating applications, be sure to adhere to the high contrast standards on MSDN. Be sure not to hard-code colors and have alternative color icons available for high-contrast setting users. Further information on high contrast in Win32 is available on the High Contrast Parameter page at MSDN.
There are two additional accessibility issues that you will want to think through when developing your product. These are color and sound.
Text and background contrasts need to meet at least a 5:1 color contrast ratio. In addition, keep color choices appropriate for users with colorblindness. Be sure to provide visual cues in formats which rely solely on color to convey changes or information in the user interface (UI). Different icons or use of words will help colorblind users get the information they need.
Provide closed captioning or visual notifications for sounds used in applications. Users with hearing impairments or computers that do not have sound available will need alternate notifications such as these.
Win32 Accessibility Parameters: For more information about Win32 accessibility parameters, visit the Accessibility Parameterspage on MSDN.
Using common controls can sometimes provide insufficient flexibility for end-user scenarios when developing Win32 applications. In these cases, you may choose to create custom Win32 controls for your application. This decision, however, can be very expensive depending on the complexity of the control. For example, when creating a custom interface with rich functionality, you must manually code to provide programmatic access for each unique control in that custom implementation, as well as create the logical hierarchy and raise events for clients.
This section will provide you with information about creating custom controls using UIA. Important topics covered for custom controls include:
Understanding the UIA Architecture
UIA enables programmatic access to AT through six components:
Exploring UIA Components
The UIA Tree
The UIA Tree represents the entire UI. The root element is always the desktop, and the child elements (called fragments) are application windows. The UIA Tree maps to all the elements on the desktop.
The UIA Tree is not a fixed structure and is seldom seen in its totality because it might contain thousands of elements. Parts of it are built as they are needed, and it can undergo changes as elements are added, moved, or removed. To help AT clients process UI information more effectively, the framework supports alternative views of the UIA Tree which may be used by some applications:
Examples of UI items that contribute to the logical structure of the UI, but are not interactive themselves, are item containers such as list view headers, toolbars, menus, and the status bar.
Non-interactive items that will be seen in the control view are graphics with information and static text in a dialog box. Non-interactive items that are included in the control view cannot receive keyboard focus. Non-interactive items used simply for layout or decorative purposes will not be seen in the control view. An example is a panel that was used only to lay out the controls in a dialog box but does not itself contain any information.
The control view is obtained by searching for elements that have the IsControlElement property set to true, or by using the ControlViewWalker to navigate the tree.
For example, the values in a drop-down combo box will appear in the content view because they represent the information being used by an end user. In the content view, a combo box and list box are both represented as a collection of UI items where one, or perhaps more than one, item can be selected. That one is always open and one can expand and collapse is irrelevant in the content view because it is designed to show the data, or content, that is being presented to the user.
UIA exposes every piece of the UI to client applications as an Automation Element. Providers supply property values for each element. Elements are exposed as a tree structure, with the desktop as the root element.
Automation elements sometimes implement methods that allow AT to interact with the element. When the user invokes a method on an element, it automatically invokes the corresponding method on the provider.
Automation Element Properties:
UIA providers expose properties of UI Automation elements. These properties enable UIA client applications to discover information about pieces of the user interface (UI), especially controls, including both static and dynamic data.
The UIA specification defines two kinds of automation properties:
1. Automation Element Properties: apply to all elements, provide fundamental information about the element such as its name.
2. Control Pattern Properties: apply to control patterns, such as ScrollPattern properties that enable a client application to discover whether a window is vertically or horizontally scrollable.
Control patterns are collections of associated properties, events, and methods that describe an element. There are 22 control patterns defined to date, and more than one pattern can apply to a single element. Control patterns also expose methods that enable clients to get further information about the element and to provide input. The pattern might be something simple like the Invoke pattern, which lets clients invoke a control.
Each pattern is its own interface. When you implement a pattern you must implement all the properties and entire interface correctly or it will not compile properly.
Automation events notify applications of changes to and actions taken with automation elements. Unlike WinEvents, UIA events are not based on a broadcast mechanism. UIA clients register for specific event notifications and can request that specific UIA properties and control pattern information be passed into their event handlers. In addition, a UIA event contains a reference to the element that raised it. Providers can improve performance by raising events selectively, depending on whether any clients are listening.
Test Before Implementing Events: Test your code before implementing events. This allows for tweaks to the code before adding the additional complexity of events to it.
Automation elements expose common properties of the UI elements they represent. One of these properties is the UIA control type, which defines its basic appearance and functionality as a single recognizable entity, for example, a button or check box.
In UI Automation, a control type is a set of conditions that a control must meet in order to use the ControlTypeProperty property. The conditions include specific guidelines for UIA tree structure, UIA property values, control patterns, and UIA events.
Select the correct control type for your control by thinking through the functionality of the control, not its appearance. For example, an image that is clickable might use the Button control type, which has an invoke functionality, whereas the Image control type does not.
Control Type Flexibility: The total number of pre-defined control types is significantly lower than MSAA accRole definitions, because you can combine UIA control patterns to express a larger set of features while MSAA roles cannot. You can also customize the description of control type by LocalizedControlType property while keeping the baseline type as defined.
Additional information about the Microsoft UI Automation Community Promise and UI Automation Specification can be found on MSDN.
Required UIA Properties: Name and Automation ID
Certain automation properties can be left as default. However, when creating custom controls, there are two required properties that must be set directly by the developer. These are:
The Name property should always be consistent with the label text on screen. For example, the Name must be “Browse…” for the button element with “Browse…” as the label. Do not include the control role or type information such as “button” or “list” in the Name. This will cause conflict with the text from LocalizedControlType property. The control type and control patterns are responsible for describing the functionality, not the Name, of an element.
When the corresponding label text is not visible on screen or when it is replaced by graphics, alternative text (alt text) should be chosen. Good alt text is a concise description of the UI function or the feature as if it was labeled by the simple text. For example, the Windows Start menu button should have the Name “Start” instead of “Windows Logo on blue round sphere graphics.” It is a good idea, when doing spec reviews, to ensure alt text is defined for any graphics or images.
The Control Type is a well-known identifier within UI Automation that indicates what kind of control an element represents, such as a combo box or a button. Having a well-known identifier makes it easier for AT software to determine what types of controls are available in the user interface, and how to interact with the controls. Choose your control type by reviewing the possible choices in the UIA Control Type enumeration, and then selecting the one that best represents your control.
If you pick a standard control type, you do not need to define a Localized Control Type; the UI Automation system will provide a localized form of the control type automatically. If you choose the Custom control type, please define a Localized Control Type using a sort, localized name for the type of control you are creating.
Each control type has a standard set of control properties, patterns, and events that must be implemented. For example, elements with the Combo Box control type always support the ExpandCollapse and Selection control patterns and their associated events. Choosing a control type is an important decision, since it gives you a further set of requirements for your implementation. Further information about Control Types is available on MSDN.
The Automation ID uniquely identifies a UIA Element within its siblings. Having a unique identifier is important for both assistive technologies and test automation frameworks. The Automation ID is ideally a unique identity for the entire Logical Hierarchy, but is required to be unique within its siblings. For example, an application may contain a menu control with multiple top-level menu items that, in turn, have multiple child menu items. These secondary menu items may be identified by a generic scheme such as "Item1", "Item 2", and so on, allowing duplicate identifiers for children across top-level menu items. However, giving each item a completely unique name or string within the product allows for easier identification. The Automation ID is noted in the code.
Information Icon: Automation ID in Other Languages The Automation ID does not change regardless of language. A button name might be different in French, but the Automation ID retains the original name given by the developer.
The code for implementing Name and Automation ID are similar. Here is a sample of what your code might look like:
Note: pRetVal [out, retval] - When this method returns, contains the property value, or NULL if the property is not supported by this provider. This parameter is passed uninitialized.
Designing a Custom Control
Designing and implementing a custom UI Automation solution is a three step process:
Use Common Controls Where Viable Many scenarios can be accomplished with common controls and still be usable, accessible, and aesthetic. Prior to creating a custom control application, confirm that you cannot accomplish your scenarios with the controls provided by the platform. This will save time and money for your finished product.
Implementing a Custom Control
Each control type has its own set of patterns, methods, events, and properties that need to be implemented for the control to compile and function correctly. Now that the control type components for the information grid in Product X have been planned out, the tactics for implementing the control in an accessible manner are much simpler. For each item in the control chart, be sure to implement the correct UIA properties. The process for creating a custom control from scratch will now be addressed.
Step 1: Exposing the Provider
When implementing UIA in Win32, developers must include the Uiautomation.h header in the application. Also, in order to set up UIA to work in your custom control, you must set up an object that implements the UIA API to be returned when WM_GETOBJECT is called. The way this is done in Win32 is by hooking WMGETOBJECT to implement the correct core provider interface, which in this case is IRawElementProviderSimple.
UI Automation provider interfaces are much easier to implement than IAccessible, and they can be implemented by managed or unmanaged providers. The interfaces expose the same basic information as IAccessible (locations, tree structure, focus and hit testing support). Code that implements these interfaces are visible to UI Automation clients, but is also made available as IAccessible implementations for in-process or out-of-process MSAA clients. These methods are also used by clients to access property and pattern values/support information.
Every UIA provider must implement one of the following core provider interfaces for accessibility:
For Product X, the data grid custom control requires that IRawElementProviderFragmentRoot and IRawElementProviderFragment also be implemented. Any custom control which contains automation elements within it, such as the data grid, needs to have these providers implemented in order to create an accurate UI Automation Tree.
Sample code for exposing the provider:
Step 2: Implementing UIA properties
Once the API is set up, you can then begin implementing the control types and the corresponding properties from your control chart. To show how this is done, we can expand the DataGrid control type portion of the control chart to see that we will need to implement. The code must include the correct:
Here is a breakdown of the properties for the DataGrid control type for Product X:
1. ControlType DataGrid
1. IGridProvider Interface Properties
1. IScrollProvider Interface Properties
2. IScrollProvider Interface Methods
1. ISelectionProvider Interface Properties
2. ISelectionProvider Interface Methods
1. ITableProvider Interface Properties
2. ITableProvider Interface Methods
i. Automation ID
vii. LabeledBy (not needed)
viii. LocalizedControlType=”data grid”
c. UI Automation Events
ii. BoundingRectangleProperty property-changed event
iii. IsEnabledProperty property-changed event
iv. IsOffscreenProperty property-changed event
vii. CurrentViewProperty property-changed event
viii. HorizontallyScrollableProperty property-changed event
ix. HorizontalScrollPercentProperty property-changed event
xi. VerticallyScrollableProperty property-changed event
xii. VerticalScrollPercentProperty property-changed events
xiii. VerticalViewSizeProperty property-changed event
Step 3a: Implementing Patterns
Providers support control patterns by implementing interfaces that are appropriate to the control type. For example, the provider for a button control must implement IInvokeProvider. A pointer to the object that implements this interface (it may be same object that implements IRawElementProviderSimple) is returned by IRawElementProviderSimple::GetPatternProvider.
In the case of Product X, we know one piece of the control is created using the DataGrid control type. Since this control is scrollable, four patterns will need to be implemented:
For more information on which patterns are required for your control type are available on MSDN.
Implement each pattern and its properties for the control type you wish to use. To begin implementing a pattern, the Toggle pattern for example, the code would look like this:
Code sample taken from MSDN.
In order to get patterns, the following code would be implemented:
Code sample taken from Code magazine article Making Custom Controls Accessible.
Step 3b Implementing Pattern Properties & Methods
Each pattern for the control has properties and methods that need to be implemented for them. In the case of Product X, let’s explore the Selection pattern.
In the case of Selection, there are two properties that must be implemented:
Select the provider for your pattern for more information on the required properties and methods for your pattern type.
Methods provide a means of supporting how the process of a pattern is implemented, such as GetColumnHeaders or SetScrollPercent. Using the Selection pattern again, there is one required method for the ISelectionProvider interface, which is GetSelection. GetSelection retrieves a UIA provider for each child element that is selected.
Code for implementing the toggle method would look like this:
Note: MoveToNextState is a function that will actually perform the action of toggling. It will change the UI as well as invoke the action associated with toggling.
Step 4: Implementing Control Properties
Once you have implemented all of the appropriate control patterns for your control type, you should then move on to implementing the required control properties for it. As with all controls using UIA, this control requires a Name and Automation ID. In addition, the DataGrid control type also needs the following properties implemented:
The code for implementing a property, such as IsContentElement, would look like this:
Step 5: Checking In
Once you have implemented a control type, the patterns, methods, and pattern and control properties you should spend a little time doing unit testing to ensure your code will expose correctly to AT. UISpy (add link to this) or another UI Automation test tool will allow you to double check that your code is exposing the correct information. Be aware that some functionalities of the testing will be limited because events are not yet implemented. Once you’ve done unit testing to ensure Name, Automation ID, and other information is reporting properly, you can move onto step 6.
Step 6: Implementing UIA Events
The purpose of an event is to notify the AT of something taking place in the UI. For example, the event identified by Invoke_InvokedEvent_GUID should be raised whenever the control is invoked, either through direct user input or by the client application through the control pattern.
To optimize performance, a provider can selectively raise events, or raise no events at all if no client application is registered to receive them. You can call the UiaClientsAreListening function to ascertain whether AT has subscribed to any events. For more precise information about what events are of interest to clients, implement the IRawElementProviderAdviseEvents interface in your provider object. The methods of this interface will be called whenever a client subscribes or unsubscribes to an event.
For the DataGrid control type, the following events are required:
Supporting Navigation for Custom Controls
When you implement a provider for a complex custom control using UIA you must support navigation between the root node of the fragment and its descendants, and between sibling nodes.
Navigation of elements within a fragment must be supported. The fragment root supports navigation to its children, which descendants support navigation in a variety of directions including: back to the parent, to their next and previous siblings, and to any children they may have. Each element in the complex custom control needs to have IRawProviderFragment implemented for it, and the root will also require IRawProviderFragmentRoot to be implemented in addition to the fragment provider. The structure of a fragment is determined by your implementation of IRawElementProviderFragment::Navigate.
Correcting Siblings as Parent/Child Relationships When two or more elements are each contained in a UIA fragment, and are each contained in a window, the UIA Tree shows the HWNDs as siblings by default rather than a parent-child relationship. To correct this, reposition the HWND-hosted element as a child of the root element by implementing IRawElementProviderHwndOverride. When IRawElementProviderHwndOverride::GetOverrideProviderForHwnd is called for the child element's HWND, return your custom provider for that element.
Registering Completely Custom Controls
If you create controls with functionality that cannot be represented by currently provided control patterns or properties, UIA offers further extensibility through the registration of custom control patterns, properties, and events.
Creating a custom UI Automation control pattern, property, and/or event requires careful planning, implementation, and testing. Here are the steps you would follow to do so:
A custom property, event, or pattern is specified by filling out a UIAutomationPropertyInfo, UIAutomationEventInfo or UIAutomationPatternInfo struct as appropriate, and then calling the appropriate Register method on the IUIAutomationRegistrar object. This returns an integer property, event or pattern identifier that can then be used in any UI Automation API that uses such an identifier. For example, the PropertyId returned by RegisterProperty can then be used in IUIAutomationElement::GetCurrentPropertyValue or in IUIAutomation::CreatePropertyCondition.
The following must be specified (in the appropriate structure) for a custom item:
Custom properties require a value identifying the type of the property, for example, whether it is an integer or a string, to be specified.
In addition, custom patterns also require the following to be specified:
How Clients and Providers Support Custom Control Patterns
In order to take advantage of newly registered control pattern, both clients and providers are required to supply a small amount of support code.
Clients use a client interface object (for example, an IUIAutomationCustomPattern interface) that has getter functions for cached and current properties, as well as methods.
Providers implement a provider interface (for example, an ICustomProviderinterface) that has getters and setters for each property, as well as methods.
To support the client API object, the code that registers a pattern must supply a factory for creating instances of a Client Wrapper. This wrapper implements the client API as a COM interface and forwards all the property getter requests and methods calls to an IUIAutomationPatternInstance that is provided by UI Automation. The UI Automation framework then takes care of the rest of marshalling the call.
On the provider side, the code that registers a pattern must also supply a “pattern handler” object that performs the reverse function of the Client Wrapper. The UI Automation Framework forwards the property and method requests to the pattern handler object. The pattern handler then calls the appropriate method on the target object’s provider interface.
The UI Automation framework takes care of all communication between the client and provider, both of which register corresponding control pattern interfaces. The Client Wrapper and Pattern Handler need to map only between C++ interface methods calls with positional arguments and parameters.
Tools & Resources
Now that you’ve learned more about developing accessible products and services, you may want to explore the subject further. Here are some online resources you might find helpful.
Congratulations, you have completed the Windows (Win32) Accessibility for Developers course.
You now have an increased understanding on how to use MSAA and UIA in Win32 to create programmatic access for users of Assistive Technology (AT). You can also see the benefits of including accessibility into your product development cycle in a programmatic way to enhance the development process. Further courses are available on how to write accessible code and address platform-specific issues for accessibility. You can consult the Microsoft Accessibility developer portal on MSDN for more information.
The courses in the Accessibility Training for Developers include: