COM/OCX/ActiveX開発でハマる登録とbitnessの罠

· · COM, ActiveX, OCX, Visual Studio, Windows開発, 32bit, 64bit, Interop

COM コンポーネントや OCX / ActiveX の案件は、コードそのものよりも 実行環境・登録・ホスト・権限 の境界でハマりやすいです。

ありがちなのは、こんな症状です。

  • ビルドは通るのに、起動すると 0x80040154
  • 自分の開発機では動くのに、他の PC では動かない。
  • 実行時は動くのに、Visual Studio の Designer だけ死ぬ。
  • 管理者で起動したら動くのに、通常権限では壊れる。
  • regsvr32 を叩いているのに、なぜか直らない。

このへんは、個別のバグというより、COM の前提がどこかで噛み合っていない 状態です。

COM / ActiveX / OCX の言葉自体を先に整理したい場合は、まず COM / ActiveX / OCX とは何か - 違いと関係をまとめて解説 を読むと全体像を掴みやすいです。 この記事では、その次の段階として、実際にどこで詰まりやすいか を、Visual Studio のビット数や管理者権限まわりも含めて整理します。

1. まず結論

先に、実務で効く言い方をするとこうです。

  1. COM / OCX / ActiveX のトラブルは、コードのロジックより bitness(32bit / 64bit)・登録先・ホスト・権限 の不一致で起きることが多いです。
  2. Visual Studio 2022 は 64bit プロセス なので、昔は通っていた 32bit 前提のデザイン時連携が、そのままでは壊れます。12
  3. regsvr32何でも登録する魔法のコマンドではありません。ネイティブの in-proc COM サーバー(DLL / OCX)向けです。 .NET Framework を COM 公開するなら Regasm.exe、.NET 5+ / .NET 6+ / .NET 8+ では生成された .comhost.dll を登録する流れになります。3456
  4. 「管理者で動くなら OK」は危険です。per-user 登録でたまたま見えている、あるいは 本来インストーラーでやるべき登録を開発機だけ手で済ませている ことが珍しくありません。378

つまり、COM / OCX / ActiveX を扱うときは、まずこの 4 軸で見るのが安全です。

  • どのプロセスがホストするのか
  • そのプロセスは 32bit か 64bit か
  • どこに登録されているのか(HKCU / HKLM、32bit view / 64bit view)
  • その操作や実行に管理者権限が要るのか

2. 症状から逆引きすると、だいたいこう見える

症状 まず疑うこと よくある本当の原因
0x80040154 Class not registered 未登録 実際には「別ビット数側にだけ登録されている」「そのユーザーにしか登録されていない」ことも多い
DllRegisterServer failed: 0x80070005 権限不足 標準ユーザーで登録しようとしている、post-build で昇格なしに登録している
VS2022 で Designer だけ壊れる Designer の制約 32bit COM / ActiveX を 64bit の Visual Studio 側が直接読めない
管理者で起動したときだけ動く 権限の問題 本質は権限そのものより、登録スコープやインストール設計のズレであることが多い
64bit アプリから 32bit OCX を呼べない COM の仕組みの制約 in-proc サーバーはホストと同じ bitness でないとロードできない
UI スレッドでは動くのにバックグラウンドスレッドで固まる スレッドモデル STA / MTA、CoInitializeEx、メッセージループの前提違反

0x80040154 は公式には REGDB_E_CLASSNOTREG で、文字通り Class not registered です。9 また、regsvr320x80070005 は、公式にも 管理者権限がなくレジストリや System32 に書けない ケースとして説明されています。10

ここで大事なのは、エラー名をそのまま信じすぎない ことです。 たとえば Class not registered は「完全に未登録」とは限らず、違うレジストリ view に登録されているそのユーザーにしか見えない場所に登録されている だけでも起きます。117

3. Visual Studio のビット数でハマる

3.1. Visual Studio 2022 は 64bit になった

ここは、今の COM / ActiveX 開発で一番ハマりやすい点です。

Visual Studio 2022 は devenv.exe64bit only です。1 そのため、WinForms のデザイン時体験では、Visual Studio 側が 32bit コンポーネントを直接ロードできません。Microsoft も、Visual Studio 2022 は 64bit プロセスなので、32bit の .NET / COM / ActiveX コンポーネントをロードできないと明記しています。2

つまり、昔こうだったものが、

  • プロジェクトは x86
  • 参照先の ActiveX も x86
  • Visual Studio 自体も 32bit

という前提でなんとなく成立していたのに、VS2022 では

  • 実行時のアプリは x86 で動ける
  • でも Designer は 64bit の Visual Studio 側で動く

というねじれが起きます。 この結果、実行時は生きているのに Designer だけ落ちる という、かなり嫌な状態になります。2

3.2. AnyCPU にしたら解決する、とは限らない

これもよくある誤解です。

AnyCPU は、依存先まで中立になる魔法ではありません。 Microsoft の説明でも、AnyCPU に見えるコンポーネントでも、その先で 32bit 固定の COM / ActiveX を参照していれば、Visual Studio 2022 のデザイン時には問題になります。2

なので、AnyCPU にしてエラーが消えないときは、

  • そのアセンブリの先に 32bit ネイティブ依存がないか
  • ActiveX / OCX が x86 固定ではないか
  • Designer 時だけ読み込まれるコードがないか

を疑ったほうが早いです。

3.3. System32SysWOW64 の罠

Windows x64 では、名前の印象と実態がずれているので混乱しがちです。

Microsoft Learn では、x64 Windows 上の %windir%\System3264bit アプリケーション用 と説明されています。32bit 側は WOW64 のファイルシステムリダイレクタによって別の場所へ誘導されます。12 レジストリも同様で、WOW64 のレジストリリダイレクタが 32bit / 64bit に 別の論理 view を見せます。11

このため、手元で切り分けるときは、どのビット数の regsvr32 を使っているか を明示したほうが安全です。

# 64bit DLL / OCX を登録したい場合
C:\Windows\System32\regsvr32.exe vendor.ocx

# x64 Windows 上で 32bit DLL / OCX を登録したい場合
C:\Windows\SysWOW64\regsvr32.exe vendor.ocx

この罠の嫌なところは、間違った側に登録すると、登録したつもりなのに目的のプロセスから見えない ことです。 結果として、

  • regsvr32 は成功した
  • でもアプリからは 0x80040154
  • レジストリを見ると、あるように見える
  • でも見ているのは別 view

という状態になります。1113

3.4. regsvr32 で何でも登録できるわけではない

ここも誤解の多いところです。

ネイティブの in-proc COM サーバーは、通常 DllRegisterServer / DllUnregisterServer をエクスポートして自己登録をサポートします。3 regsvr32 は、そういう DLL / OCX に対して使う道具です。4

一方で、.NET Framework のアセンブリを COM から使いたい場合は、基本は Regasm.exe です。Microsoft Learn でも、COM で使用するアセンブリの登録には Regasm.exe を使う と説明されています。514

さらに、.NET 5+ / .NET 6+ / .NET 8+ の COM 公開では少し事情が変わり、<EnableComHosting>true</EnableComHosting> を設定してビルドすると *.comhost.dll が生成され、それを regsvr32 で登録します。6

つまり、ざっくり分けるとこうです。

公開したいもの 代表的な登録手段
ネイティブ C++ の DLL / OCX regsvr32
.NET Framework アセンブリを COM 公開 Regasm.exe
.NET 5+ / 6+ / 8+ の COM 公開 生成された .comhost.dllregsvr32

この違いを混ぜると、よくあるのが、

  • マネージド DLL に regsvr32 をかける
  • 当然 DllRegisterServer が見つからない
  • そこで「DLL が壊れている」と誤解する

というパターンです。

タイプライブラリが必要な世界(VBA / VB6 / 一部の早期バインディング相手)では、さらに TLB の生成と登録 も別問題になります。 .NET Framework では Regasm.exe /tlb でタイプライブラリを生成・登録できますし、Microsoft も「型の登録」と「タイプライブラリの登録」は別活動だと説明しています。15

4. 管理者権限でハマる

4.1. post-build で登録していて、管理者でしか成功しない

Visual Studio の C++ ビルドでは、build event や custom build step で regsvr32.exe を呼ぶこと自体は普通にできます。Microsoft Learn でも、post-build event の例として regsvr32.exe による登録が挙がっています。16

ただし、できること安全なこと は別です。

標準ユーザーで regsvr32 を実行すると、レジストリや System32 へ書き込めず 0x80070005 になることがあります。Microsoft の KB でも、その原因は 管理者権限がないこと だと整理されています。10

ここで起きがちなのは、

  • Visual Studio を通常権限で起動すると build は通る
  • でも post-build の登録だけ失敗する
  • 失敗ログを見逃す
  • 直前の古い登録が残っているので、手元ではたまたま動く
  • クリーン環境では当然動かない

という事故です。

この手のプロジェクトでは、ビルドと登録を分ける のが基本です。

  • ビルドはバイナリを作るだけ
  • 登録は明示的な install step / script / installer で行う
  • CI では「登録を要する step」を build と別ジョブにする

この分離だけで、かなり事故が減ります。

4.2. per-user 登録と per-machine 登録を混ぜると壊れる

COM は HKCR を見ている、という覚え方だけだと、ここで詰まります。

実際には Microsoft Learn にある通り、COM は HKEY_CURRENT_USER\Software\Classes を先に見て、その後にコンピューター全体の情報を扱います。3 また、HKEY_CLASSES_ROOTHKLM\Software\ClassesHKCU\Software\Classes の merged view です。717

つまり、

  • 開発者 A のユーザーで手動登録した
  • A のアカウントでは動く
  • 開発者 B では動かない
  • サービスアカウントでも動かない
  • 管理者で動かすと挙動が変わる

ということが普通に起きます。

さらに Microsoft は、管理者権限を必要とするアプリケーションは、依存 COM オブジェクトをインストール時に per-machine の COM 構成ストアへ登録するべき としています。87

なので、開発現場ではこの区別をはっきりさせておくべきです。

  • 自分のユーザーだけで使う開発用登録 なのか
  • そのマシンの全ユーザーで使う本番登録 なのか
  • サービスや昇格アプリが参照する登録 なのか

これを曖昧にすると、「なぜか管理者でだけ動く」「Explorer 拡張では動くのにサービスでは動かない」みたいな話になります。

4.3. Visual Studio を常時「管理者として実行」にするのは解決ではない

必要な場面があるのは事実です。 ただ、Visual Studio を常時管理者で起動しておくと、本来インストーラーや登録スクリプトで解決すべき問題を IDE 側の昇格で隠してしまう ことがあります。

しかも Visual Studio 自体も、昇格時には per-user extension の扱いが変わります。Microsoft Learn でも、Visual Studio を elevated で動かすと per-user extensions が無効化される 設定があることが説明されています。18

なので運用としては、

  • 普段の開発は通常権限
  • 登録が必要な step だけ、明示的に昇格した Developer Command Prompt / PowerShell / installer で行う
  • 「管理者でしか再現しない」なら、その前提自体を仕様として整理する

のほうが、後で困りません。

5. ActiveX / OCX 固有でハマること

5.1. デザイン時ライセンスと実行時ライセンスが別

OCX / ActiveX で地味に厄介なのが、ライセンス です。

特に古い ActiveX コントロールでは、design-time licenserun-time license が分かれていることがあります。MFC の ActiveX ドキュメントでも、ライセンスファイルやライセンスキーによって design-time / run-time を分ける仕組みが説明されています。1920

この世界では、

  • 実行時には使える
  • でもフォームに貼ろうとすると「ライセンスがない」
  • 開発機 A では貼れる
  • 開発機 B では貼れない

ということが起きます。

「このコンポーネントはライセンスが見つからない」「適切なライセンスがない」というエラーは、昔の ActiveX では珍しくありません。21

5.2. WinForms に載せた時点で、すでにラッパーが入っている

WinForms で ActiveX を使うとき、Windows Forms は ActiveX をそのままホストしているわけではありません。 Microsoft Learn の Aximp.exe ドキュメントにある通り、ActiveX Control Importer は COM タイプライブラリから WinForms 用のラッパーを生成 し、それを AxHost ベースのコントロールとして扱います。2223

つまり、問題は 1 層ではなく、

  1. 元の OCX / ActiveX 本体
  2. タイプライブラリ
  3. 生成された interop / wrapper
  4. WinForms Designer / runtime

の複数層に分かれます。

そのため、

  • ベンダー OCX を入れ替えたらイベントシグネチャが変わった
  • 参照の貼り直しで wrapper が再生成され、差分が大量に出た
  • 開発機ごとに interop の生成結果が微妙に違う

といったことが起きます。

Choose Toolbox Items で表示されたから安心、ではありません。 Designer が載せられるか、実行時にイベントが来るか、配布先で wrapper ごと成立するか は別々に見たほうが安全です。

5.3. STA / MTA とメッセージループを甘く見ると固まる

COM は、使うスレッドごとに CoInitializeEx で初期化する必要があります。Microsoft Learn でも、COM を使う各スレッドは個別に CoInitializeEx を呼ぶ 必要があると明記されています。24

また、STA(single-threaded apartment)では メッセージループが必要 です。2425

特に UI 系の OCX / ActiveX は STA 前提が多いので、

  • UI スレッドでは動く
  • Task.Run や ThreadPool へ投げたら固まる
  • イベントが返ってこない
  • たまにだけ再現する

という、嫌な不具合になります。

さらに STA では、インターフェイス ポインターをそのまま別スレッドへコピーしてはいけない、必要ならマーシャリングする、という前提もあります。2425

この手の不具合は、0x80040154 ほど親切ではなく、固まる・返ってこない・たまに落ちる としか見えないので、レジストリ系トラブルと同じくらい時間を食います。

6. 現場で効く切り分け順

実務では、最初から深追いするより、この順で切ると速いです。

6.1. まず「どのプロセスが何bitか」を固定する

最初に見るのはここです。

  • ホストは何か(Visual Studio Designer / 自前アプリ / Office / Access / Explorer / ブラウザ互換環境)
  • そのホストは 32bit か 64bit か
  • 対象の DLL / OCX は 32bit か 64bit か
  • それは in-proc か out-of-proc か

ここが曖昧なままレジストリを見始めると、だいたい迷子になります。

6.2. 次に「登録の種類」を確認する

次に見るべきは、何を何で登録するのが正しいのか です。

  • ネイティブ DLL / OCX → regsvr32
  • .NET Framework COM 公開 → Regasm.exe
  • .NET 5+ / 6+ / 8+ COM 公開 → .comhost.dll
  • そもそも self-registration を持たない DLL → regsvr32 ではない

この分類だけで、かなりの誤爆を止められます。

6.3. そのあとで「どこに登録されたか」を見る

見る場所は、単なる HKCR では足りません。

  • HKCU\Software\Classes
  • HKLM\Software\Classes
  • 必要なら 32bit / 64bit の registry view
  • 対象の ProgID / CLSID / TypeLib
  • InprocServer32 / LocalServer32
  • ThreadingModel
  • 参照先 DLL の実体パス

HKCR にはある だけでは不十分で、誰から、どの bitness で、どの view を見ているか まで揃えて初めて意味があります。711

6.4. 最後に「権限で隠れていないか」を見る

最後に、問題が本当に権限なのか、それとも 権限によって別の登録が見えているだけか を確認します。

  • 標準ユーザー / 管理者で挙動は変わるか
  • Visual Studio を昇格すると何が変わるか
  • サービスアカウントや別ユーザーでも再現するか
  • インストーラーを通したクリーン環境でも成立するか

開発機 1 台でしか見ていないと、ここは本当に見誤ります。

7. 先に決めておくと事故が減る運用

COM / ActiveX / OCX の開発や保守では、実装テクニックより 運用の決め方 のほうが効くことがあります。

7.1. 先に bitness 方針を決める

最初に、これを決めます。

  • x86 固定で行くのか
  • x64 を正とするのか
  • 両対応するのか
  • その部品は in-proc でなければならないのか

特にベンダー OCX が x86 固定なら、そこを無視してアプリだけ x64 化しても、あとで詰まります。 このテーマは、より大きい構成の話として 32bit アプリから 64bit DLL を呼び出す方法 - COM ブリッジが役立つケーススタディ も関連します。

7.2. 登録戦略を決める

登録も、場当たりでやらないほうがよいです。

  • マシン全体で使う → installer で per-machine 登録
  • そのユーザーだけで使う → per-user を意図的に使う
  • 自分のアプリだけで閉じる → registration-free COM を検討
  • 開発用にだけ必要 → 明示的な dev setup script に閉じ込める

registration-free COM は、レジストリではなく manifest でアクティブ化情報を持てるので、登録地獄を減らす 手段として有効です。Win32 側の registration-free COM も、.NET 側の RegFree COM も公式に説明があります。26627

7.3. 生成物を source control の外に置きすぎない

OCX / ActiveX 系でありがちなのが、依存物の散逸です。

  • OCX 本体
  • 依存 DLL
  • TLB
  • .lic
  • interop DLL
  • AxHost wrapper
  • 登録スクリプト
  • サンプルホスト

このへんが人のローカルだけにあると、数か月後に確実に事故ります。

最低でも、

  • どのバージョンを前提にしているか
  • 何をどの順序で入れるか
  • どのコマンドで登録するか
  • x86 / x64 のどちら向けか

は、コードと同じ場所に残したほうが安全です。

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

このテーマは、いきなり全面改修に入る前の 切り分け方針整理 だけでも価値が出やすいです。

たとえば、以下のような相談とは特に相性がよいです。

  • 0x800401540x80070005 の原因を、bitness / 登録 / 権限に分けて整理したい
  • Visual Studio 2022 に上げたら Designer が壊れたので、どこまで救えるか見たい
  • ベンダー OCX を残したまま、周辺を .NET や C# に寄せたい
  • x86 固定資産をどこまで延命し、どこから bridge / wrap / replace するか決めたい
  • 手作業の regsvr32 依存をやめて、install / deploy を再設計したい

置き換える・包む・残す、の判断については ActiveX / OCX を今どう扱うか - 残す・包む・置き換える判断表 も参考になるはずです。

9. まとめ

COM コンポーネントや OCX / ActiveX 開発でハマるとき、原因はだいたいこの 4 つに行き着きます。

  1. bitness が噛み合っていない
  2. 登録方法が間違っている
  3. 登録スコープ(HKCU / HKLM、32bit / 64bit view)がズレている
  4. 権限でたまたま見えているだけの状態を、正常だと思っている

Visual Studio 2022 の 64bit 化で、昔の「なんとなく動いていた」設計は、かなり表面化しやすくなりました。12 だからこそ、COM / OCX / ActiveX を触るときは、まず コードを書く前に環境の前提を揃える のが近道です。

regsvr32 を何回叩くかより、

  • どのプロセスがホストしているか
  • そのプロセスは何bitか
  • どこに登録するべきか
  • その登録は本当に管理者前提なのか
  • Designer と runtime を分けて見ているか

を整理したほうが、はるかに速く解けます。


参考

  1. Microsoft Learn, Visual Studio 2022 version 17.0 Release Notesdevenv.exe is now 64-bit only 2 3

  2. Microsoft Learn, Troubleshoot 32-bit problems - Windows Forms — Visual Studio 2022 は 64bit プロセスであり、32bit の .NET / COM / ActiveX を直接ロードできないこと、out-of-process designer の制約。  2 3 4 5

  3. Microsoft Learn, Classes and Servers — COM の登録、HKCU / HKCR、self-registration と DllRegisterServer。  2 3 4

  4. Microsoft Learn, regsvr32regsvr32 の構文と役割。  2

  5. Microsoft Learn, COM へのアセンブリの登録 — .NET Framework の COM 登録は Regasm.exe。  2

  6. Microsoft Learn, COM への .NET Core コンポーネントの公開EnableComHosting、生成される .comhost.dllregsvr32EnableRegFreeCom。  2 3

  7. Microsoft Learn, Merged View of HKEY_CLASSES_ROOT — HKCR は HKLM と HKCU の merged view。  2 3 4 5

  8. Microsoft Learn, HKEY_CLASSES_ROOT Key — 管理者権限を必要とするアプリは per-machine COM 構成への登録を推奨。  2

  9. Microsoft Learn, COM Error Codes (Generic) (Winerror.h)REGDB_E_CLASSNOTREG (0x80040154) など。 

  10. Microsoft Learn, You receive 0x80070005 error when you try to register a DLL by using Regsvr32.exe — 権限不足で DLL 登録に失敗する典型例。  2

  11. Microsoft Learn, Registry Redirector — WOW64 における 32bit / 64bit レジストリ view。  2 3 4

  12. Microsoft Learn, File System Redirector — x64 Windows の %windir%\System32 と WOW64 のファイルシステムリダイレクト。 

  13. Microsoft Learn, 64 ビット バージョンの Windows での 32 ビット プログラムの互換性に関する考慮事項の概要 — WOW64 によるファイル / レジストリ リダイレクト。 

  14. Microsoft Learn, Regasm.exe (Assembly Registration Tool)Regasm.exe の役割と /tlb などのオプション。 

  15. Microsoft Learn, Packaging a .NET Framework Assembly for COM — タイプライブラリと Regasm.exe /tlb。 

  16. Microsoft Learn, Understanding Custom Build Steps and Build Events — post-build event で regsvr32.exe を使う例。 

  17. Microsoft Learn, 上級ユーザー向けの Windows レジストリHKCU\Software\ClassesHKLM\Software\Classes、HKCR の挙動。 

  18. Microsoft Learn, Find, install, and manage extensions for Visual Studio — elevated 実行時の per-user extension の扱い。 

  19. Microsoft Learn, MFC ActiveX Controls: Licensing an ActiveX Control — design-time / run-time license、.LIC。 

  20. Microsoft Learn, Application Settings, MFC ActiveX Control Wizard — ランタイムライセンス生成と .lic ファイル。 

  21. Microsoft Learn, License information for this component not found. You don’t have an appropriate license to use this functionality in the design environment. 

  22. Microsoft Learn, Aximp.exe (Windows Forms ActiveX Control Importer) — ActiveX を WinForms 用ラッパーへ変換。 

  23. Microsoft Learn, AxHost Class — ActiveX Control Importer が生成する AxHost ベースのラッパー。 

  24. Microsoft Learn, COM ライブラリの初期化CoInitializeEx、各スレッドごとの初期化、STA のメッセージループ。  2 3

  25. Microsoft Learn, Single-Threaded アパートメント — STA のメッセージループ、マーシャリング、ThreadingModel。  2

  26. Microsoft Learn, Registration-Free COM オブジェクトの作成 — activation context による登録不要 COM。 

  27. Microsoft Learn, 登録を必要としない COM 相互運用機能 — .NET Framework の registration-free COM interop。 

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

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

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

著者プロフィール

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

小村 豪

合同会社小村ソフト 代表

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

ブログ一覧に戻る