什麼是 Reg-Free COM - 免註冊使用 COM 的機制,以及合用與不合用的情境
· 小村 豪 · COM, Reg-Free COM, Registration-Free COM, Windows 開發, Legacy 技術
COM/ActiveX/OCX 的案子,每次發布與更新總會冒出一堆老問題。
- 需要
regsvr32 - 常常要管理員權限
- 和其他應用裝的別版本打架
- 解除安裝後還把別的產品一起拖下水
- 開發機能跑,但乾淨環境跑不起來
能把這個泥巴戰相當程度地化解的,就是 Reg-Free COM。 不過它的名字聽起來豪氣,並不是「COM 的一切麻煩都消失的魔法」。消掉的主要是 被全域註冊牽著走的那種麻煩。bitness、相依 DLL、type library、執行緒模型的難題並不會跟著消失。
本文以 在 Windows 桌面應用上把 COM DLL/OCX 關在應用本地使用 的脈絡為主軸,來整理 Reg-Free COM。
1. 先下結論(一句話)
先給一個粗但實用的說法:
- Reg-Free COM 是把 COM 的註冊資訊從登錄檔改放到 manifest 裡
- 執行時,
CoCreateInstance或CLSIDFromProgID解析會 先看 Activation Context - 所以 COM DLL/OCX 可以以應用為單位放成 private
- 主要好處是 好做 XCOPY 發布、容易避開版本衝突、解除安裝較不會波及別人
- 但 32bit/64bit 的問題不會消失,這邊靠意志力也過不去
- 另外 相依 DLL、type library、設計時參考、非標準的註冊依賴 還是要另外考量
- 實務上,想把應用專屬的 COM 零件放在身邊 時相當合用
總之,Reg-Free COM 是 把 COM 的 activation 拉回以應用為單位 的機制。
2. 本文所說的 Reg-Free COM
Reg-Free COM 是 Registration-Free COM 的縮寫。
這裡的「免註冊」指的是 使用 COM 時不必全面依賴 HKCR / CLSID / InprocServer32 這類全域登錄。 並不是「COM 本身消失」,也不是「不再需要 GUID」。
本文主要涵蓋下列對象:
- 原生 COM DLL
- 基於 ATL 的 COM server
- ActiveX / OCX
- 以 .NET Framework 為基礎的 COM interop
- 透過 .NET 5+ / .NET 8 的 COM host 發布
另外要特別強調的兩點:
- Reg-Free COM 是「activation」的議題
- type 資訊的發布與設計時的參考設定,可能會作為另一條線留存
這兩件事一混在一起,討論就會變混濁。
3. 先用一張圖收攏
先把整體用一張圖看會比較快。
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
一般 COM 在 CoCreateInstance 時,會去登錄檔找「應該載入哪個 DLL」。
Reg-Free COM 則是先看 當下有效的 activation context,從那裡的 manifest 資訊做解析。
因此,同一台機器上,應用 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 就是用來減輕這種發布模型痛點的機制。
5. Reg-Free COM 的機制
5.1 在 application manifest 寫上相依關係
首先,應用端要在 application manifest 中寫 自己相依於哪個 side-by-side assembly。
這份 manifest 可以:
- 放在 EXE 旁邊的
MyApp.exe.manifest - 或作為資源嵌入 EXE
實務上,想讓發布與替換直觀就放外部檔;想讓發布單純、不易壞就用嵌入式,兩種都常見。
另外,當外部檔與嵌入版同時存在時,檔案系統上的 manifest 會優先。
5.2 在 component manifest 寫上 COM 資訊
接著,COM 這一端要把 原本放登錄檔的資訊 寫到 component manifest 裡。
裡面會有例如:
comClassclsidprogidthreadingModeltypelib- 必要時再加 proxy / stub 或 window class 等
也就是 用 XML 描述 COM 的長相,取代登錄檔。
這份 manifest 也可以:
- 做成與 DLL 分開的檔案
- 嵌入 DLL 作為資源
實務上通常 以 private assembly 嵌入 DLL 比較不易出事。分離檔雖然直觀,但容易在「檔名與 assemblyIdentity 的對應」「放在哪個資料夾」「漏拷貝」等地方絆倒。
5.3 執行時先看 activation context
Reg-Free COM 的核心就在這。
當應用呼叫 CLSIDFromProgID 或 CoCreateInstance 時,COM runtime 會先去看 目前啟用的 activation context。
若其中有必要的 ProgID → CLSID、CLSID → DLL 資訊,就能不靠登錄檔解析。
反之,若 manifest 缺少必要資訊,它就會掉回一般的以登錄檔為主的解析路徑。 這個行為會造就經典陷阱:開發機剛好能跑。以為做成 Reg-Free 了,實際上卻是被本機既有註冊救了一命。
這是 Reg-Free COM 最惱人的坑。
6. 好處是什麼
Reg-Free COM 的好處在實務上相當明顯。
6.1 好做 XCOPY 發布
可以把必要檔案都放進應用資料夾,安裝器與註冊步驟都會輕很多。
當然,若要寫到 Program Files 下,權限還是另一件事,但至少可以減少 為了 COM 註冊而做的管理員動作。
6.2 減少版本衝突
同一台機器上有多個版本的 COM 零件時,各應用可以各用各的版本。 「因為別的產品被安裝導致行為突然改變」這類事故會相當程度減少。
6.3 常常不必大改現有程式碼
Reg-Free COM 動的是 怎麼解析,而不是 呼叫方的寫法。
所以如果條件契合,往往 CoCreateInstance 那側的程式碼幾乎不動就能導入。
6.4 刪除與 rollback 變輕鬆
因為被鎖在以應用為單位,所以更新或 rollback 都很直觀。 極端地說,就是 可以用整包資料夾換掉 的思維。
7. 合用與不合用的情境
7.1 合用的情境
下列情境,Reg-Free COM 相當有力:
| 狀況 | 契合度 |
|---|---|
| 想把應用專屬的 COM DLL/OCX 一起封裝 | 非常好 |
| 想讓同一台 PC 多版本共存 | 非常好 |
| 想避免廠商零件的註冊事故 | 好 |
| 想在既有桌面應用裡 private 使用 ActiveX/OCX | 好 |
| 想讓發布變輕,但既有呼叫端儘量不動 | 好 |
典型上與 業務桌面應用、設備整合工具、VB6/MFC/WinForms 既有資產 的契合度相當高。
7.2 不合用,或要小心觀察的情境
反之下列情境要謹慎:
| 狀況 | 說明 |
|---|---|
| 想在整台機器層級共享 COM | Reg-Free 的優勢被稀釋 |
| bitness 根本沒對上 | Reg-Free 解不了 |
| 強烈依賴非標準的註冊資訊或自訂安裝流程 | 不容易改寫成 manifest |
| 相依 DLL 或 VC++ runtime 的發布還沒整理 | 終究會在別的地方絆倒 |
| 設計時工具或 IDE 的參考設定以登錄檔為前提 | 需要另一套運維設計 |
最後一點特別關鍵。 Reg-Free COM 幫的是 執行時的 activation,並無法一次把 設計時 UI 的參考設定所依賴的前提 也一起改掉。
8. 常見誤解
8.1 Reg-Free COM 能讓 bitness 問題消失
不會。 32bit 行程只能載入 32bit in-proc COM DLL,64bit 行程只能載入 64bit DLL。 這一點 Reg-Free 與否都一樣。
8.2 Reg-Free COM 完全不看登錄檔
也不對。 manifest 缺資訊時,仍會掉回以登錄檔為主的解析路徑。 所以 開發機能跑 ≠ Reg-Free 架構正確。
8.3 Reg-Free COM 也會自動處理 type library
這個只對一半。
manifest 裡是可以寫 typelib,但 VBA 的參考設定、C++ 的 #import、.NET 設計時 interop 的生成 等 type 資訊的處理,通常還要另做設計。
Reg-Free COM 先解決的是 能啟動; 怎麼帶型別做開發 是下一個議題。
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 | 基本以 application manifest + component manifest 思考 |
| .NET Framework 版 COM interop | 除了 Win32 風格的 application manifest,還要有 managed 元件側的 manifest |
| .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 兩層。
這比原生 COM 稍微更麻煩。 會出現「Reg-Free COM 我懂了,但一牽到 managed 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。
這裡仍要強調:Reg-Free COM 與 TLB 策略是兩件事。 .NET Core/.NET 5+ 不像 .NET Framework 時代那樣「從組件自然長出 TLB」。如果要帶型別使用,TLB 的生成、嵌入、註冊要另外規劃。
10. 最小組合示意
以下示意 MyApp.exe 以 Reg-Free COM 使用 Vendor.CameraControl.dll 的最小組合。
10.1 檔案組成示意
MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll
上例中 假設 component manifest 已嵌入 DLL。 外部檔也可以,但剛開始嵌入會比較好整理。
10.2 application manifest 示意
<?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 component manifest 示意
<?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 正確填入。
11. 常見坑
11.1 開發機能跑,發布端跑不起來
先懷疑的是 其實是被本機的登錄檔救了一命。 Reg-Free COM 最好要在 乾淨環境 驗證。
11.2 出現「side-by-side configuration is incorrect」啟動不了
這一類通常源於 manifest 不一致、相依 DLL 缺件、VC++ runtime 缺件、架構對不起來。
訊息本身相當不親切,靠 Event Log 與 sxstrace 追蹤是常用做法。
11.3 component manifest 與 application manifest 的對應偏掉
- name 不同
- version 不同
- processorArchitecture 不同
- 拷貝過去的 manifest 其實是舊版
看起來只是小差異,但啟動時影響很大。
11.4 漏帶相依 DLL
只盯著 Vendor.CameraControl.dll 而沒注意到它會再去載入 Vendor.Helper.dll、VC++ runtime、proxy/stub DLL 等。
Reg-Free COM 處理的是 COM 註冊問題,原生相依解析問題 並沒有被一併處理。
11.5 把 type library 與參考設定的運維往後拖
就算 runtime activation 通了,當:
- 想從 VBA 做 early binding
- C++ 想
#import - .NET 端想在設計時產生 interop
這些需求出現時,就需要一套 type 資訊的發布方式。 Reg-Free COM 不會自動搞定這一塊,所以 runtime 與 design-time 要分開思考。
12. 總結
一句話概括:Reg-Free COM 是 把 COM 的註冊資訊從整台機器收回到以應用為單位 的機制。
因此能帶來:
- 把 COM DLL/OCX 關在應用本地
- 減少版本衝突
- 簡化發布與 rollback
但是以下仍然重要:
- 32bit/64bit
- 相依 DLL
- TLB/參考設定
- 非標準的註冊相依
- 在乾淨環境做驗證
所以導入 Reg-Free COM 的基本姿態:
- 看作是 activation 的議題
- 拆開 runtime 與 design-time 的討論
- 在乾淨環境驗證
- 先把 bitness 與相依 DLL 弄齊
按這個順序做,事故會少很多。
13. 相關文章
- COM/ActiveX/OCX 是什麼 - 差異與關係總整理
- 今天的 ActiveX/OCX 該怎麼處理 - 留、包、換的判斷表
- 在 VBA 中帶型別使用 .NET 8 的 DLL - COM 發布 + dscom 產生 TLB
14. 參考資料
- Microsoft Learn - Creating Registration-Free COM Objects
- Microsoft Learn - Application Manifests
- Microsoft Learn - Assembly Manifests
- Microsoft Learn - Manifest File Schema
- Microsoft Learn - Registration-Free COM Interop (.NET Framework)
- Microsoft Learn - Expose .NET Core components to COM
- Microsoft Learn - sxstrace
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
COM / ActiveX / OCX 是什麼 - 差異與關係一次整理
從實務角度釐清 COM、ActiveX、OCX 三者的差異與關係:COM 是 Windows 元件互動的 binary 契約底層,ActiveX 是以 COM 為基礎的可嵌入 control 脈絡,OCX 則為 ActiveX control 常見的副檔名。讀完能分清機制、...
開發 COM 元件、OCX/ActiveX 時常見的坑 - 整理 Visual Studio 的 32bit/64bit、註冊、管理員權限
整理開發 COM、OCX、ActiveX 元件時最容易卡關的四個面向:宿主行程的 32bit/64bit、Visual Studio 2022 變成 64bit 後的設計時整合、regsvr32 與 Regasm 的註冊位置、以及管理員權限與 HKCU/HKLM 的關係,協...
Excel 報表輸出該怎麼做 - COM 自動化 / Open XML / 範本方式的判斷表
從 Windows 應用與業務系統的角度,把 Excel 報表輸出拆成驅動 Excel 與組裝 Excel 檔案兩條路。整理 COM 自動化、Open XML 直接生成、範本套版、既有 VBA 併用的取捨,並針對使用者編輯、夜間批次、大量輸出等情境,給出不易壞且容易維運的選...
ActiveX / OCX 現在如何處理 - 保留・包裝・取代的判斷表
整理在實務專案中遇到 ActiveX 或 OCX 時的判斷流程,從 UI 部件、機器控制、報表、瀏覽器依賴到 32bit 與 64bit 的牆壁,依照保留・包裝・取代三種選項列出對照表與決策流程,並說明註冊發佈與 STA 等容易絆倒的細節,幫讀者選出最低成本的下一步。
Media Foundation 是什麼 - COM 和 Windows 媒體 API 的臉浮現的原因
整理 Media Foundation 為何讓人覺得像 COM:其本體是媒體處理平台,但 source、transform、sink、callback 之間的邊界以 COM 介面表現,因此 HRESULT、GUID、apartment 自然浮現,並指出 Source Rea...
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
ActiveX 遷移
整理保留、包裝或替換 COM / ActiveX / OCX 資產的階段性判斷的主題頁面。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
Windows 應用程式開發
支援包含常駐處理、設備連動、運作日誌與可維護結構的 Windows 桌面應用程式。
既有資產活用 & 遷移支援
在持續活用 COM / ActiveX / OCX 資產、原生程式碼與 32 位元相依的同時,協助規劃階段性的遷移。
作者檔案
本文作者的個人檔案頁面。
Go Komura
小村軟體有限公司 代表
以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。