Il existe trois façons de charger l’objet Engine dans ABBYY FineReader Engine 12. Chacune de ces méthodes de chargement présente des spécificités qui influent sur l’utilisation de l’objet selon le contexte. Les deux premières conviennent davantage aux applications interactives qui ne sont pas destinées au traitement simultané de plusieurs requêtes. La troisième est plus adaptée aux solutions serveur.
Lors de l’utilisation de langages de haut niveau (par exemple .NET), il faut recourir à des mécanismes de bas niveau pour charger des bibliothèques dynamiques et appeler les fonctions qu’elles exposent.
Code C#
public class EngineLoader : IDisposable{ public EngineLoader() { // Initialisez ces variables avec le chemin complet vers FREngine.dll, votre Customer Project ID // et, le cas échéant, le chemin vers votre fichier de jeton de licence en ligne ainsi que le mot de passe de la licence en ligne string enginePath = ""; string customerProjectId = ""; string licensePath = ""; string licensePassword = ""; // Charger la bibliothèque 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"); } // Convertir les pointeurs en délégués initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer( initializeEnginePtr, typeof(InitializeEngine)); deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer( deinitializeEnginePtr, typeof(DeinitializeEngine)); dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer( dllCanUnloadNowPtr, typeof(DllCanUnloadNow)); // Appeler la fonction InitializeEngine // en passant le chemin vers le fichier de licence en ligne et le mot de passe de la licence en ligne int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, "", "", false, ref engine); Marshal.ThrowExceptionForHR(hresult); } catch (Exception) { // Libérer la bibliothèque FREngine.dll engine = null; // Supprimer tous les objets avant l'appel à FreeLibrary GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); FreeLibrary(dllHandle); dllHandle = IntPtr.Zero; initializeEngine = null; deinitializeEngine = null; dllCanUnloadNow = null; throw; } } // Fonctions 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); // Fonctions 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 privées 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;}
Chargement de l’objet Engine au moyen de COM dans le processus en cours
L’objet Engine est chargé comme serveur in-process dans le même processus que celui dans lequel l’application s’exécute. L’objet Engine est chargé à l’aide de l’objet InprocLoader, qui implémente l’interface IEngineLoader.
Avantages
Limites
Tous les objets ABBYY FineReader Engine sont entièrement thread-safe et peuvent être créés et utilisés dans différents threads.
Lorsqu’il est utilisé depuis l’appartement STA principal, le niveau de performance est identique à celui obtenu avec les interfaces nues. En cas d’accès depuis différents threads, une surcharge liée au marshaling peut se produire, mais elle est négligeable dans la plupart des scénarios.
L’enregistrement de FREngine.dll est requis lors de l’installation de l’application finale sur l’ordinateur de l’utilisateur final.
Pour enregistrer FREngine.dll lors de l’installation de votre application sur l’ordinateur d’un utilisateur final, utilisez l’utilitaire regsvr32. Si vous êtes sur un système d’exploitation 64 bits, la version 64 bits de regsvr32 s’exécute par défaut. Utilisez la ligne de commande suivante :
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Chargement de l’objet Engine via COM dans un processus séparé
L’Engine est chargé en tant que serveur hors processus dans un processus séparé. L’objet Engine est chargé au moyen de l’objet OutprocLoader, qui implémente l’interface IEngineLoader.
Avantages
Limitations
Tous les objets ABBYY FineReader Engine sont entièrement thread-safe. Chaque instance de l’Engine s’exécute dans un processus séparé, en parallèle des autres.
Un pool de processeurs peut être organisé pour exploiter pleinement la puissance CPU de l’ordinateur.
Il existe une légère surcharge de marshalling.
L’enregistrement de FREngine.dll est requis lors de l’installation de l’application finale sur l’ordinateur d’un utilisateur final.
En cas d’utilisation sous des comptes avec des autorisations limitées, les autorisations nécessaires doivent être accordées.
Il est impossible d’accéder à une image de page en tant que HBITMAP.
Ne peut pas être utilisé avec les composants visuels, car ceux-ci ne fonctionnent pas avec plusieurs processus.
Cette méthode de chargement de l’objet Engine est utilisée, notamment, dans l’exemple de code EnginesPool, qui fournit une solution réutilisable pour les applications multithread.
Les autorisations de compte peuvent être configurées à l’aide de l’utilitaire DCOM Config (saisissez DCOMCNFG dans la ligne de commande, ou sélectionnez Panneau de configuration > Outils d’administration > Services de composants). Dans l’arborescence de la console, localisez le dossier Services de composants > Ordinateurs > Poste de travail > Configuration DCOM, faites un clic droit sur ABBYY FineReader Engine 12.5 Loader (Local Server), puis cliquez sur Propriétés. Une boîte de dialogue s’ouvre. Cliquez sur l’onglet Sécurité. Sous Autorisations de lancement, cliquez sur Personnaliser, puis sur Modifier pour spécifier les comptes autorisés à lancer l’application.
Notez que sur un système d’exploitation 64 bits, l’application DCOM enregistrée est disponible dans la console MMC 32 bits, qui peut être lancée à l’aide de la ligne de commande suivante :
"mmc comexp.msc /32"
Pour enregistrer FREngine.dll lors de l’installation de votre application sur l’ordinateur d’un utilisateur final, utilisez l’utilitaire regsvr32. Si vous utilisez un système d’exploitation 64 bits, la version 64 bits de regsvr32 s’exécute par défaut. Utilisez la ligne de commande suivante :
regsvr32 /s /n /i:"<path to the Inc folder>" "<path to FREngine.dll>"
Nous vous recommandons d’utiliser une licence réseau aussi bien pour déboguer votre application serveur que pour l’exécuter.
De plus, vous pouvez gérer la priorité d’un processus hôte et vérifier s’il est en cours d’exécution à l’aide de l’interface IHostProcessControl.