Reg-Free COM이란 - 등록 없이 COM을 쓰는 구조

· 업데이트: · · COM, Reg-Free COM, Registration-Free COM, Windows 개발, 레거시 기술

수정 이력(8건, 최종 수정 2026년 09월 03일)

이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.

관련 기사 링크를 한국어 permalink에 맞추는 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
permalink·저자 표기·지식 맵 래퍼·깨진 내부 링크 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
일본어 원문의 완역으로 다시 번역했습니다. 기존 한국어판은 원문의 일부만 옮긴 축약본이라 절, 표, Mermaid 그림, 그림 설명, FAQ가 빠져 있었습니다. 일본어 원문에 맞춰 이들을 모두 복원했고, 기술적인 주장은 일본어판과 같습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.21635177)
구조의 해결 순서나 구성·검증 절차를 그림으로도 따라갈 수 있도록 Mermaid 그림을 16점 추가했습니다(본문 500〜750자당 1그림 규약에 맞춘 것입니다). 본문 문장은 바꾸지 않았습니다.
글 맨 앞에 「이 글의 지식 맵」 절을 추가했습니다. 본문에서 다루는 개념과 그 관계를 요약·그림·상세 페이지 링크로 정리한 것입니다. 본문의 주장은 바꾸지 않았습니다.
외부 리뷰(1283건) 대응으로 본문을 갱신했습니다. 개별 변경 내용은 아래 이력을 참조하세요.
매니페스트 배치와 포함, 클린 환경에서의 확인 절차를 새로 넣었습니다. 아울러 기존 예가 「DLL에 포함하는 가정」이라고 쓰면서 assembly 이름이 DLL 이름과 다른 별도 파일 배치 방식이었던 불일치를 고치고, 포함할 때의 명명 규칙(assembly 이름=DLL 이름, 리소스 ID는 1)을 표로 보였습니다. `sxstrace` 절차와 용어 정의표도 추가하고, 비유로 적었던 5곳을 구체적인 서술로 고쳤습니다.
본문 중 관련 글 링크 문구가 링크 대상의 현재 제목과 어긋나 있던 것을 실제 제목에 맞췄습니다. 본문 내용은 바꾸지 않았습니다.
최초 공개
이 글을 인용하기(DOI: 10.5281/zenodo.21635176)

이 글은 Zenodo에 보관되어 있습니다. 항상 최신 버전으로 연결되는 DOI와 지금 보고 있는 버전에 고정된 DOI를 아래에 함께 제시합니다.

Go Komura (2026). 「Reg-Free COM이란 - 등록 없이 COM을 쓰는 구조」. 합동회사 코무라소프트. https://doi.org/10.5281/zenodo.21635176 https://comcomponent.com/ko/blog/what-is-reg-free-com/

DOI(최신 버전)
10.5281/zenodo.21635176
DOI(이 버전)
10.5281/zenodo.22217457

COM / ActiveX / OCX 안건에서는 배포와 갱신마다 같은 문제가 반복됩니다.

  • regsvr32가 필요함
  • 관리자 권한이 필요해지기 쉬움
  • 다른 앱이 넣은 다른 버전과 충돌함
  • 제거 후에 다른 제품까지 말려듦
  • 개발 PC에서는 동작하는데 클린 환경에서는 동작하지 않음

이 수고를 꽤 줄일 수 있는 것이 Reg-Free COM입니다. 다만 이름에 비해 「COM의 번거로움이 전부 사라지는 마법」은 아닙니다. 사라지는 것은 주로 글로벌 등록에 끌려가는 번거로움입니다. bitness, 의존 DLL, 형식 라이브러리, 스레드 모델의 어려움까지는 사라지지 않습니다.

Reg-Free COM에서 사라지는 것과 남는 것Reg-Free COM에서 사라지는 것은 주로 글로벌 등록에 끌려가는 번거로움이며, bitness나 의존 DLL, 형식 라이브러리, 스레드 모델의 어려움은 사라지지 않음을 나타내는 그림.Reg-Free COM글로벌 등록의 번거로움은 줄어듦남는 어려움도 있다bitness / 의존 DLL / 형식 라이브러리

그림 1: 마법이 아니라, 사라지는 번거로움과 남는 번거로움을 나눠서 기대한다.

이 글에서는 Reg-Free COM을 Windows 데스크톱 앱에서 COM DLL / OCX를 앱 로컬에 가둬 쓰는 맥락을 중심으로 정리합니다.

대상 독자와 전제

기존 COM DLL / OCX를 쓰는 Windows 데스크톱 앱을 배포하고 있고, regsvr32와 관리자 권한에서 벗어나고 싶은 개발자를 대상으로 씁니다. COM의 기초(CLSID, ProgID, CoCreateInstance, in-proc 서버)를 한 번은 만져 본 전제입니다. 아직 그 부분이 흐릿하다면, 먼저 「COM / ActiveX / OCX란 무엇인가 - 차이와 관계를 정리해 해설」을 읽고 오는 편이 빠릅니다.

절차 부분은 Windows SDK의 mt.exesxstrace를 쓰므로, Visual Studio 또는 Windows SDK가 들어 있는 환경을 가정합니다.

1. 먼저 결론(한 마디로)

먼저 거칠지만 도움이 되는 표현으로 말하면 이렇습니다.

  • Reg-Free COM은 COM의 등록 정보를 레지스트리가 아니라 매니페스트로 가지는 방식입니다
  • 실행 시에는 CoCreateInstanceCLSIDFromProgID의 해결에서 액티베이션 컨텍스트가 먼저 보입니다
  • 그래서 COM DLL / OCX를 앱마다 private로 둘 수 있게 됩니다
  • 주된 이점은 XCOPY 배포가 쉬운 것, 버전 충돌을 피하기 쉬운 것, 제거가 잘 깨지지 않는 것입니다
  • 다만 32bit / 64bit 문제는 사라지지 않습니다. 이 점은 매니페스트 작성법으로는 피할 수 없습니다
  • 또한 의존 DLL, 형식 라이브러리, 설계 시 참조, 비표준 등록 의존은 따로 생각해야 합니다
  • 실무에서는 앱 전용 COM 부품을 옆에 두고 싶을 때 꽤 잘 맞습니다

요컨대 Reg-Free COM은 COM의 액티베이션을 앱 단위로 되돌리는 구조입니다.

등록 정보의 자리가 바뀐다Reg-Free COM은 COM의 등록 정보를 레지스트리가 아니라 매니페스트로 가지며, CoCreateInstance 등의 해결에서 액티베이션 컨텍스트가 먼저 보이므로 COM 부품을 앱마다 private로 둘 수 있음을 나타내는 그림.등록 정보를 매니페스트로 가진다해결 시 액티베이션 컨텍스트가 먼저COM 부품을 앱마다 private로 둘 수 있다XCOPY 배포나 충돌 회피가 쉽다

그림 2: 레지스트리에서 매니페스트로, 해결의 입구가 바뀌는 것이 본질이다.

이 글의 지식 맵

Reg-Free COM은 COM의 등록 정보를 레지스트리가 아니라 매니페스트로 가지게 하고, 실행 시에는 액티베이션 컨텍스트를 먼저 보고 DLL을 해결하는 구조입니다. 애플리케이션 매니페스트가 의존 대상인 side-by-side assembly를 선언하고, 컴포넌트 매니페스트가 CLSID나 ProgID 등 원래 레지스트리에 있던 정보를 가진다는 분담으로, mt.exe로 매립하고 sxstrace로 해결 실패를 추적합니다. 다만 32bit/64bit의 일치 요건은 해소되지 않고 의존 DLL이나 타입 라이브러리의 처리는 별개의 논점으로 남으므로, VB6·MFC·WinForms 같은 기존 데스크톱 자산의 앱 로컬화에는 맞는 반면, 머신 전체에서의 COM 공유가 필요한 장면에는 맞지 않습니다. .NET 5+/.NET 8에서는 EnableComHosting으로 comhost를 만들고, EnableRegFreeCom을 활성화함으로써 Reg-Free COM용 side-by-side 매니페스트를 출력할 수 있습니다.

Reg-Free COMReg-Free COM이 액티베이션 컨텍스트와 side-by-side assembly의 구조로 COM의 등록 정보를 앱 단위로 가지게 한다는 것, 애플리케이션 매니페스트와 컴포넌트 매니페스트의 역할 분담, mt.exe에 의한 구성과 sxstrace에 의한 장애 조사, .NET 5+의 comhost와의 관계를 보여주는 그림이용한다이용한다이용한다전제로 한다구현을 담당한다전제로 한다의 후속이용한다에서 구성할 수 있다에서 확인할 수 있다에서 구성할 수 있다전제로 한다이용한다전제로 한다에서 구성할 수 있다구현을 담당한다이용한다이용한다이용한다이용한다이용한다이용한다권장되는 대응권장되는 대응권장되는 대응사용은 비권장Reg-Free COM(등록 불필요 COM)활성화 컨텍스트애플리케이션 매니페스트(Win32 side-by-side)컴포넌트 매니페스트(assembly manifest)side-by-side assembly비트수 일치 요건regsvr32타입 라이브러리(TLB)mt.exe(매니페스트 도구)sxstraceprivate assembly 탐색 순서.NET(Core 이후)COM host(*.comhost.dll)EnableComHostingEnableRegFreeComVisual Basic 6.0(VB6)CLSID(Class ID)ProgID(Programmatic Identifier)COM(컴포넌트 오브젝트 모델)ActiveXOCXMFC(Microsoft Foundation Classes)Windows FormsCOM의 시스템 전역 공유

그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 26건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle

2. 이 글에서 말하는 Reg-Free COM

Reg-Free COM은 Registration-Free COM의 약자입니다. 「등록 불필요 COM」이라고 쓰이기도 합니다.

여기서 말하는 「등록 불필요」는 COM을 쓰기 위해 HKCR / CLSID / InprocServer32 같은 글로벌 레지스트리 등록에 전면 의존하지 않는다는 뜻입니다. COM 자체가 사라진다는 것도, GUID가 불필요해진다는 것도 아닙니다.

이 글에서 주로 다루는 대상은 다음과 같습니다.

  • 네이티브 COM DLL
  • ATL 기반 COM 서버
  • ActiveX / OCX
  • .NET Framework 기반 COM 상호 운용
  • .NET 5+ / .NET 8의 COM host를 쓴 공개

반대로 이 글에서 강조하고 싶은 것은 두 가지입니다.

  1. Reg-Free COM은 「액티베이션」의 이야기이다
  2. 형식 정보의 배포나 설계 시 참조 설정은, 별도의 논점으로 남는 경우가 있다

여기를 섞으면 이야기가 꽤 흐려집니다.

섞으면 안 되는 두 논점Reg-Free COM은 액티베이션의 이야기이며, 형식 정보의 배포나 설계 시 참조 설정은 별도의 논점으로 남는 경우가 있으므로 이 둘을 섞으면 이야기가 흐려짐을 나타내는 그림.Reg-Free COM액티베이션의 이야기형식 정보의 배포·설계 시 참조별도의 논점으로 남는다섞으면 이야기가 흐려진다

그림 3: 실행 시의 이야기와 설계 시의 이야기는, 처음부터 나눠서 다룬다.

3. 먼저 한 장으로 정리

그림에 들어가기 전에, 이 글에서 반복해서 나오는 4개 용어만 먼저 정의해 둡니다.

용어 의미
액티베이션 컨텍스트 (activation context) 「지금 이 스레드는 어느 assembly의 어느 버전을 쓸지」를 유지하는, 실행 시의 데이터 구조입니다. CoCreateInstance는 레지스트리보다 여기를 먼저 봅니다
side-by-side assembly 같은 이름의 부품을 버전을 달리해 같은 머신에 공존시키기 위한 Windows 구조입니다. 매니페스트로 식별되며, assemblyIdentity가 이름표에 해당합니다
애플리케이션 매니페스트 EXE 쪽에 붙이는 XML로, 「자신은 어느 side-by-side assembly에 의존하는지」를 적습니다
컴포넌트 매니페스트 (assembly manifest) 부품 쪽에 붙이는 XML로, 「이 assembly는 어떤 파일을 포함하고, 어떤 COM 클래스를 공개하는지」를 적습니다. 원래 레지스트리에 들어가 있던 정보가 여기로 옵니다

액티베이션 컨텍스트는 스레드마다 가집니다. COM은 생성 측 스레드의 액티베이션 컨텍스트를 호스트 측 스레드로 넘긴 뒤에 LoadLibraryDllGetClassObject를 호출하므로, 호출 측에서 특별한 준비는 필요 없습니다.

그다음에 전체 그림을 한 장으로 보는 편이 빠릅니다.

MyApp.exeApplication ManifestdependentAssemblyComponent / Assembly Manifestfile / comClass / typelibVendorControl.dll / .ocxActivation ContextCLSIDFromProgID / CoCreateInstance

그림 4: 앱의 매니페스트에서 컴포넌트의 매니페스트를 따라가, 레지스트리 없이 DLL에 도달한다.

보통의 COM에서는 CoCreateInstance할 때 레지스트리를 따라가며 어느 DLL을 로드할지를 정합니다. Reg-Free COM에서는 그 앞에 지금 유효한 액티베이션 컨텍스트를 보고, 거기에 적힌 매니페스트 정보로 해결합니다.

이 때문에 같은 머신에서도 앱 A와 앱 B가 다른 버전의 같은 계통 COM 부품을 안고 움직이기 쉬워집니다. COM의 공유 문화를, 조금 앱 로컬 쪽으로 되돌리는 느낌입니다.

4. 왜 보통의 COM 배포는 무거워지기 쉬운가

보통의 COM 배포가 무거운 것은 COM 자체보다 글로벌 등록이라는 전제가 있기 때문입니다.

COM 클래스를 쓰려면 대략 이런 정보가 필요합니다.

정보 역할
CLSID 클래스를 유일하게 식별하는 GUID
ProgID 사람이 다루기 쉬운 이름
InprocServer32 어느 DLL을 로드할지
ThreadingModel Apartment / Both 등의 전제
TypeLib 형식 정보

이들이 레지스트리에 들어가면 머신 전체에서는 편리합니다. 여러 앱에서 공유하기 쉽기 때문입니다.

다만 실무에서는 이 공유가 역효과를 냅니다.

  • 어떤 제품의 설치가 다른 제품의 COM 등록을 덮어씀
  • 제거 프로그램이 「자기 것만 지운 셈」으로 공유 COM을 깨뜨림
  • 개발 PC에 우연히 들어 있는 등록이 프로덕션 머신에는 없음
  • 32bit와 64bit 등록이 맞지 않아, 증상만 이상하게 어긋남

COM 본체보다 배포 모델 쪽이 사람을 더 괴롭히는 경우가 꽤 많습니다. Reg-Free COM은 이 배포 모델의 고통을 줄이기 위한 구조입니다.

글로벌 공유가 역효과를 내는 흐름COM의 등록 정보가 레지스트리에 들어가면 머신 전체에서 공유하기 쉬워지지만, 실무에서는 다른 제품에 의한 덮어쓰기나 제거 시의 말려듦, 개발 PC와 프로덕션 머신의 환경 차로 역효과를 내기 쉽고, COM 본체보다 배포 모델이 사람을 괴롭힘을 나타내는 그림.등록 정보를 머신 전체에서 공유여러 앱에서 쓸 수 있어 편리실무에서는 공유가 역효과를 냄덮어쓰기 / 말려듦 / 환경 차배포 모델이 사람을 괴롭힘

그림 5: 고통의 정체는 COM 자체가 아니라, 글로벌 등록이라는 전제이다.

5. Reg-Free COM의 구조

5.1 애플리케이션 매니페스트에 의존 관계를 적는다

먼저 앱 쪽은 자신이 어느 side-by-side assembly에 의존하는지를 애플리케이션 매니페스트에 적습니다.

이 매니페스트는

  • MyApp.exe.manifest처럼 EXE 옆에 두기
  • EXE에 리소스로 포함하기

어느 쪽으로도 다룰 수 있습니다. 실무에서는 배포와 교체를 보기 쉽게 하려면 외부 파일, 깨지기 어려움과 배포의 단순함을 우선하면 포함, 이렇게 나누는 경우가 많습니다.

참고로 외부 파일 쪽과 포함 쪽이 둘 다 있으면 파일 시스템의 매니페스트가 우선됩니다.

5.2 컴포넌트 매니페스트에 COM 정보를 적는다

다음으로 COM 쪽은 원래 레지스트리에 들어가 있던 정보를 컴포넌트 매니페스트에 가집니다.

여기에 들어가는 것은 예를 들어 이런 정보입니다.

  • comClass
  • clsid
  • progid
  • threadingModel
  • typelib
  • 필요하면 proxy / stub이나 window class 등

즉 레지스트리 대신 XML로 COM의 겉모습을 기술하는 이미지입니다.

이 매니페스트는

  • DLL과 별도 파일로 두기
  • DLL에 리소스로 포함하기

어느 쪽으로도 구성할 수 있습니다.

실무에서는 private assembly로 DLL에 포함하는 편이 사고를 줄이는 경우가 많습니다. 별도 파일 운용은 알기 쉬운 반면, 파일 이름과 assemblyIdentity의 대응, 배치 위치, 복사 누락에 발목이 잡히기 쉽기 때문입니다.

컴포넌트 매니페스트를 두는 방법원래 레지스트리에 들어가 있던 comClass나 clsid, typelib 등의 정보를 컴포넌트 매니페스트가 XML로 가지며, DLL과 별도 파일로 둘지 DLL에 리소스로 포함할지를 고를 수 있고, 실무에서는 포함이 사고를 줄이기 쉬움을 나타내는 그림.레지스트리에 있던 정보를 XML로 가진다별도 파일로 둔다DLL에 포함한다복사 누락 등으로 발목이 잡히기 쉽다실무에서는 사고를 줄이는 경우가 많다

그림 6: 정보의 내용은 같아도, 두는 방식의 선택이 사고율을 좌우한다.

5.3 실행 시에는 액티베이션 컨텍스트가 먼저 보인다

Reg-Free COM의 핵심은 여기입니다.

앱이 CLSIDFromProgIDCoCreateInstance를 호출하면, COM 런타임은 활성 액티베이션 컨텍스트를 봅니다. 거기에 필요한 ProgID → CLSID, CLSID → DLL 정보가 있으면 레지스트리 없이 해결할 수 있습니다.

반대로 필요한 정보가 매니페스트에 부족하면 통상의 등록 기반 해결로 떨어집니다. 이 동작 때문에 개발 PC에서는 우연히 동작한다는 함정이 생깁니다. Reg-Free로 된 줄 알았는데 실제로는 로컬 등록에 기대고 있던 경우입니다.

여기가 Reg-Free COM에서 가장 성가신 함정입니다.

등록 기반 해결로 떨어지는 함정CoCreateInstance의 해결에서는 액티베이션 컨텍스트가 먼저 보이지만, 매니페스트에 필요한 정보가 부족하면 통상의 등록 기반 해결로 떨어지므로, 개발 PC에서는 로컬 등록에 기대어 우연히 동작한다는 함정이 생김을 나타내는 그림.충분하다부족하다해결은 액티베이션 컨텍스트가 먼저매니페스트에 정보가 충분한가레지스트리 없이 해결등록 기반 해결로 떨어진다개발 PC에서는 우연히 동작하는 함정

그림 7: 조용히 떨어지는 폴백이, 이 구조에서 가장 큰 함정이다.

6. 무엇이 좋은가

Reg-Free COM의 이점은 실무에서 꽤 분명합니다.

6.1 XCOPY 배포가 쉽다

앱 폴더에 필요한 파일을 모아 둘 수 있어, 설치 프로그램이나 등록 처리가 가벼워집니다. 물론 Program Files 아래에 쓰면 권한은 다른 이야기지만, 적어도 COM 등록을 위한 관리자 작업은 줄이기 쉽습니다.

6.2 버전 충돌을 줄이기 쉽다

같은 머신에 COM 부품의 여러 버전이 있어도, 앱마다 쓰는 판을 나누기 쉬워집니다. 다른 제품의 설치로 갑자기 동작이 바뀌었다는 사고를 꽤 피하기 쉬워집니다.

6.3 기존 코드를 크게 바꾸지 않아도 되는 경우가 많다

Reg-Free COM은 기존 코드의 호출 방식을 근본부터 바꾸기보다 해결 방식을 바꾸는 구조입니다. 그래서 잘 맞으면 CoCreateInstance 쪽 코드를 거의 건드리지 않고 도입할 수 있습니다.

6.4 삭제와 롤백이 편해진다

앱 단위로 가둬 있으므로 갱신과 롤백이 꽤 단순해집니다. 극단적으로 말하면 폴더째 교체하는 발상을 취하기 쉬워집니다.

앱 단위로 가두는 이점COM 부품을 앱 단위로 가두면 XCOPY 배포의 쉬움, 버전 충돌 회피의 쉬움, 기존 코드를 거의 바꾸지 않는 도입, 삭제와 롤백의 단순함이라는 이점이 생김을 나타내는 그림.앱 단위로 가둔다XCOPY 배포가 쉽다버전 충돌을 줄일 수 있다폴더째 교체할 수 있다호출 코드는 거의 건드리지 않는다

그림 8: 이점은 모두, 가뒀다는 하나의 성질에서 나온다.

7. 맞는 장면·맞지 않는 장면

7.1 맞는 장면

이런 경우에는 Reg-Free COM이 꽤 유력합니다.

상황 궁합
앱 전용 COM DLL / OCX를 같이 넣고 싶다 아주 좋음
같은 PC에 여러 버전을 공존시키고 싶다 아주 좋음
벤더 부품의 등록 사고를 피하고 싶다 좋음
ActiveX / OCX를 기존 데스크톱 앱에서 private로 쓰고 싶다 좋음
배포를 가볍게 하면서, 기존 호출은 크게 바꾸고 싶지 않다 좋음

전형적으로는 업무 데스크톱 앱, 장치 연동 도구, VB6 / MFC / WinForms의 기존 자산과 궁합이 좋습니다.

7.2 맞지 않거나, 신중히 봐야 할 장면

한편 신중히 보는 편이 좋은 경우도 있습니다.

상황 코멘트
COM을 머신 전체에서 공유하고 싶다 Reg-Free의 이점이 적다
bitness가 맞지 않는다 Reg-Free로는 해결되지 않는다
비표준 등록 정보나 독자 설치에 강하게 의존한다 매니페스트화하기 어렵다
의존 DLL이나 VC++ 런타임 배포가 정리되어 있지 않다 결국 다른 곳에서 넘어진다
설계 시 도구나 IDE의 참조 설정이 레지스트리 전제다 별도의 운용 설계가 필요

특히 마지막 점이 중요합니다. Reg-Free COM은 실행 시 액티베이션을 돕지만, 설계 시 참조 설정 UI가 무엇을 전제로 하는지까지 한 번에 바꿔 주지는 않습니다.

실행 시는 도움이 되지만 설계 시는 남는다Reg-Free COM은 실행 시 액티베이션을 돕지만, 설계 시 도구나 IDE의 참조 설정이 레지스트리 전제인 경우에는 그대로는 바뀌지 않아 별도의 운용 설계가 필요함을 나타내는 그림.실행 시의 액티베이션Reg-Free가 도와 준다설계 시의 참조 설정 UI레지스트리 전제인 경우가 있다별도의 운용 설계가 필요

그림 9: 움직이는 구조가 갖춰져도, 개발하는 구조는 따로 갖춘다.

8. 흔한 오해

8.1 Reg-Free COM이면 bitness 문제는 사라진다

사라지지 않습니다. 32bit 프로세스에는 32bit in-proc COM DLL만 로드할 수 있고, 64bit 프로세스에는 64bit DLL만 들어갑니다. 이 점은 Reg-Free에서도 예전과 같습니다.

8.2 Reg-Free COM이면 레지스트리를 전혀 보지 않는다

이것도 틀립니다. 매니페스트에 필요 정보가 부족하면 통상의 등록 기반 해결로 떨어집니다. 그래서 개발 PC에서 성공 = Reg-Free 구성이 올바르다고 할 수는 없습니다.

8.3 Reg-Free COM이면 형식 라이브러리 이야기도 자동으로 정리된다

여기는 반만 맞습니다. 매니페스트에 typelib 정보도 쓸 수 있지만, VBA의 참조 설정, C++의 #import, .NET 쪽의 설계 시 참조 생성처럼 형식 정보의 취급은 따로 설계가 필요한 경우가 흔합니다.

Reg-Free COM은 우선 기동할 수 있게 하는 이야기입니다. 형식을 붙여 어떻게 개발할지는 그다음 논점입니다.

기동 이야기와 형식 이야기의 순서매니페스트에 typelib 정보도 쓸 수 있지만, VBA의 참조 설정이나 C++의 import, .NET의 설계 시 참조 생성 등 형식 정보의 취급은 따로 설계가 필요하며, Reg-Free COM은 우선 기동할 수 있게 하는 이야기이고 형식이 있는 개발은 그다음 논점임을 나타내는 그림.Reg-Free COM을 구성한다우선 기동할 수 있게 한다다음에 형식을 붙여 어떻게 개발할지VBA 참조 설정 / import / interop 생성

그림 10: typelib를 쓸 수 있는 것과, 형식 정보 운용이 끝난 것은 별개이다.

8.4 Reg-Free COM이면 어떤 ActiveX / OCX든 그대로 된다

여기도 위험합니다. 컴포넌트가 표준 COM 등록 정보에 올라타 있으면 진행하기 쉽지만, 독자 레지스트리 설정, 추가 설치, 라이선스 처리, 다른 모듈들에 대한 의존이 깊으면 Reg-Free화는 갑자기 까다로워집니다.

8.5 Reg-Free COM과 .NET Framework / .NET 8은 대체로 같다

비슷한 점은 있지만 툴체인은 꽤 다릅니다. .NET Framework + RegAsm 맥락과 .NET 5+ / .NET 8 + comhost 맥락은, 같은 COM이라도 발판이 다릅니다.

9. 네이티브 / .NET Framework / .NET 5+ / .NET 8의 차이

여기는 섞이기 쉬우므로 한 번 나눠 봅니다.

계통 대략 정리
네이티브 COM DLL / OCX 애플리케이션 매니페스트 + 컴포넌트 매니페스트로 생각하는 것이 기본
.NET Framework 기반 COM 상호 운용 Win32 스타일 애플리케이션 매니페스트에 더해, 매니지드 컴포넌트 쪽 매니페스트도 필요
.NET 5+ / .NET 8에서 COM 공개 EnableComHosting으로 COM host를 만들고, EnableRegFreeCom으로 Reg-Free용 manifest를 생성할 수 있다

9.1 .NET Framework 기반 COM

.NET Framework 기반 COM에서는 COM 앱 쪽의 Win32 스타일 application manifest매니지드 컴포넌트 쪽의 component manifest의 2단 구성이 됩니다.

즉 네이티브 COM 때보다 manifest가 한 장 늘어납니다. 10.4의 이름과 리소스 ID 제약은 이쪽 component manifest에도 마찬가지로 적용됩니다.

9.2 .NET 5+ / .NET 8에서의 COM 공개

.NET 5+ / .NET 8에서는 COM 공개의 입구가 *.comhost.dll이 됩니다. 여기에 EnableRegFreeCom=true를 넣으면 Reg-Free COM용 side-by-side manifest가 출력됩니다.

형식 정보의 취급이 별도의 논점이 되는 것은 8.3과 같지만, .NET Core / .NET 5+에서는 여기가 더 바뀝니다. .NET Framework 때처럼 어셈블리에서 TLB가 자연스럽게 나오는 세계가 아니므로, 형식이 있는 이용이 필요하면 TLB의 생성·포함·등록을 따로 조립해야 합니다. 구체적인 절차는 「.NET 8 DLL을 VBA에서 타입이 지정된 상태로 쓰는 방법 - COM 공개와 dscom TLB」에 정리해 두었습니다.

.NET 5 이후의 Reg-Free COM.NET 5 이후에는 EnableComHosting으로 COM 공개의 입구가 되는 comhost.dll을 만들고, EnableRegFreeCom을 켜면 Reg-Free COM용 side-by-side 매니페스트가 출력되지만, TLB의 생성이나 등록은 따로 조립해야 함을 나타내는 그림.EnableComHosting으로 빌드comhost.dll이 입구가 된다EnableRegFreeCom을 켠다Reg-Free용 매니페스트가 출력된다TLB의 취급은 따로 조립한다

그림 11: .NET 8에서는 속성 두 개로 발판이 생기지만, 형식 정보는 별 작업이다.

10. 최소 구성 이미지

여기서는 MyApp.exeVendor.CameraControl.dll을 Reg-Free COM으로 쓰는 최소 이미지를 보입니다.

10.1 파일 구성 이미지

MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.Asm.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll

위 예에서는 컴포넌트 매니페스트를 별도 파일로 둔 가정입니다. DLL에 포함하는 형태로도 할 수 있지만, 그때는 assembly 이름과 리소스 ID에 정해진 제약이 붙습니다. 절차마다 10.4에서 다룹니다.

10.2 애플리케이션 매니페스트의 이미지

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="KomuraSoft.MyApp"
    version="1.0.0.0"
    processorArchitecture="amd64" />

  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Vendor.CameraControl.Asm"
        version="1.0.0.0"
        processorArchitecture="amd64" />
    </dependentAssembly>
  </dependency>
</assembly>

10.3 컴포넌트 매니페스트의 이미지

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    type="win32"
    name="Vendor.CameraControl.Asm"
    version="1.0.0.0"
    processorArchitecture="amd64" />

  <file name="Vendor.CameraControl.dll">
    <comClass
      clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
      progid="Vendor.CameraControl.1"
      threadingModel="Apartment"
      tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}" />

    <typelib
      tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}"
      version="1.0"
      helpdir="" />
  </file>
</assembly>

이 예에서 정말 중요한 것은 XML의 세부보다 앱 쪽 dependentAssembly와 컴포넌트 쪽 assemblyIdentity가 일치하는 것입니다. 여기가 어긋나면 오류 겉모습만으로는 원인을 알 수 없는 기동 실패가 됩니다.

참고로 위의 GUID와 이름은 설명용 예입니다. 실제로는 컴포넌트가 공개하는 CLSID / TLBID / ProgID / threading model에 맞춰 올바르게 써야 합니다.

두 매니페스트의 일치 요건앱 쪽 dependentAssembly와 컴포넌트 쪽 assemblyIdentity는 이름이나 버전이 일치해야 하며, 여기가 어긋나면 오류 겉모습만으로는 원인을 알 수 없는 기동 실패가 됨을 나타내는 그림.일치어긋남앱 쪽 dependentAssembly이름이나 버전이 일치하는가컴포넌트 쪽 assemblyIdentity해결이 성립한다원인이 안 보이는 기동 실패

그림 12: XML의 세부보다, 양쪽 이름표가 일치하는지가 생사를 가른다.

10.4 매니페스트를 어디에 둘지, 어떻게 포함할지

여기가 절차로서 가장 막히기 쉬운 곳입니다. 별도 파일로 둘지, 바이너리에 포함할지에 따라 붙여도 되는 이름이 바뀝니다.

side-by-side는 private assembly를 앱 폴더에 대해 이 순서로 찾습니다.

  1. WinSxS 폴더
  2. <appdir>\<assemblyname>.DLL
  3. <appdir>\<assemblyname>.manifest
  4. <appdir>\<assemblyname>\<assemblyname>.DLL
  5. <appdir>\<assemblyname>\<assemblyname>.manifest

assembly 이름과 같은 이름의 DLL이 먼저 발견되면, 거기서 탐색이 멈춥니다. 여기서 다음 두 가지밖에 성립하지 않습니다.

두는 방식 assembly 이름 파일 포함처 리소스 ID
별도 파일 DLL 이름과 다른 이름으로 한다. 예: Vendor.CameraControl.Asm Vendor.CameraControl.Asm.manifest를 DLL 옆에 둔다 포함하지 않음
DLL에 포함 DLL 이름과 같아도 된다. 예: Vendor.CameraControl Vendor.CameraControl.dll 1

즉 10.2와 10.3의 예처럼 Vendor.CameraControl.Asm이라는 이름을 쓴다면, 그것은 별도 파일 방식입니다. 포함으로 바꾸려면 assemblyIdentitynameVendor.CameraControl로 바꾸고, dependentAssembly 쪽도 같은 이름으로 맞춥니다.

탐색이 멈추는 구조side-by-side는 private assembly를 WinSxS부터 앱 폴더 순으로 찾고, assembly 이름과 같은 이름의 DLL이 먼저 발견되면 거기서 탐색이 멈추므로, 별도 파일 운용에서는 assembly 이름을 DLL 이름과 다르게 두어야 함을 나타내는 그림.발견없음private assembly 탐색을 시작assembly 이름과 같은 DLL을 찾는다거기서 탐색이 멈춘다같은 이름의 manifest 파일을 찾는다별도 파일 운용에서는 이름을 다르게 한다

그림 13: 이름 붙이기 제약은, 탐색이 중간에 멈추는 사양에서 온다.

하나 더, 틀리기 쉬운 제약이 있습니다. 컴포넌트 매니페스트는 EXE 리소스에 넣을 수 없습니다. EXE에 넣을 수 있는 것은 애플리케이션 매니페스트 쪽입니다.

포함에는 Windows SDK의 mt.exe(매니페스트 도구)를 씁니다. Visual Studio의 개발자 명령 프롬프트에서 실행합니다.

rem 1. 포함하기 전에, 먼저 구문 검사를 통과시킨다
mt.exe -manifest MyApp.exe.manifest -validate_manifest
mt.exe -manifest Vendor.CameraControl.manifest -validate_manifest

rem 2. 애플리케이션 매니페스트를 EXE에 포함한다
mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;#1

rem 3. 컴포넌트 매니페스트를 DLL에 포함한다(리소스 ID는 1)
mt.exe -manifest Vendor.CameraControl.manifest -outputresource:Vendor.CameraControl.dll;#1

rem 4. 포함됐는지, 꺼내서 확인한다
mt.exe -inputresource:Vendor.CameraControl.dll;#1 -out:extracted.manifest

4번째 명령으로 꺼낸 extracted.manifest를 원래 XML과 견주면, 「포함한 줄 알았는데 들어가 있지 않았다」를 없앨 수 있습니다.

mt.exe로 포함하는 절차mt.exe에서는 먼저 validate_manifest로 구문 검사를 통과시키고, 애플리케이션 매니페스트를 EXE에, 컴포넌트 매니페스트를 리소스 ID 1로 DLL에 포함한 뒤, 마지막으로 꺼내 원래 XML과 견주어 확인하는 흐름을 나타내는 그림.구문 검사를 통과시킨다앱 쪽을 EXE에 포함한다부품 쪽을 DLL에 포함한다〔ID 1〕꺼내서 원래 XML과 견준다

그림 14: 포함은, 확인까지 포함해 하나의 절차로 돌린다.

mt.exe에는 주의점이 두 가지 있습니다.

  • 매니페스트가 참조하는 파일은 매니페스트와 같은 디렉터리에 둬야 합니다. <file name="Vendor.CameraControl.dll">라고 썼다면 그 DLL을 매니페스트 옆에 두고 실행합니다. 빌드 출력과 매니페스트 관리 위치가 나뉘어 있으면 여기서 멈춥니다
  • -outputresource에서 리소스 ID를 생략하면 CREATEPROCESS_MANIFEST_RESOURCE(= 1)가 쓰입니다. 의도치 않게 1이 되어도 곤란하지 않도록 ;#1은 명시해 두는 편이 읽기 쉽습니다

이미 포함된 것을 교체하기만 하면 -updateresource:<파일>;#1을 쓸 수 있습니다. 이것은 -inputresource-outputresource에 같은 인수를 넘기는 것과 같은 뜻입니다.

10.5 클린 환경까지 포함한 확인 절차

Reg-Free COM은 「개발 PC에서 동작했다」가 거의 의미가 없습니다. 로컬 레지스트리 등록에 기대고 있을 뿐이라는 가능성이 항상 남기 때문입니다. 다음 순서로 확인합니다.

  1. 빌드하고, 배포물 일체를 한 폴더에 모은다. EXE, 매니페스트, COM DLL, 의존 DLL, VC++ 런타임, proxy / stub DLL까지
  2. 검증 환경을 마련한다. 대상 COM이 한 번도 등록된 적 없는 환경이 이상적입니다. Windows 샌드박스를 쓰면 매번 깨끗한 상태에서 시험할 수 있습니다
  3. 그 환경에서, 대상 COM이 미등록임을 먼저 확인한다. 아래 명령으로 키를 찾을 수 없다는 오류가 나면 미등록입니다
  4. 폴더를 복사해, 그대로 기동한다. 설치 프로그램도 regsvr32도 실행하지 않습니다
  5. COM 객체 생성까지 통과하는지 확인한다. 기동만으로는 지연 생성 컴포넌트는 검증할 수 없습니다. 실제로 CoCreateInstance가 도는 화면이나 기능까지 움직입니다
  6. 실패하면 11.2의 절차로 로그를 딴다

절차 3에서 쓰는 명령은 이것입니다.

reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:64
reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:32
reg query "HKCR\Vendor.CameraControl.1"

32bit와 64bit 레지스트리 뷰는 별개이므로, 앱 bitness에 맞는 쪽을 반드시 봅니다. /reg:64/reg:32를 둘 다 보면 확실합니다.

개발 PC에서 시험하고 싶을 때는 일단 regsvr32 /u Vendor.CameraControl.dll로 등록을 뺀 뒤 확인합니다. 다만 다른 제품이 같은 COM을 쓰는 환경에서는 영향이 나오므로, 클린 환경을 마련하는 편이 안전합니다.

클린 환경에서의 확인 흐름배포물 일체를 한 폴더에 모으고, 대상 COM이 등록된 적 없는 검증 환경을 마련한 뒤, 미등록임을 먼저 확인하고 폴더를 복사해 그대로 기동하며, CoCreateInstance가 도는 기능까지 움직여 확인하는 흐름을 나타내는 그림.실패하면배포물 일체를 모은다클린 검증 환경을 마련미등록임을 먼저 확인복사해 그대로 기동COM 생성이 도는 기능까지 움직인다로그를 따서 조사한다

그림 15: 미등록 확인을 끼워 넣음으로써, 우연히 동작하는 경우를 검증에서 배제한다.

11. 빠지기 쉬운 곳

11.1 개발 PC에서는 동작하는데, 배포 대상에서 동작하지 않는다

먼저 의심할 것은 실제로는 레지스트리 등록에 기대고 있던 패턴입니다. Reg-Free COM 검증은 가능하면 클린 환경에서 하는 편이 안전합니다.

11.2 「side-by-side configuration is incorrect」로 기동하지 않는다

이 계열은 manifest 불일치, 의존 DLL 부족, VC++ 런타임 부족, 아키텍처 차이 등으로 일어납니다. 표면의 오류 문장만으로는 꽤 불친절하므로, 이벤트 로그sxstrace로 추적하는 것이 정석입니다.

이벤트 로그는 이벤트 뷰어 > Windows 로그 > Application을 열고, 소스가 SideBySide인 오류를 찾습니다. 어느 assembly 해결에서 실패했는가가 여기에 나옵니다.

sxstrace는 실패를 재현하면서 캡처합니다. 명령 프롬프트는 관리자로 열어 두면 확실합니다.

rem 1. 추적을 시작한다. 이 창은 연 채로 둔다
sxstrace trace -logfile:sxstrace.etl

rem 2. 다른 창에서 앱을 기동하고, 실패를 재현한다

rem 3. 추적을 멈춘다. 1의 창에서 Enter를 누르거나, 다른 창에서 다음을 실행한다
sxstrace stoptrace

rem 4. 원본 .etl을 사람이 읽을 수 있는 형식으로 변환한다
sxstrace parse -logfile:sxstrace.etl -outfile:sxstrace.txt

중지 프롬프트를 내고 싶지 않으면 절차 1에 -nostop을 붙입니다. 출력이 너무 길면 절차 4에 -filter:MyApp.exe를 더해 대상 앱 분만 좁힐 수 있습니다.

변환 후의 sxstrace.txt에는 어느 매니페스트를 찾아, 어디서 일치하지 않았는가가 순서대로 늘어섭니다. 10.4의 이름 붙이기를 틀린 경우도, 여기서 「찾아 간 파일 이름」을 보면 알 수 있습니다.

side-by-side 오류를 조사하는 방법side-by-side configuration is incorrect로 기동하지 않을 때는 이벤트 뷰어에서 SideBySide 소스의 오류를 확인하고, sxstrace로 추적을 시작해 실패를 재현한 뒤, 중지 후 parse로 사람이 읽을 수 있는 형식으로 변환해 불일치 지점을 쫓는 흐름을 나타내는 그림.이벤트 로그에서 SideBySide를 확인sxstrace로 추적 시작앱을 기동해 실패를 재현중지하고 parse로 변환탐색과 불일치 지점을 읽는다

그림 16: 표면의 오류 문장으로 고민하지 말고, 로그와 추적으로 해결의 길을 쫓는다.

11.3 component manifest와 application manifest의 대응이 어긋난다

  • name이 다르다
  • version이 다르다
  • processorArchitecture가 다르다
  • 복사한 줄 알았던 manifest가 오래됐다

이 정도는 겉보기에는 아주 작은 차이지만, 기동 시에는 꽤 크게 작용합니다.

11.4 의존 DLL을 빠뜨린다

Vendor.CameraControl.dll만 보고 만족하면, 그 다음에 읽히는 Vendor.Helper.dll, VC++ 런타임, proxy / stub DLL이 빠집니다. Reg-Free COM은 COM 등록 문제를 줄이지만, 네이티브 의존 해결 문제까지 없애 주지는 않습니다.

11.5 type library나 참조 설정 운용을 뒤로 미룬다

런타임 activation만 통과해도,

  • VBA에서 초기 바인딩하고 싶다
  • C++에서 #import하고 싶다
  • .NET 쪽에서 설계 시에 interop을 만들고 싶다

가 되면 형식 정보를 나눠 주는 방법이 필요합니다. Reg-Free COM이 여기를 자동으로 전부 맞춰 주지는 않으므로, runtime과 design-time을 나눠 생각하는 것이 중요합니다.

12. 정리

Reg-Free COM을 한 마디로 말하면, COM의 등록 정보를 머신 전체에서 앱 단위로 옮기는 구조입니다.

이로써

  • COM DLL / OCX를 앱 로컬에 가두기 쉽다
  • 버전 충돌을 줄이기 쉽다
  • 배포와 롤백을 단순화하기 쉽다

는 이점이 있습니다.

한편

  • 32bit / 64bit
  • 의존 DLL
  • TLB / 참조 설정
  • 비표준 등록 의존
  • 클린 환경에서의 검증

은 여전히 중요합니다.

그래서 Reg-Free COM을 도입할 때의 기본 자세는 이렇습니다.

  1. 이것은 activation의 이야기이다고 선을 긋는다
  2. runtime과 design-time의 논점을 나눈다
  3. 클린 환경에서 확인한다
  4. bitness와 의존 DLL을 먼저 맞춘다

이 순서로 보면 사고를 꽤 줄일 수 있습니다.

도입 시의 기본 자세Reg-Free COM을 도입할 때는 이것은 액티베이션의 이야기라고 선을 긋고, 실행 시와 설계 시의 논점을 나누며, 클린 환경에서 확인하고, bitness와 의존 DLL을 먼저 맞추는 순서로 보면 사고가 줄어듦을 나타내는 그림.activation의 이야기라고 선을 긋는다runtime과 design-time을 나눈다클린 환경에서 확인한다bitness와 의존 DLL을 먼저 맞춘다

그림 17: 네 가지 자세를 순서대로 지키면, 도입 사고는 꽤 줄일 수 있다.

13. 관련 글

14. 참고 자료

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

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

ActiveX 이관

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

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

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

Reg-Free COM이란 무엇인가요?
COM의 등록 정보를 레지스트리가 아니라 매니페스트로 가지는 구조이며, Registration-Free COM의 약자입니다. 실행 시에는 CoCreateInstance나 CLSIDFromProgID의 해결에서 액티베이션 컨텍스트가 먼저 보이고, 거기에 적힌 매니페스트 정보로 DLL을 해결합니다. 이로써 COM DLL/OCX를 앱마다 private로 둘 수 있어, XCOPY 배포가 쉽고, 버전 충돌을 피하기 쉬우며, 제거가 잘 깨지지 않는다는 이점이 있습니다.
Reg-Free COM이면 32bit/64bit 문제도 해결되나요?
해결되지 않습니다. 32bit 프로세스에는 32bit in-proc COM DLL만 로드할 수 있고, 64bit 프로세스에는 64bit DLL만 들어갑니다. 이 점은 Reg-Free에서도 예전과 같습니다. 의존 DLL과 VC++ 런타임 배포, 형식 라이브러리, 설계 시 참조 설정, 비표준 등록 정보에 대한 의존도 따로 생각해야 합니다. Reg-Free COM에서 사라지는 것은 주로 글로벌 등록에 끌려가는 번거로움뿐입니다.
Reg-Free COM 구성이 개발 PC에서는 동작하는데 배포 대상에서 동작하지 않는 이유는 무엇인가요?
먼저 의심할 것은, 실제로는 레지스트리 등록에 기대고 있던 패턴입니다. 매니페스트에 필요한 정보가 부족하면 COM 런타임은 통상의 등록 기반 해결로 떨어지므로, 개발 PC에서는 로컬 등록 덕분에 우연히 동작하는 경우가 있습니다. 그래서 Reg-Free COM 검증은 클린 환경에서 하는 편이 안전합니다. 「side-by-side configuration is incorrect」로 기동하지 않을 때는 매니페스트 불일치나 의존 DLL 부족 등이 원인이며, 이벤트 로그와 sxstrace로 추적하는 것이 정석입니다.
.NET 8로 만든 COM 컴포넌트도 Reg-Free COM으로 할 수 있나요?
할 수 있습니다. .NET 5+/.NET 8에서는 EnableComHosting으로 COM 공개의 입구가 되는 *.comhost.dll을 만들고, 여기에 EnableRegFreeCom=true를 넣으면 Reg-Free COM용 side-by-side manifest가 출력됩니다. 다만 Reg-Free COM과 TLB 전략은 별개의 논점입니다. .NET Core/.NET 5+에서는 .NET Framework 때처럼 어셈블리에서 TLB가 자연스럽게 나오지 않으므로, VBA 초기 바인딩처럼 형식이 있는 이용이 필요하면 TLB의 생성·포함·등록을 따로 정리하는 편이 안전합니다.

저자 프로필

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

Go Komura

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

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

블로그 목록으로 돌아가기