OK, so I think I'm going to need some advice about how the callback mechanism works.
What I have read about JNA callbacks implies that they occur on their own thread, however, in what I am doing, the thread is not visible in the Java debugger, and they appear to occur on the main thread.
I will explain what I am trying to achieve.
To get a callback event from a COM object we have to make a COM call ConnectionPoint::Advise(IUnknown* pUnkSink, DWORD* pdwCookie).
Using JNA, I can get a ConnectionPoint object, and can call this method.
The pointer to an IUnknown object, pUnkSink, is an object that will be called back by the COM object with event notifications.
In reality one can pass a pointer to an IDispatch object (which inherits from IUnknown) and this same object is used to handle the event callbacks.
I can construct the equivalent of a C++ object, in C, by using a struct with a vtable pointer to function pointers.
I appear to be able to do this using JNA also, (see code below).
The IUnknown methods ("QueryInterface", "AddRef", "Release") are all successfully calledback as part of the initial Advise call (on the same thread according to the Java debugger),
however, at the end of the sequence of QueryInterface calls that are made, Word appears to 'hang' as though its main thread is busy.
The Java program is happy to continue, however, it of course doesn't get any events, because Word is "on hold".
When the Java program exits, Word happily continues with no issue.
I can replicate the same program using C/C++, including artificial construction of the IDispatch object using structs.
Everything works fine, but the calls to QueryInterface (after Advise), appear to be on different threads,
and COM events are successfully received - on a different thread.
Any help or explanation about callback threads or anything else gratefully received :-)
DispatchListerner and Vtable "Structures" shown below:
public class DispatchListener extends Structure {
public DispatchListener(IDispatchCallback callback) {
this.vtbl = this.constructVTable();
this.initVTable(callback);
super.write();
}
public DispatchVTable.ByReference vtbl;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "vtbl" });
}
protected DispatchVTable.ByReference constructVTable() {
return new DispatchVTable.ByReference();
}
protected void initVTable(final IDispatchCallback callback) {
this.vtbl.QueryInterfaceCallback = new DispatchVTable.QueryInterfaceCallback() {
@Override
public HRESULT invoke(Pointer thisPointer, REFIID.ByValue refid, PointerByReference ppvObject) {
return callback.QueryInterface(refid, ppvObject);
}
};
this.vtbl.AddRefCallback = new DispatchVTable.AddRefCallback() {
@Override
public int invoke(Pointer thisPointer) {
return callback.AddRef();
}
};
this.vtbl.ReleaseCallback = new DispatchVTable.ReleaseCallback() {
@Override
public int invoke(Pointer thisPointer) {
return callback.Release();
}
};
this.vtbl.GetTypeInfoCountCallback = new DispatchVTable.GetTypeInfoCountCallback() {
@Override
public HRESULT invoke(Pointer thisPointer, UINTByReference pctinfo) {
return callback.GetTypeInfoCount(pctinfo);
}
};
this.vtbl.GetTypeInfoCallback = new DispatchVTable.GetTypeInfoCallback() {
@Override
public HRESULT invoke(Pointer thisPointer, UINT iTInfo, LCID lcid, PointerByReference ppTInfo) {
return callback.GetTypeInfo(iTInfo, lcid, ppTInfo);
}
};
this.vtbl.GetIDsOfNamesCallback = new DispatchVTable.GetIDsOfNamesCallback() {
@Override
public HRESULT invoke(Pointer thisPointer, REFIID.ByValue riid, WString[] rgszNames, int cNames, LCID lcid,
DISPIDByReference rgDispId) {
return callback.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
}
};
this.vtbl.InvokeCallback = new DispatchVTable.InvokeCallback() {
@Override
public HRESULT invoke(Pointer thisPointer, DISPID dispIdMember, REFIID.ByValue riid, LCID lcid, WORD wFlags,
DISPPARAMS.ByReference pDispParams, VARIANT.ByReference pVarResult, EXCEPINFO.ByReference pExcepInfo,
IntByReference puArgErr) {
return callback.Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}
};
}
}
public class DispatchVTable extends Structure {
public static class ByReference extends DispatchVTable implements Structure.ByReference {
}
public QueryInterfaceCallback QueryInterfaceCallback;
public AddRefCallback AddRefCallback;
public ReleaseCallback ReleaseCallback;
public GetTypeInfoCountCallback GetTypeInfoCountCallback;
public GetTypeInfoCallback GetTypeInfoCallback;
public GetIDsOfNamesCallback GetIDsOfNamesCallback;
public InvokeCallback InvokeCallback;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "QueryInterfaceCallback", "AddRefCallback", "ReleaseCallback","GetTypeInfoCountCallback", "GetTypeInfoCallback",
"GetIDsOfNamesCallback", "InvokeCallback" });
}
public static interface QueryInterfaceCallback extends StdCallLibrary.StdCallCallback {
WinNT.HRESULT invoke(Pointer thisPointer, REFIID.ByValue refid, PointerByReference ppvObject);
}
public static interface AddRefCallback extends StdCallLibrary.StdCallCallback {
int invoke(Pointer thisPointer);
}
public static interface ReleaseCallback extends StdCallLibrary.StdCallCallback {
int invoke(Pointer thisPointer);
}
public static interface GetTypeInfoCountCallback extends StdCallLibrary.StdCallCallback {
WinNT.HRESULT invoke(Pointer thisPointer, UINTByReference pctinfo);
}
public static interface GetTypeInfoCallback extends StdCallLibrary.StdCallCallback {
WinNT.HRESULT invoke(Pointer thisPointer, UINT iTInfo, LCID lcid, PointerByReference ppTInfo);
}
public static interface GetIDsOfNamesCallback extends StdCallLibrary.StdCallCallback {
WinNT.HRESULT invoke(Pointer thisPointer, REFIID.ByValue riid, WString[] rgszNames, int cNames, LCID lcid,
DISPIDByReference rgDispId);
}
public static interface InvokeCallback extends StdCallLibrary.StdCallCallback {
WinNT.HRESULT invoke(Pointer thisPointer, DISPID dispIdMember, REFIID.ByValue riid, LCID lcid, WORD wFlags,
DISPPARAMS.ByReference pDispParams, VARIANT.ByReference pVarResult, EXCEPINFO.ByReference pExcepInfo,
IntByReference puArgErr);
}
}