VARIANT[] array corruption occures by calling Oleacc -> AccessibleChildren method

89 views
Skip to first unread message

j r

unread,
Mar 9, 2015, 11:11:17 AM3/9/15
to jna-...@googlegroups.com
By calling the calling AccessibleChildren for an IAccessible interface i get a corrupted array of VARIANTs



My code is like 

       
        WinNT.HRESULT hr;
       
long childCount;
       
LongByReference returnCount = new LongByReference();

       
if (pAcc == null) {
           
return new WinNT.HRESULT(-1);
       
}
        childCount
= pAcc.getAccChildCount();

       
if (childCount  == 0) {
           
return new WinNT.HRESULT(-1);
       
}

       
Variant.VARIANT tableRef = new Variant.VARIANT();
//more info [Array-of-Structure Arguments] http://twall.github.io/jna/4.1.0/overview-summary.html#varargs
        hr
= Oleacc.INSTANCE.AccessibleChildren(pAcc.getIAccessiblePointer(), 0L, childCount, tableRef, returnCount);

       
if (COMUtils.FAILED(hr)) {
           
return hr;
       
}

       
Variant.VARIANT[] pArray = (Variant.VARIANT[])tableRef.toArray((int)childCount);


While the code throws no error and hr shows always  S_OK the pArray contains corrupted elements if there is an IDispatch element. 
Is there any way to get all IAccessible children in VARIANT?
Looks like VARIANT implementation has a bug?

Lauri W Ahonen

unread,
Mar 10, 2015, 4:50:05 AM3/10/15
to jna-...@googlegroups.com
Hi,

I remember trying to figure out why the VARIANT is broken, and ended up whipping together a minimum viable variant of my own. This snipped should get you started.

pointerVariant.ByValue varTmp = new pointerVariant.ByValue();
Memory variants = new Memory(childCount * varTmp.size());
result = Oleacc.INSTANCE.AccessibleChildren(accessible.getInterface(), 0, childCount, variants, received);
if (result != 0)
    // Deal with err
int receivedChildren = received.getValue();
for (int i = 0; i < receivedChildren; i++) {
    WinStructs.pointerVariant.ByValue v = new WinStructs.pointerVariant.ByValue(variants.share(i * size));

    v.read();

    if (v.vt == VT_DISPATCH) {

        Pointer pointer = v.trustme;

        PointerByReference dispatch = new PointerByReference(pointer);

        Oleacc.IDispatch idi = PointerToIDispatch(dispatch);

        PointerByReference childp = new PointerByReference();

        result = idi.QueryInterface(new Guid.GUID.ByReference(IID_IAccessible), childp);

        if (result == 0) {

           Oleacc.IAccessible accessible1 = PointerToIAccessible(childp);

            ...
            accessible1.Release();

       } else {

            // no interface, handle error somehow
        }

   }
    if (v.vt == VT_I4) {
     // Not all children have an interface
     String childName = accessible.getChildName(v);
     ..
    }

}

    public static class pointerVariant extends Structure {
        public short vt;
        public short wReserved1;
        public short wReserved2;
        public short wReserved3;
        public Pointer trustme;
        public Pointer trustme2;

        public pointerVariant() {
            super();
            setAlignType(Structure.ALIGN_MSVC);
        }

        protected List<String> getFieldOrder() {
            return Arrays.asList(new String[]{"vt", "wReserved1", "wReserved2", "wReserved3", "trustme", "trustme2"});
        }

        public static class ByValue extends pointerVariant implements
                Structure.ByValue {

            public ByValue(Pointer pointer) {
                super(pointer);
            }

            public ByValue() {
                super();
            }
        }

        public pointerVariant(Pointer memory) {
            super(memory);
            setAlignType(Structure.ALIGN_MSVC);
        }
    }

Lauri W Ahonen

unread,
Mar 10, 2015, 4:51:17 AM3/10/15
to jna-...@googlegroups.com

By gods Google ate my formatting. Sorry about that!

Timothy Wall

unread,
Mar 11, 2015, 5:01:06 AM3/11/15
to jna-...@googlegroups.com
Could you please provide this as a PR with an associated unit test?

Thanks
T.
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

L Will Ahonen

unread,
Mar 15, 2015, 9:54:57 PM3/15/15
to jna-...@googlegroups.com
Hi Tim,

I decided to fix the original code instead of creating a PR of the workaround. Check out https://github.com/lwahonen/jna/commit/2d75dca56cc54e9007c5219840f44c7a5ae5f71b

I couldn't figure out how to fix the ByReference[] code, but after the fix ByValue[] calls no longer crash with 

java.lang.IndexOutOfBoundsException: Bounds exceeds available space : size=8, offset=16
at com.sun.jna.Memory.boundsCheck(Memory.java:203)
at com.sun.jna.Memory.share(Memory.java:131)
at com.sun.jna.Structure.toArray(Structure.java:1434)
at com.sun.jna.Function.convertArgument(Function.java:601)
at com.sun.jna.Function.invoke(Function.java:298)
at com.sun.jna.Function.invoke(Function.java:268)
at com.sun.jna.StructureTest.testByValueArray(StructureTest.java:1977)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)

I didn't create a PR yet, as I want to have that workaround removed too.

Cheers,
Will
Reply all
Reply to author
Forward
0 new messages