COM.IUnknown.QueryInterface on 32 bit JVM

131 views
Skip to first unread message

David Akehurst

unread,
Feb 23, 2015, 8:25:31 AM2/23/15
to jna-...@googlegroups.com
OK,

so this one really has me scratching my head.

Simple bit of code,

    public static void main(String[] args) {
        HRESULT hr = Ole32.INSTANCE.CoInitialize(null);
        COMUtils.checkRC(hr);
       
        // Get CLSID for Word.Application...
        CLSID.ByReference clsid = new CLSID.ByReference();
        hr = Ole32.INSTANCE.CLSIDFromProgID("Word.Application", clsid);
        COMUtils.checkRC(hr);

        PointerByReference pUnknown = new PointerByReference();
        hr = Ole32.INSTANCE.CoCreateInstance(clsid, null, WTypes.CLSCTX_SERVER, IUnknown.IID_IUNKNOWN, pUnknown);
        COMUtils.checkRC(hr);
        Unknown unk = new Unknown(pUnknown.getValue());
       
        PointerByReference ppvObject = new PointerByReference();
        IID iid = IUnknown.IID_IUNKNOWN;
        REFIID.ByValue ri = new REFIID.ByValue(iid);
        hr = unk.QueryInterface(ri, ppvObject);
        COMUtils.checkRC(hr);
    }


Works fine on a 64 bit JVM on Windows 7 (64 bit OS).

If I run the same code on 32 bit JVM (Java 7 jdk) on Windows 7 (64 bit os), I get an error from COM when executing the 'QueryInterface' call at the end.

If I change the signature (or rather add a different temporary method QueryInterface2) to take a REFIID.ByReference insteead of a REFIID.ByValue,
the 32 bit version works, and the 64 bit version seems to work, although the new signature breaks if used in other places (i.e. the callback code).

Any clues as to what is going on here would be gratefully received.
The C++ signature is "QueryInterface(REFIID riid,void * *ppvObject)"
 where REFIID is "#define REFIID const IID &"
IID is a typedef of GUID, which in turn is a struct.

Daniel Doubrovkine

unread,
Feb 23, 2015, 10:20:32 AM2/23/15
to jna-...@googlegroups.com
What error do you get from QueryInterface? E_NOINTERFACE, E_POINTER or something else?

Does CoInitializeEx with different threading model change anything to this picture?

What's CLSCTX_SERVER? I know of REMOTE_SERVER and INPROC_SERVER :)


--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

David Akehurst

unread,
Feb 23, 2015, 10:39:15 AM2/23/15
to jna-...@googlegroups.com
Error message is

 com.sun.jna.platform.win32.COM.COMException: The parameter is incorrect. 

using CLSCTX_INPROC_SERVER or CLSCTX_REMOTE_SERVER give 'Class not registered' as the error.
(which may well indicate that the problem is about COM not registering things for 64 and 32 bit, I will investigate this, thanks)


changing the threading model has no effect.





--
You received this message because you are subscribed to a topic in the Google Groups "Java Native Access" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jna-users/NhxBAGdNcH0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jna-users+...@googlegroups.com.

David Akehurst

unread,
Feb 23, 2015, 10:50:36 AM2/23/15
to jna-...@googlegroups.com
using CLSCTX_INPROC_SERVER or CLSCTX_REMOTE_SERVER give 'Class not registered' as the error.
but the error occurs at the 'CoCreateInstance' call.

using CLSCTX_LOCAL_SERVER, gives the same error.

Timothy Wall

unread,
Feb 23, 2015, 9:17:42 PM2/23/15
to jna-...@googlegroups.com
If REFIID is “const IID &”, then it needs to be a pointer type.

Lauri W Ahonen

unread,
Feb 24, 2015, 1:55:57 AM2/24/15
to jna-...@googlegroups.com
Hi,

I have QueryInterface working as follows, just using Guid.GUID instead of REFIID

Guid.GUID IID_IAccessible = new Guid.GUID("618736e0-3c3d-11cf-810c-00aa00389b71");
PointerByReference childp = new PointerByReference();
result = iUnk.QueryInterface(new Guid.GUID.ByReference(IID_IAccessible), childp);
if (result == 0) {
Oleacc.IAccessible accessible = PointerToIAccessible(childp);
..
    accessible.Release();
}

public static Oleacc.IAccessible PointerToIAccessible(final PointerByReference ptr) {
    final Pointer interfacePointer = ptr.getValue();
final Pointer vTablePointer = interfacePointer.getPointer(0);
final Pointer[] vTable = new Pointer[27]; // Just counted through the number of functions in the interface spec
vTablePointer.read(0, vTable, 0, 27);
return new Oleacc.IAccessible() {

public int QueryInterface(Guid riid, PointerByReference ppvObject) {
Function f = Function.getFunction(vTable[0], Function.ALT_CONVENTION); // Index here comes from COM interface
return f.invokeInt(new Object[]{interfacePointer, riid, ppvObject});
}

public int Release() {
Function f = Function.getFunction(vTable[2], Function.ALT_CONVENTION);
return f.invokeInt(new Object[]{interfacePointer});
}
        ...
        ...
        ...

Timothy Wall

unread,
Feb 24, 2015, 6:57:42 AM2/24/15
to jna-...@googlegroups.com
Thanks for the feedback. The reason that GUID[.ByReference] works is that you’re using a pointer type.

Note that the .ByReference in this case is superfluous, since struct arguments are taken to be by reference by default for parameters and return values.

The reason why REFIID.ByValue may work under 64-bit is that sometimes the calling conventions for a struct passed by value or by reference are the same and only differ in the actual pointer passed to the callee. By-value calls usually allocate a temporary struct, populate it, then pass its address to the callee.
Reply all
Reply to author
Forward
0 new messages