I'm integrating in Java with a DLL that allows me to add an instance to be notified.
I have tried several solutions and in none of them was the COM object able to notify me. I suspect that the way I am creating my object, COM is not able to locate it by its GUID.
The DLL has no documentation. I'm trying to integrate it into Java just by looking at an example made in C#. I'll summarize the example code and attach it here.
Could someone save me?
Below is the definition of the object that I use to define my notifiable. This object is created by the DLL itself from another call and so far I have managed to implement it correctly in Java.
C# example:
[Guid("A23FF6FE-1240-436B-A885-000000000000"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INotifier
{
[PreserveSig]
int AddNotifiable([MarshalAs(UnmanagedType.IUnknown)] object a_Notifiable);
[PreserveSig]
int RemoveNotifiable([MarshalAs(UnmanagedType.IUnknown)] object a_Notifiable);
}
My Java class:
@ComInterface(iid = "{A23FF6FE-1240-436B-A885-000000000000}")
public class Notifier extends Unknown {
public Notifier() {
super();
}
public Notifier( Pointer pointer ) {
super( pointer );
}
public int addNotifiable( IUnknown notifiable ) {
return this._invokeNativeInt( 3, new Object[] { this.getPointer(), notifiable } );
}
public int removeNotifiable( IUnknown notifiable ) {
return this._invokeNativeInt( 4, new Object[] { this.getPointer(), notifiable } );
}
}
So far, so good. Now comes the problem, when I add my notifiable, the DLL accepts it but I am not notified at any time.
How notifiable is defined in the C# example:
[Guid("4069843E-7584-4C9A-B167-000000000000"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INotifiable
{
[PreserveSig]
void Event([MarshalAs(UnmanagedType.IUnknown)] object a_Sender);
}
How I defined my notifiable in Java:
@ComInterface(iid = "{4069843E-7584-4C9A-B167-000000000000}")
public class Notifiable extends Unknown {
public Notifiable() {
}
public Notifiable( Pointer pointer ) {
super( pointer );
}
public void Event( final Object sender ) {
System.err.println( "Notifiable.Event Sender: " + sender );
}
}
When I add my notifiable to the notifier, nothing happens. How I did it in Java:
Notifiable myNotifiable = new Notifiable();
// notifier was created by DLL and is a valid object
notifier.addNotifiable( myNotifiable ); // returns OK code
I've already tried creating my notifiable using the Ole32.INSTANCE.CoCreateInstance method, but this DLL is not a DLL registered in the system (and it shouldn't be). I've also tried creating the COM object's VTable manually, and I wasn't successful either.
Here's how I tried to implement it by creating the VTable manually:
@ComInterface(iid = "{4069843E-7584-4C9A-B167-000000000000}")
public class Notifiable implements IUnknownCallback {
public final static IID IID_NOTIFIABLE = new IID( "{4069843E-7584-4C9A-B167-000000000000}" ); //$NON-NLS-1$
private int refCounter = 1;
private final Pointer pointer;
private final Pointer vtable;
private final QueryInterfaceCallback queryInterfaceCallback;
private final AddRefCallback addRefCallback;
private final ReleaseCallback releaseCallback;
private final OnEventCallback onEventCallback;
public Notifiable() {
queryInterfaceCallback = this::QueryInterface;
addRefCallback = this::AddRef;
releaseCallback = this::Release;
onEventCallback = this::Event;
vtable = new Memory( Native.POINTER_SIZE * 4 );
vtable.setPointer( 0 * Native.POINTER_SIZE, CallbackReference.getFunctionPointer( queryInterfaceCallback ) );
vtable.setPointer( 1 * Native.POINTER_SIZE, CallbackReference.getFunctionPointer( addRefCallback ) );
vtable.setPointer( 2 * Native.POINTER_SIZE, CallbackReference.getFunctionPointer( releaseCallback ) );
vtable.setPointer( 3 * Native.POINTER_SIZE, CallbackReference.getFunctionPointer( onEventCallback ) );
pointer = new Memory( Native.POINTER_SIZE );
pointer.setPointer( 0, vtable );
}
@Override
public Pointer getPointer() {
return pointer;
}
@Override
public HRESULT QueryInterface( REFIID refid, PointerByReference ppvObject ) {
if ( null == ppvObject ) {
return new HRESULT( WinError.E_POINTER );
}
if ( refid.getValue().equals( IID_NOTIFIABLE ) ) {
ppvObject.setValue( this.getPointer() );
} else if ( refid.getValue().equals( Unknown.IID_IUNKNOWN ) ) {
ppvObject.setValue( this.getPointer() );
} else {
return new HRESULT( WinError.E_NOINTERFACE );
}
AddRef();
return WinError.S_OK;
}
@Override
public int AddRef() {
return ++refCounter;
}
@Override
public int Release() {
return --refCounter;
}
public void Event( final Object sender ) {
System.err.println( "Notifiable.Event Sender: " + sender );
}
public interface QueryInterfaceCallback extends StdCallLibrary.StdCallCallback {
HRESULT invoke( Guid.REFIID riid, PointerByReference ppvObject );
}
public interface AddRefCallback extends StdCallLibrary.StdCallCallback {
int invoke();
}
public interface ReleaseCallback extends StdCallLibrary.StdCallCallback {
int invoke();
}
public interface OnEventCallback extends StdCallLibrary.StdCallCallback {
void invoke( Pointer val );
}
}
I'm new to dealing with COM objects, could someone tell me where I'm going wrong please?
QueryInterfaceon a class that extendsUnknownTake a look at this test class and see if you can do something similar.