Does Clarion have UIA/MSAA support for LIST/DROP controls?

We are working on accessibility compliance (WCAG/Section 508) for a Clarion 11.0 app (Clarion Template chain) we sell to government clients. Our LIST and DROP controls show up in Inspect.exe as a blank “pane” (UIA_PaneControlTypeId, no name) — the native class is ClaDrop_09560000H, which isn’t a standard Windows control class, so screen readers like NVDA read nothing when they hit it.

Has anyone run into this and found a fix? Specifically:

  • Does a newer Clarion version/patch add native UIA or MSAA support for these controls?
  • Has anyone built a custom accessibility wrapper (WM_GETOBJECT / IAccessible) for ClaList/ClaDrop windows they could point me to?

We have ~500 of these controls across the app, so a runtime-level or template-level fix would save us a lot of pain. Any pointers appreciated.

Inspect.exe is showing a dropdown as two window controls.

Other window/control inspector type have pickers so the drop down part is never seen.

I also found the .net WPF framework iirc (one of the .net frameworks at least) also hid all controls and their text using spy/inspector tools so it wasnt possible to extract data from apps.

Best example of this behaviour is using a spy/inspector tool on the new windows settings (gear icon) (old control panel) for win10+.

ControlSpy2 shows you how the standard win32 api controls work with different styles.

The Clarion dropdown list isnt a std win32 api ComboBox or ComboBoxEx control so you’ll need to do a bit more digging to get the data out of the control.

Have you tried a clarion combobox in Inspect.exe to see if it works the same way as a clarion drop down list ie two parts no text to extract or like a std win32 api combobox control?

Hi

So firstly, all versions of clarion have the same owner drawn controls.

I set Claude to work on this issue to judge how well it could work with a complex problem. I haven’t got Claude to write the template wrappers around this, but the following solution and code works in narrator for a LIST control, I presume it would be easy to convert to others.

NaratorTest.zip (7.7 KB)

You may need to unblock the zip after downloading.

Feel free to use the code as you please (No support provided :smiley: ). Shout if you are having any issues compiling.

Mark

UPDATE: I have created a repository for this so others can have a look at the code easily rather than downloading the zip: clarion-accessible-list

Since Clarion 11.13505 there is an undocumented PROP to get a &QUEUE of the LIST FROM(Q) that was added for AnyScreen.

This can have a bad value so I protect it with code like this that checks for a String FROM or a VLB that return bad values that would GPF:

  MAP
ListFromQProp   PROCEDURE(LONG ListFEQ),LONG    !New 11.13505 LIST FROM() &Queue as a NUMBER to &=()
   ...
ListFromQProp   PROCEDURE(LONG ListFEQ) ! wrap code to get 7A23h &Queue to protect from GPF
FromQ LONG
FromP LONG
PROP:FromPtr  EQUATE(7A0EH) !ABLLIST.INT &= IMappedListContents ? 0800xxxxH usually, 7C98h also an II ptr?
PROP:FromQRef EQUATE(7A23H) !Showed up in 13505 = &QUEUE unless no FROM(Q) then ?= Interface for WB see 0800xxxxh
  CODE
  IF ~ListFEQ{PROP:From} AND ListFEQ{PROP:VLBval}=0 THEN    !From('Text') or VLB &A23h would return a pointer that GPFs 
     FromQ=ListFEQ{PROP:FromQRef}                           !The New 11.13505 Property of LIST for FROM(Q)
     IF FromQ=08004FF0h THEN FromQ=0.                       !If No From(Q) RTL {7A23h}=08004FF0h always ????
     IF FromQ THEN 
        FromP=ListFEQ{PROP:FromPtr} 
        IF ABS(FromQ-FromP)<7FFFh THEN FromQ=0. !HACK - Interface pointer?  not From(Q), can't use this.
     END                                        !       This would only happen with No FROM() at all.
     IF FromQ>0 AND FromQ<=4096 THEN FromQ=0.   !Null Pointer memory region
  END
  RETURN FromQ

Another way that would work in all versions is to use a Template to define a ?List{'Prop_FromQ'} user defined property with the Queue address to QRef &= (QAddress). That calls the below procedure for all LIST’s in the APP.

CBListPropFromQ PROCEDURE(LONG FEQ,*QUEUE FrmQ,<STRING NameQ>)
Ref GROUP,AUTO
Q    &QUEUE
L    LONG,OVER(Q)   !FYI probably better to use INSTANCE(Q,Thread)
  END
  CODE
  Ref.Q &=FrmQ 
  FEQ{'FromQ'}=Ref.L 
  FEQ{'FromWho'}=CHOOSE(~OMITTED(NameQ),NameQ,'Queue' & Ref.L)
  RETURN

Clarion Folders is an example that uses this property:

Window Preview Class uses that PROP to show any LIST and Queue at runtime.

Thanks Carl,

I hadn’t appreciated the undocumented PROP, however, not all users are on this version of clarion, so I’m not sure it’s useful with the code written.

Mark

Mark, thanks this is great. However, I was not able to incorporate it into a multi-dll APP. I was trying to just put it into one of the .app DLLs. Maybe some of this stuff needs to be put into the .exe app and/or the data DLL? I tried moving the call to OleInitialize(0) to various spots. The program crashes without any warning message when OleInitialize(0) is called.

Hi Rich,

You will need to export the SVCom code from your data dll, so add

_svLinkMode_=>1;_svDllMode_=>1

to the conditional compilation symbols there, then in every other app that uses the code

_svLinkMode_=>0;_svDllMode_=>1

Note I haven’t tested in multidll but this should then work as SVCOM.INC is an ABC defined class, but just needs the switches above.

HTH
Mark