[Accessibility-ia2] registering a proxy dll
mick at kulgan.net
Wed Mar 19 06:58:09 PDT 2008
For a long while now, I have been aware of a limitation of IAccessible2,
when used in a portable situation with an out-of-process AT. For
example: where either the AT is on a usb key, or both the AT and the
application are on a USB key. In this example USB key is really talking
about the fact that the product is not installed on the system, it could
be on a read-only drive, and it may have very limited user privilages.
both NVDA and Accessibility Probe are examples of out-of-process ATs.
When asking for an IAccessible2 object from an application over a
process boundary, a IA2 proxy dll must be registered in order for the OS
to understand how to martial the information. Up until now both NVDA
developers and Accessibility Probe developers were under the impression
that you have to register the IAccessible2 dll in the registry using
regsvr32. And of course to do this, you probably need elevated user
privilages which usually means doing this at install time.
However, thanks to a particular person on the IA2 panel at CSUN, I now
have a much clearer idea on how to solve this issue.
The steps to make an interface usable with out registering the dll are
*Load the DLL library in to the process with something like LoadLibrary
*Look up the DllGetClassObject function in this dll with GetProcAddress.
*Call the DllGetClassObject function giving it IID_IAccessible2,
IID_IUnknown, and a pointer to an IUnknown (which will receive the newly
instanciated class object).
This class object is a class factory which can create all the
*Call CoRegisterClassObject, giving it IID_IAccessible2, the IUnknown
you got from DllGetClassObject, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE,
and a pointer to a long (where a special registration cooky can be
stored for later use). This step lets your process know about this class
object. All requests to create IAccessible2 interfaces will go to this
*Finally call CoRegisterPSClsid for each of the IAccessible2 interface
IIDs, and IID_IAccessible2. This step tells your process that for any of
these IIDs, use the class object that was registered under the IID of
There is another step, that you need to perform once you are finnished
with IAccessible2 (probably when your process is about to terminate) and
*Call CoRevokeClassObject, giving it that registration cooky you got
from CoRegisterClassObject. This unregisters the class object from your
process, and also makes sure it gets cleaned up etc.
However, all these steps must be executed in each apartment that needs
to access or create IAccessible2 objects. So this means that the steps
need to be performed both in the AT and in the application.
This also indirectly means that the IA2 proxy dll must not only be
included with the AT, but also included with the application as well.
I have been trying to work out a way so that the application does not
need to perform these steps, but I don't think it is possible. It seems
both the AT and the application must understand the martialling
techniques for all the interfaces.
Here is a bit of c++ code which clearly shows how to make IA2 work in a
I do strongly believe it is important for ATs such as NVDA to be able to
access IAccessible2 applications (such as Firefox3) even if NVDA is run
off a USB key. Blind and vision impaired people are wanting a truely
portable screen reader more and more, so they can simply go up to any
computer (whether it be at a university or a friend's house or perhaps a
net cafe, and wack in their USB key and be able to use the system). NVDA
is fully portable except for IAcessible2 support.
As I have also noted, this does also effect Accessibility probe, which
currently needs you to manually register actf-ia2.dll before you can
view IAccessible2 objects.
We have two options about how to move forward in making sure that
out-of-process ATs can use IAccessible2 portably:
1. The AT sets up IA2 support in its own process, and the application
also sets up IA2 support in its own process (example: NVDA, and
Firefox3). This means two copies of the dll, and a change of code to
both NVDA and Firefox3.
2. The AT sets up IA2 support in its own process, but then injects a
small bit of code in to the application, which sets up IA2 support in
the application, for the application. This means there only needs to be
one copy of the dll, and no change needs to be made to the application.
However the code that the AT uses to force IA2 to be set up in the
application could be more complex than it needs to be, plus its another
lot of injection that doesn't really have to happen. Note that for any
process the AT wants to access, it must first inject and set up IA2,
before it can then in its own process access IA2 from the application.
In my opinion this is rather inefficient and a lot more work than it has
to be. However I can also see how changes to applications can also be
I have tested the IA2 setup code in both NVDA, and by injection,
firefox3, and the code definitely works; ia2 dll does not have to be
registered. However I must point out that the change I made to NVDA was
very hackish, and it rode on the back of some virtualBuffer code, so I
only got IA2 support when NVDA rendered documents. My point is that
although I know the method works, I would certainly be happyer seeing
each application set up IA2 itself.
I think this is an issue we need to talk about in great detail.
Many people have asked me why does NVDA not totally go in-process (which
would fix the IA2 issue). The answer is: we may one day. But if we do it
would be such a massive change that the project would not be called
NVDA, it would also no longer be written in Python. But, the fact still
remains that not just NVDA is affected by this problem.
What are peoples thoughts on this issue?
Does anyone know of any ways we can improve the code, or completely
remove the need for the application having to setup IA2 in its own process?
Pete Brunet wrote:
> Mick, I couldn't find anything like CoRegisterPS or CoRegisterProxyStub
> that Glen mentioned during the IA2 panel.
> I found DllRegisterServer and the REGISTER_PROXY_DLL macro but haven't
> taken the time to read the docs to get a feel for if that would be of
> any help.
> I also wonder if you can just directly add keys to the registry using
> RegCreateKeyEx, RegSetValueEx, RegCloseKey?
> I also wonder about the proxy DLL. I searched the registry with regedit
> and found one entry
> where the key name is (Default) and the value is
> C:\WINDOWS\system32\IAccessible2Proxy.dll and the GUID in the key name
> is the one for IAccessibleHyperLink. But why don't I see the GUIDs for
> all the other interfaces?
> Do you know of a tool that could inspect the proxy DLL and dump out the
> interface names, method names, and method signatures?
> *Pete Brunet*
> IBM Accessibility Architecture and Development
> 11501 Burnet Road, MS 9022E004, Austin, TX 78758
> Voice: (512) 838-4594, Cell: (512) 689-4155
> Ionosphere: WS4G
More information about the Accessibility-ia2