Files
loongoffice/winaccessibility
Michael Weghorn 071b626079 tdf#91739 wina11y: Create AccObject for parent as necessary
In `AccObjectWinManager::InsertAccObj`, when no HWND
was explicitly passed, it is attempted to retrieve the
HWND from the parent's `AccObject`.

If no parent AccObject exists yet, create/insert that
one first.

This fixes the following assert seen when using NVDA's SayAll
feature to read the whole document with sample document mentioned in NVDA
issue [1], also attached as attachment 196385 in tdf#91739
for reference:

    Assertion failed: pIAccessible && "Couldn't retrieve IAccessible object for relation target.", file C:/tools/cygwin/home/user/development/git/libreoffice/winaccessibility/source/UAccCOM/MAccessible.cxx, line 2755

It's also reproducible when manually trying to get the next
flows-to relation target via NVDA's Python console when the
first cell in the table has focus:

    >>> focus.flowsTo

The issue is not reproducible when focus had been in the
second cell before, as an accessible object has already
been created otherwise in that case.

Backtrace:

    1  abort                                   ucrtbase             0x7fff3b72286e
    2  get_wpgmptr                             ucrtbase             0x7fff3b7241b5
    3  wassert                                 ucrtbase             0x7fff3b7244f1
    4  CMAccessible::get_relationTargetsOfType MAccessible.cxx 2755 0x7fff1e028729
    5  NdrSendReceive                          RPCRT4               0x7fff3d4ca2d3
    6  NdrStubCall2                            RPCRT4               0x7fff3d4625a7
    7  CStdStubBuffer_Invoke                   combase              0x7fff3cfbc4ac
    8  RoGetAgileReference                     combase              0x7fff3cf669c3
    9  RoGetAgileReference                     combase              0x7fff3cf6674e
    10 HSTRING_UserSize                        combase              0x7fff3cfbefb6
    11 DllGetClassObject                       combase              0x7fff3cf470b3
    12 CoWaitForMultipleHandles                combase              0x7fff3cf6774d
    13 RoGetActivatableClassRegistration       combase              0x7fff3cf2eb26
    14 CoGetMarshalSizeMax                     combase              0x7fff3cf5cfba
    15 CallWindowProcW                         USER32               0x7fff3ccbef5c
    16 DispatchMessageW                        USER32               0x7fff3ccbe684
    17 ImplSalDispatchMessage                  salinst.cxx     475  0x7ffed452d378
    18 ImplSalYield                            salinst.cxx     552  0x7ffed452da9d
    19 WinSalInstance::DoYield                 salinst.cxx     581  0x7ffed452cfa1
    20 ImplYield                               svapp.cxx       385  0x7ffed78befc4
    21 Application::Yield                      svapp.cxx       474  0x7ffed78c2cd2
    22 Application::Execute                    svapp.cxx       361  0x7ffed78bc656
    23 desktop::Desktop::Main                  app.cxx         1691 0x7ffeecf689b7
    24 ImplSVMain                              svmain.cxx      228  0x7ffed78d3d4c
    25 SVMain                                  svmain.cxx      261  0x7ffed78d45a2
    26 soffice_main                            sofficemain.cxx 121  0x7ffeecfb9064
    27 sal_main                                main.c          51   0x7ff782681013
    28 main                                    main.c          49   0x7ff78268105a
    29 __scrt_common_main_seh                  exe_common.inl  288  0x7ff782681344
    30 BaseThreadInitThunk                     KERNEL32             0x7fff3bb07374
    31 RtlUserThreadStart                      ntdll                0x7fff3d85cc91

[1] https://github.com/nvaccess/nvda/issues/8152#issuecomment-2342167620

Change-Id: I246251f06d1885e0da96600ffc7dd0549854382f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173224
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
2024-09-12 07:07:49 +02:00
..

Windows Accessibility Bridge

This code provides a bridge between our internal Accessibility interfaces (implemented on all visible 'things' in the suite: eg. windows, buttons, entry boxes etc.) - and the Windows MSAA / IAccessible2 COM interfaces that are familiar to windows users and Accessible Technologies (ATs) such as the NVDA screen reader.

The code breaks into three bits:

  • source/service/

    • the UNO service providing the accessibility bridge. It essentially listens to events from the LibreOffice core and creates and synchronises COM peers for our internal accessibility objects when events arrive.
  • source/UAccCom/

    • COM implementations of the MSAA / IAccessible2 interfaces to provide native peers for the accessibility code.
  • source/UAccCOMIDL/

    • COM Interface Definition Language (IDL) for UAccCom.

Here is one way of visualising the code / control flow

VCL <-> UNO toolkit <-> UNO a11y <-> win a11y <-> COM / IAccessible2

vcl/ <-> toolkit/ <-> accessibility/ <-> winaccessibility/ <-> UAccCom/

Threading

It's possible that the UNO components are called from threads other than the main thread, so they have to be synchronized. It would be nice to put the component into a UNO apartment (and the COM components into STA) but UNO would spawn a new thread for it so it's not possible. The COM components also call into the same global AccObjectWinManager as the UNO components do so both have to be synchronized in the same way.

So we use the SolarMutex for all synchronization since anything else would be rather difficult to make work. Unfortunately there is a pre-existing problem in vcl with Win32 Window creation and destruction on non-main threads where a synchronous SendMessage is used while the SolarMutex is locked that can cause deadlocks if the main thread is waiting on the SolarMutex itself at that time and thus not handing the Win32 message; this is easy to trigger with JunitTests but hopefully not by actual end users.

Debugging / Playing with winaccessibility

If NVDA is running when soffice starts, IA2 should be automatically enabled and work as expected. In order to use 'accprobe' to debug it is necessary to override the check for whether an AT (like NVDA) is running; to do that use:

SAL_FORCE_IACCESSIBLE2=1 soffice.exe -writer

Then you can use accprobe to introspect the accessibility hierarchy remotely, checkout:

http://accessibility.linuxfoundation.org/a11yweb/util/accprobe/

But often it's more useful to look at NVDA's text output window.