There are three ways to load the Engine object in ABBYY FineReader Engine 12. Each of the loading methods has its own specifics affecting the use of the object in different circumstances. The first two methods are most suitable for use in interactive applications which are not intended for simultaneous processing of multiple requests. The third method is most suitable for server solutions.
When working with high-level languages (for instance, .NET), low-level means must be used to load dynamic libraries and to call functions published in them.
C# code
public class EngineLoader : IDisposable{ public EngineLoader() { // Initialize these variables with the full path to FREngine.dll, your Customer Project ID, // and, if applicable, the path to your Online License token file and the Online License password string enginePath = ""; string customerProjectId = ""; string licensePath = ""; string licensePassword = ""; // Load the FREngine.dll library 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"); } // Convert pointers to delegates initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer( initializeEnginePtr, typeof(InitializeEngine)); deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer( deinitializeEnginePtr, typeof(DeinitializeEngine)); dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer( dllCanUnloadNowPtr, typeof(DllCanUnloadNow)); // Call the InitializeEngine function // passing the path to the Online License file and the Online License password int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, "", "", false, ref engine); Marshal.ThrowExceptionForHR(hresult); } catch (Exception) { // Free the FREngine.dll library engine = null; // Deleting all objects before FreeLibrary call GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); FreeLibrary(dllHandle); dllHandle = IntPtr.Zero; initializeEngine = null; deinitializeEngine = null; dllCanUnloadNow = null; throw; } } // Kernel32.dll functions [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 functions [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 variables private FREngine.IEngine engine = null; // Handle to FREngine.dll private IntPtr dllHandle = IntPtr.Zero; private InitializeEngine initializeEngine = null; private DeinitializeEngine deinitializeEngine = null; private DllCanUnloadNow dllCanUnloadNow = null;}
Loading the Engine object by means of COM into the current process
The Engine is loaded as an in-process server into the same process where the application is running. The Engine object is loaded using the InprocLoader object, which implements the IEngineLoader interface.
Advantages
Limitations
All ABBYY FineReader Engine objects are completely thread-safe and can be created and used in different threads.
When working from the Мain STA apartment, performance is the same as when working with the naked interfaces. When accessing from different threads, marshalling overhead may occur, but it is negligible in most scenarios.
Registration of FREngine.dll is required when installing the final application on an end user’s computer.
To register FREngine.dll when installing your application on an end-user computer, use the regsvr32 utility. If you are on a 64-bit operating system, the 64-bit version of regsvr32 will run by default. Use the following command line:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Loading the Engine object by means of COM into a separate process
The Engine is loaded as an out-of-process server into a separate process. The Engine object is loaded by means of the OutprocLoader object, which implements a IEngineLoader interface.
Advantages
Limitations
All ABBYY FineReader Engine objects are completely thread-safe. Each instance of the Engine runs in a separate process parallel to the others.
A pool of processors can be organized to make full use of the computer’s CPU power.
There is small marshalling overhead.
Registration of FREngine.dll is required when installing the final application on an end user’s computer.
When working under accounts with limited permissions, the necessary permissions must be granted.
It is impossible to access a page image as HBITMAP.
Cannot be used with Visual Components, as they do not work with multiple processes.
This way of loading the Engine object is used, in particular, in EnginesPool code sample, which provides a reusable solution for multithreaded applications.
Account permissions can be set up using the DCOM Config utility (either type DCOMCNFG in the command line, or select Control Panel > Administrative Tools > Component Services). In the console tree, locate the Component Services > Computers > My Computer > DCOM Config folder, right-click ABBYY FineReader Engine 12.5 Loader (Local Server), and click Properties. A dialog box will open. Click the Security tab. Under Launch Permissions, click Customize, and then click Edit to specify the accounts that can launch the application.
Note that on a 64-bit operating system the registered DCOM-application is available in the 32-bit MMC console, which can be run using the following command line:
"mmc comexp.msc /32"
To register FREngine.dll when installing your application on an end-user computer, use the regsvr32 utility. If you are on a 64-bit operating system, the 64-bit version of regsvr32 will run by default. Use the following command line:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
We recommend that you use a Network license both for debugging your server application and for running it.
Additionally you can manage the priority of a host process and control whether it is alive using the IHostProcessControl interface.