32bit 앱에서 64bit DLL을 호출하는 방법 - COM 브리지가 도움이 되는 케이스 스터디

· · COM, Windows 개발, 32bit, 64bit

32bit 앱에서 64bit DLL을 호출하는 방법 - COM 브리지가 도움이 되는 케이스 스터디

32bit 앱에서 64bit DLL을 호출하고 싶다는 요건은 Windows에서는 꽤 전형적입니다. 특히 기존 자산을 남긴 채 64bit 쪽 기능만 쓰고 싶을 때, COM 브리지 구성이 현실적인 해답이 되기 쉽습니다.

1. 상정 상황

32bit의 기존 앱을 유지하면서 64bit DLL의 처리를 쓰고 싶은 경우입니다.
하지만 32bit 프로세스는 64bit DLL을 로드할 수 없습니다. 이것은 OS 수준의 제약입니다.

흔한 상황은 다음과 같은 것들입니다.

  • 기존 32bit 앱은 자산으로서 크기가 크고, 바로 이전할 수 없음
  • 64bit DLL 쪽에 신기능이 있거나 의존 라이브러리가 64bit 전용
  • 32bit 쪽에서 「타입 있는 형태로」 호출하고 싶음

이때 「같은 프로세스 안에서 호출하는 것」은 불가능합니다.

2. 해결 방법

해결의 기본은 Out-of-proc COM(EXE 서버)으로 분리하는 것입니다.
64bit DLL은 64bit COM 서버(EXE)에서 호출하고, 32bit 앱은 COM을 경유해 사용합니다.

흐름은 다음과 같습니다.

  1. 64bit COM LocalServer(EXE)를 준비하고, 내부에서 64bit DLL을 호출
  2. COM 인터페이스(IDL/TypeLib)를 공유하고 타입을 공개
  3. 32bit 앱은 COM을 「타입 있는 형태로」 호출(Proxy/Marshal로 교환)

주의점으로는 다음이 있습니다.

  • 32bit/64bit의 등록은 별도(WOW6432Node 포함)
  • 독자 구조체는 마샬링 설계가 필요
  • IPC 오버헤드가 있으므로 고빈도 호출은 주의

즉, 「64bit 처리를 별도 프로세스로 내보내고 COM으로 다리를 놓는 것」이 왕도입니다.

3. 처리 흐름(시퀀스 다이어그램)

다음은 32bit 앱이 64bit DLL의 처리를 호출할 때의 흐름입니다.

sequenceDiagram
    participant App as 32bit 클라이언트 앱
    box rgba(100,100,255,0.1) COM이 자동으로 처리(개발자는 의식 불필요)
        participant Proxy as COM Proxy
(32bit 쪽) participant RPC as RPC/IPC
(프로세스 간 통신) participant Stub as COM Stub
(64bit 쪽) end participant Server as 64bit COM Server
(EXE) participant DLL as 64bit DLL App->>Proxy: ICalcService.Add(1, 2) rect rgba(100,100,255,0.1) Note over Proxy: 파라미터를 마샬링 Proxy->>RPC: 직렬화된 데이터 RPC->>Stub: 프로세스 경계를 넘어 전송 Note over Stub: 파라미터를 언마샬링 end Stub->>Server: Add(1, 2) Server->>DLL: 네이티브 함수 호출 DLL-->>Server: 결과: 3 Server-->>Stub: 결과: 3 rect rgba(100,100,255,0.1) Note over Stub: 반환 값을 마샬링 Stub-->>RPC: 직렬화된 결과 RPC-->>Proxy: 프로세스 경계를 넘어 전송 Note over Proxy: 반환 값을 언마샬링 end Proxy-->>App: 결과: 3

포인트:

  • 32bit 앱은 ICalcService 인터페이스를 통해 타입 안전하게 호출할 수 있음
  • COM 런타임이 자동으로 Proxy/Stub를 생성·관리
  • 프로세스 간 통신 오버헤드가 있으므로, 세세한 호출보다 일괄 처리가 바람직함

4. 샘플 코드(이미지)

다음은 개념의 이미지입니다. 실제로는 등록이나 TypeLib 생성 등이 필요합니다.

// 공유 인터페이스(IDL 상당)
[ComVisible(true)]
[Guid("7A4B5B23-0A2F-4D2B-9D4D-8A2A92B8B001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalcService
{
    int Add(int a, int b);
}

// 64bit COM LocalServer(EXE 쪽)
[ComVisible(true)]
[Guid("1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11")]
[ClassInterface(ClassInterfaceType.None)]
public class CalcService : ICalcService
{
    public int Add(int a, int b)
    {
        // 여기서 64bit DLL을 호출
        return a + b;
    }
}

// 32bit 앱 쪽(클라이언트)
Type t = Type.GetTypeFromProgID("KomuraSoft.CalcService");
var calc = (ICalcService)Activator.CreateInstance(t);
int result = calc.Add(1, 2);

이 형태로 만들면 32bit 쪽은 「타입 있는 형태로」 다룰 수 있습니다.
COM이 내부에서 프록시/스텁을 사용해 IPC 경유로 호출해 줍니다.

5. 완전한 샘플 코드

위의 개념을 실제로 동작하는 형태로 구현한 샘플을 GitHub에서 공개하고 있습니다.

Call64bitDLLFrom32bitProc - GitHub

이 리포지토리에는 다음이 포함되어 있습니다.

  • Call64bitDLLFrom32bitProc/ - 64bit COM LocalServer (EXE)
  • X64DLL/ - 64bit DLL(실처리)
  • X86App/ - 32bit 클라이언트 (WinForms)
  • scripts/ - COM 서버 등록·해제 스크립트

README에 기재된 절차를 따라 빌드·등록하면 실제로 32bit 프로세스에서 64bit DLL을 호출하는 동작을 확인할 수 있습니다.

6. 참고 자료

  • Component Object Model (COM)의 개요
    https://learn.microsoft.com/en-us/windows/win32/com/component-object-model–com–portal
  • COM LocalServer32의 등록
    https://learn.microsoft.com/en-us/windows/win32/com/localserver32
  • COM 인터페이스의 기본
    https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model
  • COM Interop(.NET에서의 이용)
    https://learn.microsoft.com/en-us/dotnet/standard/native-interop/cominterop

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

ActiveX 이관

COM / ActiveX / OCX 자산을 유지할지, 감쌀지, 교체할지의 단계적 판단을 정리한 토픽 페이지입니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기