New Generic Sink Approach

The current implementation of GenericSink has type conversion short comings. GenericSink is used when we want COM objects to send events to java. The mechanism jSegue uses tries to make COM ConnectionPoint sinks appear to java as listeners. On the native side jSegue uses a C++ class named GenericSink. GenericSink implements the IDispatch COM interface. When IDispatch::Invoke is called GenericSink tries to find the right java method to call, then it tries to convert the native arguments (which are all VARIANTs) to java types. Finally, it calls the java method.

The current release of jSegue is the start of a new architecture where we move the lookup of the java method to call to the java side. From the native side we always call ComObject.Invoke and let that method find the right java method to call. This allows more flexibility on the java side including implementing a generic sink that overrides ComObject.Invoke and potentially handles the call without calling a java interface method created by tlb2java.

The main motivation for this change is that the current parameter conversion code in GenericSink fails to handle some of the more complicated VARIANT types. For example, a VT_BYREF | VT_BOOL causes the type conversion routines to return an error. jSegue has code that can convert from VT_BYREF | VT_BOOL to boolean[], but this code is not used by GenericSink, which uses an older set of conversion routines.

For now, the old GenericSink mechanism is the default. However, if you pass a ComObject subclass as a sink, jSegue will use the new mechanism. That is, it will convert from VARIANT to the correct java type for each parameter. Then we call ComObject.Invoke passing the array of converted parameters. The order is in the same order as the parameters are declared, COM passes the arguments in reverse order. jSegue maps the named parameters to their positional equivalents.

This much is now working and both the old and new methods co-exist for now. The advantage of the new approach is that we use the Reverse COM VARIANT to java type support, which handles more types of VARIANTs. The type conversion in GenericSink was not shared with the Reverse COM conversion and does not handle as many types of VARIANTs.

This release of ComObject.Invoke does not contain the java code required to lookup the right java method and call it with java reflection. That should be in a forth coming release. The main remaining work is to do some java to java type conversions. For example, a VARIANT only has types for IUnknown and IDispatch. So, we need to convert from IDispatch to IFoo in some cases. Also, a VARIANT wraps a VT_BYREF on the java side by setting the reference property (getReference/setReference). But, the original type information may have used an array of size one. So, this level of type conversion needs to look for a mismatch between the java type and the target java type of the method and try to convert. In the case of a VT_BYREF ComObject.Invoke will get called with a VARIANT, but the target java type may be an array. By calling VARIANT.getReference we will have an array which we can then use to call the target method.