Microsoft Active Accessibility

Active Accessibility is an architecture developed by Microsoft designed to make software more accessible. So far all the methods we've discussed have dealt only with Windows system settings and functions. Active Accessibility provides a whole new set of function calls and interfaces to enable you to create applications that developers of accessibility aids, such as screen readers, can interface with.

That's the good news. The bad news is that Active Accessibility is still a relatively new architecture. As of this writing, Active Accessibility is still on version 1.1. This version has a number of limitations, the first of which is that it's not available on Windows NT 4. If you're developing with Windows 9x, you can install the SDK and implement the functions and procedures in your development project. However, the Active Accessibility SDK will not install under Windows NT 4.

Now for the next problem: Active Accessibility—the SDK and all the documentation—were designed for C++. The SDK comes with a sample Visual Basic 4 program that does run under Visual Basic 6. The SDK also comes with a type library that you can import into your Visual Basic project. The problem with the type library is that the function calls tend to differ slightly from those in the C++ documentation, and they don't come with any documentation of their own.

So, that said, we're going to make do with what we have and get as much out of this technology as possible in preparation for the improvements Microsoft's Active Accessibility group will make in the future. We'll walk through a sample program, AAccess (shown in Figure 16-6), that demonstrates how to use some of the object retrieval calls and shows what kind of accessible object information is available.

click to view at full size.

Figure 16-6 Active Accessibility sample program

Why Should I Use Active Accessibility?

Before starting in on a discussion of how to use Active Accessibility, I need to offer a little more of an explanation as to the purpose of Active Accessibility and how it works.

Active Accessibility uses Component Object Model (COM) technology to expose interfaces that provide a common means of communication among applications. What does that mean? Let's look at an example. Accessible computing often involves more than the guidelines and considerations discussed so far in this chapter. For computers to be accessible to everyone, special devices, known as accessibility aids, sometimes are required. Examples of such aids are screen readers and special input devices. The developers of accessibility aids must create software that communicates with the existing operating system and application software running on the computer. Without Active Accessibility, establishing these communications can be difficult. In order for the accessibility aid software to communicate with the system software, it's required to know or discover a lot of details about the specific types of software. When software applications are created with Active Accessibility, the accessibility aids don't need to know any application-specific details. They can find out what is on the screen and how to use it from the common interfaces exposed by Active Accessibility.

From this you might have figured out that there are two sides to Active Accessibility: the client and the server. The client is the hardware and software for the accessibility aid that is trying to retrieve information. The server is the software application that is exposing accessible interfaces so that the client can easily retrieve the desired user interface information.

My intent when I started writing this was to demonstrate how to make your Visual Basic application available as a server. Unfortunately, after a lot of work and some discussion with Microsoft's Active Accessibility group, I've discovered that the technology isn't quite ready yet for a Visual Basic server. As I said before, Active Accessibility is still very new, and it wasn't designed for use with Visual Basic. So what I've done instead is demonstrate what can be done from the client side. This will at least give you a chance to see how Active Accessibility works and should help prepare you to use it in the future.

Setting Up Your Project

Before you start building your project you of course need to load the Microsoft Active Accessibility SDK (MSAASDK), which you'll find on the companion CD for this book. After you've loaded the SDK, you must create a reference in your project to the Accessibility DLL, OLEACC.DLL. Select References from the Project menu, then click the Browse button to find the OLEACC.DLL file. By default this file is located in the \Windows\System folder. Once you've created the reference, you can view the Accessibility library through the Object Browser in Visual Basic. When you select Accessibility from the Project/Library drop-down list in the Object Browser, you won't see anything in the Classes or Member Of lists because the Accessibility settings are hidden. You need to right-click in the Members Of pane and select Show Hidden Members to view the Accessibility classes and members.

NOTE


If you're working without a mouse and you want to view the hidden files in the Object Browser, tab to the Members pane and press Shift+F10 to display the shortcut menu. Press H (for Show Hidden Members) on your keyboard and then press Enter.

Another means of accessing the shortcut menu is to enable the Windows MouseKeys option. Select Accessibility Options from the Control Panel and select the Mouse tab. Check the Use MouseKeys checkbox and click OK. You can now perform the right-click action in the Object Browser using your numeric keypad by pressing the minus key and then pressing the 5 key.

Retrieving Accessibility Information

Three main functions allow you to retrieve information about objects in an application: AccessibleObjectFromEvent, AccessibleObjectFromWindow, and AccessibleObjectFromPoint. We won't be looking at events here, but we will be retrieving objects directly from a window and retrieving objects based on where the mouse is pointing on the form.

Retrieving objects from a window

The frmAccess form in the AAccess sample contains a number of standard controls, including list boxes, check boxes, and radio buttons. So the first thing we want to do is find which of these controls are accessible through the Active Accessibility interface. We need to start with a type declaration and a function declaration, which must go in a standard module, in this case mAccess.

Type tGUID     lData1            As Long     nData2            As Integer     nData3            As Integer     abytData4(0 To 7) As Byte End Type Declare Function AccessibleObjectFromWindow Lib "oleacc" _     (ByVal hWnd As Long, ByVal dwId As Long, _     riid As tGUID, ppvObject As Object) As Long 

The tGUID type is a UDT that maps to the C++ REFIID structure, often called the class ID. The value we assign to this UDT is the class ID of the interface we want to retrieve. We'll be retrieving the IAccessible interface provided by Active Accessibility. AccessibleObjectFromWindow will return the IAccessible interface for the window object with the given window handle (hWnd).

    Dim oIA     As IAccessible     Dim tg      As tGUID     Dim lReturn As Long     ' Define the GUID for the IAccessible interface.     ' {618736E0-3C3D-11CF-810C-00AA00389B71}     With tg         .lData1 = &H618736E0         .nData2 = &H3C3D         .nData3 = &H11CF         .abytData4(0) = &H81         .abytData4(1) = &HC         .abytData4(2) = &H0         .abytData4(3) = &HAA         .abytData4(4) = &H0         .abytData4(5) = &H38         .abytData4(6) = &H9B         .abytData4(7) = &H71     End With     ' Retrieve the IAccessible interface for the form.     lReturn = AccessibleObjectFromWindow(frmAccess.hwnd, 0, tg, oIA) 

We now have an IAccessible interface for the form object contained in oIA. What we really want is to find out what accessible objects are on the form. For this we need to make a call to the AccessibleChildren function. Declare the function in the mAccess module as follows:

Declare Function AccessibleChildren Lib "oleacc" _     (ByVal paccContainer As IAccessible, ByVal iChildStart As Long, _      ByVal cChildren As Long, rgvarChildren As Variant, _      pcObtained As Long) As Long 

The first parameter is the IAccessible interface we just retrieved. The second parameter, iChildStart, is a zero-based index specifying which child you want to start retrieving. The third parameter indicates how many children you want to retrieve. AccessibleChildren returns an array of Variants in the rgvarChildren parameter. This array can contain either a list of objects or a list of system-defined object identifiers. The final parameter returns the number of objects that were retrieved into the array.

    Dim lStart      As Long     Dim lHowMany    As Long     Dim avKids()    As Variant     Dim lGotHowMany As Long     ' Get the IAccessible interface     ' Initialize     lStart = 0     ' accChildCount returns the number of children for the given object.     lHowMany = oIA.accChildCount     ReDim avKids(lHowMany _ 1) As Variant     lGotHowMany = 0     ' Retrieve the form's children.     lReturn = AccessibleChildren(oIA, lStart, lHowMany, _                                  avKids(0), lGotHowMany) 

At this point it appears that we have an IAccessible interface for the form and an array of child objects. Unfortunately, a quick look at the avKids array in the debugger shows this not to be the case.

click to view at full size.

AccessibleChildren has returned an array of Longs. These Long values represent those system-defined object identifiers I mentioned earlier. Fortunately, one of these identifiers happens to identify the form, so we must search for the form and start again.

Dim oNewIA       As IAccessible Dim avMoreKids() As Variant ' The first call to AccessibleChildren retrieved system information. ' Now we need to find the form object again. For i = 0 To lGotHowMany _ 1     If oIA.accName(avKids(i)) = frmAccess.Caption Then         Set oNewIA = oIA.accChild(avKids(i))         lHowMany = oNewIA.accChildCount     End If Next i ' Retrieve the children for the actual form IAccessible interface ' this time. ReDim avMoreKids(lHowMany _ 1) As Variant lReturn = AccessibleChildren(oNewIA, lStart, lHowMany, _                              avMoreKids(0), lGotHowMany) 

If you check the avKids array now, you'll see it's full of IAccessible objects, as shown here.

click to view at full size.

In the AAccess sample, I put this functionality in the cmdOK_Click event procedure so that we could retrieve the objects and then display them in a list box on the screen. Here are the results:

click to view at full size.

You might be surprised at the list you see. To start with, if you scroll through the list you'll notice that nine controls were returned. But if you count the controls on the form, you'll find eleven (two labels, one text box, two list boxes, two check boxes, two radio buttons, and two command buttons). The missing controls in the list are the labels. Labels are not included as accessible objects.

The next thing you'll notice is that some of the controls in the list don't have names. We retrieve the name from the IAccessible.accName property. For Visual Basic forms and controls, accName is the same as the corresponding Caption property. The list boxes and the text box don't have Caption properties, so their names aren't displayed in the list box.

Retrieving objects from a point

Another means of retrieving information about accessible objects is to query the object at a specific point on the screen. With Active Accessibility this is done with the AccessibleObjectFromPoint function. In our AAccess sample, when the user clicks the mouse, we'll find the accessible object at the point of the mouse click and display some of the object's properties in a list box. First let's declare the types and functions we need in our standard module.

Type tPOINT     lx As Long     ly As Long End Type Declare Function GetCursorPos Lib "user32" _     (lpPoint as tPOINT) As Long Declare Function AccessibleObjectFromPoint Lib "oleacc" _     (ByVal lx As Long, ByVal ly As Long, ppacc As IAccessible, _      pvarChild As Variant) As Long 

The tPOINT UDT maps to the Win32 POINT structure, which contains the coordinates for a point on the screen. You pass these x and y coordinates to AccessibleObjectFromPoint to retrieve the IAccessible object located at that point. The last parameter, pvarChild, returns a Variant. If the value is 0, the ppacc parameter contains the IAccessible interface of the child object, such as a command button on the form. A non-zero value in pvarChild indicates that the ppacc parameter contains the IAccessible interface of the parent object.

Because we're capturing the mouse location with Click events, the AccessibleObjectFromPoint logic is in a private subroutine that is called by each of the Click event procedures.

Private Sub GetClickEvent()     Dim tp      As tPOINT     Dim oIA     As IAccessible     Dim vKid    As Variant     Dim lResult As Long     ' Get the cursor position where the mouse was clicked.     Call GetCursorPos(tp)     ' Get the IAccessible interface of the object located under      ' the cursor position.     lResult = AccessibleObjectFromPoint(tp.lx, tp.ly, oIA, vKid)     ' Add the object's accessibility information to the list box.     On Error Resume Next  ' Not all the acc properties will work                           ' with all the returned objects.     With lstList2         .AddItem "Object Name: " & oIA.accName(vKid)         .AddItem "Default Action: " &  oIA.accDefaultAction(vKid)         .AddItem "Keyboard Shortcut: " & _                  oIA.accKeyboardShortcut(vKid)     End With End Sub 

Now when you run the AAccess sample you can click the different controls on the form and see what happens. The results will be similar to those shown here:

click to view at full size.

You can see that clicking labels doesn't have any effect. This means they're not supported as accessible objects. If you click the Form Objects button you see the properties for the button in the list box on the right, and the list on the left is populated with the form objects we retrieved with calls to AccessibleObjectFromWindow and AccessibleChildren. Once the list box on the left is populated, you can click individual list elements and see their properties in the list box on the right. You can also see how the default action changes when you toggle check boxes on and off.

Where Do I Go From Here?

In reviewing the AAccess sample, we've seen how to call the base functions for retrieving accessible objects and how to retrieve some of the properties of those objects. These are the beginnings of using Active Accessibility to expose objects and communicate between applications. The MSAASDK is an evolving architecture and I recommend that you check Microsoft's Web site for updates to the SDK and to accessibility issues in general. See the section "More Information," below.



Ltd Mandelbrot Set International Advanced Microsoft Visual Basics 6. 0
Advanced Microsoft Visual Basic (Mps)
ISBN: 1572318937
EAN: 2147483647
Year: 1997
Pages: 168

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net