跳转到主要内容
ABBYY FineReader Engine 中的某些对象被称为”可连接对象”。这意味着它们实现了 IConnectionPointContainer 接口。可连接对象支持 ABBYY FineReader Engine 与其客户端之间的通信。
在 Linux 中,以进程外服务器方式加载的 Engine 对象不支持使用回调。
对于 Windows 用户,每个 FRE 可连接对象提供两种类型的连接点——一种使用调度接口,另一种使用派生自 IUnknown 的接口。调度接口专为在 Visual Basic 及类似环境中自动调用而设计,而基于 vtbl 的接口则适合在 C++ 中使用。
下表列出了 ABBYY FineReader Engine 中的可连接对象及其对应的回调接口 (调度接口) :
调度接口 (Dispinterface) 为 Windows 专用。
对象回调接口 (调度接口)
FRDocumentIFRDocumentEvents (DIFRDocumentEvents)
FRPagesIFRPagesEvents (DIFRPagesEvents)
FRPageIFRPageEvents (DIFRPageEvents)
ImageDocumentIImageDocumentEvents (DIImageDocumentEvents)
Windows Visual Components 若 ABBYY FineReader Engine 客户端应用程序需要接收 ABBYY FineReader Engine 中特定事件的通知,则需实现特定类型的接口,并将实现这些接口的对象”注册”到相应的可连接对象上。
有两个全局方法用于连接和断开通知源:
HRESULT AdviseFREngineObject( IUnknown* object, IUnknown* callback, DWORD* cookie );
HRESULT UnAdviseFREngineObject( IUnknown* object, DWORD cookie );
class CFRDocumentCallback: public IFRDocumentEvents {
public:
...
    // 提供 IUnknown 方法的简单实现
    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;
    }
}
// 提供 IFRDocumentEvents 方法的实现
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; }
};
// 假设我们已经获取了 FRDocument 对象
IFRDocument* document;
// 创建回调对象
CFRDocumentCallback callbackObject;
// 将监听器注册到通知源
DWORD cookie; // 用于存储 Advise 方法返回的 cookie 的变量
AdviseFREngineObject( frDocument, &callbackObject, &cookie );
// 处理文档
...
// 通知完成后,监听器不再需要,应取消注册
UnadviseFREngineObject( frDocument, cookie );
这些方法需要将某个可连接对象作为 object 参数传入,并将相应的回调接口作为 callback 参数传入。您需要实现必要的接口,并将实现该接口的对象”注册”到相应的可连接对象。下面以 FRDocument 对象为例进行说明。
  1. 实现 IFRDocumentEvents 接口。由于该接口派生自 IUnknown 接口,客户端对象还需实现 IUnknown 方法:
  2. 之后,可使用 CFRDocumentCallback 类接收来自 FRDocument 对象的通知。将此对象注册到通知源 (错误处理已省略) :
Linux 用户还可参考 EventsHandling 示例。
本主题的其余内容适用于 FRE for Windows 的用户。
适用于 Windows:
只需使用 WithEvents 声明可连接对象,并实现相应回调接口的方法,同时还需显式指定与事件关联的事件处理程序。对于 FRDocument 对象,操作步骤如下:
  1. 使用 WithEvents 声明 FRDocument 对象:
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. 在 Sub 中实现 DIFRDocumentEvents 调度接口的必要方法,示例如下。
如果您希望在程序执行期间随时启动和停止事件处理 (使用 AddHandler 和 RemoveHandler 语句) :或者直接指定该过程处理特定事件 (在定义时使用 Handles 关键字) :
  1. 将已实现的事件处理程序连接到事件源,使用 FRDocument 对象执行处理,然后断开处理程序:
在 C++ 中,您需要实现必要的接口,获取连接点,并将实现该接口的对象”注册”到相应的可连接对象。以下以 FRDocument 对象为例进行说明。
  1. 实现 IFRDocumentEvents 接口。由于该接口派生自 IUnknown 接口,客户端对象还需实现 IUnknown 方法:
class CFRDocumentEventsListener : public IFRDocumentEvents {
public:
...
    // 提供 IUnknown 方法的简单实现。也可以通过继承某个支持 COM 的标准类来实现
    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;
    }
    // 提供 IFRDocumentEvents 方法的实现
 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; }
};
// 假设我们已经获取了 FRDocument 对象
IFRDocument* document;
// 在 FRDocument 对象上查询 IConnectionPointContainer
IConnectionPointContainer* pContainer=0;
document->QueryInterface(IID_IConnectionPointContainer, (void**)&pContainer);
// 获取可连接对象中连接点上 IConnectionPoint 接口的指针
IConnectionPoint* pPoint=0;
pContainer->FindConnectionPoint(__uuidof(IFRDocumentEvents),
                                &pPoint);
// 在 CFRDocumentEventsListener 类与连接点之间建立连接
CFRDocumentEventsListener listener;
IUnknown* listenerUnknown=0;
listener.QueryInterface(IID_IUnknown, (void**)&listenerUnknown);
// 将监听器注册到通知源
DWORD cookie; // 用于存储 IConnectionPoint::Advise 方法返回的 cookie 的变量
pPoint->Advise(listenerUnknown, &cookie);
// 处理文档
...
// 通知完成后,监听器不再需要,应取消注册
pPoint->Unadvise(cookie);
  1. 随后,CFRDocumentEventsListener 类可用于接收来自 FRDocument 对象的通知。将此对象注册到通知源 (省略错误处理) :
C# 的操作流程与 Visual Basic .NET 类似。您需要实现回调接口的必要方法,并将已实现的事件处理程序连接到事件源。以下以 FRDocument 对象为例进行说明。
  1. 实现 IFRDocumentEvents 接口的必要方法:
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. 将事件处理程序连接到事件源,使用 FRDocument 对象进行处理,然后断开处理程序:
Windows 用户请参阅 COM 相关文档,以获取有关可连接对象的详细说明。 您还可以参阅 FRE for Linux (C++) 和 Windows (C#、支持原生 COM 的 C++、原始 C++、Visual Basic .NET) 中提供的 EventsHandling 示例。