Mmarquee Mmarquee - 1 year ago 179
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 Source

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()