ActiveX / OCX を今どう扱うか - 残す・包む・置き換える判断表

· 更新日: · · COM, ActiveX, OCX, .NET, Windows開発, モダナイゼーション

更新履歴(7件・最終更新 2026年08月30日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

ActiveX / OCX を包むときの選択肢として、5.2 に DllSurrogate を足しました。対象が in-proc の COM サーバーなら、CLSID に AppID を付けてその AppID キーへ空文字の DllSurrogate を書くだけで、こちらのコードを1行も書かずに out-of-proc にできます。ただしサロゲートは bitness の差を消してくれるわけではなく、外れるのは同じプロセスに載せなければならないという制約だけで、呼び出しは out-of-proc になりマーシャリングとプロセス間通信のコストがそのまま乗ります。サロゲートで足りる場合と自前のヘルパー EXE が要る場合の線引きを表にまとめ、参考資料も2件足しました。登録手順そのものは別の記事に置いてあるので、ここではリンクだけにしています。
追加した図のMermaidソースの字下げを記事内の規約に統一し、レビュー指摘のあった図の表現を本文の記述に合わせて調整しました。本文の文章は変えていません。
レビュー指摘に対応し、今日追加した図のうち幅が大きすぎたものを縦向きの構成に直し、一部の図とキャプションの表現を本文の記述に合わせて正確にしました。本文の文章は変えていません。
本文の流れ・分岐・構造を図でも追えるように、Mermaid図を19点追加しました(地の文500〜750字につき1図の規約に合わせたものです)。既存の2図にはキャプションを追加しています。本文の文章は変えていません。
記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
4手法それぞれの「最初の一歩」を表にまとめ、`aximp`の実コマンド(生成ファイル名がProgIDから決まる点を含む)、Reg-Free COMの最小マニフェスト、LocalServer方式のレジストリキーと`/regserver`の慣例を追加しました。用語表とIEモードの設定方法(ポリシー名と優先順位)も追加し、相談の章をまとめの後ろへ移しました。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589615)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「ActiveX / OCX を今どう扱うか - 残す・包む・置き換える判断表」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589615 https://comcomponent.com/blog/2026/03/12/001-activex-ocx-keep-wrap-replace-decision-table/

DOI(最新版)
10.5281/zenodo.21589615
DOI(この版)
10.5281/zenodo.22170278

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. まず結論(ひとことで)
  2. この記事でいう ActiveX / OCX
  3. まず見る判断表
    • 3.1. 全体像
    • 3.2. 残す判断
    • 3.3. 包む判断
    • 3.4. 置き換える判断
    • 3.5. ブラウザ依存は別枠で考える
  4. 判断を狂わせやすい論点
    • 4.1. UI 部品なのか、仕様を抱えた部品なのか
    • 4.2. 32bit / 64bit とプロセス境界
    • 4.3. 登録、配布、権限、ライセンス
    • 4.4. STA / メッセージループ / コールバック
    • 4.5. テストがあるか、観測できるか
  5. 典型パターン別のおすすめ
    • 5.1. いまも安定して動く社内デスクトップアプリ
    • 5.2. 32bit OCX を 64bit 側へ持っていきたい
    • 5.3. IE / WebBrowser 前提の画面
    • 5.4. 機器制御や独自仕様を抱えた ActiveX
  6. よくあるアンチパターン
  7. 移行を始めるときのチェックリスト
  8. ざっくり使い分け
  9. まとめ
  10. こういう相談は相性がよい
  11. 参考資料

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全24件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

1. まず結論(ひとことで)

  • ActiveX / OCX を見たら、最初に判断すべきは「古いかどうか」ではなく、その部品が何を引き受けているか です
  • 単なる UI 部品なら、置き換えは比較的しやすいです
  • 機器制御、帳票、独自ファイル形式、長年の運用癖を抱えているなら、いきなり再実装するより まず包む ほうが安全です
  • デスクトップで安定稼働しており、変更範囲が小さいなら、残す判断も十分ありです
  • ブラウザ上の ActiveX 依存は、延命はできても未来は細いので、置き換え優先で見たほうがよいです
  • 32bit OCX を 64bit プロセスへそのまま読み込むことはできません。ここは気合いでは越えられません
  • 登録、依存 DLL、管理者権限、ライセンス、STA / MTA など、実装以外の摩擦 が難所になりやすいです
  • 「とりあえず全面リライト」と「怖いから永久凍結」は、どちらも事故率が高いです

要するに、判断の順番はこうです。

  1. その OCX は何を持っているのか
  2. 同一プロセスで使う必要があるのか
  3. 32bit / 64bit、登録、ブラウザ依存で詰まらないか
  4. テスト可能な境界を作ってから置き換えるべきか

この順で見ると、かなり整理しやすくなります。

判断の順番そのOCXが何を持っているか、同一プロセスで使う必要があるか、32bit/64bitや登録やブラウザ依存で詰まらないか、テスト可能な境界を作ってから置き換えるべきかの順で見る。そのOCXは何を持っているか同一プロセスが必要かbitness・登録・ブラウザで詰まるか境界を作ってから置き換えるか

図1: 「古いかどうか」ではなく、この順で見ると残す・包む・置き換えるが整理しやすい。

2. この記事でいう ActiveX / OCX

先に、この記事での言葉の使い方を押さえておきます。

言葉 この記事での意味
COM Windows のバイナリ互換コンポーネントモデル。公開インターフェース、登録、Apartment Model などの土台です
ActiveX / OCX 実務では、COM ベースのコントロールやその周辺資産をまとめて指して使われがちです。特に .ocx の UI コントロールや IE / コンテナに埋め込む部品を含むことが多いです
WebBrowser / IE 系依存 ActiveX そのものではなくても、「IE の世界観」を前提にした埋め込みブラウザや連携を含みます。判断上はかなり近い問題になります

厳密には ActiveX と COM は同じものではありません。 ただ、実務で困る地点はかなり似ています。

  • 32bit / 64bit が噛み合うか
  • 登録や依存 DLL をどう配るか
  • どのホスト / コンテナで動くのか
  • STA、メッセージループ、コールバックで詰まらないか
  • ブラウザ依存が残っていないか

この記事では、こうした実務上の判断ポイントをまとめて扱います。

実務で困る地点厳密にはActiveXとCOMは同じものではないが、bitnessの噛み合い、登録や依存DLLの配布、どのホストで動くか、STAやコールバックの前提、ブラウザ依存という実務で困る地点はかなり似ている。ActiveX / OCX案件bitnessが噛み合うか登録・依存DLLの配布どのホストで動くかSTA・コールバックの前提ブラウザ依存が残っていないか

図2: ActiveXとCOMは厳密には別物でも、実務で詰まる地点はこのあたりに集中する。

なお、この先で当たり前のように出てくる略語を、先にまとめておきます。7 章のチェックリストで「ProgID と CLSID を洗い出す」と言われても、そこが分からないと動けないためです。

用語 読み方・正式名 意味
CLSID Class ID COM コンポーネントの実装(クラス)を一意に指す GUID。レジストリの登録もこの値が鍵になります
ProgID Programmatic Identifier CLSID に付けた、人が読める名前。Excel.Application のような文字列です
IID Interface ID COM インターフェースを一意に指す GUID。CLSID とは別物です
TLB Type Library インターフェース、メソッド、引数の型といった型情報をバイナリで持つファイル。VB6 や .NET から「型付きで」呼べるのはこれがあるからです
RegAsm Assembly Registration Tool .NET Framework 付属のツール。.NET アセンブリを COM から使えるようにレジストリへ登録します
AxHost Windows Forms 上で ActiveX コントロールをホストするための基底クラスです
AxImp ActiveX Control Importer OCX から Windows Forms 用のラッパーアセンブリを生成するツールです
in-proc / out-of-proc プロセス内 / プロセス外 呼び出し元と同じプロセスで動く(DLL や OCX)か、別プロセスで動く(EXE のサーバー)か
LocalServer COM サーバーを EXE として別プロセスで動かす形態。bitness の壁を越えたり、クラッシュを隔離したりできます
Reg-Free COM / side-by-side 登録不要 COM レジストリ登録なしで、アプリ側のマニフェストに書いた情報で COM を解決する仕組みです
design-time / runtime ライセンス 開発時 / 実行時 ベンダー製コントロールで、開発機で画面に貼るときと、配布先で実行するときとでライセンスの扱いが分かれていることがあります
adapter / facade 既存の細かい API を、自分たちに都合のよい粗い API に置き換える設計上の型です
STA / MTA Single / Multi Threaded Apartment COM のスレッドモデル。どのスレッドから呼んでよいかの約束が変わります

3. まず見る判断表

3.1. 全体像

まずはこの表から見ると、だいたいの方針が決まります。

状況 まずの選択 理由
ブラウザ上の ActiveX に依存している 置き換える寄り Edge 本体は ActiveX 非対応で、IE モードは延命策としての位置づけだから
デスクトップアプリで OCX が安定稼働し、変更範囲が小さい 残す寄り いま崩すコストのほうが大きいことが多いから
周辺だけ .NET 化したいが、コントロールの挙動が読めない 包む寄り 先に境界を整理したほうが安全だから
32bit OCX を 64bit プロセスへそのまま入れたい 包む / 構成変更 in-proc では越えられない境界だから
UI 部品としてしか使っておらず、代替がある 置き換える寄り 表面の置換で済みやすいから
ベンダー終了、署名、登録、依存 DLL で毎回事故る 置き換える寄り 運用コストが技術的負債として表面化しているから
機器制御、帳票、独自プロトコルを内包している 包む寄り まず振る舞いを固定化しないと置換コストが読めないから
はいいいえはいはいいいえいいえはいいいえはいいいえActiveX / OCX があるブラウザ依存?置き換えを優先IE モードは延命策主に UI 部品?同等の代替がある?置き換えを検討まず包んで境界を整理機器制御・独自仕様・帳票ロジックを抱えている?まず包むテストを揃えてから段階置換登録・bitness・配布が痛い?構成を見直すout-of-proc / 別プロセス連携 / Reg-Free COM を検討残す判断も現実的

図3: 最初の分岐はブラウザ依存かどうかで、その後はUI部品か・代替があるか・仕様を抱えているかで方針が決まる。

以下、各パターンを順番に見ていきます。

3.2. 残す判断

ActiveX / OCX だからといって、すぐ置換対象になるわけではありません。こういう条件が揃うなら、残すのがいちばん安いことは普通にあります。

  • 利用範囲が閉じていて、社内配布や装置同梱など運用環境が固定されている
  • そのコントロールがいまも安定稼働しており、変更要求が大きくない
  • ベンダーがまだ現役、または自社で最低限の保守ができる
  • ブラウザ依存ではなく、デスクトップの既存ホスト上で完結している
  • 32bit / 64bit の前提を当面変えなくてよい

ここで大事なのは、残す = 放置 ではないことです。残すなら、少なくともこのくらいはやっておきたいところです。

  • 対応 OS、bitness、必要な依存 DLL、登録手順を文章で残す
  • インストール、登録、解除を人力メモではなくスクリプトやインストーラーへ寄せる
  • クリーン環境でのスモークテストを用意する
  • コントロールへの呼び出しをアプリ全体へばらまかず、できるだけ 1 か所に寄せる

いちばんまずいのは、「動いているので触らない」を 10 年続けて、誰も前提を説明できなくなることです。 残す選択をするほど、前提の見える化 は重要になります。

残す判断とセットの見える化残す判断は放置ではなく、前提の文書化、登録手順のスクリプト化、クリーン環境でのスモークテスト、呼び出し箇所の集約をセットで行う。残す判断前提を文章で残す登録手順をスクリプト化スモークテストを用意呼び出しを1か所に寄せる

図4: 残す=放置ではなく、残す選択をするほど前提の見える化をセットで行う。

3.3. 包む判断

実務では、この選択がいちばん仕事になります。

ここでいう「包む」は、ActiveX / OCX を狭い境界の内側に閉じ込めて、 周辺からは新しい API や新しい画面部品として見せることです。

これはかなり有効です。 なぜなら、古い部品の挙動が読み切れない段階で全面再実装に入ると、仕様発掘と不具合再現の二重苦になりやすいからです。 まずは古い部品を隔離し、境界だけ整える ほうが安全です。

包むという選択の構図ActiveX / OCXを狭い境界の内側に閉じ込め、周辺からは新しいAPIや画面部品として見せることで、挙動が読み切れない段階での全面再実装による仕様発掘と不具合再現の二重苦を避ける。ActiveX / OCX狭い境界の内側に閉じ込める新しいAPIとして見せる周辺は新しい窓口だけを見る仕様発掘と再現の二重苦を回避

図5: 「包む」は古い部品の隔離と新しい窓口づくりで、全面再実装の前段として効く。

包み方にはいくつか型があります。

包み方 向く場面 見るポイント
WinForms ホスト + AxHost / Aximp 既存デスクトップ画面に埋めたい、少数画面だけ残したい STA、イベント、デザイン時依存、ライセンス
32bit helper EXE / COM LocalServer / 別プロセス橋渡し 64bit 側へ寄せたい、クラッシュを隔離したい プロセス間通信、起動順、監視、デプロイ
.NET 側の COM 互換窓口 既存 COM 呼び出し元は残しつつ中身を更新したい IID / CLSID / TLB / 登録方法 / bitness

方針が決まったあと、最初の一歩がどこかも書いておきます。

包み方 最初にやること 詳しい手順
WinForms ホスト + AxHost Visual Studio でツールボックスを右クリック →「ツールボックス アイテムの選択」→「COM コンポーネント」タブから対象を選ぶ。コマンドラインなら aximp COM/OCX/ActiveX開発でハマる登録とbitnessの罠
32bit helper EXE / LocalServer 32bit の EXE 側を COM サーバーとして登録し、64bit 側からは out-of-proc で呼ぶ COMが役立つケーススタディ-32bitアプリから64bit DLLを呼び出したいとき
Reg-Free COM アプリ側のマニフェストに filecomClass を書き、レジストリ登録なしで解決させる Reg-Free COMとは - 登録不要でCOMを使う仕組み
.NET 側の COM 互換窓口 .NET 側を COM 公開し、必要なら dscom で TLB を生成する .NET 8 DLLをVBAから型付きで使う方法 - COM公開とdscom TLB

aximp は Visual Studio の Developer Command Prompt から実行します。

aximp C:\path\to\MyControl.ocx

これで、COM 型の runtime callable wrapper と、AxHost から派生した Windows Forms 用のラッパーの 2 つが生成されます。ファイル名は元のファイル名ではなく ProgID から決まる ので、そこだけ注意してください。Microsoft のドキュメントの例だと、msdxm.ocx からは MediaPlayer.dllAxMediaPlayer.dll が出ます。後者を参照に追加し、AxMediaPlayer をフォームへ貼る形になります。

aximpが生成するものaximpにOCXを渡すと、COM型のruntime callable wrapperとAxHost派生のWindows Forms用ラッパーの2つが生成され、後者を参照に追加してフォームへ貼る。ファイル名は元のファイル名ではなくProgIDから決まる。対象のOCXaximpを実行COM型のラッパーDLLAxHost派生のラッパーDLL参照に追加しフォームへ貼るファイル名はProgIDから決まる

図6: aximpの出力は2つのDLLで、フォームへ貼るのはAxHost派生のラッパー側。

Reg-Free COM の場合、アプリ側のマニフェストは最小でこういう形です。

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="MyApp" version="1.0.0.0" />
  <file name="MyControl.ocx">
    <comClass
      clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
      threadingModel="Apartment"
      progid="MyCompany.MyControl.1" />
  </file>
</assembly>

LocalServer 方式なら、レジストリ上は HKEY_CLASSES_ROOT\CLSID\{CLSID}\LocalServer32 に EXE のパスが入ります。ATL や MFC で作った EXE サーバーなら、慣例として MyServer.exe /regserver/unregserver で自己登録・解除できるようになっていることが多いです。ただし bitness ごとにレジストリのビューが分かれるので、32bit の EXE は 32bit 側のレジストリに登録される という点は必ず意識してください。

LocalServer登録とレジストリのビューLocalServer方式ではCLSID配下のLocalServer32にEXEのパスが入り、regserverの慣例で自己登録できるが、bitnessごとにレジストリのビューが分かれ、32bitのEXEは32bit側のレジストリに登録される。32bit64bitEXEサーバーLocalServer32にパスを登録EXEのbitnessは?32bit側のビューに登録64bit側のビューに登録

図7: LocalServerの登録先はbitnessごとに分かれたレジストリのビューで決まる。

特に大事なのは、包むときに 古い API をそのまま 200 個コピーしない ことです。 それをやると、古い都合を新しいコードへそのまま輸入するだけになります。

包むときは、このあたりを意識するとかなりましになります。

  • 粗い粒度のメソッドにする
  • 画面コードから直接 OCX を触らせない
  • 失敗時に必要なログを境界で取る
  • タイムアウト、再試行、例外変換の責務を境界で決める
  • 将来の置き換え先も同じインターフェースで差し替えられるようにする

新しい .NET 側で COM の入口だけ残したい場合もあります。 この場合は、「中身は更新しつつ、COM 契約だけ維持する」という構成が現実的です。 ただし、.NET Framework 時代の感覚で「とりあえず RegAsm」で済むとは限りません。 今の .NET の COM host、TLB、bitness、Registry-Free COM の扱いは、先に設計しておいたほうが後で楽です。 このあたりは、.NET 8 DLLをVBAから型付きで使う方法 - COM公開とdscom TLBReg-Free COMとは - 登録不要でCOMを使う仕組み で、それぞれ手順まで書いています。

境界で決める責務包むときは粗い粒度のメソッドにし、画面コードから直接OCXを触らせず、ログやタイムアウトや例外変換の責務を境界で決め、将来の置き換え先も同じインターフェースで差し替えられるようにする。包む境界粗い粒度のメソッドログを境界で取るタイムアウトと例外変換同じ窓口で将来差し替え古いAPIを200個コピーしない

図8: 包む価値は境界に責務を集めることにあり、古いAPIの丸写しではその価値が出ない。

3.4. 置き換える判断

置き換えに向いているのは、主に 表面の古さ が問題になっているケースです。

こういうときは置き換え優先で見たほうがよいです。

  • その ActiveX が UI 部品としてしか使われていない
  • ベンダーが .NET / WPF / WebView2 向けの後継を出している
  • ブラウザ依存や IE 前提が足を引っ張っている
  • 登録、署名、管理者権限、セキュリティ設定で毎回つまずく
  • 代替実装を検証できるテストや業務シナリオがある

逆に、見た目が古いからという理由だけで機器制御や帳票ロジックまで抱えた部品を一気に捨てにいくと、だいたい泥になります。

置き換えるなら、まずは UI から です。

  • グリッド
  • カレンダー
  • ツリー
  • ブラウザ表示部
  • 単純な入力補助

このあたりは、比較的置き換えやすいです。一方で、UI に見えても中身が濃いものもあります。

  • ベンダー製の機器制御 ActiveX
  • 印刷や帳票生成と一体化したコントロール
  • 独自ファイル形式の読み書きを内包しているコントロール
  • COM コールバックやスレッド前提を抱えたコントロール

この差を見誤ると、工数見積もりが一気に壊れます。

置き換え判断の見分けUI部品としてしか使われておらず代替があるなら置き換えやすいが、UIに見えても機器制御・帳票・独自形式・スレッド前提を抱えた部品は中身が濃く、いきなり捨てにいくと泥になる。表面の古さだけ仕様の塊を抱えている見た目の裏に何があるか置き換えやすい一気に捨てると泥になるまず包む側の判断へ

図9: 置き換え向きかどうかは「表面の古さ」と「中身の濃さ」の見分けで決まる。

3.5. ブラウザ依存は別枠で考える

ここはかなり別枠です。

ブラウザ上の ActiveX は、デスクトップの OCX と違って、 今後もそのまま伸ばしていく理由がかなり弱いです。

理由は単純で、現代のブラウザ基盤がそこを主戦場にしていないからです。 Microsoft Edge 自体は ActiveX をサポートしていません。 一方で、IE モードは設定されたサイトに対して IE 系のエンジンを使い、ActiveX を含む一部の IE 機能を動かすための互換レイヤーとして使えます。

つまり、

  • いま動かすための延命 はできる
  • でも、長期の設計としては未来が太いわけではない

ということです。

ブラウザ上のActiveXの位置づけMicrosoft Edge自体はActiveXをサポートせず、IEモードは設定されたサイトにIE系エンジンを使う互換レイヤーなので、いま動かす延命はできても長期の設計としては未来が太くない。ブラウザ上のActiveXEdge本体では動かないIEモードで延命はできる長期の未来は細い置き換え優先で見る

図10: ブラウザ依存のActiveXは延命と恒久設計を分けて考え、置き換え優先で見る。

同じことは、Windows アプリに埋め込んだ WebBrowser コントロールにも起きます。 WebBrowser は IE 系の世界観を引きずるので、単に HTML を表示したいだけなら、今からの新規作業は WebView2 を第一候補にしたほうが自然です。

ただし、ここで気を付けたいのは、WebView2 は WebBrowser の完全な差し替え部品ではない ことです。

  • IE DOM 前提のスクリプト
  • ActiveX 依存
  • window.external まわりの前提
  • セキュリティゾーンやイントラネット前提の挙動

このあたりは、そのままでは移りません。 置き換えるなら、描画エンジンだけでなく、ブラウザとネイティブの接続面 も設計し直す必要があります。

WebView2にそのまま移らないものWebView2はWebBrowserコントロールの完全な差し替え部品ではなく、IE DOM前提のスクリプト、ActiveX依存、window.externalまわりの前提、セキュリティゾーン前提の挙動はそのままでは移らない。WebBrowserからWebView2へHTML表示だけなら第一候補そのまま移らないものIE DOM前提のスクリプトActiveX依存window.external前提セキュリティゾーンの挙動

図11: WebView2は描画エンジンの交換部品ではあっても、IE世界観の接続面までは引き継がない。

4. 判断を狂わせやすい論点

4.1. UI 部品なのか、仕様を抱えた部品なのか

これは最重要です。

古いグリッドやカレンダーなら、見た目とイベントの互換を見ればかなり話が進みます。 一方で、機器制御や帳票や独自形式を抱えた ActiveX は、見た目の裏に仕様の塊があります。

同じ「画面上のコントロール」に見えても、実際にはこれだけの幅があります。

  • ただの一覧表示部品
  • 独自プロトコルで装置へ命令を飛ばしている部品
  • 内部でタイムアウト、再接続、再送、例外吸収までやっている部品
  • 印刷やエクスポート形式の互換を背負っている部品

後者をいきなり再実装するのは、だいたい仕様発掘プロジェクトになります。 ここは先に包むほうが安全です。

UI部品か仕様を抱えた部品か同じ画面上のコントロールに見えても、ただの一覧表示部品と、装置への命令や再接続や帳票互換まで抱えた部品では幅があり、後者のいきなりの再実装は仕様発掘プロジェクトになる。画面上のコントロールただの表示部品仕様の塊を抱えた部品互換を見れば話が進むいきなり再実装は仕様発掘化先に包むほうが安全

図12: 最重要の見分け。見た目が同じでも、裏に仕様の塊があるかどうかで進め方が変わる。

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 は別問題です。 ここを雑に始めると、ビルドは通るのに配布先で動かない、という嫌なやつが出てきます。

32bit OCXと64bit化の三択32bit OCXは64bitプロセスへin-procで読み込めないため、ホストを32bitのまま維持する、32bitの別プロセスに閉じ込めてIPCやout-of-proc COMでつなぐ、依存を外せる所から置き換えるの三択になる。32bit OCXはin-proc不可ホストを32bitのまま維持32bit別プロセスに閉じ込める外せる所から置き換えるIPCやout-of-proc COMで接続

図13: bitnessの壁は気合いでは越えられず、現実的な選択肢はこの三択に落ちる。

4.3. 登録、配布、権限、ライセンス

技術的には呼べるのに、配布で死ぬ。 これは ActiveX / OCX ではかなりよくあります。

難所になりやすいのはこのあたりです。

  • regsvr32 の前提が人依存になっている
  • 依存 DLL の配置が暗黙になっている
  • 管理者権限が必要なのに、運用手順へ落ちていない
  • ベンダー製コントロールの design-time / runtime ライセンスが分かれている
  • 開発機では動くのに、クリーン環境では動かない

このあたりは、コードを 1 行も触らなくてもプロジェクトを止めます。

登録不要の構成や side-by-side 配置で楽になるケースもありますが、魔法の粉ではありません。 コンテナ側や配布方式との相性確認は必要です。

要するに、ActiveX / OCX の移行は 実装だけでなく配布設計 でもあります。 ここを後回しにすると、最後に派手に転びます。

配布で止まる難所regsvr32の人依存、暗黙の依存DLL配置、運用手順に落ちていない管理者権限、design-timeとruntimeで分かれるライセンスは、コードを1行も触らなくてもプロジェクトを止める。配布設計regsvr32が人依存依存DLLが暗黙管理者権限が手順外ライセンスが二分コードを触らなくても止まる

図14: 技術的には呼べても配布で死ぬ、という難所は実装と別枠で設計しておく。

4.4. STA / メッセージループ / コールバック

ActiveX / OCX は、ただの DLL 呼び出しではありません。 COM のスレッドモデルやメッセージループの前提を持っていることがあります。

特に注意したいのは、次のようなケースです。

  • UI スレッド前提でしか安定しない
  • STA 前提なのに MTA 側から雑に呼んでいる
  • 同期呼び出し中にコールバックが返ってくる
  • イベントを受けるスレッド前提が曖昧

この辺りは、最初は「たまに固まる」「たまにイベントが来ない」という怪談の顔をして現れます。 でも中身はだいたい前提違反です。

なので、包むときも置き換えるときも、 どのスレッドで生成し、どのスレッドで呼び、どこでイベントを受けるか は先に固定したほうがよいです。

スレッド前提を先に固定するどのスレッドで生成し、どのスレッドで呼び、どこでイベントを受けるかを先に固定しないと、たまに固まる・たまにイベントが来ないという前提違反の怪談になる。先に固定する3点どのスレッドで生成するかどのスレッドで呼ぶかどこでイベントを受けるか曖昧だと前提違反の怪談化

図15: 「たまに固まる」の中身はだいたい前提違反で、スレッドの約束を先に固定して防ぐ。

4.5. テストがあるか、観測できるか

置き換えが難しいのは、コードが古いからだけではありません。 何をもって「同じように動いた」と言えるか がないからです。

こういうものがあるだけでもかなり違います。

  • 操作シナリオごとのスモークテスト
  • 入出力サンプル
  • 画面キャプチャや帳票サンプル
  • エラーパターンと期待挙動
  • タイムアウト時や装置未接続時のログ

特に機器や帳票が絡むと、仕様書より現物の挙動のほうが真実、という妙なことが起きます。 ここで観測手段がないと、置き換えは発掘調査に変わります。

観測手段が置き換えを支えるスモークテストや入出力サンプル、帳票サンプル、エラーパターンと期待挙動といった観測手段が無いと、何をもって同じように動いたと言えるかが無く、置き換えは発掘調査に変わる。あるない観測手段はあるか同じに動いたと言える置き換えが発掘調査化スモークテストやサンプル類

図16: 置き換えの難しさはコードの古さより、「同じに動いた」を言える観測手段の有無で決まる。

5. 典型パターン別のおすすめ

5.1. いまも安定して動く社内デスクトップアプリ

おすすめは、残す寄り です。

こういう条件なら、無理に剥がさないほうがよいことが多いです。

  • 社内限定で使っている
  • 対象端末や OS がある程度固定されている
  • その OCX は数画面でしか使っていない
  • 改修要求は小さく、寿命も読めている

ただし、そのまま裸で置いておくのではなく、 呼び出し箇所だけは寄せておいたほうが後で効きます。

つまり、方針としてはこうです。

  • いまは残す
  • でも、境界だけ整える
  • 置き換えが必要になったときに、そこから着手できる形にする

この 3 段構えが素直です。

5.2. 32bit OCX を 64bit 側へ持っていきたい

おすすめは、包む / 構成変更 です。

ここは真正面から行くと詰みます。 32bit OCX を 64bit プロセスへ in-proc で入れることはできないからです。

現実的には、32bit のヘルパープロセスや LocalServer 側に閉じ込めて、 64bit アプリとは粗い API で通信する構成が扱いやすいです。

32bit OCX32bit ヘルパー / LocalServer64bit .NET アプリ32bit OCX32bit ヘルパー / LocalServer64bit .NET アプリ粗い API で依頼in-proc 呼び出し結果 / イベント変換済み結果

図17: 32bitヘルパーに閉じ込めたOCXを、64bitアプリから粗いAPI越しに使う構成。

ここでのポイントは、細かいメソッドを全部そのまま中継しない ことです。 プロセス間境界は、細かい呼び出しを大量に流すとすぐつらくなります。

  • 1 操作 = 1 要求 くらいの粒度に寄せる
  • 戻り値やエラーを意味のある単位に整形する
  • ログを境界で取る

この形にしておくと、後で中身を本当に置き換えるときも楽です。

ここまでは自前のヘルパー EXE を前提に書きましたが、その手前にもう一段、先に確認しておきたい選択肢があります。

その OCX / DLL が in-proc の COM サーバー、つまり InprocServer32 で登録できるものなら、Windows 付属のサロゲートプロセスに載せて out-of-proc の Local Server として出せます。 CLSID に AppID を付け、その AppID キーへ空文字の DllSurrogate を書くだけで、こちらのコードは 1 行も要りません。 登録の手順は COM/OCX/ActiveX開発でハマる登録とbitnessの罠 の 3.5 にまとめています。

ただし、サロゲートは bitness の差を消してくれるわけではありません。 消えるのは 同じプロセスに載せなければならない という制約だけで、呼び出しは out-of-proc になり、マーシャリングとプロセス間通信のコストはそのまま乗ります。

どちらを選ぶかは、だいたいこの表で決まります。

状況 選ぶもの 理由
メソッド呼び出しとイベントで完結する自動化オブジェクト まずサロゲート 登録だけで out-of-proc 化でき、書くコードが無いから
やり取りする型が IDispatch や登録済み proxy / stub でマーシャリングできる まずサロゲート 境界を越える手当てが既にあるから
その CLSID に LocalServer32 などの EXE 登録がすでにある サロゲートは出番なし EXE サーバーやサービスの起動が常に優先されるから
フォームに貼って描画させるビジュアルなコントロールとして使いたい 別の構成を考える ウィンドウはホストのプロセス内にある前提だから
細かい呼び出しが高頻度で、そのまま中継すると重い 自前のヘルパー EXE 粗い API に束ねる層を自分で持つ必要があるから
独自インターフェースにマーシャラーが無い 自前のヘルパー EXE proxy / stub を用意するか、境界の型を自分で決めるほうが早いから
初期化順、再接続、タイムアウト、ログを自分で握りたい 自前のヘルパー EXE サロゲートのプロセス寿命は COM 任せだから

つまり、サロゲートは まず試す価値のある最小手 で、自前の EXE は 境界を自分で設計したいときの手 です。 3.1 の表の「32bit OCX を 64bit プロセスへそのまま入れたい → 包む / 構成変更」は変わりません。その「包む」の中に 2 段ある、と読んでください。

5.3. IE / WebBrowser 前提の画面

おすすめは、置き換え優先 です。

ここは「今動く」と「今後も楽に保てる」が一致しにくい領域です。 IE モードは互換のためにかなり助かりますが、それでも前提は IE 系のままです。

なので、考え方としてはこう分けるのが分かりやすいです。

  • 社内業務を止めないために IE モードで延命する
  • ただし、延命と恒久設計を混同しない
  • 置き換え先は WebView2、純 Web、ネイティブ UI + Web のハイブリッドなどから選ぶ

延命側の具体的な手当ても書いておきます。IE モードは「Edge を入れれば勝手に効く」ものではなく、対象サイトをポリシーで指定して初めて IE 系のエンジンで開かれます。設定の入口はこの 3 つです。

やり方 設定 補足
サイトを列挙する Microsoft Edge 78 以降のグループポリシー「Configure the Enterprise Mode Site List」に、エンタープライズ モード サイト一覧の XML の場所を指定する いちばん基本の形です
旧 IE 側の一覧を流用する Internet Explorer のポリシー「Use the Enterprise Mode IE website list」 Edge 側のポリシーがあると、そちらが優先されます
イントラネット全体を回す Microsoft Edge 77 以降のグループポリシー「Send all intranet sites to Internet Explorer」を有効にする 対象が広くなるので、棚卸しの代わりにはなりません

前提として、Windows と Edge に最新の更新が入っていること、Microsoft Edge の管理用テンプレートが導入されていること、Windows の機能で Internet Explorer 11 が有効になっていることが必要です。ここが欠けていると IE モードは失敗します。

なお、IE モードでは ActiveX コントロールや Browser Helper Object が動きます。つまり 延命は本当にできます。だからこそ、終了条件を決めずに使い続けると抜けられなくなります。剥がし方の話は IEモード依存システムの脱却ガイド にまとめています。

IEモード延命の考え方IEモードは対象サイトをポリシーで指定して初めて効き、ActiveXも動くので延命は本当にできるが、延命と恒久設計を混同せず、終了条件を決めて使わないと抜けられなくなる。対象サイトをポリシーで指定IEモードで開かれるActiveX込みで延命できる終了条件を決めて使う決めないと抜けられなくなる

図18: IEモードの延命は「本当に効く」からこそ、終了条件とセットで使う。

特に WebBrowser コントロールを単に HTML ビューアとして使っているだけなら、 置き換え優先度は高いです。

一方で、ブラウザ内の ActiveX がローカルファイル、装置、署名、独自アドオンのような役割まで持っているなら、 それは描画エンジンの交換ではなく ネイティブ連携の再設計 です。 ここは少し話が重くなります。

5.4. 機器制御や独自仕様を抱えた ActiveX

おすすめは、まず包む です。

このタイプは、見た目より中身が濃いです。 SDK の資料が薄くても、現場で長年動いてきた結果として、 こうした挙動が暗黙に積まれていることがあります。

  • 接続失敗時の待ち方
  • タイムアウト後の再試行
  • イベント順序
  • 実機の癖を吸収する回避処理
  • 例外やエラーコードの解釈

この手の部品を「どうせ古いから」で作り直すと、かなりの確率で現場試験が燃えます。

なので、まずはここから始めるのが安全です。

  1. 既存部品を境界の内側へ閉じ込める
  2. ログを足して、何が起きているか見えるようにする
  3. テストシナリオと実機パターンを集める
  4. その後で、置き換え可能な範囲を切り出す

派手さはありませんが、実務ではこれがいちばん効きます。

仕様を抱えたActiveXの進め方既存部品を境界の内側へ閉じ込め、ログを足して何が起きているか見えるようにし、テストシナリオと実機パターンを集め、その後で置き換え可能な範囲を切り出すという順で進める。境界の内側へ閉じ込めるログを足して見える化シナリオと実機パターン収集置き換え可能な範囲を切り出す

図19: 機器制御や独自仕様を抱えた部品は、この順で進めると現場試験が燃えにくい。

6. よくあるアンチパターン

アンチパターン 何がつらいか まずの直し方
ActiveX があるので全面リライト 仕様漏れと工数爆発が起きやすい まず棚卸しと境界切り出し
32bit OCX を 64bit アプリへそのまま入れようとする 原理的に無理 32bit 側へ隔離するか、構成を変える
コントロール API を画面中から直呼びしている 置き換え不能になりやすい adapter / facade に寄せる
regsvr32 手順を人力運用している 環境差異で毎回事故る インストーラー、スクリプト、マニフェスト化を検討
IE モードがあるので安心する 延命と恒久対応を混同しやすい 置き換え計画と終了条件を決める
置き換え前に振る舞いを記録していない 完成判定ができない スモークテスト、サンプルデータ、ログを揃える

この中で、特に実務でよく見るのは 3 つです。

  1. 全面リライトを急ぐ
  2. bitness の壁を軽く見る
  3. API をアプリ全体へばらまく

この 3 つを避けるだけでも、かなり事故率は下がります。

特によく見る3つのアンチパターン全面リライトを急ぐ、bitnessの壁を軽く見る、コントロールAPIをアプリ全体へばらまくの3つを避けるだけでも事故率はかなり下がる。全面リライトを急ぐこの3つを避けるbitnessの壁を軽く見るAPIを全体へばらまく事故率がかなり下がる

図20: アンチパターンの中でも遭遇率が高いのはこの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. まとめ

ActiveX / OCX をどう扱うかは、レガシーだから嫌う、で決める話ではありません。

まず見るべきポイントは 4 つあります。

  1. その部品は単なる UI か、それとも仕様を抱えた境界面か
  2. 同一プロセスで使う必要があるか
  3. 32bit / 64bit、登録、ブラウザ依存、ライセンスで詰まらないか
  4. 置き換え前に、振る舞いを観測できるか

この 4 つが見えれば、だいたいこう整理できます。

  • 安定稼働していて寿命も読めるなら、残す
  • 周辺だけ近代化したいなら、包む
  • UI 部品やブラウザ依存なら、置き換える
  • 仕様の塊を抱えた部品は、まず包んでから段階置換する

レガシー技術は、笑う対象ではなく、歴史と契約が詰まった現物 です。 ただし、現物に付き合うための境界設計は必要です。

「残す・包む・置き換える」を混ぜて考えられるようになると、 ActiveX / OCX の案件は、急に扱える問題に変わってきます。

まとめの整理安定稼働で寿命が読めるなら残す、周辺だけ近代化したいなら包む、UI部品やブラウザ依存なら置き換える、仕様の塊を抱えた部品はまず包んでから段階置換するという整理を示す。ActiveX / OCXの扱い安定稼働なら残す周辺の近代化なら包むUIやブラウザ依存は置換仕様の塊は包んで段階置換

図21: 4つの見るべきポイントが見えれば、残す・包む・置き換えるはこの形に整理できる。

10. こういう相談は相性がよい

このテーマは、いきなり開発に入る前の 方針整理 だけでも価値が出やすいです。

たとえば、こういう相談はかなり相性がよいです。

  • どの OCX を本当に置き換えるべきか、棚卸ししたい
  • 32bit / 64bit の詰まりどころだけ先に整理したい
  • .NET へ寄せたいが、COM の入口だけは残したい
  • ベンダー終了した ActiveX の延命策と撤退戦を比較したい
  • IE / WebBrowser 依存をどこから剥がせるか見たい
  • まずは 1 画面、1 機能だけ安全に分離したい

ActiveX / OCX の案件は、実装より先に 境界をどう切るか が勝負になることが多いです。 全面改修の前段として、現状整理、構成比較、移行順序の設計から入るだけでも、かなり意味があります。

11. 参考資料

  • Microsoft Learn: AxHost Class (System.Windows.Forms)
    • https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.axhost
  • Microsoft Learn: Aximp.exe (Windows フォーム ActiveX コントロール インポーター)
    • https://learn.microsoft.com/ja-jp/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: DllSurrogate
    • https://learn.microsoft.com/en-us/windows/win32/com/dllsurrogate
  • Microsoft Learn: Registering the DLL Server for Surrogate Activation
    • https://learn.microsoft.com/en-us/windows/win32/com/registering-the-dll-server-for-surrogate-activation
  • Microsoft Learn: Microsoft Edge に関してよく寄せられる質問
    • https://learn.microsoft.com/ja-jp/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/
  • KomuraSoft Blog: COMのSTA/MTAでハングを避けるための基礎知識
    • https://comcomponent.com/blog/2026/01/31/000-sta-mta-com-relationship/
  • KomuraSoft Blog: C++のネイティブDLLをC#から使うとき、C++/CLIでラッパーを作ったほうがよい理由
    • https://comcomponent.com/blog/2026/03/07/000-cpp-cli-wrapper-for-native-dlls/
  • KomuraSoft Blog: COMが役立つケーススタディ-32bitアプリから64bit DLLを呼び出したいとき
    • https://comcomponent.com/blog/2026/01/25/002-com-case-study-32bit-to-64bit/
  • KomuraSoft Blog: COM / ActiveX / OCX とは何か - 違いと関係をまとめて解説
    • https://comcomponent.com/blog/2026/03/13/000-what-is-com-activex-ocx/
  • KomuraSoft Blog: .NET 8 DLLをVBAから型付きで使う方法 - COM公開とdscom TLB
    • https://comcomponent.com/blog/2026/03/16/007-dotnet8-dll-typed-vba-com-dscom-tlb/
  • KomuraSoft Blog: Reg-Free COMとは - 登録不要でCOMを使う仕組み
    • https://comcomponent.com/blog/2026/03/16/011-what-is-reg-free-com/
  • KomuraSoft Blog: COM/OCX/ActiveX開発でハマる登録とbitnessの罠
    • https://comcomponent.com/blog/2026/04/15/001-com-ocx-activex-pitfalls-visual-studio-bitness-admin-rights/
  • KomuraSoft Blog: IEモード依存システムの脱却ガイド
    • https://comcomponent.com/blog/2026/04/25/003-ie-mode-internal-web-system-life-extension-and-exit/
  • KomuraSoft Blog: IEモードの次はWebView2でいいのか ── ActiveXが動かない制約と現実的な移行設計
    • https://comcomponent.com/blog/webview2-embed-web-ui-in-windows-apps/

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

ActiveX / OCXは置き換えるべきですか?
「古いかどうか」ではなく、その部品が何を引き受けているかで判断します。単なるUI部品で代替があれば置き換え、機器制御・帳票・独自ファイル形式を抱えているならまず包んで境界を整理し、安定稼働していて変更範囲が小さいなら残す判断も現実的です。「とりあえず全面リライト」と「怖いから永久凍結」はどちらも事故率が高い選択です。
32bit OCXを64bitアプリから使えますか?
in-procでは使えません。OCXは読み込むプロセスとbitnessを揃える必要があり、これは原理的な制約です。現実的な選択肢は、当面ホストアプリも32bitのまま維持する、32bitの別プロセス(ヘルパーEXEやCOM LocalServer)へ閉じ込めて64bit側とはIPCやout-of-proc COMでつなぐ、そのOCX依存を外せるところから先に置き換える、の三択です。
ブラウザのActiveX依存はどうすべきですか?
置き換え優先で見たほうがよいです。Microsoft Edge自体はActiveXをサポートしておらず、IEモードは延命策としての位置づけです。WebBrowserコントロールも同様にIE系の世界観を引きずるため、単にHTMLを表示したいだけならWebView2が第一候補です。ただしWebView2は完全な差し替え部品ではなく、IE DOM前提のスクリプトやwindow.externalまわりの前提はそのままでは移りません。
ActiveX / OCXを「包む」とは具体的に何をすることですか?
ActiveX / OCXを狭い境界の内側に閉じ込めて、周辺からは新しいAPIや画面部品として見せることです。WinFormsホスト+AxHost、32bitヘルパーEXEやLocalServerでの別プロセス橋渡し、.NET側のCOM互換窓口といった型があります。包むときは古いAPIをそのまま大量コピーせず、粗い粒度のメソッドにし、境界でログ・タイムアウト・例外変換の責務を決め、将来の置き換え先も同じインターフェースで差し替えられる形にします。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る