Mmarquee Mmarquee - 4 months ago 80
Java Question

Invalid Memory Access exception when calling COM interface via JNA

I am trying to isolate an issue I have when I am calling the MS AutomationClient COM control from JNA.

I have created a handler for the overall library :

public static UIAutomationHandler create() {
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_APARTMENTTHREADED);
PointerByReference pbr = new PointerByReference();
WinNT.HRESULT hr = Ole32.INSTANCE.CoCreateInstance(
CLSID_CUIAutomation,
null,
WTypes.CLSCTX_SERVER,
IID_IUIAutomation,
pbr);
COMUtils.checkRC(hr);
UIAutomationHandler tb = new UIAutomationHandler(pbr.getValue());
return tb;
}


and I have written methods that call the COM methods (this is an example that works):

public void GetRootElement(PointerByReference elt) {
int result = this._invokeNativeInt(5, new Object[]{this.getPointer(), elt});
COMUtils.checkRC(new WinNT.HRESULT(result));
}


When I call the CreateAndCondition method, which takes 2 other properties, and gives back another property, which looks as follows:

public void CreateAndCondition(Pointer condition0, Pointer condition1, PointerByReference condition) {

int result = this._invokeNativeInt(25, new Object[]{this.getPointer(), condition0, condition1, condition});
COMUtils.checkRC(new WinNT.HRESULT(result));
}


The following code has been extracted and simplified as much as I can ..

PointerByReference pbr0 = new PointerByReference();
PointerByReference pbr1 = new PointerByReference();
PointerByReference pbr = new PointerByReference();

Variant.VARIANT var1 = new Variant.VARIANT.ByReference();
Variant.VARIANT var2 = new Variant.VARIANT.ByReference();

var2.setValue(Variant.VT_INT, ControlType.Window);
var1.setValue(Variant.VT_BSTR, sysAllocated);

this.handler.CreatePropertyCondition(PropertyID.Name.getValue(), var1, pbr0);
this.handler.CreatePropertyCondition(PropertyID.ControlType.getValue(), var2, pbr1);
this.handler.CreateAndCondition(pbr0.getPointer(), pbr1.getPointer(), pbr);


I get the following stack trace:

Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:386)
at com.sun.jna.Function.invoke(Function.java:321)
at com.sun.jna.Function.invoke(Function.java:276)
at com.sun.jna.Function.invoke(Function.java:267)
at com.sun.jna.Function.invokeInt(Function.java:674)
at com.sun.jna.platform.win32.COM.COMInvoker._invokeNativeInt(COMInvoker.java:27)
at mmarquee.automation.uiautomation.impl.UIAutomationHandler.CreateAndCondition(UIAutomationHandler.java:82)
at mmarquee.automation.UIAutomation.getDesktopWindow(UIAutomation.java:205)
at mmarquee.automation.TestMainWPF.run(TestMainWPF.java:57)
at mmarquee.automation.MainWPF.main(MainWPF.java:23)


I have written versions of this code for Delphi and an old version that used the com4jna library, but this seems to have me defeated.

So what am I doing wrong ?

Thanks in advance

UPDATE: I believe that the problem is actually in the definition of the GetPropertyCondition, which takes a Variant (as below).

public void CreatePropertyCondition(int propertyId, Variant.VARIANT value, PointerByReference elt) {
int result = this._invokeNativeInt(UIA_CREATE_PROPERTY_CONDITION, new Object[]{this.getPointer(), propertyId, value, elt});
COMUtils.checkRC(new WinNT.HRESULT(result));
}


When I QueryInterface on the returned object, then I get the same error. So it something to do with marshalling the variant via COM.

Answer

Several things were wrong, but the calling code should look more like the following:

Variant.VARIANT.ByValue var1 = new Variant.VARIANT.ByValue();
Variant.VARIANT.ByValue var2 = new Variant.VARIANT.ByValue();

var2.setValue(Variant.VT_INT, ControlType.Window);
var1.setValue(Variant.VT_BSTR, sysAllocated);

this.handler.CreatePropertyCondition(PropertyID.Name.getValue(), var1, pbr0);
this.handler.CreatePropertyCondition(PropertyID.ControlType.getValue(), var2, pbr1);
this.handler.CreateAndCondition(pbr0.getValue(), pbr1.getValue(), pbr);

With the Variants being ByValue rather than ByReferece, and input to CreateAndCondition being .getValue(), rather than .getPointer()