Hay tres formas de cargar el objeto Engine en ABBYY FineReader Engine 12. Cada método de carga tiene sus propias particularidades, que afectan al uso del objeto en distintas circunstancias. Los dos primeros métodos son los más adecuados para aplicaciones interactivas que no están pensadas para procesar varias solicitudes simultáneamente. El tercer método es el más adecuado para soluciones de servidor.
Al trabajar con lenguajes de alto nivel (por ejemplo, .NET), deben utilizarse mecanismos de bajo nivel para cargar bibliotecas dinámicas y llamar a las funciones expuestas por ellas.
Código C#
public class EngineLoader : IDisposable{ public EngineLoader() { // Inicializa estas variables con la ruta completa a FREngine.dll, tu Customer Project ID // y, si corresponde, la ruta a tu archivo de token de licencia en línea y la contraseña de la licencia en línea string enginePath = ""; string customerProjectId = ""; string licensePath = ""; string licensePassword = ""; // Carga la biblioteca 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"); } // Convierte los punteros en delegados initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer( initializeEnginePtr, typeof(InitializeEngine)); deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer( deinitializeEnginePtr, typeof(DeinitializeEngine)); dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer( dllCanUnloadNowPtr, typeof(DllCanUnloadNow)); // Llama a la función InitializeEngine // y pasa la ruta al archivo de licencia en línea y la contraseña de la licencia en línea int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, "", "", false, ref engine); Marshal.ThrowExceptionForHR(hresult); } catch (Exception) { // Libera la biblioteca FREngine.dll engine = null; // Elimina todos los objetos antes de llamar a FreeLibrary GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); FreeLibrary(dllHandle); dllHandle = IntPtr.Zero; initializeEngine = null; deinitializeEngine = null; dllCanUnloadNow = null; throw; } } // Funciones de 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); // Funciones de 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(); // Variables privadas private FREngine.IEngine engine = null; // Handle de FREngine.dll private IntPtr dllHandle = IntPtr.Zero; private InitializeEngine initializeEngine = null; private DeinitializeEngine deinitializeEngine = null; private DllCanUnloadNow dllCanUnloadNow = null;}
Carga del objeto Engine mediante COM en el proceso actual
El Engine se carga como un servidor en proceso dentro del mismo proceso en el que se ejecuta la aplicación. El objeto Engine se carga mediante el objeto InprocLoader, que implementa la interfaz IEngineLoader.
Ventajas
Limitaciones
Todos los objetos de ABBYY FineReader Engine son completamente seguros para subprocesos y pueden crearse y usarse en distintos subprocesos.
Al trabajar desde el apartamento STA principal, el rendimiento es el mismo que al trabajar con las interfaces directas. Al acceder desde distintos subprocesos, puede producirse una sobrecarga de marshaling, pero es insignificante en la mayoría de los casos.
Es necesario registrar FREngine.dll al instalar la aplicación final en el equipo del usuario final.
Para registrar FREngine.dll al instalar su aplicación en un equipo de usuario final, use la utilidad regsvr32. Si está en un sistema operativo de 64 bits, la versión de 64 bits de regsvr32 se ejecutará de forma predeterminada. Use la siguiente línea de comandos:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Carga del objeto Engine mediante COM en un proceso independiente
El Engine se carga como un servidor fuera del proceso en un proceso independiente. El objeto Engine se carga mediante el objeto OutprocLoader, que implementa la interfaz IEngineLoader.
Ventajas
Limitaciones
Todos los objetos de ABBYY FineReader Engine son completamente seguros para subprocesos. Cada instancia del Engine se ejecuta en un proceso independiente en paralelo con las demás.
Se puede organizar un pool de procesadores para aprovechar al máximo la capacidad de la CPU del equipo.
Hay una pequeña sobrecarga de marshaling.
Es necesario registrar FREngine.dll al instalar la aplicación final en el equipo del usuario final.
Al trabajar con cuentas con permisos limitados, se deben conceder los permisos necesarios.
Es imposible acceder a una imagen de página como HBITMAP.
No puede usarse con Visual Components, ya que no funcionan con varios procesos.
Esta forma de cargar el objeto Engine se usa, en particular, en el ejemplo de código EnginesPool, que proporciona una solución reutilizable para aplicaciones multihilo.
Los permisos de la cuenta pueden configurarse con la utilidad DCOM Config (ya sea escribiendo DCOMCNFG en la línea de comandos o seleccionando Panel de control > Herramientas administrativas > Servicios de componentes). En el árbol de la consola, localice la carpeta Component Services > Computers > My Computer > DCOM Config, haga clic con el botón derecho en ABBYY FineReader Engine 12.5 Loader (Local Server) y luego en Propiedades. Se abrirá un cuadro de diálogo. Haga clic en la pestaña Seguridad. En Permisos de inicio, haga clic en Personalizar y, a continuación, en Editar para especificar las cuentas que pueden iniciar la aplicación.
Tenga en cuenta que, en un sistema operativo de 64 bits, la aplicación DCOM registrada está disponible en la consola MMC de 32 bits, que puede ejecutarse mediante la siguiente línea de comandos:
"mmc comexp.msc /32"
Para registrar FREngine.dll al instalar su aplicación en un equipo de usuario final, use la utilidad regsvr32. Si usa un sistema operativo de 64 bits, se ejecutará de forma predeterminada la versión de 64 bits de regsvr32. Use la siguiente línea de comandos:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Recomendamos que utilice una licencia de red tanto para depurar su aplicación de servidor como para ejecutarla.
Además, puede administrar la prioridad de un proceso anfitrión y controlar si sigue en ejecución mediante la interfaz IHostProcessControl.