【发布时间】:2021-08-26 04:52:57
【问题描述】:
我正在使用 JNA 访问以下COM API。我创建了这个类,它映射了 API 的“IMGApplication”接口和一些方法
public class IMGApplication extends Dispatch {
private static final GUID IID_IMGApplication = new GUID("5FD5D92B-A4B6-4B32-AC3D-A6FF7AE83CD8");
public IMGApplication() {
}
private IMGApplication(Pointer pvInstance) {
super(pvInstance);
}
public static IMGApplication create(CLSID.ByReference clsIdByRef) {
try {
PointerByReference pointerByRef = new PointerByReference();
HRESULT hres = Ole32.INSTANCE.CoCreateInstance(clsIdByRef, null, WTypes.CLSCTX_INPROC_SERVER, IID_IMGApplication, pointerByRef);
if (COMUtils.SUCCEEDED(hres)) {
return new IMGApplication(pointerByRef.getValue());
} else {
return null;
}
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
public void minimize() {
try {
HRESULT hres = (HRESULT)this._invokeNativeObject(8, new Object[]{this.getPointer()}, HRESULT.class);
COMUtils.checkRC(hres);
} catch(Exception e) {
e.printStackTrace();
}
}
public void maximize() {
try {
HRESULT hres = (HRESULT)this._invokeNativeObject(9, new Object[]{this.getPointer()}, HRESULT.class);
COMUtils.checkRC(hres);
} catch(Exception e) {
e.printStackTrace();
}
}
public void setPosition(long x, long y, long width, long height) {
try {
HRESULT hres = (HRESULT)this._invokeNativeObject(11, new Object[]{this.getPointer(), new NativeLong(x), new NativeLong(y), new NativeLong(width), new NativeLong(height)}, HRESULT.class);
COMUtils.checkRC(hres);
} catch(Exception e) {
e.printStackTrace();
}
}
public void shutdownMG() {
try {
HRESULT hres = (HRESULT)this._invokeNativeObject(12, new Object[]{this.getPointer()}, HRESULT.class);
COMUtils.checkRC(hres);
} catch(Exception e) {
e.printStackTrace();
}
}
public void startMG(int startMode) {
try {
HRESULT hres = (HRESULT)this._invokeNativeObject(20, new Object[]{this.getPointer(), startMode}, HRESULT.class);
COMUtils.checkRC(hres);
} catch(Exception e) {
e.printStackTrace();
}
}
}
还有 Main(它是一个 Lotus Notes Java 代理)
public class JavaAgent extends lotus.domino.AgentBase {
public void NotesMain() {
private boolean comWasInitialized = false;
try {
if(!COMUtils.comIsInitialized()) {
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_APARTMENTTHREADED);
} else {
comWasInitialized = true;
}
CLSID.ByReference clsIdRef = new CLSID.ByReference();
HRESULT hRes = Ole32.INSTANCE.CLSIDFromProgID("mgAPI.mg_API", clsIdRef);
COMUtils.checkRC(hRes);
IMGApplication ComIMGApplication = IMGApplication.create(clsIdRef);
ComIMGApplication.startMG(0); //<--- Works
ComIMGApplication.maximize(); //<--- Invalid Memory Access exception
ComIMGApplication.minimize(); //<--- Invalid Memory Access exception
ComIMGApplication.shutdownMG(); //<--- Invalid Memory Access exception
ComIMGApplication.Release();
} catch(Exception e) {
e.printStackTrace();
} finally {
if(comWasInitialized == false) {
if(COMUtils.comIsInitialized()) {
Ole32.INSTANCE.CoUninitialize();
}
}
}
}
}
我已经使用 OLE/COM 对象查看器检查了 COM API。 “IMGApplication”接口扩展IDispatch和IUnknown。
所以它有来自IUnknown的3个方法QueryInterface、AddRef、Release和来自IDispatch的4个方法GetTypeInfoCount、GetTypeInfo、GetIDsOfNames、Invoke。
“IMGApplication”接口中第一个方法(BringToFront())的vtblId必须在索引7处,最后一个在索引21处。
不幸的是,唯一有效的方法是startMG() (vtblId 20)。在所有其他方法上,我得到“无效的内存访问异常”。
【问题讨论】:
-
documentation for StartMG 状态为
Mode参数:目前您只能使用定义为mgAPI::esmStandard = 0的EMGStartMode "esmStandard"。你正在通过 1。 -
可能不相关,但可能是一个问题,您正在有条件地初始化 COM,但总是取消初始化它,即使它已经在其他地方初始化。仅当您成功初始化后才取消初始化。同样不相关,您应该扩展
Dispatch而不是Unknown。这不会影响您看到的错误。 -
StartMG调用的返回值是多少?是INVALID_MODE(-1610350590) 吗?如果是这样,您可能还没有真正开始它。 -
MGStarted() 的文档说您应该等待它成功启动,然后再传递其他 API 请求。您可能处于竞争状态,试图在它完成初始化之前最大化它。
-
ComIMGApplication.startMG(1)是一个错字。在我的程序中,我将 0 作为参数传递(我已在上面的代码中更正了它)。startMG(0)工作正常。当我调用它时,程序正在启动。当然,我不会一个接一个地调用所有函数。在我的示例代码中,我只想展示哪些方法有效,哪些无效。问题是,在程序完全启动并初始化后,maximize()或minimize()等其他方法都不起作用。我得到“无效的内存访问异常”。错误。谢谢!!