ActiveX / OCX 現在如何處理 - 保留・包裝・取代的判斷表

· · COM, ActiveX, OCX, .NET, Windows 開發, 現代化

ActiveX / OCX 這個詞會出現的案件,通常氣氛都有點沉重。

  • VB6 或舊的 C++ / MFC 應用程式還在現役
  • 產業機器或計測儀的 SDK 只提供 OCX
  • 公司內部 Web 是以 ActiveX 為前提,從 IE 模式脫身不了
  • 想從 32bit 轉到 64bit,但 1 個 OCX 在搖頭

但是,在這裡「因為舊所以全部丟掉」或「因為在動所以永久保存」,兩個都很粗糙。 重要的是要分辨這個 ActiveX / OCX 只是單純的 UI 部件,還是抱有業務規格或機器規格的邊界面。

本文在發現 ActiveX / OCX 時, 以容易判斷的順序整理應該選擇保留・包裝・取代中的哪一個。

對象例如以下的情況。

  • VB6 / MFC / WinForms 系的既有桌面應用程式
  • 往 C# / .NET 的階段性遷移
  • 包含 WebBrowser / IE 模式的舊式畫面
  • 包含廠商製 ActiveX 控制項的 Windows 應用程式

1. 先講結論(一句話)

  • 看到 ActiveX / OCX,最先該判斷的不是「是否舊」,而是這個部件承擔了什麼
  • 如果是單純的 UI 部件,取代相對容易
  • 如果抱有機器控制、報表、獨自檔案格式、長年運營習慣,比起立即重新實作,先包裝比較安全
  • 如果在桌面上穩定運作且變更範圍小,保留的判斷也充分可行
  • 瀏覽器上的 ActiveX 依賴雖然可以延命,但未來很窄,最好以取代優先來看
  • 無法將 32bit OCX 直接載入 64bit 行程中。這裡靠氣勢是跨不過的
  • 註冊、依賴 DLL、系統管理員權限、授權、STA / MTA 等,實作以外的摩擦容易成為難關
  • 「總之全面重寫」與「因為害怕就永久凍結」,兩者事故率都很高

簡言之,判斷的順序大概如下。

  1. 那個 OCX 持有什麼
  2. 是否必須在同一行程中使用
  3. 在 32bit / 64bit、註冊、瀏覽器依賴上是否會卡住
  4. 是否應該在建立可測試的邊界後再取代

以這個順序來看,會變得相當容易整理。

2. 本文中所說的 ActiveX / OCX

這裡稍微整理一下用語。

用語 本文中的意義
COM Windows 的二進位相容元件模型。是公開介面、註冊、Apartment Model 等的基礎
ActiveX / OCX 在實務上,常被用來統稱 COM 基礎的控制項或其周邊資產。特別常包含 .ocx 的 UI 控制項或嵌入到 IE / 容器的部件
WebBrowser / IE 系依賴 就算不是 ActiveX 本身,也包含以「IE 的世界觀」為前提的嵌入式瀏覽器或連動。從判斷角度來說,是相當相近的問題

嚴格來說 ActiveX 和 COM 不是同樣的東西。 但是,實務上困擾的地點相當類似。

  • 32bit / 64bit 是否契合
  • 如何發佈註冊或依賴 DLL
  • 在哪個主機 / 容器上運作
  • 是否在 STA、訊息迴圈、回呼中卡住
  • 瀏覽器依賴是否還留存

本文將這些實務上的判斷要點一併處理。

3. 首先看的判斷表

3.1. 整體概觀

先看這個表,大致方針就會決定。

狀況 先選的 理由
依賴瀏覽器上的 ActiveX 偏向取代 Edge 本體不支援 ActiveX,IE 模式只是作為延命策略
桌面應用程式中 OCX 穩定運作,變更範圍小 偏向保留 現在拆掉的成本通常比較大
只想把周邊 .NET 化,但控制項的行為讀不透 偏向包裝 先整理邊界比較安全
想把 32bit OCX 直接放入 64bit 行程 包裝 / 構成變更 in-proc 無法跨越的邊界
只當作 UI 部件使用,且有替代品 偏向取代 表面的取代較容易解決
廠商終止、簽章、註冊、依賴 DLL 每次都出事 偏向取代 運營成本以技術債的形式浮現
內含機器控制、報表、獨自協議 偏向包裝 不先固定行為就無法估算取代成本
flowchart TD
    start["有 ActiveX / OCX"] --> q1{"瀏覽器依賴?"}
    q1 -- "是" --> p1["優先取代<br/>IE 模式是延命策"]
    q1 -- "否" --> q2{"主要是 UI 部件?"}
    q2 -- "是" --> q3{"有同等的替代嗎?"}
    q3 -- "是" --> p2["檢討取代"]
    q3 -- "否" --> p3["先包裝整理邊界"]
    q2 -- "否" --> q4{"抱有機器控制・獨自規格・報表邏輯?"}
    q4 -- "是" --> p4["先包裝<br/>備好測試後階段性取代"]
    q4 -- "否" --> q5{"註冊・bitness・發佈會痛?"}
    q5 -- "是" --> p5["重新檢視構成<br/>檢討 out-of-proc / 別行程連動 / Reg-Free COM"]
    q5 -- "否" --> p6["保留的判斷也現實可行"]

以下依序看各模式。

3.2. 保留的判斷

不是因為 ActiveX / OCX 就立刻成為取代對象。 如果以下條件齊備,保留是最便宜的情況相當常見。

  • 使用範圍封閉,公司內部發佈或裝置同捆等運營環境固定
  • 該控制項現在也穩定運作,變更要求不大
  • 廠商還在現役,或自家公司能做最低限度的維護
  • 不是瀏覽器依賴,而是在桌面的既有主機上完結
  • 32bit / 64bit 的前提短期內不需要改變

這裡重要的是,保留 ≠ 放置。 要保留的話,至少以下事項最好要做。

  • 把對應 OS、bitness、必需的依賴 DLL、註冊步驟以文件留下
  • 把安裝、註冊、解除從人力筆記靠向腳本或安裝程式
  • 準備乾淨環境下的冒煙測試
  • 不要把對控制項的呼叫散佈到整個應用程式,盡量集中到 1 個地方

最糟的是把「因為在動所以不碰」持續 10 年,沒人能說明前提的狀況。 越是選擇保留,前提的可視化就越重要。

3.3. 包裝的判斷

在實務上,這個選擇最常成為工作。

這裡說的「包裝」是將 ActiveX / OCX 封閉在狹窄邊界的內側, 從周邊看起來是新的 API 或新的畫面部件。

這相當有效。 因為在舊部件的行為讀不透的階段進入全面重新實作,容易陷入規格挖掘與缺陷重現的雙重辛苦。 先把舊部件隔離,只整頓邊界比較安全。

包裝的方式,例如以下這些。

包裝方式 適合的場面 要看的要點
WinForms 主機 + AxHost / Aximp 想嵌入既有桌面畫面、只想保留少數畫面 STA、事件、設計時依賴、授權
32bit helper EXE / COM LocalServer / 別行程橋接 想靠向 64bit 側、想隔離崩潰 行程間通訊、啟動順序、監視、部署
.NET 端的 COM 相容窗口 想保留既有 COM 呼叫端的同時更新內容 IID / CLSID / TLB / 註冊方法 / bitness

特別重要的是在包裝時不要把舊 API 原樣複製 200 個。 那樣做只是把舊的事情原樣進口到新程式碼。

包裝時意識以下會好很多。

  • 做成粗粒度的方法
  • 不讓畫面程式碼直接碰 OCX
  • 在邊界取得失敗時必要的日誌
  • 在邊界決定逾時、重試、例外轉換的職責
  • 讓將來的取代目標也能以相同介面替換

有時想在新的 .NET 側只保留 COM 入口。 這種情況下,「內容更新的同時只維持 COM 合約」的構成是現實的。 但是,用 .NET Framework 時代的感覺認為「總之用 RegAsm」能解決並不成立。 現在 .NET 的 COM host、TLB、bitness、Registry-Free COM 的處理最好先設計好,後面會比較輕鬆。

3.4. 取代的判斷

適合取代的主要是表面的舊成為問題的案例。

例如,以下時候最好以取代優先來看。

  • 那個 ActiveX 只作為 UI 部件使用
  • 廠商推出了 .NET / WPF / WebView2 的後繼
  • 瀏覽器依賴或 IE 前提拖後腿
  • 註冊、簽章、系統管理員權限、安全設定每次都絆到
  • 有能驗證替代實作的測試或業務情境

相反地,只因為外觀舊就一口氣去捨棄連機器控制或報表邏輯都抱有的部件,通常會變成爛泥。

要取代的話,先從 UI 開始。

  • 格線
  • 行事曆
  • 樹狀結構
  • 瀏覽器顯示部
  • 簡單的輸入輔助

這一帶相對容易取代。 另一方面,以下這些看似 UI 但內容濃厚。

  • 廠商製的機器控制 ActiveX
  • 與列印或報表產生一體化的控制項
  • 內含獨自檔案格式讀寫的控制項
  • 抱有 COM 回呼或執行緒前提的控制項

看錯這個差別,工時估算會一口氣崩壞。

3.5. 瀏覽器依賴要另外考慮

這裡相當另外。

瀏覽器上的 ActiveX 與桌面的 OCX 不同, 今後直接繼續延伸的理由相當薄弱。

理由很單純,因為現代的瀏覽器基礎並不把那裡當成主戰場。 Microsoft Edge 本身不支援 ActiveX。 另一方面,IE 模式可以作為對已設定的網站使用 IE 系引擎、讓包含 ActiveX 在內的一部分 IE 功能運作的相容層來使用。

也就是說,

  • 可以做現在能動的延命
  • 但是,作為長期設計未來不會太粗

這樣。

同樣的事也發生在嵌入到 Windows 應用程式的 WebBrowser 控制項。 因為 WebBrowser 帶著 IE 系的世界觀,如果只是要顯示 HTML,從現在開始的新規作業以 WebView2 為第一候補比較自然。

但是,這裡要注意 WebView2 不是 WebBrowser 的完整替換部件。

  • 以 IE DOM 為前提的腳本
  • ActiveX 依賴
  • window.external 周邊的前提
  • 安全區域或內網前提的行為

這一帶無法直接移植。 要取代的話,不只是渲染引擎,瀏覽器與原生的連接面也需要重新設計。

4. 容易弄亂判斷的論點

4.1. 是 UI 部件還是抱有規格的部件

這是最重要的。

如果是舊的格線或行事曆,看外觀和事件的相容就能讓事情相當推進。 另一方面,抱有機器控制或報表或獨自格式的 ActiveX,外觀背後有規格的塊。

例如,看起來同樣是「畫面上的控制項」,實際上有以下差異。

  • 單純的清單顯示部件
  • 以獨自協議對裝置發命令的部件
  • 內部做到逾時、重新連線、重送、例外吸收的部件
  • 扛著列印或匯出格式相容性的部件

一口氣重新實作後者,通常會變成規格挖掘專案。 這裡先包裝比較安全。

4.2. 32bit / 64bit 與行程邊界

這裡常被忽略,但相當本質。

in-proc 的 OCX 必須與載入的行程 bitness 一致。 也就是說,無法將 32bit OCX 直接載入 64bit 應用程式。

這時的現實選項大致是以下之一。

  • 暫時主機應用程式端也保持 32bit
  • 封閉到 32bit 的別行程,與 64bit 端用 IPC 或 out-of-proc COM 連接
  • 從能拆掉該 OCX 依賴的地方先取代

這裡「Any CPU 所以應該能搞定」通常行不通。 在新的 .NET 端做 COM 相容窗口的情況,managed 程式碼的外觀與實際 COM host 的 bitness 是不同問題。 在這裡粗略開始,會出現建置通過卻在發佈處不能動的討厭傢伙。

4.3. 註冊、發佈、權限、授權

技術上能呼叫,但在發佈處死掉。 這在 ActiveX / OCX 相當常見。

容易成為難關的例如以下。

  • regsvr32 的前提變成人依賴
  • 依賴 DLL 的放置變成隱性
  • 需要系統管理員權限卻沒落實到運營步驟
  • 廠商製控制項的 design-time / runtime 授權分開
  • 在開發機能動,在乾淨環境不能動

這一帶即使不碰一行程式碼也能讓專案停滯。

也有用免註冊構成或 side-by-side 配置變輕鬆的情況,但不是魔法粉。 需要確認與容器端或發佈方式的相性。

簡言之,ActiveX / OCX 的遷移不只是實作也是發佈設計。 在這裡拖延,最後會華麗地跌倒。

4.4. STA / 訊息迴圈 / 回呼

ActiveX / OCX 不是單純的 DLL 呼叫。 有時帶有 COM 的執行緒模型或訊息迴圈的前提。

特別要注意的是以下情況。

  • 只在以 UI 執行緒為前提才穩定
  • 以 STA 為前提卻從 MTA 側粗略呼叫
  • 同步呼叫中回呼回來了
  • 接收事件的執行緒前提曖昧

這一帶最初以「偶爾會卡住」「偶爾事件不來」的怪談臉出現。 但內容通常是前提違反。

所以不管是包裝還是取代, 要在哪個執行緒建立、在哪個執行緒呼叫、在哪裡接收事件最好先固定。

4.5. 是否有測試、是否能觀測

取代難的不只是因為程式碼舊。 基於什麼能說「同樣地運作了」沒有。

例如,光是有以下就相當不同。

  • 每個操作情境的冒煙測試
  • 輸入輸出樣本
  • 畫面截圖或報表樣本
  • 錯誤模式與期望行為
  • 逾時時或裝置未連接時的日誌

特別是機器或報表相關時,會發生規格書不如實物行為才是真相的奇怪情況。 這裡沒有觀測手段,取代就變成發掘調查。

5. 各典型模式的推薦

5.1. 現在也穩定運作的公司內部桌面應用程式

推薦是偏向保留

以下條件的話,不勉強撕掉會比較好的情況很多。

  • 僅在公司內部使用
  • 對象端末或 OS 某種程度固定
  • 該 OCX 只在幾個畫面使用
  • 改修要求小,壽命也可預期

但是,不要就這樣赤裸放著, 把呼叫位置集中起來對後面有幫助。

也就是說,方針是這樣。

  • 現在保留
  • 但是,只整頓邊界
  • 需要取代時,做成能從那裡著手的形式

這 3 段式構成比較自然。

5.2. 想把 32bit OCX 帶到 64bit 側

推薦是包裝 / 構成變更

這裡正面衝會卡死。 因為無法把 32bit OCX 以 in-proc 放入 64bit 行程。

現實上封閉到 32bit 的輔助行程或 LocalServer 側, 與 64bit 應用程式用粗 API 通訊的構成比較好處理。

sequenceDiagram
    participant App as 64bit .NET 應用程式
    participant Bridge as 32bit 輔助 / LocalServer
    participant Ocx as 32bit OCX

    App->>Bridge: 以粗 API 委託
    Bridge->>Ocx: in-proc 呼叫
    Ocx-->>Bridge: 結果 / 事件
    Bridge-->>App: 已轉換的結果

這裡的要點是不把細的方法全部原樣轉發。 行程間邊界,細的呼叫大量流動會立刻痛苦。

  • 集中到 1 操作 = 1 要求左右的粒度
  • 把回傳值或錯誤整形到有意義的單位
  • 在邊界取得日誌

做成這個形式,以後真正取代內容時也輕鬆。

5.3. 以 IE / WebBrowser 為前提的畫面

推薦是取代優先

這裡是「現在能動」與「今後也能輕鬆維持」不易一致的領域。 IE 模式為了相容相當有幫助,但前提還是 IE 系。

所以思考方式以下比較好懂。

  • 為了不讓公司內部業務停止,以 IE 模式延命
  • 但是,不要混淆延命與恆久設計
  • 取代目標從 WebView2、純 Web、原生 UI + Web 的混合等選

特別是只當作 HTML 檢視器使用 WebBrowser 控制項的情況, 取代優先度高。

另一方面,瀏覽器內的 ActiveX 也擔任本地檔案、裝置、簽章、獨自插件等角色的話, 那不是渲染引擎的更換,而是原生連動的重新設計。 這裡話題會變得有點重。

5.4. 抱有機器控制或獨自規格的 ActiveX

推薦是先包裝

這類型外觀比內容淡。 就算 SDK 的資料薄,作為在現場多年運作的結果, 以下的行為可能隱性堆積。

  • 連接失敗時的等待方式
  • 逾時後的重試
  • 事件順序
  • 吸收實機習性的迴避處理
  • 例外或錯誤碼的解釋

這類部件以「反正舊」重新製作,相當高機率現場測試會燒起來。

所以先做以下比較安全。

  1. 把既有部件封閉到邊界內側
  2. 加上日誌,讓能看見發生了什麼
  3. 收集測試情境與實機模式
  4. 然後,切出可取代的範圍

沒有華麗感,但在實務上這最有效。

6. 常見的反面模式

反面模式 什麼痛苦 先的修正方法
因為有 ActiveX 所以全面重寫 容易發生規格遺漏和工時爆炸 先盤點與邊界切出
試圖把 32bit OCX 直接放入 64bit 應用程式 原理上不可能 隔離到 32bit 側或改變構成
從畫面中直接呼叫控制項 API 容易變成無法取代 集中到 adapter / facade
以人力運營 regsvr32 步驟 環境差異每次出事 檢討安裝程式、腳本、manifest 化
因為有 IE 模式而安心 容易混淆延命與恆久對應 決定取代計畫與終了條件
取代前沒有記錄行為 無法做完成判定 備好冒煙測試、樣本資料、日誌

其中實務上特別常見的是以下 3 個。

  1. 倉促全面重寫
  2. 輕視 bitness 的牆
  3. 把 API 散佈到整個應用程式

光避免這 3 個,事故率就會相當下降。

7. 開始遷移時的檢核表

ActiveX / OCX 的案件,比起立刻進入實作,先盤點會比較順利。 順序大致如下。

  1. 清查使用中的 OCX / DLL
    • 檔名、版本、ProgID、CLSID、廠商、授權的有無
  2. 清查在哪裡使用
    • 畫面、功能、報表、裝置、批次、Office 連動等
  3. 確認 bitness 與主機條件
    • 32bit / 64bit、in-proc / out-of-proc、STA 前提、瀏覽器依賴
  4. 確認發佈條件
    • 註冊方法、依賴 DLL、系統管理員權限、靜默安裝、乾淨環境重現
  5. 做冒煙測試
    • 不只是正常系,包含失敗時、未連接時、逾時時
  6. 做邊界
    • adapter、service、facade、別行程橋接等
  7. 以 1 畫面、1 功能、1 裝置等小單位嘗試
  8. 從順利的邊界依序擴大保留 / 包裝 / 取代

跳過這個步驟,後面連「什麼很難」都難以說明。

8. 大致的使用區分

狀況 先選的
僅公司內部穩定運作,變更也小 保留
只想把周邊 .NET 化 包裝
32bit / 64bit 衝突 包裝 / 構成變更
IE / WebBrowser / 瀏覽器 ActiveX 依賴 取代
單純的 UI 部件且有替代 取代
抱有機器控制、報表、獨自規格 包裝
註冊或發佈每次都絆倒 包裝或取代

迷惑時,先分辨是 UI 部件還是抱有規格的邊界面,就會相當不容易偏離。

9. 這種諮詢相性很好

這個主題即使只是進入開發前的方針整理,也容易產生價值。

例如,以下的諮詢相性相當好。

  • 想盤點應該真正取代哪個 OCX
  • 只想先整理 32bit / 64bit 的卡點
  • 想往 .NET 靠,但只想保留 COM 的入口
  • 想比較廠商終止的 ActiveX 的延命策與撤退戰
  • 想看從哪裡能拆掉 IE / WebBrowser 依賴
  • 先只想安全分離 1 畫面、1 功能

ActiveX / OCX 的案件,比起實作,如何切邊界才是勝負的情況很多。 作為全面改修的前階段,從現狀整理、構成比較、遷移順序的設計入手,光這樣就很有意義。

10. 總結

如何處理 ActiveX / OCX,不是以「因為是舊技術所以討厭」來決定的話題。

先該看的是以下 4 個。

  1. 那個部件是單純的 UI 還是抱有規格的邊界面
  2. 是否必須在同一行程中使用
  3. 32bit / 64bit、註冊、瀏覽器依賴、授權是否會卡住
  4. 取代前是否能觀測行為

看見這 4 個後,大致可以整理如下。

  • 穩定運作且壽命可預期就保留
  • 只想把周邊現代化就包裝
  • UI 部件或瀏覽器依賴就取代
  • 抱有規格塊的部件先包裝後階段取代

舊技術不是嘲笑的對象,而是充滿歷史與合約的實物。 但是,需要與實物打交道用的邊界設計。

能混合思考「保留・包裝・取代」時, ActiveX / OCX 的案件會突然變成能處理的問題。

11. 參考資料

  • Microsoft Learn: AxHost Class (System.Windows.Forms)
    • https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.axhost
  • Microsoft Learn: Aximp.exe (Windows Forms ActiveX Control Importer)
    • https://learn.microsoft.com/en-us/dotnet/framework/tools/aximp-exe-windows-forms-activex-control-importer
  • Microsoft Learn: How to: Add ActiveX Controls to Windows Forms
    • https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-add-activex-controls-to-windows-forms
  • Microsoft Learn: Expose .NET Core components to COM
    • https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com
  • Microsoft Learn: Registration-Free COM Interop
    • https://learn.microsoft.com/en-us/dotnet/framework/interop/registration-free-com-interop
  • Microsoft Learn: 關於 Microsoft Edge 的常見問題
    • https://learn.microsoft.com/en-us/deployedge/microsoft-edge-frequently-asked-questions
  • Microsoft Learn: What is Internet Explorer (IE) mode?
    • https://learn.microsoft.com/en-us/deployedge/edge-ie-mode
  • Microsoft Learn: WebBrowser Class (System.Windows.Forms)
    • https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser
  • Microsoft Learn: Introduction to Microsoft Edge WebView2
    • https://learn.microsoft.com/en-us/microsoft-edge/webview2/
  • 合同會社小村軟體 Blog: COM 的 STA/MTA 為避免當機的基礎知識
    • https://comcomponent.com/blog/2026/01/31/000-sta-mta-com-relationship/
  • 合同會社小村軟體 Blog: 從 C# 使用 C++ 原生 DLL 時,建議用 C++/CLI 做包裝的理由
    • https://comcomponent.com/blog/2026/03/07/000-cpp-cli-wrapper-for-native-dlls/
  • 合同會社小村軟體 Blog: COM 有用的案例研究 - 想從 32bit 應用程式呼叫 64bit DLL 時
    • https://comcomponent.com/blog/2026/01/25/002-com-case-study-32bit-to-64bit/

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽