메인 콘텐츠로 건너뛰기
이 항목은 Windows용 FRE에 적용됩니다.
ABBYY FineReader Engine 12에서 Engine 객체를 로드하는 방법은 세 가지입니다. 각 로드 방식에는 각기 고유한 특성이 있어, 상황에 따라 객체 사용 방식에 영향을 미칩니다. 처음 두 가지 방법은 여러 요청을 동시에 처리하도록 설계되지 않은 대화형 애플리케이션에 가장 적합합니다. 세 번째 방법은 서버 솔루션에 가장 적합합니다.

FREngine.dll을 수동으로 로드하고 “순수” 인터페이스로 작업하기

이는 엔진 객체를 로드하는 표준적인 방법입니다. 엔진 객체에 대한 참조를 얻으려면 InitializeEngine 함수를 호출합니다.

장점

제한 사항

  • 최상의 성능을 제공합니다.
  • FREngine.dll을 등록할 필요가 없습니다.
public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // 이 변수들을 FREngine.dll의 전체 경로, Customer Project ID,
        // 그리고 해당하는 경우 Online License token file의 경로와 Online License password로 초기화합니다
        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 password를 전달합니다
            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 변수
    private FREngine.IEngine engine = null;
    // FREngine.dll에 대한 핸들
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}

COM을 통해 현재 프로세스에 엔진 객체 로드하기

엔진은 애플리케이션이 실행 중인 동일한 프로세스 내에 인프로세스 서버로 로드됩니다. 엔진 객체는 IEngineLoader 인터페이스를 구현하는 InprocLoader 객체를 사용해 로드됩니다.

장점

제한 사항

  • 모든 ABBYY FineReader Engine 객체는 완전히 스레드 안전하며, 서로 다른 스레드에서 생성하고 사용할 수 있습니다.
  • Main STA apartment에서 작업할 때의 성능은 순수 인터페이스를 사용할 때와 동일합니다. 다른 스레드에서 액세스하면 마샬링 오버헤드가 발생할 수 있지만, 대부분의 시나리오에서는 무시할 수 있는 수준입니다.
  • 최종 사용자 컴퓨터에 최종 애플리케이션을 설치할 때 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을 사용해 엔진 객체를 별도의 프로세스에 로드하기

엔진은 아웃오브프로세스 서버로서 별도의 프로세스에 로드됩니다. 엔진 객체는 IEngineLoader 인터페이스를 구현하는 OutprocLoader 객체를 통해 로드됩니다.

장점

제한 사항

  • 모든 ABBYY FineReader Engine 객체는 완전한 스레드 안전성을 제공합니다. 각 엔진 인스턴스는 서로 병렬로 별도의 프로세스에서 실행됩니다.
  • 컴퓨터의 CPU 성능을 최대한 활용할 수 있도록 프로세서 풀을 구성할 수 있습니다.
  • 약간의 마샬링 오버헤드가 있습니다.
  • 최종 사용자 컴퓨터에 최종 애플리케이션을 설치할 때 FREngine.dll을 등록해야 합니다.
  • 제한된 권한의 계정으로 작업하는 경우 필요한 권한을 부여해야 합니다.
  • 페이지 이미지를 HBITMAP으로 액세스할 수 없습니다.
  • Visual Components는 여러 프로세스에서 작동하지 않으므로 사용할 수 없습니다.
IEngineLoader engineLoader = new FREngine.OutprocLoader();
IEngine engine = engineLoader.InitializeEngine( customerProjectId, licensePath, licensePassword, "", "", false);
try {
 ...
} finally {
 engineLoader.ExplicitlyUnload();
}
이 엔진 객체 로드 방식은 특히 다중 스레드 애플리케이션을 위한 재사용 가능한 솔루션을 제공하는 EnginesPool 코드 sample에서 사용됩니다.
  • 계정 권한은 DCOM Config 유틸리티를 사용하여 설정할 수 있습니다(명령줄에 DCOMCNFG를 입력하거나 Control Panel > Administrative Tools > Component Services를 선택). 콘솔 트리에서 Component Services > Computers > My Computer > DCOM Config 폴더를 찾은 다음, ABBYY FineReader Engine 12.5 Loader (Local Server)를 마우스 오른쪽 버튼으로 클릭하고 Properties를 클릭합니다. 그러면 대화 상자가 열립니다. Security 탭을 클릭합니다. Launch Permissions에서 Customize를 클릭한 다음 Edit를 클릭하여 애플리케이션을 시작할 수 있는 계정을 지정합니다.
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 license를 사용하는 것이 좋습니다.
또한 IHostProcessControl 인터페이스를 사용하여 호스트 프로세스의 우선순위를 관리하고 해당 프로세스가 실행 중인지 여부를 제어할 수 있습니다.

비교 표

아래 표는 세 가지 로드 방식의 특성을 요약한 것입니다.
특성순수 인터페이스인프로세스 서버아웃오브프로세스 서버
프록시 없이 작동(마샬링 오버헤드 없음)일부 제한 있음아니요
멀티스레드 애플리케이션에서 작동일부 제한 있음
프로세스 병렬 실행 가능(서버 솔루션의 경우)아니요아니요
FREngine.dll 등록 불필요아니요아니요
실행 권한을 설정할 필요 없음아니요
new 연산자를 사용해 객체를 생성할 수 있음. 스크립트에서 사용 가능.아니요
페이지 이미지에 HBITMAP으로 액세스 가능아니요
별도 프로세스에서 작동(장애 격리, 재시작)아니요아니요
Visual Components와 함께 사용 가능아니요

참고 항목

멀티스레드 서버 애플리케이션에서 ABBYY FineReader Engine 사용