# Copyright 2000, Phill Wolf.  See README.

# Win32::ActAcc (Active Accessibility) documentation

=head1 NAME

Win32::ActAcc - `Active Accessibility' for task automation, GUI testing

=head1 SYNOPSIS

Win32::ActAcc gives Perl scripts free 
run of the Active Accessibility client API; IAccessible; and ``WinEvents''.

Active Accessibility lets Perl scripts see what's on the screen, even
when programs use ``custom controls'', lightweight (drawn) controls 
that are not technically windows, and the like:  VB for example.  

You'll want to additionally use Win32::GuiTest, and other Win32 modules,
if you want your script to click, type, manipulate the clipboard, etc.

 use Win32::OLE;
 use Win32::ActAcc;
 Win32::OLE->Initialize(); 

 # Start navigating window tree at its root -- the Desktop.
 $accObj = Desktop();
 @childAccObjs = $accObj->AccessibleChildren();

 $name = $accObj->get_accName();
 $rolename = Win32::ActAcc::GetRoleText($accObj->get_accRole());

=head1 DESCRIPTION

=head2 What does it all mean?

Win32::ActAcc broadly parallels the Active Accessibility spec.  

=over 4

=item *

You obtain accessible objects and event streams using the Active Accessibility API, via I<Win32::ActAcc>.

=item *

You manipulate an accessible object using IAccessible, via I<Win32::AO>.

=back 4

This pod doesn't duplicate the Active Accessibility spec.  See L<"SEE ALSO">. 

B<Note to folks already acquainted with Active Accessibility:> 
If you've programmed with Active Accessibility in C, you know first-hand that Active Accessibility was
designed with the convenience of the I<server> programmer in mind, and little
regard for the happiness of the I<client>.  Clients often need not one, but two 
handles to refer to an accessible GUI feature - an IAccessible* and a "child ID".  
Win32::ActAcc wraps that pair of 
handles in a single Perl object representing each accessible GUI feature:  Win32::AO, for Accessible Object.

This manual makes the following notational innovations:

=over 4

=item 1

We preserve the name Microsoft chose for the methods and functions that
come more or less straight out of the Active Accessibility SDK.

=item 2

Active Accessibility has some minor imperfections.  Of course, Win32::ActAcc also has imperfections.
To aid the reader in distinguishing the two, we have taken the liberty of calling out
some "Active Accessibility weirdnesses" as such.

=back 4

=head2 Samples

B<aaDigger.pl> shows how to traverse the tree of accessible objects.

B<aaEvents.pl> shows you the WinEvents that reflect what you're doing with the GUI.

B<aaWhereAmI.pl> shows how to link a pixel location with its accessible object.

eg/B<aaAIMEliza.pl>, at the risk of getting ridiculous, shows how to 
make Chatbot::Eliza respond to your incoming AOL Instant Messages.  AIM is an 
application whose GUI is not made of standard controls, so this is an example
of something you could not do (without constantly doing a File-Save As)
with tools based on the Win32 API, window-classes and window-messages.

See under L<"Tools"> for more about aaDigger, aaEvents, and aaWhereAmI.  

=head2 Active Accessibility client API

The client API exposes jumping-off points like Desktop and AccessibleObjectFromWindow,
and "helper functions" like GetRoleText.  

If this is your first reading, you may want to read about 
Desktop and AccessibleObjectFromWindow in this section,
then skip to L<"Win32::ActAcc::AO">.

=head3 Desktop

Obtain an "accessible object" representing the desktop, so you can call the object's 
Active Accessibility methods:

 $accObj = Desktop();
 die unless 'Win32::ActAcc::AO' eq ref($accObj);

The Desktop is a natural starting-point for traversing the tree of Accessible Objects.

Once you've got an accessible object, see L<"Win32::ActAcc::AO"> on how to use it.

If you do not have a clear picture in mind of the accessible-object "tree" of 
which Desktop is the root, go try out the L<"aaDigger.pl"> tool.  

=head3 AccessibleObjectFromWindow

If you have an HWND, you can convert it to an Accessible Object with AccessibleObjectFromWindow:

 $accObj = AccessibleObjectFromWindow($hwnd);
 die unless 'Win32::ActAcc::AO' eq ref($accObj);

AccessibleObjectFromWindow's optional second parameter defaults to OBJID_WINDOW.  
Win32::ActAcc defines all the OBJID constants for Perl.  (They come from WinAble.h.)
See L<OBJID constants>.

=head3 AccessibleObjectFromPoint

AccessibleObjectFromPoint checks the screen at the specified point and returns
an accessible object representing the interactive item at that location.

 my $accObj = AccessibleObjectFromPoint($x, $y);

Speaking of ($x, $y), how do you figure out where the mouse is?  You can 
subscribe to the WinEvents stream and watch for mouse location-change events.
See sample aaEvents.pl to see how this works.

Not all "accessible" objects are in the Desktop-rooted hierarchy.  Therefore, 
AccessibleObjectFromPoint may be the only way to access some ``accessible'' objects.

=head3 click

 Win32::ActAcc::click($xpix, $ypix, \$eh);

click() "clicks" somewhere on the screen, but first, it
activates the optional event monitor, so you can capture the consequences
of the click.  See L<"activate"> and L<"menuPick">.

You should use Win32::GuiTest for any extensive GUI manipulation.  Win32::ActAcc's "click" method is not 
as flexible.

=head3 GetRoleText

Returns localized name of a role-number.

 my $chRole = Win32::ActAcc::GetRoleText($accObj->get_accRole());

=head3 GetStateText

Returns localized name of a state-number.  

 my $statebit = Win32::ActAcc::STATE_SYSTEM_FOCUSED();
 my $statename = Win32::ActAcc::GetStateText($statebit);

Active Accessibility weirdness note:  States are I<combinations>
of state-bits such as STATE_SYSTEM_FOCUSED (see L<STATE constants>).  
GetStateText returns the name of 
only one of the bits that are set in the argument.
If you want a quick way to get the I<whole> truth about 
I<all> the bits that are set, call L<"GetStateTextComposite"> instead.

=head3 GetStateTextComposite

Returns a localized string of state texts, representing all of the turned-on state
bits in the argument.

 $stateDesc = Win32::ActAcc::GetStateTextComposite( $accObj->get_accState() );

=head3 StateConstantName

Returns the C constant name for a state-bit defined in OleAcc.h (see L<STATE constants>).

=head3 ObjectIdConstantName

Returns the C constant name for an object ID defined in OleAcc.h.

=head3 nav

nav finds a child Accessible Object by following a path from a starting point.
The path specifies the name and/or role of each object along the path.

You can use nav to find the Start button.  Giving undef as the starting point makes
nav begin with the Desktop.

 $btnStart = Win32::ActAcc::nav(Desktop(), [ "{window}", "{window}Start", "{push button}Start" ] );

nav is also useful finding a control on a dialog:

 $accObjOk = Win32::ActAcc::nav($accObjDlg, [ "OK" ]);

=head3 menuPick

menuPick traverses a menu (starting with a menu bar), making a list of choices.
Each choice is a regexp that must match one menu item.
Right before making the final choice, menuPick activates your event monitor,
so you can catch the consequences of the menu choice.

 my $menubar = ...
 my $ehDlg = Win32::ActAcc::createEventMonitor(0);
 menuPick($menubar, +[ qr/Format/, qr/Font/ ], \$ehDlg);
 $ehDlg->waitForEvent(
   +{ 'event'=>Win32::ActAcc::EVENT_SYSTEM_DIALOGSTART() });

(Note:  menuPick is still experimental.  It works with Notepad.)

=head3 CHILDID_SELF and lots of other constants

Use Win32::ActAcc constants as though they were functions:

 die unless (0 == Win32::ActAcc::CHILDID_SELF());

Win32::ActAcc provides the following Active Accessibility constants
in addition to CHILDID_SELF and CCHILDREN_FRAME:

=head4 EVENT constants

=constants ActAcc.xs CONST_TEST\((EVENT_.*)\)

=head4 OBJID constants

=constants ActAcc.xs CONST_TEST\((OBJID_.*)\)

=head4 STATE constants

=constants ActAcc.xs CONST_TEST\((STATE_.*)\)

=head4 ROLE constants

=constants ActAcc.xs CONST_TEST\((ROLE_.*)\)

=head4 SELFLAG constants

=constants ActAcc.xs CONST_TEST\((SELFLAG_.*)\)

=head4 NAVDIR constants

=constants ActAcc.xs CONST_TEST\((NAVDIR_.*)\)

=head2 Win32::ActAcc::AO

IAccessible methods are in the Win32::ActAcc::AO package, so you can use them the
object-oriented way.

=head3 Comparing Accessible Objects

AO's that map to HWNDs can be compared by getting their HWNDs and comparing those.  Since AO's without HWNDs cannot 
be compared, you will want to avoid planning algorithms that depend on comparing accessible objects.

 $h1 = $ao1->WindowFromAccessibleObject();
 $h2 = $ao2->WindowFromAccessibleObject();
 if ($h1 == $h2) { ... }

You generally can't compare two AO objects directly because of the following weirdness.

Active Accessibility weirdness note:  The default Active Accessibility server helper 
built into Windows to represent standard controls 
returns a new object in response to any query.  If an Active Accessibility client requests the same accessible GUI 
feature several times, it gets several different IAccessible* pointers back. 

Win32::ActAcc always uses the same
Perl object for any given IAccessible-and-childID pair, so if you have a stable
server (which you probably don't), you can take advantage in Perl.  

=head3 describe

Produces human-readible (appropriate for debugging) description of an AO. 
Here's an example, with the fields labeled.

 window:emacs: ActAcc.pod {sizeable+moveable+focusable,(4,44,1009,663),id=0,000402e2}
 ^      ^--title/text      ^-- 'state' bits            ^               ^--ID                   
 |                                                     |                    ^-- HWND
 +-role                                                +-(left,top,width,height)

describe() isn't supposed to die.  If something goes wrong, it returns an 
incomplete or empty string.

 print $accObj->describe();

If your script displays the results of describe() to its user, you
might also want to print out describe_meta() at least once.  It names
the fields. 

 print Win32::ActAcc::AO::describe_meta();

=head3 WindowFromAccessibleObject

Reverses L<"AccessibleObjectFromWindow">:  

 $hwnd = $accObj->WindowFromAccessibleObject(); 

If no HWND corresponds to the object, WindowFromAccessibleObject dies, so you might
want to run it inside an eval().

=head3 get_accName

Returns the 'name' property of the accessible object.  
For editable text and combo box objects, it appears 
this is the label Windows supposes the object has: it is usually 
identical to the text of the immediately-preceding text object.
For windows, this is the title.  For client areas, this is 
the same as the title of the enclosing window.

 $name = $accObj->get_accName();

Returns undef if the object doesn't have this property.

=head3 get_accRole

 $role = $accObj->get_accRole();

Returns a number, probably one of the Active Accessibility ROLE_ constants
(see L<ROLE Constants>).  You can convert the number
to a string with Win32::ActAcc::GetRoleText.
Returns undef if the object doesn't have this property.

=head3 AccessibleChildren

 @ch = $accObj->AccessibleChildren();

Returns a list of the accessible objects that are children
of $accObj.  By default it omits the invisible children:
the no-argument form of AccessibleChildren is short for

 @ch = $accObj->AccessibleChildren(Win32::ActAcc::STATE_SYSTEM_INVISIBLE(), 0);

The first parameter is a bit mask with 1's for the bits
that matter as criteria, and the second parameter is the bit values
to find in each of the '1' positions in the mask.  

To find only the invisible
children, you can use:

 @ch = $accObj->AccessibleChildren(
    Win32::ActAcc::STATE_SYSTEM_INVISIBLE(), 
	Win32::ActAcc::STATE_SYSTEM_INVISIBLE());

which means that the INVISIBLE bit should be included in the comparison, and it must be 1.  
See L<STATE constants>.

Active Accessibility weirdness note:  You will probably want to use AccessibleChildren() instead of 
get_accChildCount() and get_accChild().  AccessibleChildren probably calls those
and then improves the results.  But, AccessibleChildren frequently returns fewer
children than get_accChildCount says it should.

Active Accessibility weirdness note:  Some objects report 1 child with AccessibleChildren, yet 
accNavigate reveals more children.  You can work around this problem by calling
L<"NavigableChildren"> instead.  Note that NavigableChildren may have its own drawbacks.

In the Active Accessibility SDK, AccessibleChildren() is part of
the API, not part of IAccessible.

=head3 NavigableChildren

Similar to AccessibleChildren, but uses accNavigate instead.  
Rule of thumb:  Use AccessibleChildren unless it obviously is missing
the children; in that case try NavigableChildren.

 my @ch = $menu->NavigableChildren();

=head3 get_accParent

 $p = $accObj->get_accParent();

Returns the parent object.  Returns undef if the object has no parent.

=head3 get_accState

 $state = $accObj->get_accState();

Returns a number composed of bits defined by the Active Accessibility STATE_ constants
(STATE_SYSTEM_NORMAL, etc.).  See L<"GetStateText"> and <"GetStateTextComposite">.

Returns undef if the object doesn't have this property.

=head3 get_accValue

Returns the 'value' of the accessible object:  the stuff in an editable 
text control, the outline-level of an outline item, etc. 

 $value = $accObj->get_accValue();

Returns undef if the object doesn't have this property.

=head3 accLocation

 my ($left, $top, $width, $height) = $accObj->accLocation();

Returns the accessible object's location on the screen, in pixels.  (0,0) is
at the top left.  Dies if the object doesn't have this property.

=head3 accNavigate

 my $smch = $accObj->accNavigate(Win32::ActAcc::NAVDIR_FIRSTCHILD());
 while (defined($smch))
 {
 	my $n = $smch->get_accName();
 	print STDERR "$n\n";
 	$smch = $smch->accNavigate(Win32::ActAcc::NAVDIR_NEXT());
 }

Returns an Accessible Object representing one of the base object's relations.  
Win32::ActAcc defines the family of NAVDIR constants from OleAcc.h.
See L<NAVDIR constants>.

accNavigate does not move focus, nor perform any other action on behalf of the user.  

=head3 get_accDescription

 $desc = $accObj->get_accDescription();

Returns undef if the object doesn't have this property.
If you're trying to debug your script, L<"describe"> is probably more appropriate,
since it appears most accessible objects don't define their description.  

=head3 get_accHelp

 $help = $accObj->get_accHelp();

Returns undef if the object doesn't have this property.

=head3 get_accDefaultAction

 $da = $accObj->get_accDefaultAction();

Returns undef if the object doesn't have this property.

=head3 get_accKeyboardShortcut

 $ks = $accObj->get_accKeyboardShortcut();

Returns undef if the object doesn't have this property.

=head3 get_accChildCount

 $nch = $accObj->get_accChildCount();

See L<"AccessibleChildren">.

=head3 get_accChild

 $ch = $accObj->get_accChild(3);

See L<"AccessibleChildren">.

=head3 get_accFocus

 $f = $accObj->get_accFocus();

=head3 accDoDefaultAction

 $accObj->accDoDefaultAction();

Active Accessibility weirdness note:  Sometimes doesn't do anything.

=head3 get_itemID

 $plusOrDot = (Win32::ActAcc::CHILDID_SELF() == $ch[$i]->get_itemID()) ? '+' : '.';

get_itemID() returns the item-ID that is part of the identity of the 
accessible object.

=head3 accSelect

 $accObj->accSelect(Win32::ActAcc::SELFLAG_TAKEFOCUS());

See L<SELFLAG constants>.

=head3 click

 $accObj->click(\$eh);

click() "clicks" the center of the accessible object, but first, it
activates the optional event monitor, so you can capture the consequences
of the click.  See L<"activate"> and L<"menuPick">.

=head3 findDescendant

Applies a code-ref or regexp to each child, grand-child, etc.  
In scalar context, returns the first
Accessible Object for which the code-ref returns a true value,
or for which the regexp indicates a match.  In array context, returns 
a list of all matching Accessible Objects.

 $btnClose = $wNotepadApp->findDescendant( 
	sub{	
		my $n = $_->get_accName(); 
		(defined($n) && $n eq "Close") && 
			($_->get_accRole() == Win32::ActAcc::ROLE_SYSTEM_PUSHBUTTON()) 
	});

=head3 Release

 $accObj->Release();

Accessible objects are COM objects, so each one must
be Released when you're done with it.  
Perl's garbage collector and Win32::ActAcc::AO 
conspire to automatically Release the accessible objects, so you should not 
need to call Release in your scripts.

=head2 WinEvents

WinEvents allow a script to keep apprised of windows appearing, disappearing, moving around, and
so forth; and thereby to react to the consequences of an action.  

For example, the
script can press Start and then, by watching the event stream, latch onto the menu that comes up.  

To watch the event stream, call createEventMonitor() and then use the 
EventMonitor's waitForEvent() or getEvent() method.  Refer to the aaEvents sample.

See also L<"Event Details">.

=head3 createEventMonitor

 my $ehDlg = createEventMonitor(1);

createEventMonitor creates a Win32::ActAcc::EventMonitor object,
which the script can poll for WinEvents using waitForEvent() or getEvent().

The "1" means the EventMonitor is immediately activated.  Otherwise
the EventMonitor is latent until activated, which typically happens in
one of two ways:

=over 4

=item *

you call L<"activate">.

=item *

you call a method (like click or L<"menuPick">) that activates the monitor so you
can capture the results of the click.

=back 4

=head3 EventMonitor

Here are the methods on the EventMonitor object you get from createEventMonitor.

=head4 waitForEvent

Sometimes, you want to see I<whether> something happens.  Other times, you I<know>
what will happen, but you want to find out which Accessible Object it happens to.
waitForEvent() meets both needs.

Here's a sample of how to wait (for up to 30 seconds) for a Notepad window to appear.

 $aoNotepad = $eh->waitForEvent(
  +{ 'event'=>Win32::ActAcc::EVENT_OBJECT_SHOW(),
     'name'=>qr/Notepad/,
     'role'=>Win32::ActAcc::ROLE_SYSTEM_WINDOW() }, 30);

waitForEvent blocks the script until a matching event arrives, or the
timeout expires.  The return value is the accessible object of the
winning event, or undef if the timeout expired.  So: You see how the
sample cunningly not only learns I<that> a Notepad windows has
appeared, but actually gets its Accessible Object for later use (such
as to I<close> the window).

You can omit the timeout, in which case waitForEvent waits for a
matching event, which might mean waiting a very long time indeed.

The hash's entries are:

=over 4

=item *

B<event>:  an event constant I<(remember the parentheses--see sample above)>.  See L<EVENT Constants>.

=item *

B<name> (optional): a regexp or string to match the name of the
accessible object of the event.  If it's a string, it must match
exactly--case matters and it must match the entire name.  

=item *

B<role> (optional):  a role constant that must match the accessible object of the event, e.g., Win32::ActAcc::ROLE_SYSTEM_WINDOW().  See L<ROLE Constants>.

=back 4

If your desires don't fit the hash mold, you can give a code-reference
instead.  waitForEvent returns when the code returns any non-undef.
waitForEvent returns what the code returned.

 $eh->waitForEvent(sub{print Win32::ActAcc::Event::evDescribe(@_)."\n";undef}, $secs);

=head4 getEvent

You will usually want to use waitForEvent.  But, just in case, there I<is> a way to 
retrieve one event at a time.

getEvent retrieves an event from the event monitor, or undef if no event is ready. 

The event is a blessed hash (L<"Win32::ActAcc::Event">).

=head4 clear

 $eh->clear();

Erases the backlog of events on the event monitor.

=head4 synch

synch() lets you bookmark an EventMonitor and return later to the bookmarked point.

 $eh1->synch($eh2);

"Synchronizes" $eh1 with $eh2 by setting $eh1's event-buffer cursor to $eh2's, 
so that $eh1->getEvent() will
return the same event as $eh2->getEvent().  synch() can move the monitor forward or backward;
in other words, it can both advance and rewind.  (But, when rewinding, watch out for 
buffer overrun. The spot you rewind to, may have been re-used since the time the event
was written that you think you are rewinding to.)

=head4 isActive

 $a = $eh->isActive();

Returns a true value if the event monitor is active, a false
value if it is latent.

=head4 activate

 $eh->activate(1); # activate
 $eh->activate(0); # deactivate

Activating a monitor makes it "catch up" with all events received so far,
and makes it sensitive to future events.  Activating an already-active
monitor has no effect on it.

Deactivating a monitor makes it useless, until it is reactivated.

=head4 getEventCount

 my $ec = $eh->getEventCount();

Returns a cumulative total number of events caught by the 
event hook installed by Win32::ActAcc.  (All EventMonitor objects
feed from this same event hook.)

=head4 debug_spin

This debug function displays the EventMonitor's events for a certain number of seconds.

 $eh->debug_spin(60);

=head3 Win32::ActAcc::Event

An event is an object of type Win32::ActAcc::Event.  It's a hash with fields
as described in the API documentation:

 event
 hwnd
 idObject
 idChild
 dwmsEventTime

 $e = $eh->getEvent();
 print $$e{'event'} . "\n";

``Event'' is a constant (see L<EVENT Constants>).  You can test it like this:

 next unless Win32::ActAcc::EVENT_OBJECT_VALUECHANGE()==$$e{'event'};

=head4 getAO

 $accObj = $e->getAO();

Returns the accessible object that the event pertains to.  

Active Accessibility weirdness note:  
getAO sometimes dies with an access-violation error.  
You may want to put your calls to getAO into an eval.

=head4 evDescribe

 print $e->evDescribe() . "\n";

Good for debugging - returns some information about the event.

=head3 EventConstantName

Returns the C constant name for a WinEvent number defined in WinAble.h.
See L<EVENT Constants>.

=head3 AccessibleObjectFromEvent

Obtain an "accessible object" from information in a WinEvent.  
(You may prefer to use the object-oriented $e->L<"getAO">() way instead.)

 my $accObj = AccessibleObjectFromEvent($$e{'hwnd'}, $$e{'idObject'}, $$e{'idChild'});

=head3 Event Details

Each Perl process with an active EventMonitor installs an Active
Accessibility "in-proc" event hook that records all events in a
fixed-size circular buffer.  

All of the script's EventMonitor objects cursor through the process' lone
circular buffer.

You will want to tightly bracket the
scope of your EventMonitor objects (or deactivate them 
as soon as they are no longer interesting) since the event hook slows down
your computer slightly and it's a pity to leave an event hook going when you 
don't need it.  

There's no overrun indicator on the circular
buffer, so try to keep your EventMonitors reasonably up-to-date lest
you miss an event.

EventMonitors don't seem to pick up any WinEvents from I<Command Prompt>
windows in Windows 2000.  Perhaps these windows are owned by a process that resists
in-proc event hooks.  Hmm.

Circular buffer size (in events) for this build of ActAcc:

=constants AAEvtMon.h define BUF_CAPY_IN_EVENTS \((5000)\)

=head2 Tools

=head3 aaDigger.pl

aaDigger lets you navigate the hierarchy of accessible objects, 
rooted at the Desktop window.  aaDigger has its own L<manpage|aaDigger>.

When you're planning an Active Accessibility script, aaDigger helps you get your feet
on the ground.

=head3 aaEvents.pl

aaEvents makes a continuous display of your system's WinEvents.  
When you're casting about for clues about which event your
script should be keying to a real-world occurrence, aaEvents 
can help you make up your mind.

=head3 aaWhereAmI.pl

aaWhereAmI continuously describes the accessible object under the cursor at any
given moment.  

Active Accessibility weirdness note:  Not all accessible objects have
a place in the hierarchy that has Desktop at its root.  

=head1 BUGS, LIMITATIONS, AND SHORTCOMINGS

You can't use an "accessible object" with Win32::OLE.  Especially with
Microsoft Office, it would be nice to get a "native object model"
IDispatch* from AccessibleObjectFromWindow, and hand it off to
Win32::OLE to make Office-specific OLE Automation method calls.

There's no overrun indicator on an EventMonitor.  You can't tell it to ignore
mouse-move events - not even redundant or superseded ones.

Win32::ActAcc probably doesn't work multi-threaded.

nav() and findDescendant() should accept the same path arguments.  
And the path notation should provide a dizzying combination of XPath and
regular-expression features.  (For XPath, see http://www.w3.org/TR/xpathZ<>.)

EventMonitors install only in-proc hooks.  Maybe that's why they don't
pick up any events from Command Prompt windows.

Win32::ActAcc doesn't do Unicode.  If you run aaDigger.pl and point it
to the Russian version of Windows Media Player, the text all comes
back as question marks.

=head1 INSTALLATION

=head2 Installation from source code

 perl makefile.pl
 nmake 
 nmake install
 nmake test

Yes, you have to install it before you test it.  Otherwise it can't
find its DLL.  Probably someone will figure out how to fix this.

Prerequisites:

=over 4

=item *

You may need Visual C++ 6.0 SP 4.  The C/C++ part of Win32::ActAcc might not
be portable to other compilers.

=item *

You need the July 2000 "Platform SDK".  
Earlier versions of the Active Accessibility SDK could give problems compiling.

=item *

The test suite requires Notepad.exe on the path.  Also, it requires
Win32::GuiTest.

=item *

The Eliza-AOLInstantMessenger sample requires up-to-date HTML parsing
modules.  It will tell you if yours are missing or out-of-date.

=back 4

=head2 Installation for ActivePerl users (PPM)

ActivePerl users can install Win32::ActAcc using PPM.  

=over 4

=item 1

Unzip the zip (Win32-ActAcc-n.n.zip).  Make sure your unzip
program preserved the directory tree: for example, you should see
Win32-ActAcc.tar.gz in an "x86" subdirectory under the directory that
contains ActAcc.html (the documentation).

=item 2

Open a command prompt window.

=item 3

In the command prompt, "cd" to the directory that contains ActAcc.html.

=item 4

In the command prompt, issue the following command.

 ppm install --location=. Win32-ActAcc

=back 4

To check the installation, you may try aaDigger.pl.  The test suite
(nmake test) doesn't seem to work if you do the ppm installation.

=head2 Files Installed

=over 4

=item *

In bin:  aaDigger.bat and aaDigger.pl, aaEvents.bat and aaEvents.pl, 
aaWhereAmI.bat and aaWhereAmI.pl

=item *

In site\lib\Win32:  aaDigger.pl, aaEvents.pl, aaWhereAmI.pl, ActAcc.pm, ActAcc.pod

=item *

In site\lib\auto\Win32\ActAcc:  ActAcc.dll, ActAccEM.dll

=back 4

=head1 COPYRIGHT

Copyright 2001, Phill Wolf. 

You may use Win32::ActAcc under the terms of the Artistic License, as
specified in the README file of the Perl distribution.

=head1 AUTHOR

Phill Wolf, pbwolf@cpan.org

=head1 SEE ALSO

Active Accessibility documentation.  As of this writing, it is available on 
http://msdn.microsoft.com on the "Libraries" page:

 Platform SDK
  User Interface Services
   Accessibility
    Microsoft Active Accessibility

Win32::OLE

Win32::GuiTest

=cut
