Question

I am trying to access a device through a COM object in a JAVA interface.

The particular call (as described by the manufacturer) is:

Name: ScanUSB

Parameters: [out] VARIANT* serialNumbers

Use: serialNumbers is a pointer to a VARIANT containing an array of BSTR.

The exact call doesn't matter, but I need to feed it a BSTR array through the Java interface. A VB demo for the COM interface simply does this with the commandlm_Co1.ScanUSB(snNum), with Dim snNum As Object = Nothing. The Items in snNum are then displayed in a dropdown menu.

I am trying to do this with JACOB, as I have had the most luck with communication. This is more or less what I am using:

import com.jacob.com.Variant;
import com.jacob.com.Dispatch;

public class JunoReader {
  public JunoReader() {
    Dispatch oOphirLink = new Dispatch("clsid:{--the id of the device here--}");
    Variant snNum = new Variant();
    Variant testing = Dispatch.call(oOphirLink,"ScanUSB", snNum);
    println(testing);
    }
}

When I run this, everything compiles properly and I can confirm that I am communicating with the device, but all I get back is the null Variant that I put in.

My question is: How can I feed a BSTR array to a COM object through a JAVA interface?

Thanks!

Was it helpful?

Solution

So, one month and zero free time later, I have an answer to my own question and that answer is "Use Python".

Python allows users to access COM objects with the comtypes module, effectively with a single command:

from comtypes.client import CreateObject
target_guid = CreateObject("{TARGET-COM-CLSID-HERE}")

This allows python to talk with whatever the COM object is, so there was none of the trouble that Java was giving me. The single line: target_guid.ScanUSB() produced (u'717610',), the serial number of the target device. Notice that Python has no trouble reading the Unicode produced by the COM object.

The second trick involves Python's COM server, generated with the win32com module. Because the COM servers can be registered to Windows, I don't have to worry about where the dll is located. All I need is the clsid. To build the python COM server, I followed the instructions for a "quick start to server side COM and Python". So what does it all look like?

Python code:

class OphirPyCOM:

    _reg_clsid_ = "{PYTHON-COM-CLSID-HERE}"
    _reg_desc_ = "Python COM server"
    _reg_progid_ = "Python COM server"
    _public_methods_ = [    'Hello', 
                            'ConnectOphir', 
                            'ScanUSB', """More methods here"""
                            ]
    _public_attrs_ = ["""Some public attributes"""]
    _readonly_attrs_ = ["""some read-only attributes"""]

    def __init__(self):
        """some variables declared here"""

    def Hello(self, who):
        """Verifies a connection"""
        return "{PYTHON-COM-CLSID-HERE}" + str(who) 

    def ConnectOphir(self,clsid):
        """Connects to the target COM Object"""
        from comtypes.client import CreateObject
        self.target_guid = CreateObject(clsid)
        return "OphirLMMeasurement object created."

    def ScanUSB(self):
        """Communicates with the target device"""
        self.connected_inst = self.target_guid.ScanUSB()
        for i in range(0,len(self.connected_inst)):
            self.inst_list.append(str(self.connected_inst[i]))
        return self.inst_list

if __name__ == "__main__":
    # use 'python com.py' to register the COM server
    # use 'python com.py --unregister' to unregister it
    print "Registering COM server..."
    import win32com.server.register
    win32com.server.register.UseCommandLine(OphirPyCOM)

We can run that with the command line and get it registered. Then we take the values over to Java with JACOB:

import com.jacob.com.Variant;
import com.jacob.com.Dispatch;

public class JunoReader {

  String pyClsid = "{PYTHON-COM-CLSID-HERE}"; // This is where your python COM clsid goes
  String opClsid = "{TARGET-COM-CLSID-HERE}"; // This is where your ultimate target clsid goes 

  public JunoReader() {
    _pyClsid = "clsid:" + pyClsid
    // This finds the COM object location:
    Dispatch oOphirLink = new Dispatch(_pyClsid);  
  }

  public String HandShake() {
    String _talkBack = "is connected.";
    Variant _handShake = Dispatch.call(oOphirLink,"Hello",_talkBack); // I am trying to look for the Juno...
    return (_handShake.toString());
  }

  public String ConnectOphir() {
    Variant _connectOphir = Dispatch.call(oOphirLink,"ConnectOphir", opClsid); // Connect to the target COM object
    return (_connectOphir.toString());
  }

  public String ScanUSB() {
    Variant _serialNumberList = Dispatch.call(oOphirLink,"ScanUSB"); // This scans the USB ports for devices
    return (_serialNumberList.toString());
  }
}

calling JunoReader.ScanUSB() produces: 717610, exactly like it is supposed to. Implementing the subsequent methods of the manufacturer dll allowed me to read data from this device into a Java applet. Problem solved.

A caveat: you may need to unregister the Python COM every time you change the change the source file and then re-register with a different clsid. Java was having a tough time establishing a connection to the updated code unless I used a new clsid every time I changed the file.

Why did I spend all this time typing this up? Because most of the advice related to reading native data types into Java involved some version of JNI and JNA. I spent weeks trying to get the tutorials to compile and didn't make any progress. On the other hand, I thought of this approach yesterday and can now communicate with my device through Java. The Python COM server provided a simple, straightforward way to interface Java with native applications. No UnsatisfiedLinkErrors, no Can't find librarys, no Classpath and JAVA_HOME issues. I didn't need to learn C or C++ and all the Python tutorials worked as described with no necessary modification.

To summarize, if you are having trouble reading native data types into Java, just set up a Python COM server and let Python's dynamic typing do the work for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top