Skip to main content
Some of the objects in ABBYY FineReader Engine are so-called “connectable objects.” This means that they implement the IConnectionPointContainer interface. Connectable objects support communication between ABBYY FineReader Engine and its clients.
In Linux , the Engine object loaded as an out-of-process server does not support working with callbacks.
For Windows users, each of the FRE connectable objects provides connection points of two types — one that uses a dispatch interface and one that uses the interface derived from IUnknown. The dispatch interface is designed for automatic use in Visual Basic and similar environments, while the vtbl-based interface is suitable for use in C++.
In the table below, you can find the list of connectable objects in ABBYY FineReader Engine and corresponding callback interfaces (dispinterfaces):
Dispinterfaces are Windows-specific.
ObjectCallback Interface (Dispinterface)
FRDocumentIFRDocumentEvents (DIFRDocumentEvents)
FRPagesIFRPagesEvents (DIFRPagesEvents)
FRPageIFRPageEvents (DIFRPageEvents)
ImageDocumentIImageDocumentEvents (DIImageDocumentEvents)
Windows Visual Components ABBYY FineReader Engine client application that wants to receive notifications of certain events in ABBYY FineReader Engine should implement interfaces of a specific type and “advise” the objects implementing these interfaces to the corresponding connectable objects.
There are two global methods used for connecting and disconnecting to the notification source:
HRESULT AdviseFREngineObject( IUnknown* object, IUnknown* callback, DWORD* cookie );
HRESULT UnAdviseFREngineObject( IUnknown* object, DWORD cookie );
class CFRDocumentCallback: public IFRDocumentEvents {
public:
...
    // Provide IUnknown methods simple implementation
    ULONG STDMETHODCALLTYPE AddRef() { return 1; }
    ULONG STDMETHODCALLTYPE Release() { return 1; }
    HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void** ppObject )
    {
        if( ppObject == 0 ) {
            return E_POINTER;
        }
    *ppObject = 0;
    if( riid == IID_IUnknown || riid == IID_IFRDocumentEvents )
    {
        *ppObject = this;
        AddRef();
        return S_OK;
    } else {
        return E_NOINTERFACE;
    }
}
// Provide IFRDocumentEvents methods implementation
HRESULT STDMETHODCALLTYPE OnProgress(
IFRDocument* sender, int percentage, VARIANT_BOOL* cancel );
HRESULT STDMETHODCALLTYPE OnWarning(
IFRDocument* sender, int index, BSTR tip, VARIANT_BOOL* cancel );
HRESULT STDMETHODCALLTYPE OnPageProcessed(
    IFRDocument* sender, int index, PageProcessingStageEnum stage ) { return S_OK; }
};
// Suppose that we have already received the FRDocument object
IFRDocument* document;
// Create callback object
CFRDocumentCallback callbackObject;
// Advise listener to the notifications source
DWORD cookie; // A variable to store the cookie returned from the Advise method
AdviseFREngineObject( frDocument, &callbackObject, &cookie );
// Process the document
...
// After notification, the listener is no longer needed and should be unadvised
UnadviseFREngineObject( frDocument, cookie );
These methods should receive one of the connectable objects as the object argument and the corresponding callback interface as the callback argument.You need to implement the necessary interface and “advise” object implementing the interface to the corresponding connectable objects. We will use the FRDocument object as an example.
  1. Implement the IFRDocumentEvents interface. As it is derived from the IUnknown interface, the client object should also implement the IUnknown methods:
  2. Then the CFRDocumentCallback class can be used to receive notifications from the FRDocument object. Advise this object to the notifications source (error handling is omitted):
Linux users can also refer to the EventsHandling sample.
The remainder of this topic applies to users of FRE for Windows.
For Windows:
Simply declare the connectable object WithEvents and implement the methods of the corresponding callback interface. You will also need to explicitly specify the event handler associated with the event.For the FRDocument object, the procedure will be the following:
  1. Declare the FRDocument object WithEvents:
Private WithEvents document As FREngine.FRDocument
Private Sub document_RecognitionOnProgress(ByVal sender As FREngine.FRDocument, _
                                           ByVal Percentage As Integer, _
                                           ByRef cancel As Boolean)
...
End Sub
Private Sub document_RecognitionOnProgress(ByVal sender As FREngine.FRDocument, _
                                           ByVal Percentage As Integer, _
                                           ByRef cancel As Boolean) Handles document.OnProgress
...
End Sub
document = Engine.CreateFRDocument
document.AddImageFile("D:\Demo.tif")
AddHandler document.OnProgress, AddressOf Me.document_RecognitionOnProgress
document.Process()
RemoveHandler document.OnProgress, AddressOf Me.document_RecognitionOnProgress
or simply use the FRDocument object for processing if you define the event handling methods with Handles keyword:
document = Engine.CreateFRDocument
document.AddImageFile("D:\Demo.tif")
document.Process()
  1. Implement the necessary methods of the DIFRDocumentEvents dispinterface in the Sub similar to the following.
If you want to start and stop event handling at any time during program execution (using AddHandler and RemoveHandler statements):or simply specify that this procedure handles a particular event (use the Handles keyword when defining):
  1. Connect the implemented event handler to the event source, use the FRDocument object for processing, then disconnect the handler:
In C++, you need to implement the necessary interface, obtain a connection point, and “advise” object implementing the interface to the corresponding connectable objects. We will use the FRDocument object as an example.
  1. Implement the IFRDocumentEvents interface. As it is derived from the IUnknown interface, the client object should also implement the IUnknown methods:
class CFRDocumentEventsListener : public IFRDocumentEvents {
public:
...
    // Provide IUnknown methods simple implementation. They may also be
    // implemented by inheritance from some standard class with COM support
    ULONG AddRef();
    ULONG Release();
    HRESULT QueryInterface(REFIID riid, void** ppvObject)
    {
        if( ppvObject == 0 )
            return E_INVALIDARG;
        if( riid == __uuidof(IFRDocumentEvents) ) {
            *ppvObject = static_cast<IFRDocumentEvents*>( this );
        } else if( riid == IID_IUnknown ) {
            *ppvObject = static_cast<IUnknown*>( this );
        } else {
            *ppvObject = 0;
            return E_NOINTERFACE;
        }
        AddRef();
        return S_OK;
    }
    // Provide IFRDocumentEvents methods implementation
 HRESULT STDMETHODCALLTYPE OnProgress(
  IFRDocument* sender, int percentage, VARIANT_BOOL* cancel );
 HRESULT STDMETHODCALLTYPE OnWarning(
  IFRDocument* sender, int index, BSTR tip, VARIANT_BOOL* cancel );
 HRESULT STDMETHODCALLTYPE OnPageProcessed(
  IFRDocument* sender, int index, PageProcessingStageEnum stage ) { return S_OK; }
};
// Suppose that we have already received the FRDocument object
IFRDocument* document;
// Query for IConnectionPointContainer on the FRDocument object
IConnectionPointContainer* pContainer=0;
document->QueryInterface(IID_IConnectionPointContainer, (void**)&pContainer);
// Obtain a pointer to the IConnectionPoint interface on a connection point within the connectable object
IConnectionPoint* pPoint=0;
pContainer->FindConnectionPoint(__uuidof(IFRDocumentEvents),
                                &pPoint);
// Establish a connection between the CFRDocumentEventsListener class and the connection point
CFRDocumentEventsListener listener;
IUnknown* listenerUnknown=0;
listener.QueryInterface(IID_IUnknown, (void**)&listenerUnknown);
// Advise listener to the notifications source
DWORD cookie; // A variable to store the cookie returned from the IConnectionPoint::Advise method
pPoint->Advise(listenerUnknown, &cookie);
// Process the document
...
// After notification, the listener is no longer needed and should be unadvised
pPoint->Unadvise(cookie);
  1. Then the CFRDocumentEventsListener class can be used to receive notifications from the FRDocument object. Advise this object to the notifications source (error handling is omitted):
C# procedure is similar to that of Visual Basic .NET. You need to implement the necessary methods of the callback interface and connect the implemented event handlers to the event source. We will use the FRDocument object as an example.
  1. Implement the necessary methods of the IFRDocumentEvents interface:
private void document_RecognitionOnProgress(FREngine.IFRDocument sender, int Percentage, ref bool cancel)
{
 ...
}
FREngine.DIFRDocumentEvents_OnProgressEventHandler recognizeOnProgressHandler =
 new FREngine.DIFRDocumentEvents_OnProgressEventHandler(
 document_RecognitionOnProgress );
document.OnProgress += recognizeOnProgressHandler;
document.Process( null, null, null );
document.OnProgress -= recognizeOnProgressHandler;
  1. Connect the event handler to the event source, use the FRDocument object for processing, then disconnect the handler:
Windows users should refer to documentation on COM for a more detailed description of connectable objects. You can also refer to the EventsHandling sample provided in FRE for Linux for C++ and Windows for C#, C++ with the Native COM Support, raw C++, Visual Basic .NET.