跳转到主要内容
本主题适用于 FRE for Windows。
在 ABBYY FineReader Engine 12 中,共有三种方式加载 Engine 对象。每种加载方式都有其特定的使用场景,会影响该对象在不同情况下的使用方式。前两种方式最适合用于无需同时处理多个请求的交互式应用程序,第三种方式则最适合服务器端解决方案。

手动加载 FREngine.dll 并使用”裸”接口

这是加载 Engine 对象的标准方法。要获取 Engine 对象的引用,请调用 InitializeEngine 函数。

优点

限制

  • 可实现最高性能。
  • 无需注册 FREngine.dll。
public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // 使用 FREngine.dll 的完整路径、您的 Customer Project ID,
        // 以及(如适用)Online License 令牌文件的路径和 Online License 密码来初始化这些变量
        string enginePath = "";
        string customerProjectId = "";
        string licensePath = "";
        string licensePassword = "";
        // 加载 FREngine.dll 库
        dllHandle = LoadLibraryEx(enginePath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
           
        try
        {
            if (dllHandle == IntPtr.Zero)
            {
                throw new Exception("Can't load " + enginePath);
            }
            IntPtr initializeEnginePtr = GetProcAddress(dllHandle, "InitializeEngine");
            if (initializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("Can't find InitializeEngine function");
            }
            IntPtr deinitializeEnginePtr = GetProcAddress(dllHandle, "DeinitializeEngine");
            if (deinitializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("Can't find DeinitializeEngine function");
            }
            IntPtr dllCanUnloadNowPtr = GetProcAddress(dllHandle, "DllCanUnloadNow");
            if (dllCanUnloadNowPtr == IntPtr.Zero)
            {
                throw new Exception("Can't find DllCanUnloadNow function");
            }
            // 将指针转换为委托
            initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer(
                initializeEnginePtr, typeof(InitializeEngine));
            deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer(
                deinitializeEnginePtr, typeof(DeinitializeEngine));
            dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer(
                dllCanUnloadNowPtr, typeof(DllCanUnloadNow));
            // 调用 InitializeEngine 函数,
            // 传入 Online License 文件路径和 Online License 密码
            int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, 
                "", "", false, ref engine);
            Marshal.ThrowExceptionForHR(hresult);
        }
        catch (Exception)
        {
            // 释放 FREngine.dll 库
            engine = null;
            // 在调用 FreeLibrary 之前销毁所有对象
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            FreeLibrary(dllHandle);
            dllHandle = IntPtr.Zero;
            initializeEngine = null;
            deinitializeEngine = null;
            dllCanUnloadNow = null;
            throw;
        }
    }
    // Kernel32.dll 函数
    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibraryEx(string dllToLoad, IntPtr reserved, uint flags);
    private const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
    [DllImport("kernel32.dll")]
    private static extern bool FreeLibrary(IntPtr hModule);
    // FREngine.dll 函数
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    private delegate int InitializeEngine(string customerProjectId, string licensePath, 
        string licensePassword, string tempFolder, string dataFolder, bool isSharedCPUCoresMode, 
        ref FREngine.IEngine engine);
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int DeinitializeEngine();
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int DllCanUnloadNow();
    // 私有变量
    private FREngine.IEngine engine = null;
    // FREngine.dll 的 Handle
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}

通过 COM 将 Engine 对象加载到当前进程中

Engine 作为进程内服务器加载到应用程序运行的同一进程中。Engine 对象通过 InprocLoader 对象加载,该对象实现了 IEngineLoader 接口。

优点

限制

  • 所有 ABBYY FineReader Engine 对象均完全线程安全,可在不同线程中创建和使用。
  • 从主 STA 单元工作时,性能与直接使用裸接口相同。从不同线程访问时可能会产生封送开销,但在大多数场景下可忽略不计。
  • 在最终用户计算机上安装应用程序时,需要注册 FREngine.dll。
IEngineLoader engineLoader = new FREngine.InprocLoader();
IEngine engine = engineLoader.InitializeEngine( customerProjectId, licensePath, licensePassword, "", "", false );
try {
 ...
} finally {
 engineLoader.ExplicitlyUnload();
}
若要在最终用户计算机上安装应用程序时注册 FREngine.dll,请使用 regsvr32 工具。如果您使用的是 64 位操作系统,则默认运行 64 位版本的 regsvr32。请使用以下命令行:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"

通过 COM 将 Engine 对象加载到独立进程中

Engine 作为进程外服务器加载到独立进程中。Engine 对象通过 OutprocLoader 对象加载,该对象实现了 IEngineLoader 接口。

优点

限制

  • 所有 ABBYY FineReader Engine 对象均完全线程安全。每个 Engine 实例在独立进程中并行运行。
  • 可组建处理器池,充分利用计算机的 CPU 性能。
  • 存在少量封送处理开销。
  • 在最终用户计算机上安装应用程序时,需要注册 FREngine.dll。
  • 在权限受限的账户下运行时,必须授予必要的权限。
  • 无法以 HBITMAP 形式访问页面图像。
  • 不能与 Visual Components 配合使用,因为 Visual Components 不支持多进程工作。
IEngineLoader engineLoader = new FREngine.OutprocLoader();
IEngine engine = engineLoader.InitializeEngine( customerProjectId, licensePath, licensePassword, "", "", false);
try {
 ...
} finally {
 engineLoader.ExplicitlyUnload();
}
这种加载 Engine 对象的方式尤其体现在 EnginesPool 代码示例中,该示例为多线程应用程序提供了可复用的解决方案。
  • 可使用 DCOM Config 实用程序设置账户权限 (在命令行中输入 DCOMCNFG,或依次选择”控制面板”>“管理工具”>“组件服务”) 。在控制台树中,找到”组件服务”>“计算机”>“我的电脑”>“DCOM 配置”文件夹,右键单击 ABBYY FineReader Engine 12.5 Loader (本地服务器) ,然后单击”属性”。此时将打开一个对话框。单击”安全”选项卡。在”启动权限”下,单击”自定义”,然后单击”编辑”以指定可启动该应用程序的账户。
请注意,在 64 位操作系统上,已注册的 DCOM 应用程序可在 32 位 MMC 控制台中使用,可通过以下命令行启动该控制台:
"mmc comexp.msc /32"
  • 在最终用户计算机上安装应用程序时,若要注册 FREngine.dll,请使用 regsvr32 工具。如果您使用的是 64 位操作系统,则默认运行 64 位版本的 regsvr32。请使用以下命令行:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
  • 我们建议您在调试和运行服务器应用程序时均使用 Network 许可证。
此外,您可以通过 IHostProcessControl 接口管理 host process 的优先级,并控制其是否保持活动状态。

对比表

下表汇总了三种加载方式的特性:
特性裸接口进程内服务器进程外服务器
无需代理即可运行 (无编组开销)存在限制
适用于多线程应用程序存在限制
可并行运行进程 (适用于服务器解决方案)
无需注册 FREngine.dll
无需配置运行权限
可使用 new 运算符创建对象,支持脚本调用
支持以 HBITMAP 形式访问页面图像
在独立进程中运行 (容错性强,支持回收)
可与 Visual Components 配合使用

另请参阅

在多线程服务器应用程序中使用 ABBYY FineReader Engine