Reputation: 31
I am using JNA to access the following COM API. I have created this class which maps the " IMGApplication" interface of the API and some of the methods
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();
}
}
}
And the Main (it is a Lotus Notes Java Agent)
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();
}
}
}
}
}
I have checked the COM API with the OLE/COM Object Viewer. The "IMGApplication" interface extends IDispatch
and IUnknown
.
So it has the 3 methods QueryInterface
, AddRef
, Release
from IUnknown
and the 4 methods GetTypeInfoCount
, GetTypeInfo
, GetIDsOfNames
, Invoke
from IDispatch
.
The vtblId
of the first method (BringToFront()
) in the "IMGApplication" interface has to be at index 7 and the last at index 21.
Unfortunately the only method that is working is startMG()
(vtblId
20). On all the other methods i get the "Invalid Memory Access exception".
Upvotes: 1
Views: 190
Reputation: 31
I think I just found the cause of the problem (thanks to the hint from Daniel with initializing). As soon as a Lotus Notes Agent is done running and is terminated, all instances are lost of course. Every when I start the Agent again it is creating a new instance of the "mgAPI.mg_API".
CLSID.ByReference clsIdRef = new CLSID.ByReference();
HRESULT hRes = Ole32.INSTANCE.CLSIDFromProgID("mgAPI.mg_API", clsIdRef);
COMUtils.checkRC(hRes);
HRESULT hres = Ole32.INSTANCE.CoCreateInstance(clsIdByRef, null, WTypes.CLSCTX_INPROC_SERVER, IID_IMGApplication, pointerByRefDispatch);
if (COMUtils.SUCCEEDED(hres)) {
return new IMGApplication(pointerByRefDispatch.getValue());
} else {
return null;
}
And of course i can not call any method other than startMG(0)
, because in this instance the program is not running yet. That's why i got the "Invalid Memory Access exception"....
I tried this and it works, exactly as it should.
if(!COMUtils.comIsInitialized()) {
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
} else {
comWasInitialized = true;
}
CLSID.ByReference clsIdRef = new CLSID.ByReference();
HRESULT hRes = Ole32.INSTANCE.CLSIDFromProgID("mgAPI.mg_API", clsIdRef);
COMUtils.checkRC(hRes);
PointerByReference pointerByRefUnknown = new PointerByReference();
HRESULT hres = OleAuto.INSTANCE.GetActiveObject(clsIdRef, null, pointerByRefUnknown);
IMGApplication ComIMGApplication = IMGApplication.create(clsIdRef);
ComIMGApplication.startMG(0);
TimeUnit.SECONDS.sleep(30);
ComIMGApplication.minimize();
ComIMGApplication.shutdownMG();
Now I have to find out how to get an instance of the program if it is already running.
I tried it with OleAuto.INSTANCE.GetActiveObject
but it did not work.
if(!COM.COMUtils.comIsInitialized()) {
Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
}
CLSID.ByReference clsIdRef = new CLSID.ByReference();
HRESULT hRes = Ole32.INSTANCE.CLSIDFromProgID("mgAPI.mg_API", clsIdRef);
COMUtils.checkRC(hRes);
PointerByReference pointerByRefUnknown = new PointerByReference();
HRESULT hres = OleAuto.INSTANCE.GetActiveObject(clsIdRef, null, pointerByRefUnknown);
Upvotes: 1