通过JNA调用COM接口时出现无效内存访问异常
Invalid Memory Access exception when calling COM interface via JNA
我试图找出我在从 JNA 调用 MS AutomationClient COM 控件时遇到的问题。
我已经为整个库创建了一个处理程序:
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;
}
并且我编写了调用 COM 方法的方法(这是一个有效的示例):
public void GetRootElement(PointerByReference elt) {
int result = this._invokeNativeInt(5, new Object[]{this.getPointer(), elt});
COMUtils.checkRC(new WinNT.HRESULT(result));
}
当我调用 CreateAndCondition 方法时,它采用另外 2 个属性,并返回另一个 属性,如下所示:
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));
}
以下代码已尽可能地提取和简化..
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);
我得到以下堆栈跟踪:
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)
我已经为 Delphi 编写了此代码的多个版本和一个使用 com4jna 库的旧版本,但这似乎让我失败了。
那我做错了什么?
提前致谢
更新:我认为问题实际上出在 GetPropertyCondition 的定义中,它采用 Variant(如下所示)。
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));
}
当我在返回的对象上查询接口时,我得到了同样的错误。所以它与通过 COM 编组变体有关。
有几处错误,但调用代码应该更像下面这样:
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);
Variants 是 ByValue 而不是 ByReferece,CreateAndCondition 的输入是 .getValue(),而不是 .getPointer()
我试图找出我在从 JNA 调用 MS AutomationClient COM 控件时遇到的问题。
我已经为整个库创建了一个处理程序:
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;
}
并且我编写了调用 COM 方法的方法(这是一个有效的示例):
public void GetRootElement(PointerByReference elt) {
int result = this._invokeNativeInt(5, new Object[]{this.getPointer(), elt});
COMUtils.checkRC(new WinNT.HRESULT(result));
}
当我调用 CreateAndCondition 方法时,它采用另外 2 个属性,并返回另一个 属性,如下所示:
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));
}
以下代码已尽可能地提取和简化..
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);
我得到以下堆栈跟踪:
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)
我已经为 Delphi 编写了此代码的多个版本和一个使用 com4jna 库的旧版本,但这似乎让我失败了。
那我做错了什么?
提前致谢
更新:我认为问题实际上出在 GetPropertyCondition 的定义中,它采用 Variant(如下所示)。
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));
}
当我在返回的对象上查询接口时,我得到了同样的错误。所以它与通过 COM 编组变体有关。
有几处错误,但调用代码应该更像下面这样:
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);
Variants 是 ByValue 而不是 ByReferece,CreateAndCondition 的输入是 .getValue(),而不是 .getPointer()