Reg-Free COM이란 - 등록 불필요로 COM을 쓰는 구조
· 업데이트: · 小村 豪 · COM, Reg-Free COM, Registration-Free COM, Windows 개발, 레거시 기술
수정 이력(1건, 최종 수정 2026년 09월 01일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- 일본어 원문의 완역으로 다시 번역했습니다. 기존 한국어판은 원문의 일부만 옮긴 축약본이라 절, 표, Mermaid 그림, 그림 설명, FAQ가 빠져 있었습니다. 일본어 원문에 맞춰 이들을 모두 복원했고, 기술적인 주장은 일본어판과 같습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.21635177)
- 최초 공개
이 글을 인용하기(DOI: 10.5281/zenodo.21635176)
이 글은 Zenodo에 보관되어 있습니다. 항상 최신 버전으로 연결되는 DOI와 지금 보고 있는 버전에 고정된 DOI를 아래에 함께 제시합니다.
小村 豪 (2026). 「Reg-Free COM이란 - 등록 불필요로 COM을 쓰는 구조」. 합동회사 코무라소프트. https://doi.org/10.5281/zenodo.21635176 https://comcomponent.com/ko/blog/2026/03/16/011-what-is-reg-free-com/
- DOI(최신 버전)
- 10.5281/zenodo.21635176
- DOI(이 버전)
- 10.5281/zenodo.22217457
COM / ActiveX / OCX 관련 프로젝트에서는 배포와 갱신 때마다 같은 문제가 나옵니다.
- regsvr32가 필요
- 관리자 권한이 필요해지기 쉬움
- 다른 앱이 넣은 다른 버전과 부딪침
- 언인스톨 후에 다른 제품까지 말려듦
- 개발기에서는 동작하는데 클린 환경에서 동작하지 않음
이 수고를 꽤 줄일 수 있는 것이 Reg-Free COM입니다. 다만 이름에 비해 「COM의 번거로움이 전부 사라지는 마법」은 아닙니다. 사라지는 것은 주로 글로벌 등록에 끌려가는 번거로움입니다. bitness, 의존 DLL, 형 라이브러리, 스레드 모델의 어려움까지는 사라지지 않습니다.
flowchart TB
accTitle: Reg-Free COM에서 사라지는 것과 남는 것
accDescr: Reg-Free COM에서 사라지는 것은 주로 글로벌 등록에 끌려가는 번거로움이며, bitness나 의존 DLL, 형 라이브러리, 스레드 모델의 어려움은 사라지지 않음을 보이는 그림.
rf1["Reg-Free COM"] --> rf2["글로벌 등록의 번거로움은 줄어든다"]
rf1 --> rf3["남는 어려움도 있다"]
rf3 -.-> rf4["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.exe와 sxstrace를 쓰므로, Visual Studio나 Windows SDK가 설치된 환경을 상정합니다.
1. 먼저 결론(한마디로)
먼저 거칠지만 도움이 되는 표현으로 하면 이렇습니다.
- Reg-Free COM은 COM의 등록 정보를 레지스트리가 아니라 매니페스트로 가지는 방식입니다
- 실행 시에는
CoCreateInstance나CLSIDFromProgID의 해결에서 액티베이션 컨텍스트가 먼저 보입니다 - 그래서 COM DLL / OCX를 앱마다 private로 가질 수 있게 됩니다
- 주된 장점은 XCOPY 배포가 쉬운 것, 버전 충돌을 피하기 쉬운 것, 언인스톨이 망가지기 어려운 것입니다
- 다만 32bit / 64bit 문제는 사라지지 않습니다. 여기는 매니페스트를 쓰는 방식으로는 피할 수 없습니다
- 또한 의존 DLL, 형 라이브러리, 설계 시 참조, 비표준적인 등록 의존은 별도로 생각할 필요가 있습니다
- 실무에서는 앱 전용의 COM 부품을 옆에 두고 싶을 때 꽤 잘 맞습니다
요컨대 Reg-Free COM은 COM의 액티베이션을 앱 단위로 되돌리는 구조입니다.
flowchart TB
accTitle: 등록 정보가 있는 곳이 바뀐다
accDescr: Reg-Free COM은 COM의 등록 정보를 레지스트리가 아니라 매니페스트로 가지며, CoCreateInstance 등의 해결에서 액티베이션 컨텍스트가 먼저 보이므로 COM 부품을 앱마다 private로 가질 수 있음을 보이는 그림.
mg1["등록 정보를 매니페스트로 가진다"] --> mg2["해결 시 액티베이션 컨텍스트가 먼저"]
mg2 --> mg3["COM 부품을 앱마다 private로 가질 수 있다"]
mg3 -.-> mg4["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 매니페스트를 출력할 수 있습니다.
flowchart LR
accTitle: Reg-Free COM
accDescr: Reg-Free COM이 액티베이션 컨텍스트와 side-by-side assembly의 구조로 COM의 등록 정보를 앱 단위로 가지게 한다는 것, 애플리케이션 매니페스트와 컴포넌트 매니페스트의 역할 분담, mt.exe에 의한 구성과 sxstrace에 의한 장애 조사, .NET 5+의 comhost와의 관계를 보여주는 그림
reg_free_com["Reg-Free COM(등록 불필요 COM)"]
activation_context["활성화 컨텍스트"]
win32_application_manifest["애플리케이션 매니페스트(Win32 side-by-side)"]
component_manifest["컴포넌트 매니페스트(assembly manifest)"]
side_by_side_assembly["side-by-side assembly"]
bitness_match_requirement["비트수 일치 요건"]
regsvr32["regsvr32"]
type_library["타입 라이브러리(TLB)"]
mt_exe["mt.exe(매니페스트 도구)"]
sxstrace["sxstrace"]
assembly_searching_sequence["private assembly 탐색 순서"]
dotnet[".NET(Core 이후)"]
comhost["COM host(*.comhost.dll)"]
enable_com_hosting["EnableComHosting"]
enable_regfreecom["EnableRegFreeCom"]
vb6["Visual Basic 6.0(VB6)"]
clsid["CLSID(Class ID)"]
progid["ProgID(Programmatic Identifier)"]
com["COM(컴포넌트 오브젝트 모델)"]
activex["ActiveX"]
ocx["OCX"]
mfc["MFC(Microsoft Foundation Classes)"]
windows_forms["Windows Forms"]
machine_wide_com_sharing["COM의 시스템 전역 공유"]
reg_free_com -->|"이용한다"| activation_context
reg_free_com -->|"이용한다"| win32_application_manifest
reg_free_com -->|"이용한다"| component_manifest
win32_application_manifest -->|"전제로 한다"| side_by_side_assembly
component_manifest -->|"구현을 담당한다"| side_by_side_assembly
reg_free_com -->|"전제로 한다"| bitness_match_requirement
reg_free_com -.->|"의 후속"| regsvr32
component_manifest -.->|"이용한다"| type_library
reg_free_com -->|"에서 구성할 수 있다"| mt_exe
reg_free_com -->|"에서 확인할 수 있다"| sxstrace
component_manifest -->|"에서 구성할 수 있다"| mt_exe
reg_free_com -->|"전제로 한다"| assembly_searching_sequence
dotnet -.->|"이용한다"| comhost
comhost -->|"전제로 한다"| enable_com_hosting
comhost -->|"에서 구성할 수 있다"| enable_regfreecom
enable_regfreecom -->|"구현을 담당한다"| reg_free_com
vb6 -.->|"이용한다"| type_library
component_manifest -->|"이용한다"| clsid
component_manifest -.->|"이용한다"| progid
reg_free_com -->|"이용한다"| com
reg_free_com -->|"이용한다"| activex
reg_free_com -->|"이용한다"| ocx
reg_free_com -->|"권장되는 대응"| vb6
reg_free_com -->|"권장되는 대응"| mfc
reg_free_com -->|"권장되는 대응"| windows_forms
reg_free_com -->|"사용은 비권장"| machine_wide_com_sharing
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 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를 쓴 공개
반대로 이 글에서 강조하고 싶은 것은 다음 2점입니다.
- Reg-Free COM은 「액티베이션」의 이야기이다
- 형 정보의 배포나 설계 시의 참조 설정은 별도의 논점으로 남을 수 있다
여기를 섞으면 이야기가 꽤 탁해집니다.
flowchart TB
accTitle: 섞으면 안 되는 두 논점
accDescr: Reg-Free COM은 액티베이션의 이야기이고, 형 정보의 배포나 설계 시의 참조 설정은 별도의 논점으로 남을 수 있으므로, 이 둘을 섞으면 이야기가 탁해짐을 보이는 그림.
pt1["Reg-Free COM"] --> pt2["액티베이션의 이야기"]
pt3["형 정보 배포·설계 시 참조"] --> pt4["별도의 논점으로 남는다"]
pt2 -.-> pt5["섞으면 이야기가 탁해진다"]
pt4 -.-> pt5
그림 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은 생성 측 스레드의 액티베이션 컨텍스트를 호스트 측 스레드에 넘긴 뒤 LoadLibrary나 DllGetClassObject를 호출하므로, 호출하는 쪽에서 특별한 준비는 필요하지 않습니다.
이를 바탕으로 전체상을 한 장으로 보는 편이 빠릅니다.
flowchart LR
APP["MyApp.exe"] --> AM["Application Manifest"]
AM --> DEP["dependentAssembly"]
DEP --> CM["Component / Assembly Manifest"]
CM --> META["file / comClass / typelib"]
META --> DLL["VendorControl.dll / .ocx"]
APP --> ACTX["Activation Context"]
ACTX --> COM["CLSIDFromProgID / CoCreateInstance"]
COM --> DLL
그림 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을 망가뜨린다
- 개발기에 우연히 들어 있는 등록이 운영기에는 없다
- 32bit와 64bit의 등록이 맞물리지 않아 현상만 기묘하게 어긋난다
즉 COM 본체보다 배포 모델 쪽이 사람을 곤란하게 하는 경우가 꽤 많습니다. Reg-Free COM은 이 배포 모델의 괴로움을 줄이기 위한 구조입니다.
flowchart TB
accTitle: 글로벌 공유가 역효과를 내는 흐름
accDescr: COM의 등록 정보가 레지스트리에 들어가면 머신 전체에서 공유하기 쉬워지지만, 실무에서는 다른 제품에 의한 덮어쓰기나 언인스톨에서의 말려듦, 개발기와 운영기의 환경 차이로 역효과가 나기 쉬우며, COM 본체보다 배포 모델이 사람을 곤란하게 함을 보이는 그림.
gs1["등록 정보를 머신 전체에서 공유"] --> gs2["여러 앱에서 쓸 수 있어 편리"]
gs1 --> gs3["실무에서는 공유가 역효과를 낸다"]
gs3 -.-> gs4["덮어쓰기 / 말려듦 / 환경 차이"]
gs3 --> gs5["배포 모델이 사람을 곤란하게 한다"]
그림 5: 괴로움의 정체는 COM 자체가 아니라 글로벌 등록이라는 전제.
5. Reg-Free COM의 구조
5.1 애플리케이션 매니페스트로 의존 관계를 쓴다
우선 앱 쪽은 자신이 어느 side-by-side assembly에 의존하고 있는지를 애플리케이션 매니페스트에 씁니다.
이 매니페스트는,
MyApp.exe.manifest처럼 EXE의 옆에 둔다- EXE에 리소스로서 매립한다
중 어느 쪽으로도 다룰 수 있습니다. 실무에서는 배포나 교체를 보기 쉽게 하고 싶다면 외부 파일, 망가지기 어려움과 배포의 단순함을 우선한다면 매립이라는 구분이 많습니다.
덧붙여 외부 파일 버전과 매립 버전의 양쪽이 있는 경우는 파일 시스템상의 매니페스트가 우선됩니다.
5.2 컴포넌트 매니페스트로 COM 정보를 쓴다
다음으로 COM 쪽은 원래 레지스트리에 들어 있던 정보를 컴포넌트 매니페스트에 가집니다.
여기에는 예를 들어 다음 같은 정보가 들어갑니다.
comClassclsidprogidthreadingModeltypelib- 필요하다면 proxy / stub이나 window class 등
즉 레지스트리 대신 XML로 COM의 외형을 기술하는 이미지입니다.
이 매니페스트는,
- DLL과 별도 파일로 둔다
- DLL에 리소스로서 매립한다
중 어느 쪽으로도 구성할 수 있습니다.
실무에서는 private assembly로서 DLL에 매립하는 쪽이 사고 나기 어려운 경우가 많습니다. 별도 파일 운영은 이해하기 쉬운 반면, 파일명과 assemblyIdentity의 대응, 배치 장소, 복사 누락에서 발을 걸기 쉽기 때문입니다.
flowchart TB
accTitle: 컴포넌트 매니페스트가 정보를 가지는 방식
accDescr: 원래 레지스트리에 들어 있던 comClass나 clsid, typelib 등의 정보를 컴포넌트 매니페스트가 XML로 가지며, DLL과 별도 파일로 두거나 DLL에 리소스로 매립하는 것을 고를 수 있고, 실무에서는 매립 쪽이 사고 나기 어려움을 보이는 그림.
cm1["레지스트리에 있던 정보를 XML로 가진다"] --> cm2["별도 파일로 둔다"]
cm1 --> cm3["DLL에 매립한다"]
cm2 -.-> cm4["복사 누락 등으로 발이 걸리기 쉽다"]
cm3 -.-> cm5["실무에서는 사고 나기 어려운 경우가 많다"]
그림 6: 정보의 내용은 같아도, 두는 방식의 선택이 사고율을 좌우한다.
5.3 실행 시에는 액티베이션 컨텍스트가 먼저 보인다
Reg-Free COM의 핵심은 여기입니다.
앱이 CLSIDFromProgID나 CoCreateInstance를 호출하면 COM 런타임은 액티브한 액티베이션 컨텍스트를 봅니다.
거기에 필요한 ProgID → CLSID, CLSID → DLL의 정보가 있으면 레지스트리를 쓰지 않고 해결할 수 있습니다.
반대로 필요한 정보가 매니페스트에 부족하면 통상의 등록 기반 해결로 떨어집니다. 이 동작 때문에 개발기에서는 우연히 동작한다는 덫이 생깁니다. Reg-Free로 할 수 있었다고 생각했는데 실제로는 로컬 등록에 도움받고 있는 것, 바로 그것입니다.
여기가 Reg-Free COM의 가장 짜증나는 함정입니다.
flowchart TB
accTitle: 등록 기반 해결로 떨어지는 함정
accDescr: CoCreateInstance의 해결에서는 액티베이션 컨텍스트가 먼저 보이지만, 매니페스트에 필요한 정보가 부족하면 통상의 등록 기반 해결로 떨어지므로, 개발기에서는 로컬 등록에 도움받아 우연히 동작하는 함정이 생김을 보이는 그림.
ac1["해결은 액티베이션 컨텍스트가 먼저"] --> ac2{"매니페스트에 정보가 충분한가"}
ac2 -->|"충분"| ac3["레지스트리를 쓰지 않고 해결"]
ac2 -->|"부족"| ac4["등록 기반 해결로 떨어진다"]
ac4 -.-> ac5["개발기에서는 우연히 동작하는 함정"]
그림 7: 조용히 떨어지는 폴백이 이 구조의 가장 큰 함정.
6. 무엇이 좋은가
Reg-Free COM의 이점은 실무에서는 꽤 분명합니다.
6.1 XCOPY 배포가 쉽다
앱 폴더에 필요한 파일을 모아 둘 수 있으므로 인스톨러나 등록 처리가 가벼워집니다.
물론 Program Files 아래에 쓴다면 권한은 별개 이야기지만, 적어도 COM 등록을 위한 관리자 작업은 줄이기 쉽습니다.
6.2 버전 충돌을 줄이기 쉽다
같은 머신 위에 복수 버전의 COM 부품이 있어도 앱마다 쓸 버전을 나누기 쉬워집니다.
다른 제품의 셋업으로 갑자기 동작이 바뀌었다는 사고를 꽤 피하기 쉬워집니다.
6.3 기존 코드를 크게 바꾸지 않아도 되는 경우가 많다
Reg-Free COM은 기존 코드의 호출 방식을 근본부터 바꾸기보다 해결하는 방식을 바꾸는 구조입니다.
그래서 잘 맞으면 CoCreateInstance 쪽 코드를 거의 건드리지 않고 도입할 수 있습니다.
6.4 삭제와 롤백이 편해진다
앱 단위로 갇혀 있으므로 갱신이나 롤백이 꽤 단순해집니다. 극단적으로 말하면 폴더째 교체하는 발상이 취하기 쉬워집니다.
flowchart TB
accTitle: 앱 단위로 가두는 것의 이점
accDescr: COM 부품을 앱 단위로 가둠으로써 XCOPY 배포의 용이함, 버전 충돌의 회피 용이함, 기존 코드를 거의 바꾸지 않는 도입, 삭제와 롤백의 단순함이라는 이점이 생김을 보이는 그림.
cl1["앱 단위로 가둔다"] --> cl2["XCOPY 배포가 쉽다"]
cl1 --> cl3["버전 충돌을 줄일 수 있다"]
cl2 -.-> cl5["폴더째 교체할 수 있다"]
cl3 -.-> cl4["호출 코드는 거의 건드리지 않는다"]
그림 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가 무엇을 전제로 하고 있는가까지 한 방에 바꿔 주지는 않습니다.
flowchart TB
accTitle: 실행 시는 도움이 되지만 설계 시는 남는다
accDescr: Reg-Free COM은 실행 시의 액티베이션을 돕지만, 설계 시의 도구나 IDE의 참조 설정이 레지스트리를 전제하는 경우는 그대로는 바뀌지 않아 별도의 운영 설계가 필요함을 보이는 그림.
rt1["실행 시의 액티베이션"] --> rt2["Reg-Free가 도와준다"]
dt1["설계 시의 참조 설정 UI"] --> dt2["레지스트리를 전제하는 경우가 있다"]
dt2 -.-> dt3["별도의 운영 설계가 필요"]
그림 9: 움직이는 구조가 갖춰져도, 개발하는 구조는 따로 갖춘다.
8. 흔한 오해
8.1 Reg-Free COM이면 bitness 문제는 사라진다
사라지지 않습니다. 32bit 프로세스에는 32bit의 in-proc COM DLL밖에 로드할 수 없고, 64bit 프로세스에는 64bit DLL밖에 들어가지 않습니다. 여기는 Reg-Free에서도 종래대로입니다.
8.2 Reg-Free COM이면 레지스트리를 일절 보지 않는다
이것도 다릅니다. 매니페스트에 필요 정보가 부족하면 통상의 등록 기반 해결로 떨어집니다. 그래서 개발기에서 성공 = Reg-Free 구성이 올바르다고는 할 수 없습니다.
8.3 Reg-Free COM이면 형 라이브러리 이야기도 자동으로 정리된다
여기는 반만 옳습니다.
매니페스트에는 typelib 정보도 쓸 수 있지만, VBA의 참조 설정, C++의 #import, .NET 쪽의 설계 시 참조 생성 등 형 정보의 취급은 별도로 설계가 필요한 경우가 평범하게 있습니다.
Reg-Free COM은 우선 기동할 수 있게 하는 이야기입니다. 어떻게 형 있게 개발할까는 그 다음의 논점입니다.
flowchart TB
accTitle: 기동의 이야기와 형의 이야기의 순서
accDescr: 매니페스트에는 typelib 정보도 쓸 수 있지만, VBA의 참조 설정이나 C++의 import, .NET의 설계 시 참조 생성 등 형 정보의 취급은 별도 설계가 필요하며, Reg-Free COM은 우선 기동할 수 있게 하는 이야기이고 형 있는 개발은 그다음 논점임을 보이는 그림.
st1["Reg-Free COM을 구성한다"] --> st2["우선 기동할 수 있게 한다"]
st2 --> st3["다음으로 형 있게 어떻게 개발할까"]
st3 -.-> st4["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 스타일의 애플리케이션 매니페스트에 더해 managed 컴포넌트 쪽의 매니페스트도 필요 |
| .NET 5+ / .NET 8에서 COM 공개 | EnableComHosting으로 COM host를 만들고, EnableRegFreeCom으로 Reg-Free용 manifest를 생성할 수 있다 |
9.1 .NET Framework 기반의 COM
.NET Framework 기반의 COM에서는 COM 앱 쪽의 Win32 스타일 application manifest와 managed 컴포넌트 쪽의 component manifest의 2단 구성이 됩니다.
즉 네이티브 COM일 때보다 manifest가 1장 늘어납니다. 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」에 정리되어 있습니다.
flowchart TB
accTitle: .NET 5 이후의 Reg-Free COM
accDescr: .NET 5 이후에는 EnableComHosting으로 COM 공개의 입구가 되는 comhost.dll을 만들고, EnableRegFreeCom을 활성화하면 Reg-Free COM용의 side-by-side 매니페스트가 출력되지만, TLB의 생성이나 등록은 별도로 조립해야 함을 보이는 그림.
dn1["EnableComHosting으로 빌드"] --> dn2["comhost.dll이 입구가 된다"]
dn2 --> dn3["EnableRegFreeCom을 활성화"]
dn3 --> dn4["Reg-Free용 매니페스트가 출력된다"]
dn4 -.-> dn5["TLB의 취급은 별도로 조립한다"]
그림 11: .NET 8에서는 속성 2개로 발판이 만들어지지만, 형 정보는 별도 작업.
10. 최소 구성 이미지
여기서는 MyApp.exe가 Vendor.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에 맞춰 올바르게 써야 합니다.
flowchart TB
accTitle: 두 매니페스트의 일치 요건
accDescr: 앱 쪽의 dependentAssembly와 컴포넌트 쪽의 assemblyIdentity는 이름과 버전이 일치해야 하며, 여기가 어긋나면 에러의 겉모습만으로는 원인을 알 수 없는 기동 실패가 됨을 보이는 그림.
mm1["앱 쪽의 dependentAssembly"] --> mm3{"이름과 버전이 일치하는가"}
mm2["컴포넌트 쪽의 assemblyIdentity"] --> mm3
mm3 -->|"일치"| mm4["해결이 성립한다"]
mm3 -->|"어긋남"| mm5["원인을 알 수 없는 기동 실패"]
그림 12: XML의 세부보다 양쪽의 명찰이 일치하는지가 생사를 가른다.
10.4 매니페스트를 어디에 두고, 어떻게 매립할까
여기가 절차상 가장 걸려 넘어지기 쉬운 곳입니다. 별도 파일로 두느냐, 바이너리에 매립하느냐에 따라 붙여도 되는 이름이 달라집니다.
side-by-side는 private assembly를 앱 폴더에 대해 다음 순서로 찾습니다.
- WinSxS 폴더
<appdir>\<assemblyname>.DLL<appdir>\<assemblyname>.manifest<appdir>\<assemblyname>\<assemblyname>.DLL<appdir>\<assemblyname>\<assemblyname>.manifest
assembly 이름과 같은 이름의 DLL이 먼저 발견되면 거기서 탐색이 멈춥니다. 여기서부터는 다음의 2가지 방식만 성립합니다.
| 두는 방식 | 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이라는 이름을 쓴다면 그것은 별도 파일의 작법입니다. 매립으로 전환하려면 assemblyIdentity의 name을 Vendor.CameraControl로 바꾸고, dependentAssembly 쪽도 같은 이름으로 맞춥니다.
flowchart TB
accTitle: 탐색이 멈추는 구조
accDescr: side-by-side는 private assembly를 WinSxS부터 앱 폴더 순으로 찾고, assembly 이름과 같은 이름의 DLL이 먼저 발견되면 거기서 탐색이 멈추므로, 별도 파일 운영에서는 assembly 이름을 DLL 이름과 다르게 해야 함을 보이는 그림.
se1["private assembly 탐색을 시작"] --> se2["assembly 이름과 같은 DLL을 찾는다"]
se2 -->|"찾음"| se3["거기서 탐색이 멈춘다"]
se2 -->|"못 찾음"| se4["같은 이름의 manifest 파일을 찾는다"]
se3 -.-> se5["별도 파일 운영에서는 이름을 다르게 한다"]
그림 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과 비교하면 「매립한 셈이었는데 들어가 있지 않았다」를 방지할 수 있습니다.
flowchart TB
accTitle: mt.exe에서의 매립 절차
accDescr: mt.exe에서는 먼저 validate_manifest로 구문 검사를 통과시키고, 애플리케이션 매니페스트를 EXE에, 컴포넌트 매니페스트를 리소스 ID 1로 DLL에 매립하며, 마지막에 꺼내 원래 XML과 비교해 확인하는 흐름을 보이는 그림.
mt1["구문 검사를 통과시킨다"] --> mt2["앱 쪽을 EXE에 매립한다"]
mt2 --> mt3["부품 쪽을 DLL에 매립한다〔ID 1〕"]
mt3 --> mt4["꺼내서 원래 XML과 비교한다"]
그림 14: 매립은 확인까지 포함해 하나의 절차로 돌린다.
mt.exe에는 주의점이 2가지 있습니다.
- 매니페스트가 참조하고 있는 파일은 매니페스트와 같은 디렉터리에 두어야 합니다.
<file name="Vendor.CameraControl.dll">이라고 썼다면 그 DLL을 매니페스트 옆에 둔 뒤 실행합니다. 빌드 출력과 매니페스트의 관리 위치가 나뉘어 있으면 여기서 막힙니다 -outputresource에서 리소스 ID를 생략하면CREATEPROCESS_MANIFEST_RESOURCE(= 1)가 쓰입니다. 의도치 않게 1이 되어도 곤란하지 않도록;#1은 명시해 두는 편이 읽기 쉽습니다
이미 매립된 것을 교체만 하고 싶다면 -updateresource:<파일>;#1을 쓸 수 있습니다. 이는 -inputresource와 -outputresource에 같은 인수를 주는 것과 같은 의미입니다.
10.5 클린 환경까지 포함한 확인 절차
Reg-Free COM은 「개발기에서 동작했다」가 거의 의미를 갖지 않습니다. 로컬 레지스트리 등록에 도움받고 있을 뿐이라는 가능성이 항상 남기 때문입니다. 다음 순서로 확인합니다.
- 빌드해서 배포물 일체를 하나의 폴더에 모은다. EXE, 매니페스트, COM DLL, 의존 DLL, VC++ 런타임, proxy / stub DLL까지
- 검증 환경을 준비한다. 대상 COM이 한 번도 등록된 적 없는 환경이 이상적입니다. Windows 샌드박스를 쓰면 매번 새하얀 상태에서 시도할 수 있습니다
- 그 환경에서 대상 COM이 미등록임을 먼저 확인한다. 아래 명령으로 키를 찾을 수 없다는 에러가 나면 미등록입니다
- 폴더를 복사해서 그대로 기동한다. 인스톨러도
regsvr32도 실행하지 않습니다 - COM 개체 생성까지 통과함을 확인한다. 기동만 해서는 지연 생성되는 컴포넌트는 검증할 수 없습니다. 실제로
CoCreateInstance가 실행되는 화면이나 기능까지 동작시킵니다 - 실패하면 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 양쪽을 다 보면 확실합니다.
개발기에서 시도하고 싶을 때는 일단 regsvr32 /u Vendor.CameraControl.dll로 등록을 해제한 뒤 확인합니다. 다만 다른 제품이 같은 COM을 쓰는 환경에서는 영향이 나오므로, 클린 환경을 준비하는 편이 안전합니다.
flowchart TB
accTitle: 클린 환경에서의 확인 흐름
accDescr: 배포물 일체를 하나의 폴더에 모으고, 대상 COM이 등록된 적 없는 검증 환경을 준비해, 미등록임을 먼저 확인한 뒤, 폴더를 복사해 그대로 기동하고, CoCreateInstance가 실행되는 기능까지 동작시켜 확인하는 흐름을 보이는 그림.
cv1["배포물 일체를 모은다"] --> cv2["클린한 검증 환경을 준비"]
cv2 --> cv3["미등록임을 먼저 확인"]
cv3 --> cv4["복사해서 그대로 기동"]
cv4 --> cv5["COM 생성이 실행되는 기능까지 동작시킨다"]
cv5 -.->|"실패하면"| cv6["로그를 채취해 조사한다"]
그림 15: 미등록 확인을 끼워 넣어, 우연히 동작하는 것을 검증에서 배제한다.
11. 빠지기 쉬운 곳
11.1 개발기에서는 동작하는데 배포처에서는 동작하지 않는다
우선 의심해야 할 것은 실은 레지스트리 등록에 도움받고 있었던 패턴입니다. 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의 이름 붙이는 방식을 잘못 쓴 경우도, 여기서 「찾으러 간 파일명」을 보면 알 수 있습니다.
flowchart TB
accTitle: side-by-side 에러를 조사하는 방법
accDescr: side-by-side configuration is incorrect로 기동되지 않을 때는, 이벤트 뷰어에서 SideBySide 소스의 에러를 확인하고, sxstrace로 트레이스를 시작해 실패를 재현한 뒤, 정지 후 parse로 사람이 읽을 수 있는 형식으로 변환해 불일치 지점을 쫓는 흐름을 보이는 그림.
sx1["이벤트 로그에서 SideBySide를 확인"] --> sx2["sxstrace로 트레이스 시작"]
sx2 --> sx3["앱을 기동해 실패를 재현"]
sx3 --> sx4["정지하고 parse로 변환"]
sx4 --> sx5["탐색과 불일치 지점을 읽는다"]
그림 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을 도입할 때의 기본 자세는 이렇습니다.
- 이것은 activation의 이야기다라고 단정한다
- runtime과 design-time의 논점을 나눈다
- 클린 환경에서 확인한다
- bitness와 의존 DLL을 먼저 갖춘다
이 순서로 보면 꽤 사고 나기 어려워집니다.
flowchart TB
accTitle: 도입 시의 기본 자세
accDescr: Reg-Free COM을 도입할 때는 이것을 액티베이션의 이야기라고 단정하고, 실행 시와 설계 시의 논점을 나누며, 클린 환경에서 확인하고, bitness와 의존 DLL을 먼저 갖춘다는 순서로 보면 사고 나기 어려움을 보이는 그림.
bs1["activation의 이야기라고 단정한다"] --> bs2["runtime과 design-time을 나눈다"]
bs2 --> bs3["클린 환경에서 확인한다"]
bs3 --> bs4["bitness와 의존 DLL을 먼저 갖춘다"]
그림 17: 4가지 자세를 순서대로 지키면 도입의 사고를 꽤 줄일 수 있다.
13. 관련 기사
- COM / ActiveX / OCX란 무엇인가 - 차이와 관계를 모아서 해설
- ActiveX / OCX를 지금 어떻게 다룰까 - 남긴다·감싼다·교체한다 판단표
- .NET 8의 DLL을 형 있게 VBA에서 쓰는 방법 - COM 공개와 dscom TLB
14. 참고 자료
- Microsoft Learn - Registration-Free COM 개체 만들기
- Microsoft Learn - 애플리케이션 매니페스트
- Microsoft Learn - Assembly Manifests(매립 시의 리소스 ID와 이름 제약)
- Microsoft Learn - Assembly Searching Sequence(private assembly의 탐색 순서)
- Microsoft Learn - Manifest File Schema
- Microsoft Learn - Mt.exe
- Microsoft Learn - 등록이 필요 없는 COM 상호 운용 기능 (.NET Framework)
- Microsoft Learn - COM으로의 .NET Core 컴포넌트 공개
- Microsoft Learn - sxstrace
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
COM / ActiveX / OCX란 무엇인가 - 차이와 관계를 정리해서 해설
Windows 레거시 프로젝트에서 자주 마주치는 COM과 ActiveX, OCX의 차이를 토대·부품·파일이라는 축으로 정리해, regsvr32와 32/64bit, IE 모드 같은 키워드를 만났을 때 헷갈리지 않고 조사와 이전 방침을 잡을 수 있도...
클립보드와 드래그 앤 드롭의 구조 ── 업무 앱에서 OLE 데이터 전송을 올바르게 다루기
Excel 표를 붙여 넣으면 서식이 무너지고, 원본 앱을 닫으면 붙여 넣을 수 없게 되는 일── 둘 다 클립보드가 같은 내용을 여러 형식으로 한꺼번에 두기 때문입니다. 표준 형식, 지연 렌더링, OLE 드래그 앤 드롭, 클립보드 기록과 클라우드 ...
오늘날의 Windows 셸 통합 ── 컨텍스트 메뉴, 파일 연결, Windows 11에서 바뀐 것
Windows 11 컨텍스트 메뉴가 「더 많은 옵션 표시」 뒤로 숨는 이유를, 확장자→ProgID→verb 연결의 기초부터 고전 셸 확장의 주의점, IExplorerCommand와 MSIX/sparse package 경로까지 한 줄로 정리합니다.
DLL・COM 인터페이스의 하위 호환성 ── 어떤 변경이 호출 측을 망가뜨리는지의 판단표
DLL이나 COM 컴포넌트의 어떤 변경이 호출 측을 망가뜨리는지. 바이너리 호환・소스 호환・동작 호환의 3계층을 정리하고, 변경 내용별 판단표, COM 인터페이스 불변의 철칙, semver 운용까지를 실무 가이드로 정리합니다.
Arm판 Windows에서 업무 앱은 동작하는가 ── x64 에뮬레이션(Prism)과 네이티브 DLL·COM의 현실
「Arm판 Windows에서 업무 앱은 동작하는가」에 개발자·정보시스템 담당자를 위해 답합니다. x64 에뮬레이션(Prism)의 구조, 드라이버 등 동작하지 않는 계층, .NET의 AnyCPU와 P/Invoke 문제, Arm 대응 체크리스트까지 ...
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
ActiveX 이관
COM / ActiveX / OCX 자산을 유지할지, 감쌀지, 교체할지의 단계적 판단을 정리한 토픽 페이지입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
기존 자산 활용 & 이관 지원
COM / ActiveX / OCX 자산, 네이티브 코드, 32비트 의존성을 유지하면서 단계적인 이관 계획을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- 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 구성이 개발기에서는 동작하는데 배포처에서 동작하지 않는 것은 왜인가요?
- 우선 의심해야 할 것은 실은 레지스트리 등록에 도움받고 있었던 패턴입니다. 매니페스트에 필요한 정보가 부족한 경우 COM 런타임은 통상의 등록 기반 해결로 떨어지므로, 개발기에서는 로컬 등록 덕분에 우연히 동작하는 경우가 있습니다. 그래서 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의 생성·매립·등록을 별도로 정리하는 편이 안전합니다.