Esistono tre modi per caricare l’oggetto Engine in ABBYY FineReader Engine 12. Ciascun metodo di caricamento presenta caratteristiche specifiche che ne influenzano l’uso in diverse circostanze. I primi due metodi sono più indicati per le applicazioni interattive che non prevedono l’elaborazione simultanea di più richieste. Il terzo metodo è invece più adatto alle soluzioni server.
Quando si lavora con linguaggi di alto livello (ad esempio .NET), è necessario utilizzare strumenti di basso livello per caricare librerie dinamiche e richiamare le funzioni da esse esportate.
Codice C#
public class EngineLoader : IDisposable{ public EngineLoader() { // Inizializza queste variabili con il percorso completo di FREngine.dll, il tuo Customer Project ID // e, se applicabile, il percorso del file token della licenza online e la relativa password string enginePath = ""; string customerProjectId = ""; string licensePath = ""; string licensePassword = ""; // Carica la libreria 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"); } // Converte i puntatori in delegati initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer( initializeEnginePtr, typeof(InitializeEngine)); deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer( deinitializeEnginePtr, typeof(DeinitializeEngine)); dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer( dllCanUnloadNowPtr, typeof(DllCanUnloadNow)); // Chiama la funzione InitializeEngine // passando il percorso del file di licenza online e la relativa password int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, "", "", false, ref engine); Marshal.ThrowExceptionForHR(hresult); } catch (Exception) { // Libera la libreria FREngine.dll engine = null; // Elimina tutti gli oggetti prima della chiamata a FreeLibrary GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); FreeLibrary(dllHandle); dllHandle = IntPtr.Zero; initializeEngine = null; deinitializeEngine = null; dllCanUnloadNow = null; throw; } } // Funzioni di 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); // Funzioni di 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(); // Variabili private private FREngine.IEngine engine = null; // Handle di FREngine.dll private IntPtr dllHandle = IntPtr.Zero; private InitializeEngine initializeEngine = null; private DeinitializeEngine deinitializeEngine = null; private DllCanUnloadNow dllCanUnloadNow = null;}
Caricamento dell’oggetto Engine tramite COM nel processo corrente
L’Engine viene caricato come server in-process nello stesso processo in cui è in esecuzione l’applicazione. L’oggetto Engine viene caricato mediante l’oggetto InprocLoader, che implementa l’interfaccia IEngineLoader.
Vantaggi
Limitazioni
Tutti gli oggetti di ABBYY FineReader Engine sono completamente thread-safe e possono essere creati e utilizzati in thread diversi.
Quando si opera dal Main STA apartment, le prestazioni sono uguali a quelle ottenute con le interfacce naked. Quando si accede da thread diversi, può verificarsi un overhead di marshalling, ma nella maggior parte degli scenari è trascurabile.
Per installare l’applicazione finale sul computer dell’utente finale, è necessario registrare FREngine.dll.
Per registrare FREngine.dll durante l’installazione dell’applicazione sul computer di un utente finale, usa l’utilità regsvr32. Se utilizzi un sistema operativo a 64 bit, per impostazione predefinita verrà eseguita la versione a 64 bit di regsvr32. Usa la seguente riga di comando:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Caricamento dell’oggetto Engine tramite COM in un processo separato
L’Engine viene caricato come server out-of-process in un processo separato. L’oggetto Engine viene caricato tramite l’oggetto OutprocLoader, che implementa l’interfaccia IEngineLoader.
Vantaggi
Limitazioni
Tutti gli oggetti di ABBYY FineReader Engine sono completamente thread-safe. Ogni istanza dell’Engine viene eseguita in un processo separato, in parallelo alle altre.
È possibile organizzare un pool di processori per sfruttare appieno la potenza della CPU del computer.
È presente un lieve overhead di marshalling.
La registrazione di FREngine.dll è necessaria durante l’installazione dell’applicazione finale nel computer dell’utente finale.
Quando si lavora con account con permessi limitati, è necessario concedere i permessi richiesti.
È impossibile accedere all’immagine di una pagina come HBITMAP.
Non può essere utilizzato con Visual Components, poiché non funzionano con processi multipli.
Questo metodo di caricamento dell’oggetto Engine viene utilizzato, in particolare, nell’esempio di codice EnginesPool, che fornisce una soluzione riutilizzabile per le applicazioni multithread.
I permessi degli account possono essere configurati tramite l’utilità DCOM Config (digitando DCOMCNFG nella riga di comando oppure selezionando Control Panel > Administrative Tools > Component Services). Nell’albero della console, individuare la cartella Component Services > Computers > My Computer > DCOM Config, fare clic con il pulsante destro del mouse su ABBYY FineReader Engine 12.5 Loader (Local Server), quindi scegliere Properties. Si aprirà una finestra di dialogo. Fare clic sulla scheda Security. In Launch Permissions, fare clic su Customize, quindi su Edit per specificare gli account che possono avviare l’applicazione.
Si noti che in un sistema operativo a 64 bit l’applicazione DCOM registrata è disponibile nella console MMC a 32 bit, che può essere eseguita usando la seguente riga di comando:
"mmc comexp.msc /32"
Per registrare FREngine.dll durante l’installazione dell’applicazione su un computer dell’utente finale, utilizzare l’utilità regsvr32. Se si usa un sistema operativo a 64 bit, per impostazione predefinita verrà eseguita la versione a 64 bit di regsvr32. Utilizzare la seguente riga di comando:
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Ti consigliamo di utilizzare una licenza di rete sia per eseguire il debug della tua applicazione server sia per mandarla in esecuzione.
Inoltre, puoi gestire la priorità di un processo host e controllare se è in esecuzione utilizzando l’interfaccia IHostProcessControl.