How to correctly consume custom com library via JNA platform

474 views
Skip to first unread message

zhu kane

unread,
Apr 17, 2017, 4:15:37 AM4/17/17
to Java Native Access
I managed to generated the Java interface and typeinfo for my custom COM library via using TlbCodeGenerator.

The interface looks like below,

/**
 * <p>uuid({B51E098D-D13C-449F-AA5B-087D0AE3A1FD})</p>
 */
@ComInterface(iid="{B51E098D-D13C-449F-AA5B-087D0AE3A1FD}")
public interface IDataProvider extends IUnknown, IRawDispatchHandle, IDispatch {
    /**
     * GetDumpStr all the data
     *
     * <p>id(0x1)</p>
     * <p>vtableId(7)</p>
     */
    @ComMethod(name = "GetDumpStr", dispId = 0x1)
    String GetDumpStr();
            
    /**
     * <p>id(0x2)</p>
     * <p>vtableId(8)</p>
     * @param key [in] {@code String}
     */
    @ComMethod(name = "GetDataByKey", dispId = 0x2)
    IDataStore GetDataByKey(String key);
            
    /**
     * <p>id(0x3)</p>
     * <p>vtableId(9)</p>
     */
    @ComMethod(name = "GetTableRowCnt", dispId = 0x3)
    Character GetTableRowCnt();
            
    /**
     * <p>id(0x5)</p>
     * <p>vtableId(10)</p>
     * @param strImgPath [in] {@code String}
     */
    @ComMethod(name = "ProcessImg", dispId = 0x5)
    String ProcessImg(String strImgPath);
            
    /**
     * <p>id(0x7)</p>
     * <p>vtableId(11)</p>
     * @param wsDir [in] {@code String}
     */
    @ComMethod(name = "SetDefsTopDir", dispId = 0x7)
    Boolean SetDefsTopDir(String wsDir);
            
    /**
     * <p>id(0x8)</p>
     * <p>vtableId(12)</p>
     */
    @ComMethod(name = "GetImgOptimized", dispId = 0x8)
    Long GetImgOptimized();
            
    /**
     * <p>id(0x9)</p>
     * <p>vtableId(13)</p>
     * @param hBitmap [in] {@code Long}
     */
    @ComMethod(name = "ProcessImg2", dispId = 0x9)
    String ProcessImg2(Long hBitmap);
            
    /**
     * <p>id(0xa)</p>
     * <p>vtableId(14)</p>
     * @param strImgPath [in] {@code String}
     */
    @ComMethod(name = "GetImgType", dispId = 0xa)
    String GetImgType(String strImgPath);
            
    
}

I'm trying to consume the COM library via JNA platform like below(I'm copying the code from Word example of JNA),

public static void main(String[] args){
        Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_APARTMENTTHREADED);
        Factory factory = new Factory();
        DataProvider ocrlibrary = factory.createObject(DataProvider.class);
        System.out.println(
                ocrlibrary.ProcessImg("https://myserver.com/7d0aa90d-03ef-4c4f-84fe-ab8b02f1c302.jpg"));

    }

But I always got below timeout exception when consuming my COM library,

Exception in thread "main" java.lang.RuntimeException: java.util.concurrent.TimeoutException
at com.sun.jna.platform.win32.COM.util.Factory.runInComThread(Factory.java:172)
at com.sun.jna.platform.win32.COM.util.Factory.createObject(Factory.java:151)
at JNATest.main(JNATest.java:27)
Caused by: java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:205)
at com.sun.jna.platform.win32.COM.util.ComThread.execute(ComThread.java:157)
at com.sun.jna.platform.win32.COM.util.Factory.runInComThread(Factory.java:170)
... 2 more

When I changed Ole32.COINIT_APARTMENTTHREADED to Ole32.COINIT_MULTITHREADED, I got COMException thrown by Windows.

Caused by: com.sun.jna.platform.win32.COM.COMException: 发生意外。(HRESULT: 80020009) (puArgErr=0)
at com.sun.jna.platform.win32.COM.COMUtils.checkRC(COMUtils.java:131)
at com.sun.jna.platform.win32.COM.util.ProxyObject.oleMethod(ProxyObject.java:657)
at com.sun.jna.platform.win32.COM.util.ProxyObject.invokeMethod(ProxyObject.java:401)
at com.sun.jna.platform.win32.COM.util.ProxyObject.invoke(ProxyObject.java:247)
at com.sun.proxy.$Proxy5.ProcessImg(Unknown Source)

I'm not sure whether my app correctly consumes COM library. Any suggestion is appreciated.

Matthias Bläsing

unread,
Apr 17, 2017, 7:31:26 AM4/17/17
to jna-...@googlegroups.com
Hey,

Am Montag, den 17.04.2017, 01:15 -0700 schrieb zhu kane:
> I managed to generated the Java interface and typeinfo for my custom COM library via using TlbCodeGenerator.
>
> The interface looks like below,
>
> [IFACE Description]
>
> I'm trying to consume the COM library via JNA platform like below(I'm copying the code from Word example of JNA),
>
> public static void main(String[] args){
>         Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_APARTMENTTHREADED);
>         Factory factory = new Factory();
>         DataProvider ocrlibrary = factory.createObject(DataProvider.class);
>         System.out.println(
>                 ocrlibrary.ProcessImg("https://myserver.com/7d0aa90d-03ef-4c4f-84fe-ab8b02f1c302.jpg"));
>
>     }
>
> But I always got below timeout exception when consuming my COM library,
>
> Exception in thread "main" java.lang.RuntimeException: java.util.concurrent.TimeoutException
> at com.sun.jna.platform.win32.COM.util.Factory.runInComThread(Factory.java:172)
> at com.sun.jna.platform.win32.COM.util.Factory.createObject(Factory.java:151)
> at JNATest.main(JNATest.java:27)
> Caused by: java.util.concurrent.TimeoutException
> at java.util.concurrent.FutureTask.get(FutureTask.java:205)
> at com.sun.jna.platform.win32.COM.util.ComThread.execute(ComThread.java:157)
> at com.sun.jna.platform.win32.COM.util.Factory.runInComThread(Factory.java:170)
> ... 2 more
>

how long does processing take normally? The
com.sun.jna.platform.win32.COM.util.Factory uses a separate thread to
run the calls and that thread also imposes an upper limit of execution
time. By default the timeout is 5000ms. You can adjust that by
instanciating your Factory with your own ComThread like so (here 30s,
30000 ms):

Factory factory = new Factory(new ComThread("COM Thread", 30000, new
Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                // do something intelligent
            }
        }));

This will still run the code as Multithreaded.

In your sample the CoInitializeEx is unnessary, as the ComThread exists
to make exaktly unnessary. You can try this:

public static void main(String[] args){
        Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
        ObjectFactory factory = new ObjectFactory();
        DataProvider ocrlibrary = factory.createObject(DataProvider.class);
        System.out.println(ocrlibrary.ProcessImg("https://myserver.com/7d0aa90d-03ef-4c4f-84fe-ab8b02f1c302.jpg"));
}

Can you offer access to the library you are using?

Greetings

Matthias

zhu kane

unread,
Apr 18, 2017, 4:39:32 AM4/18/17
to jna-...@googlegroups.com
Matthias, thanks for your replying.

I'm fine to share the library, but the library depends on third party OCR library which always communicates with license server when creating object. The windows error would be thrown if there is no valid license server available.

I still see the same error using above suggested code sample.
Also the CoInitializeEx must be called prior to creating object, otherwise below error was thrown.

Exception in thread "main" com.sun.jna.platform.win32.COM.COMException: not call CoInitialize。(HRESULT: 800401f0) (puArgErr=)
at com.sun.jna.platform.win32.COM.COMUtils.checkRC(COMUtils.java:131)
at com.sun.jna.platform.win32.COM.COMUtils.checkRC(COMUtils.java:108)
at com.sun.jna.platform.win32.COM.util.ObjectFactory.createObject(ObjectFactory.java:116)

The same library can be used in Python like below,

ret = GetModule(tlbPath)
from comtypes.gen import iCountingFlexiCaptureLib
ocrLibrary = CreateObject(iCountingFlexiCaptureLib.DataProvider)

Any further suggestion to make it work with JNA.

Thanks.

--
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/2MiE-jScLdI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jna-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matthias Bläsing

unread,
Apr 18, 2017, 1:15:01 PM4/18/17
to jna-...@googlegroups.com
Hey,

Am Dienstag, den 18.04.2017, 16:38 +0800 schrieb zhu kane:
> I still see the same error using above suggested code sample.
> Also the CoInitializeEx must be called prior to creating object,
> otherwise below error was thrown.

If you use Factory, CoInitializeEx is called for you on the thread,
that will execute your call. There is no reason to initalize COM
outside that thread, in this case.

If you use the ObjectFactory, you have to initialize COM on the thread
your yourself.

Please run this code:

public static void main(String[] args){
         Ole32.INSTANCE.CoInitializeEx(Pointer.NULL, Ole32.COINIT_MULTITHREADED);
         ObjectFactory factory = new ObjectFactory();
         DataProvider ocrlibrary = factory.createObject(DataProvider.class);
         System.out.println(ocrlibrary.ProcessImg("https://myserver.com/7d0aa90d-03ef-4c4f-84fe-ab8b02f1c302.jpg"));
}

Attach the java file you create and the resulting full(!) stacktrace, if you get an exception.

Matthias
Reply all
Reply to author
Forward
0 new messages