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

· 更新日: · · COM, ActiveX, OCX, Visual Studio, Windows開発, 32bit, 64bit, Interop

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

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

64bitプロセスから32bitのin-proc COMを使うためのDllSurrogateの説明を追加しました。regsvr32が成功しても64bitプロセスは32bitのInprocServer32を読めないこと、CLSIDにAppIDを付けてAppIDキーへ空文字のDllSurrogateを書けば新しいEXEを書かずにdllhost.exeへ載せられること、立つdllhost.exeのbitnessはクライアントではなくDLL側で決まること、LocalServer32があればEXEの起動が優先されること、そして確認手順をまとめています。サロゲートはbitnessの差を消すのではなく同一プロセス制約だけを外すもので、呼び出しはout-of-procになりマーシャリングとIPCのコストが乗る点も明記しました。
記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
登録先のレジストリキーを4通りすべて示し、総当たりで探すスクリプトと結果の読み取り方を追加しました。あわせてSTA/MTAとマーシャリングの用語定義、メッセージループがないと固まる仕組みの図、Regasmとマニフェストのコード例を追加しています。
本文中の関連記事へのリンクの文言が、リンク先の現在のタイトルと食い違っていたのを、実際のタイトルに揃えました。本文の内容は変えていません。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589787)

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

小村 豪(2026)「COM/OCX/ActiveX開発でハマる登録とbitnessの罠」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589787 https://comcomponent.com/blog/2026/04/15/001-com-ocx-activex-pitfalls-visual-studio-bitness-admin-rights/

DOI(最新版)
10.5281/zenodo.21589787
DOI(この版)
10.5281/zenodo.22170297

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)
  • その操作や実行に管理者権限が要るのか

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

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 また、regsvr32 の 0x80070005 は、公式にも 管理者権限がなくレジストリや System32 に書けない ケースとして説明されています。10

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

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

3.1 Visual Studio 2022 は 64bit になった

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

Visual Studio 2022 は devenv.exe が 64bit 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 だけ落ちる という、原因の見えにくい状態になります。実行時のホストはアプリのプロセス、デザイン時のホストは Visual Studio のプロセスであり、ホストが別物なので bitness も別 だからです。2

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

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

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

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

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

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

3.3 System32 と SysWOW64 の罠

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

Microsoft Learn では、x64 Windows 上の %windir%\System32 は 64bit アプリケーション用 と説明されています。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 で登録したときが厄介です。登録自体は成功するのに、目的のプロセスからは見えません。 結果として、

  • 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.dll を regsvr32

Regasm.exe は Developer Command Prompt / Developer PowerShell から実行します。よく使うのは次の 3 通りです。14

:: 1) アセンブリ内の公開クラスを登録する
regasm myTest.dll

:: 2) タイプライブラリも生成して登録する (VBA / VB6 など、TLB が要る相手向け)
regasm myTest.dll /tlb:myTest.tlb

:: 3) レジストリを直接変更せず、内容を .reg ファイルへ書き出して確認する
regasm myTest.dll /regfile:myTest.reg

解除は /unregister です。/tlb で登録したタイプライブラリは、/tlb と /unregister を 一緒に指定 して解除します。

regasm myTest.dll /tlb:myTest.tlb /unregister

ここで踏みやすい制約が 2 つあります。14

  • GAC に入れないアセンブリは /codebase が要ります。 /codebase は登録時のファイルパスをレジストリに記録するため、あとでアセンブリを移動すると起動に失敗します。また Microsoft は、/codebase を付けるアセンブリは 厳密名 (strong name) 付きにすることを強く推奨 しています。
  • /regfile は /unregister や /tlb と併用できません。 また /regfile が書き出すのはマネージドクラスのエントリだけで、TypeLibID と InterfaceID は出力されません。「.reg を配れば登録が済む」と考えると足りなくなります。

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

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

というパターンです。

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

3.5 64bit プロセスから 32bit in-proc を出したいとき ── DllSurrogate

3.3 と 3.4 は「登録の場所と手段が合っているか」の話でした。 ここでは、登録は正しいのに bitness が合わない ときの出口を 1 つ足しておきます。

先に結論です。

  • regsvr32 が成功していても、64bit プロセスは 32bit の InprocServer32 を読み込めません。登録の不備ではなく、in-proc の前提そのものです。
  • 新しい EXE を書かずにその DLL を 64bit 側から使いたいなら、CLSID に AppID を付け、その AppID キーへ空文字の DllSurrogate を書く のが最小の手当てです。16
  • そのとき立つのは、クライアント側ではなく InprocServer32 が指す DLL 側の bitness の dllhost.exe です。

なぜ in-proc のままでは無理なのか

2 章の症状表に挙げた「64bit アプリから 32bit OCX を呼べない」は、0x80040154 と同じ顔をしていても中身が違います。

InprocServer32 は文字どおり「呼び出し側のプロセスの中で動くサーバー」の指定です。64bit プロセスがそこに書かれた 32bit DLL をロードすることは、レジストリをどう直しても起きません。3.3 でレジストリの view が分かれているのも、元をたどればこの制約が理由です。

なので、ここから先は「登録を直す」ではなく 「別プロセスへ出す」 話になります。

サロゲートがやること

DllSurrogate は、in-proc の DLL サーバーを サロゲートプロセスに載せて Local Server として出す ための指定です。17 値を空文字にすると、Windows に付いてくる既定のサロゲート(dllhost.exe)が使われます。18

32bit の DLL なら 32bit のサロゲートが起動し、DLL はその中で 今までどおり in-proc に 読み込まれます。64bit のクライアントは、そのプロセスの外からプロキシ経由でオブジェクトを触ります。

ここは誤解されやすいので、はっきり書いておきます。 サロゲートは bitness の差を消しません。 消えるのは「同じプロセスに載せなければならない」という制約だけです。呼び出しは out-of-proc になり、マーシャリングとプロセス間通信のコストが乗ります。前提として、やり取りする型がマーシャリングできる こと(IDispatch、登録済みの proxy / stub、標準マーシャラーが扱える型のいずれか)も要ります。

もう 1 つ。サロゲートで扱いやすいのは、メソッド呼び出しとイベントで完結する自動化オブジェクトです。フォームに貼り付けて描画させるビジュアルな OCX は、ウィンドウをホストのプロセス内に持つ前提なので、この手当てだけでは片付きません。

アクティブ化がin-procとサロゲートのどちらに落ちるかin-procを含むCLSCTXで要求したとき、クライアントと同じviewのCLSIDにInprocServer32があればまずin-procで読み込まれ、無ければEXEサーバの登録があるときにサロゲートより先にそちらが起動し、EXE登録が無く空のDllSurrogateがあればDLL側のbitnessのdllhostが起動し、どれも無ければアクティブ化できないことを示す図。あるないあるないあるないクライアントがアクティブ化を要求in-procを含むCLSCTXで要求同じviewのCLSIDにInprocServer32があるか今までどおりin-procで読み込むEXEサーバの登録があるかサロゲートより先にEXEが起動空のDllSurrogateがあるかDLL側のbitnessのdllhostが起動アクティブ化できず 0x80040154

図1: 同じbitnessのInprocServer32が見えるかで最初に分かれ、見えないときだけEXEサーバ、次に空のDllSurrogateの順に落ちる。

登録の最小セット

Microsoft Learn は、DLL サーバーがサロゲートに載る条件を次のように挙げています。16

  1. CLSID キーに AppID の値があり、対応する AppID キーが存在する
  2. アクティブ化の呼び出しで CLSCTX_LOCAL_SERVER が立っていて、CLSID キーに LocalServer32 / LocalServer / LocalService が 無い
  3. CLSID キーに InprocServer32 がある
  4. InprocServer32 が指す DLL が実在する
  5. AppID キーの下に DllSurrogate の値がある

その DLL を 1 つのサロゲートで単独に動かすなら、AppID を CLSID と同じ GUID にする のが Microsoft の勧める書き方です。16

登録は 3 行で足ります。下は 32bit の COM DLL を 64bit ホストから使う場合で、GUID はプレースホルダです。先に SysWOW64 側の regsvr32 で InprocServer32 が入っている ことが前提です(3.3 参照)。

:: 管理者権限のコマンドプロンプトで実行する
set CLSID={11111111-2222-3333-4444-555555555555}
set APPID={11111111-2222-3333-4444-555555555555}

:: 1) CLSID に AppID を付ける。CLSID 配下は 32/64 で別なので view を明示する
::    64bit の COM DLL を 32bit ホストから使う逆向きなら、ここを /reg:64 に読み替える
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%" /v AppID /t REG_SZ /d "%APPID%" /f /reg:32

:: 2) 対応する AppID キーを作る。Classes\AppID は 32/64 で共有なので view の指定は要らない
reg add "HKLM\SOFTWARE\Classes\AppID\%APPID%" /f

:: 3) DllSurrogate を空の REG_SZ にする。/d を省くと空文字で作られる
reg add "HKLM\SOFTWARE\Classes\AppID\%APPID%" /v DllSurrogate /t REG_SZ /f

なぜ空文字にするのか

DllSurrogate は REG_SZ で、値そのものがサロゲートのパス です。空文字(または NULL)にすると システム既定のサロゲート が使われ、パスを書くとそのパスのカスタムサロゲートを起動しようとします。1718

つまり、親切のつもりで dllhost.exe のパスを書き込むと逆効果で、空にすること自体が「既定のものを使え」という指定 です。

なお HKLM\SOFTWARE\Classes\AppID は、Windows 7 / Windows Server 2008 R2 以降は 32bit / 64bit で 共有 されるキーで、view の区別がありません。19 一方 CLSID の配下は view が分かれるので、32bit のサーバーなら AppID 値は 32bit view の CLSID 側に付ける 必要があります。効かないときは、この 2 か所を必ずセットで確認してください。

ここは 3.3 や 6.3 の「32bit 側にしか登録されていなければ 64bit プロセスからは 0x80040154」と食い違って見えますが、あちらは in-proc の話 です。out-of-proc のアクティブ化では、クライアントとサーバーのどちらも bitness の希望を出していないとき、COM はクライアントに合う bitness のサーバーを探し、無ければもう一方の bitness のサーバーを起動します。20 だからこの手順は、CLSID 側を 32bit view に置いたままで成立します。InprocServer32 を 64bit view へコピーする必要はありません。

立つ dllhost.exe の bitness

ここが一番よく誤解されます。 サロゲートの bitness は クライアント側ではなく、InprocServer32 が指す DLL 側 で決まります。DLL はサロゲートの中で in-proc に読まれるのだから、当然そうなります。

中で読まれる COM DLL 起動する dllhost.exe
32bit %SystemRoot%\SysWOW64\dllhost.exe
64bit %SystemRoot%\System32\dllhost.exe

タスクマネージャーやプロセス エクスプローラーでコマンドラインを見ると、dllhost.exe /Processid:{...} の形で立っています。ここの GUID は CLSID ではなく AppID です。CLSID のつもりで探すと見つからないので、注意してください。

LocalServer32 があると EXE が勝つ

Microsoft Learn は、LocalServer / LocalServer32 / LocalService があるとき、サロゲートに DLL を載せるより EXE サーバーやサービスの起動が常に優先される と明記しています。16

つまりサロゲートは「EXE サーバーが無いときの出口」です。すでに EXE サーバーが登録されている CLSID に DllSurrogate を足しても、そちらは使われません。ここで優先されるのは、あくまで サロゲートに対して であって、in-proc に対してではありません。

既存の呼び出し元への影響も押さえておくと安心です。 DllSurrogate を足しても、in-proc を含む CLSCTX で作っているクライアントは、bitness が合っている限り今までどおり in-proc のまま です。CLSCTX は複数を OR で渡すと 列挙順(in-proc → local → remote)に試され、in-proc の段では InprocServer32 キーが あればそれが使われる からです。20 CLSCTX_ALL や CLSCTX_SERVER のように in-proc と local の両方を渡している呼び出しが、これに当たります。逆に CLSCTX_INPROC_SERVER だけで呼んでいる箇所は、DllSurrogate を足してもサロゲートには回りません。

そして 64bit のクライアントから見ると、32bit view に入れた InprocServer32 は 64bit view には存在しません。in-proc の段は「該当キー無し」で素通りするので、そのまま local 側(サロゲート)のアクティブ化へ進みます。bitness の違う DLL をロードしようとして失敗しているのではありません。2019

確認方法

入ったかどうかは、view を明示して読み返すのが確実です。

reg query "HKLM\SOFTWARE\Classes\CLSID\{11111111-2222-3333-4444-555555555555}\InprocServer32" /ve /reg:32
reg query "HKLM\SOFTWARE\Classes\CLSID\{11111111-2222-3333-4444-555555555555}" /v AppID /reg:32
reg query "HKLM\SOFTWARE\Classes\AppID\{11111111-2222-3333-4444-555555555555}" /v DllSurrogate

1 行目を省かないでください。reg add は指定したキーが無ければ作るので、GUID を打ち間違えたり別の view に登録していたりすると、AppID 値だけが載った空の CLSID キーができて 2 行目は通ってしまいます。InprocServer32 が同じ view にあることまで見て、はじめて確認したことになります。

DllSurrogate は 値が空のまま 出れば正解です。あとは 64bit のクライアントからオブジェクトを作り、SysWOW64 側の dllhost.exe が立つかを見ます。

  • 0x80040154 のまま → AppID 値が 32bit view の CLSID 側に付いているか、InprocServer32 が指す DLL が実在するかを見直します
  • dllhost.exe は立つのに呼び出しで落ちる → マーシャリングの前提(IDispatch / proxy-stub / 標準マーシャラー)を確認します
  • 別の EXE が立つ → その CLSID に LocalServer32 などが残っています

ここまでが「登録」の話

サロゲートで足りるのか、それとも 32bit 側に自前のヘルパー EXE を書くべきなのかは、登録ではなく 構成の選び方 です。 そちらは ActiveX / OCX を今どう扱うか - 残す・包む・置き換える判断表 の 5.2「32bit OCX を 64bit 側へ持っていきたい」で整理しています。

4. 管理者権限でハマる

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

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

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

標準ユーザーで 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_ROOT は HKLM\Software\Classes と HKCU\Software\Classes の merged view です。722

つまり、

  • 開発者 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 が無効化される 設定があることが説明されています。23

なので運用としては、

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

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

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

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

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

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

この世界では、

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

ということが起きます。

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

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

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

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

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

の複数層に分かれます。

そのため、

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

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

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

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

先に、用語を 3 つだけ定義します。

用語 意味
アパートメント (apartment) COM オブジェクトとスレッドを、同じ同時実行ルールでまとめた論理的なグループです。1 つのオブジェクトは 1 つのアパートメントにしか属せません
STA (single-threaded apartment) 1 スレッドだけが属するアパートメントです。そのオブジェクトへの呼び出しは、必ずその 1 スレッド上で実行されます
マーシャリング (marshaling) アパートメントをまたいでインターフェイスポインターを渡すときに、COM が呼び出しを橋渡しする仕組みです。プロキシとスタブを経由します

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

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

なぜメッセージループがないと固まるのか

ここは結論だけ覚えると応用が効かないので、仕組みを 1 段だけ開けておきます。

COM は STA ごとに、OleMainThreadWndClass というウィンドウクラスの 隠しウィンドウ を 1 つ作ります。別のアパートメントからそのオブジェクトを呼ぶと、呼び出しは直接の関数呼び出しにはならず、この隠しウィンドウ宛てのウィンドウメッセージ として届きます。STA のスレッドがメッセージを取り出してディスパッチすると、そのウィンドウプロシージャが対応するインターフェイスのメソッドを呼びます。30

つまり、メッセージループは「あったほうがよい作法」ではなく、呼び出しを配達する仕組みそのもの です。

OCX / ActiveXSTA スレッド隠しウィンドウのメッセージキュー別スレッドの呼び出し側OCX / ActiveXSTA スレッド隠しウィンドウのメッセージキュー別スレッドの呼び出し側メッセージループが止まっているとこの取り出しが起きず 呼び出し側は待ち続けるメソッド呼び出しがメッセージとして積まれるメッセージループが取り出すウィンドウプロシージャが対応するメソッドを呼ぶ戻り値が返る

図2: 別スレッドからの呼び出しは隠しウィンドウのメッセージとして届き、メッセージループが取り出して初めてオブジェクトに渡る。

だから、STA スレッドをブロックすると固まります。UI スレッドで Task.Wait() や Task.Result を使う、WaitOne で待つ、といった書き方はメッセージの取り出しを止めるため、COM のコールバックとアパートメント間の呼び出しが配達されなくなり、デッドロックになります。30

同じ理由で、STA のオブジェクトのインターフェイスポインターを別スレッドへそのままコピーしてはいけません。コピーすると、本来 STA スレッドへ配達されるべき呼び出しが別スレッドで直接実行され、オブジェクト側が想定していない同時実行が起きます。アパートメントをまたぐときは CoMarshalInterThreadInterfaceInStream と CoGetInterfaceAndReleaseStream でマーシャリングします。30

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

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

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

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

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

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

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

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

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

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

この 4 点が確定していないままレジストリを見始めると、どの view を見ればよいか決まらないため、調査が空回りします。まずここを固定してください。

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

見るべきキーのパス

HKEY_CLASSES_ROOT\CLSID\{...} を開くと、いま自分が実行しているツールの bitness とユーザーで見えるものだけが表示されます。切り分けでは、マージ前の実体を 4 か所に分けて見ます。CLSID の配下は WOW64 のリダイレクト対象で、32bit 側の物理的な置き場所は Classes の下の Wow6432Node です。19

見たいもの レジストリのパス
マシン全体 / 64bit view HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{CLSID}
マシン全体 / 32bit view HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Wow6432Node\CLSID\{CLSID}
そのユーザーだけ / 64bit view HKEY_CURRENT_USER\SOFTWARE\Classes\CLSID\{CLSID}
そのユーザーだけ / 32bit view HKEY_CURRENT_USER\SOFTWARE\Classes\Wow6432Node\CLSID\{CLSID}
ProgID から CLSID を引く HKEY_CLASSES_ROOT\{ProgID}\CLSID の既定値

Windows 10 / 11 の regedit.exe は 64bit プロセスなので、上のパスを そのまま入力すれば 両方の view を直接開けます。アドレスバーにパスを貼り付ければ、その位置へ移動できます。

なお、Wow6432Node を含むパスは物理的な置き場所であり、Microsoft はアプリケーションのコードから直接触らないよう案内しています。手作業の調査で見る分には問題ありませんが、スクリプトやアプリからは後述の view 指定を使うほうが安全です。11

コマンドで確認する

reg.exe なら /reg:32 と /reg:64 で view を明示できます。

reg query "HKLM\SOFTWARE\Classes\CLSID\{00000000-0000-0000-0000-000000000000}\InprocServer32" /reg:32
reg query "HKLM\SOFTWARE\Classes\CLSID\{00000000-0000-0000-0000-000000000000}\InprocServer32" /reg:64

PowerShell で 4 か所を一度に見るなら、RegistryKey.OpenBaseKey に view を渡します。PowerShell 自体の bitness に結果が引きずられないので、切り分けではこちらが確実です。

# 調べたい ProgID を 1 か所で指定する
$progId = 'Vendor.Control.1'

# 1) ProgID から CLSID を引く (HKCR は HKLM と HKCU のマージ view)
$clsid = (Get-ItemProperty -Path "Registry::HKEY_CLASSES_ROOT\$progId\CLSID" -Name '(default)' -ErrorAction Stop).'(default)'
"ProgID $progId -> CLSID $clsid"

# 2) ハイブ 2 種 x view 2 種の計 4 か所を総当たりで確認する
foreach ($hive in [Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryHive]::CurrentUser) {
    foreach ($view in [Microsoft.Win32.RegistryView]::Registry64, [Microsoft.Win32.RegistryView]::Registry32) {
        $base = [Microsoft.Win32.RegistryKey]::OpenBaseKey($hive, $view)
        $key  = $base.OpenSubKey("SOFTWARE\Classes\CLSID\$clsid\InprocServer32")
        if ($null -eq $key) {
            '{0,-12} {1,-11} : 登録なし' -f $hive, $view
        }
        else {
            '{0,-12} {1,-11} : {2} (ThreadingModel={3})' -f $hive, $view, $key.GetValue(''), $key.GetValue('ThreadingModel')
            $key.Dispose()
        }
        $base.Dispose()
    }
}

この 4 行の結果が、そのまま切り分けの答えになります。

  • 4 か所すべて「登録なし」 → 本当に未登録。登録手段が 6.2 の分類と合っているかを見直します。
  • Registry32 にだけ出る → 32bit 側にしか登録されていません。64bit プロセスからは 0x80040154 になります。
  • CurrentUser にだけ出る → そのユーザーにしか見えません。別ユーザー、サービスアカウント、昇格プロセスからは見えません。
  • パスは出るのに動かない → InprocServer32 の既定値が指すファイルが実在するか、そのファイルの bitness がホストと一致しているかを確認します。

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 も公式に説明があります。31632

仕組みとしては、COM が CoCreateInstance などを処理するとき、まずアクティブ化コンテキストを探し、そこに情報がなければレジストリを見る という順序になっています。マニフェストは、そのアクティブ化コンテキストの中身を宣言するファイルです。31

必要なマニフェストは 2 つで、どちらも exe と同じフォルダーに置きます。

1 つ目は、コンポーネント側の アセンブリマニフェスト (VendorCtl.manifest) です。どのファイルがどの CLSID を提供するかを書きます。33

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32"
                    name="MyCompany.VendorCtl"
                    version="1.0.0.0"
                    processorArchitecture="x86" />
  <file name="vendor.ocx">
    <comClass description="Vendor Control"
              clsid="{00000000-0000-0000-0000-000000000000}"
              threadingModel="Apartment"
              progid="Vendor.Control.1" />
  </file>
</assembly>

2 つ目は、アプリ側の アプリケーションマニフェスト (MyApp.exe.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="MyCompany.MyApp"
                    version="1.0.0.0"
                    processorArchitecture="x86" />
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32"
                        name="MyCompany.VendorCtl"
                        version="1.0.0.0"
                        processorArchitecture="x86" />
    </dependentAssembly>
  </dependency>
</assembly>

書くときに間違えやすいのは次の点です。33

  • 依存側の assemblyIdentity は、コンポーネント側の assemblyIdentity と完全に一致していなければなりません。 name version processorArchitecture のどれか 1 つでもずれると解決されません。
  • アセンブリ名と DLL 名は別にします。 マニフェストを別ファイルで置く場合、アセンブリ名とマニフェスト名は DLL 名と違う名前にする必要があります。
  • 要素名と属性名は大文字小文字を区別します。 comClass を ComClass と書くと読まれません。
  • processorArchitecture は bitness そのものです。 x86 の OCX に対して amd64 のアプリからは解決できません。7.1 の bitness 方針と必ず揃えてください。
  • OCX を貼り込むなら miscStatus 系の属性が要ることがあります。 レジストリの MiscStatus キーに相当する情報を、マニフェスト側で miscStatus / miscStatusContent などとして書き写す必要があります。

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

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

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

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

最低でも、

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

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

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

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

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

  • 0x80040154 や 0x80070005 の原因を、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 Notes — devenv.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, regsvr32 — regsvr32 の構文と役割。 ↩ ↩2

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

  6. Microsoft Learn, COM への .NET Core コンポーネントの公開 — EnableComHosting、生成される .comhost.dll、regsvr32、EnableRegFreeCom。 ↩ ↩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、HKLM\Software の物理的な置き場所が Wow6432Node であること、アプリから物理パスを直接触らないこと。 ↩ ↩2 ↩3 ↩4 ↩5

  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 などのオプション。 ↩ ↩2 ↩3

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

  16. Microsoft Learn, Registering the DLL Server for Surrogate Activation — サロゲートに載る条件、LocalServer / LocalServer32 / LocalService があれば EXE サーバーやサービスの起動が優先されること、AppID を CLSID と同じ GUID にする構成。 ↩ ↩2 ↩3 ↩4

  17. Microsoft Learn, DllSurrogate — AppID 配下の DllSurrogate は REG_SZ で、空文字ならシステム既定のサロゲート、パスを書けばそのパスのカスタムサロゲートが使われること。 ↩ ↩2

  18. Microsoft Learn, Using the system-supplied surrogate — 空文字または NULL を指定するとシステム既定のサロゲートが起動されること、サロゲート内のスレッドモデルとプロセス寿命の扱い。 ↩ ↩2

  19. Microsoft Learn, Registry Keys Affected by WOW64 — HKLM\SOFTWARE\Classes\CLSID と HKCU\SOFTWARE\Classes\CLSID はリダイレクト対象であること、HKLM\SOFTWARE\Classes\AppID は Windows 7 / Windows Server 2008 R2 以降は共有 (shared) であること、HKCR が両者のマージ view であること。 ↩ ↩2 ↩3

  20. Microsoft Learn, CLSCTX enumeration — 複数の CLSCTX を OR で渡すと列挙順に試されること、in-proc の段では InprocServer32 キーが存在すればそれが使われること、クライアントもサーバーも bitness の希望を出していない場合はクライアントに合う bitness のサーバーが選ばれ、無ければもう一方が起動されること。 ↩ ↩2 ↩3

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

  22. Microsoft Learn, 上級ユーザー向けの Windows レジストリ — HKCU\Software\Classes と HKLM\Software\Classes、HKCR の挙動。 ↩

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

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

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

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

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

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

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

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

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

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

  33. Microsoft Learn, Assembly Manifests — assembly / assemblyIdentity / dependency / file / comClass の各属性、REF 側と DEF 側の assemblyIdentity が一致する必要があること、名前の大文字小文字の扱い、miscStatus 系属性。 ↩ ↩2

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

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

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

よくある質問

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

0x80040154(Class not registered)はどう調べればよいですか?
公式にはREGDB_E_CLASSNOTREGで、文字通り「クラスが登録されていない」エラーですが、完全に未登録とは限りません。別ビット数側のレジストリviewにだけ登録されている、あるいはそのユーザーにしか見えないHKCU側にだけ登録されている場合でも起きます。まずホストプロセスが32bitか64bitかを固定し、次に登録手段が正しいか、そしてHKCU / HKLMと32bit / 64bit viewのどこに登録されたかを順に確認するのが早道です。
regsvr32で登録しても動かないのはなぜですか?
regsvr32はDllRegisterServerをエクスポートするネイティブのin-proc COMサーバー(DLL / OCX)向けで、何でも登録できる魔法のコマンドではありません。.NET FrameworkアセンブリのCOM公開はRegasm.exe、.NET 5以降ではEnableComHostingで生成される.comhost.dllをregsvr32で登録する流れです。また、x64 Windowsでは64bit用はSystem32、32bit用はSysWOW64のregsvr32を使い分ける必要があり、間違った側に登録すると成功したのに目的のプロセスから見えない状態になります。
Visual Studio 2022でDesignerだけ壊れるのはなぜですか?
Visual Studio 2022のdevenv.exeは64bitプロセスのため、32bitのCOM / ActiveXコンポーネントを直接ロードできないからです。実行時のアプリはx86で動けても、DesignerはVisual Studio側の64bitプロセスで動くため、実行時は生きているのにDesignerだけ落ちるというねじれが起きます。AnyCPUにしても、参照先で32bit固定のCOM / ActiveXに依存していれば問題は残ります。
管理者として実行すると動くのに、通常権限では動かないのはなぜですか?
本質は権限そのものより、登録スコープやインストール設計のズレであることが多いです。COMはHKCU\Software\Classesを先に見て、HKEY_CLASSES_ROOTはHKLMとHKCUのmerged viewです。開発者Aのユーザーで手動登録した場合、Aのアカウントでは動くのに他のユーザーやサービスアカウントでは動かない、ということが普通に起きます。開発用のper-user登録と、インストーラーで行う本番のper-machine登録を区別し、ビルドと登録を分離するのが基本です。

著者プロフィール

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

小村 豪

合同会社小村ソフト 代表

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

ブログ一覧に戻る