Windows 11 上で自己完結(self‑contained)な .NET MAUI アプリの exe を発行したのに「何も起動しない」「一瞬だけくるくるして落ちる」といった事象は、開発者にとってかなりストレスの高いトラブルです。本記事では、イベント ビューアーで coreclr.dll によるクラッシュ(例外コード 0xc0000602)が記録されるケースを例に、原因の整理と再現なく解消するための手順を、実運用視点でまとめます。
症状の概要と環境イメージ
まず、今回のケースを整理しておきます。以下のような状況に心当たりがあれば、本記事の対処がそのまま使える可能性が高いです。
- .NET MAUI で Windows 向けアプリを開発している
- 発行形式は「自己完結(self‑contained)」の exe(MSIX ではなく単一 exe またはフォルダ配布)
- Windows 11 のクライアント端末にコピーして実行すると、ウィンドウが出る前に落ちる
- イベント ビューアーを見ると、障害モジュール名が coreclr.dll、例外コードが 0xc0000602 などになっている
- 使っていた SDK は
dotnet --version => 9.0.20(9.0.2 未満) - その後、Windows Update を適用したら起動するようになった
実際に使われていた発行コマンドの一例は次のようなものです。
dotnet publish -f net9.0-windows10.0.19041.0 -c Release `
-p:WindowsPackageType=None `
-p:WindowsAppSDKSelfContained=true `
-p:RuntimeIdentifierOverride=win10-x64 `
--self-contained
ポイントは以下の 3 つです。
- 自己完結(self‑contained)で発行している
- イベント ビューアーでは coreclr.dll でクラッシュしている
- Windows Update と .NET SDK 更新で問題が解消する
結論から言えば、これは OS 側(Windows 11)の更新と.NET SDK/ランタイムの更新で解消できる問題です。自己完結発行だからといって OS の状態から完全に独立できるわけではなく、OS の修正パッチと発行時の SDK/ランタイムの品質が両方効いてきます。
自己完結(self‑contained)発行とは何か
まず、「自己完結(self‑contained)」という言葉が何を意味するのかを明確にしておきます。ここを誤解すると、
「self‑contained だから OS やインストール済み .NET とは関係ないはず」
と考えてしまい、トラブルシュートを誤った方向に進めがちです。
self‑contained と framework‑dependent の違い
| 発行方式 | 特徴 | メリット | デメリット |
|---|---|---|---|
| framework‑dependent | ターゲット PC にインストールされた .NET ランタイムを利用 | 配布サイズが小さい、OS 側のランタイム更新の恩恵を受けやすい | 対象 PC に適切なランタイムが入っていないと起動しない |
| self‑contained | アプリと一緒に .NET ランタイムや依存 DLL を同梱 | 対象 PC に .NET が入っていなくても動作させやすい | サイズが大きい、発行時点のランタイム品質に強く依存する |
self‑contained 発行は「ターゲット PC に .NET ランタイムをインストールしなくてよい」という意味であって、
- OS カーネル
- Win32 API
- グラフィックス/ウィンドウ システム(WinUI, DirectX 等)
- セキュリティ関連モジュール
といった OS 側コンポーネントの振る舞いとは無関係になるわけではありません。coreclr.dll 自体は同梱されますが、その内部で OS の機能を呼び出す際に、OS 側のバグ・変更・パッチ状態の影響を受ける可能性があります。
WindowsAppSDKSelfContained と MAUI の関係
.NET MAUI の Windows 向けアプリでは Windows App SDK(WinUI 3 など)を利用します。そこで、発行オプションに
-p:WindowsAppSDKSelfContained=true
を付けると、Windows App SDK 周りも自己完結に近い形でまとめてくれます。しかし、これもあくまで「Windows App SDK 側のランタイムやライブラリを同梱する」ためのものであり、
- OS カーネル
- Win32/COM API の実装
- Windows 11 固有の挙動
などと切り離せるわけではありません。
原因の整理:OS 更新と .NET SDK 更新で改善する理由
今回の事例では、次の 2 点を行うことで症状が解消しています。
- Windows 11 を Windows Update で最新状態に更新
- .NET SDK を 9.0.2 以降に更新して再発行
これは裏を返すと、
- 古い Windows 11 のビルドと、古い coreclr.dll(.NET ランタイム)の組み合わせで問題が出ていた
- .NET 9.0.2 以降で coreclr 側に修正が入り、既知のクラッシュが解消されている
と考えられます。自己完結発行の場合、
- アプリに同梱される coreclr.dll は「発行時の SDK/ランタイムのバージョン」で決まる
- OS の不具合修正は Windows Update に含まれる
ので、どちらか片方だけが古くても問題が残る場合があります。特に、今回のように SDK バージョンが 9.0.20 のような初期系だった場合、
- 新しい Windows 11 のビルドでしか再現しないようなバグ
- 特定の CPU、ドライバ、セキュリティ機能との組み合わせで起きる不具合
といった「組み合わせ依存のクラッシュ」が一定数存在し得ます。
したがって、
「self‑contained だから OS 側は関係ない」ではなく、「OS と SDK の両方を最新安定版に寄せることで組み合わせ不具合を潰していく」
という発想が大切です。
解決策の全体像
ここからは具体的な対処手順を整理します。流れとしては次の順番がおすすめです。
- Windows 11 を最新ビルドまで更新する
- .NET SDK を 9.0.2 以降に更新し、開発環境(Visual Studio)を再起動
- 必要に応じて MAUI の NuGet パッケージを最新安定版に更新
- 自己完結(self‑contained)で再発行する(推奨の publish コマンドに見直す)
- 発行物内の coreclr.dll バージョンと OS ビルドを確認し、それでも落ちる場合はログ/ダンプで詳細調査
以下、それぞれのステップを詳しく見ていきます。
.NET SDK/ランタイムを 9.0.2 以降へ更新する
現在の SDK/ランタイムの確認
まずは開発機にインストールされている .NET SDK/ランタイムのバージョンを確認します。コマンド プロンプトまたは PowerShell で次を実行します。
dotnet --version
dotnet --list-sdks
dotnet --list-runtimes
dotnet --version… 既定で使われている SDK のバージョンdotnet --list-sdks… インストール済み SDK の一覧dotnet --list-runtimes… インストール済みランタイムの一覧
ここで、既定の SDK が 9.0.2 以上になっていない場合は、公式インストーラ等で 9.0.2 以降(例:9.0.21 など)をインストールします。
Visual Studio と SDK の対応
.NET 9 系を使うには、対応したバージョンの Visual Studio(MSBuild)が必要です。例として、
- .NET 9.0.2xx 系をフルサポートするには Visual Studio 2022 17.13 以降が推奨
といったように、Visual Studio 自体の更新が求められることがあります。実務的には、
- Visual Studio Installer から VS 本体を最新バージョンに更新
- その際に .NET SDK もまとめてインストールされることが多い
という流れになるため、まず Visual Studio を最新系に上げ、そのうえで改めて dotnet --version を確認するのが確実です。
推奨の self‑contained 発行コマンド
SDK を更新したら、アプリを self‑contained で再発行します。RuntimeIdentifierOverride を使わず、標準の Runtime Identifier(RID)を指定する形に見直すのがおすすめです。
dotnet publish .\MyApp.csproj `
-c Release `
-f net9.0-windows10.0.19041.0 `
-r win-x64 `
-p:SelfContained=true `
-p:WindowsPackageType=None `
-p:WindowsAppSDKSelfContained=true
必要に応じて、単一ファイルにまとめたい場合は次のオプションも追加します。
-p:PublishSingleFile=true
各オプションの意味を整理
| オプション | 意味 | ポイント |
|---|---|---|
-f net9.0-windows10.0.19041.0 | ターゲット フレームワーク/Windows バージョン | Windows 10 19041 以降をターゲットとした .NET 9 |
-r win-x64 | Runtime Identifier(RID) | 標準 RID を使うのが安全。RuntimeIdentifierOverride は極力避ける |
-p:SelfContained=true | self‑contained 発行 | .NET ランタイムを同梱する |
-p:WindowsPackageType=None | MSIX ではなく「生の exe/フォルダ」として出力 | インストーラを自作する場合など |
-p:WindowsAppSDKSelfContained=true | Windows App SDK を自己完結に近い形で同梱 | クライアント環境に Windows App SDK を別途インストールしなくて済む |
-p:PublishSingleFile=true | 単一ファイルにまとめる | 配布は楽になるが、デバッグ時はフォルダ展開の方が楽なことも多い |
特に、
-p:RuntimeIdentifierOverride=...をむやみに使わない
ことが重要です。標準 RID(win-x64 など)を使っていれば、.NET ランタイム側で十分テストされた経路を通りやすくなります。
Windows 11 を最新まで更新する
つぎに、クライアント側の Windows 11 を最新状態に更新します。self‑contained 発行であっても、
- OS カーネルのバグ修正
- セキュリティ パッチ(メモリ保護や検証の強化)
- 新しい CPU・GPU・ドライバへの対応
などは Windows Update でのみ取り込まれます。特に coreclr.dll は OS のさまざまな機能を利用するため、その入り口で問題があればアプリが巻き込まれて落ちることがあります。
更新の目安
- Windows 11 22H2/23H2 いずれのエディションでも良いが、最新ビルドまで更新すること
- 社内ポリシーで更新が制限されている場合は、検証用に最新ビルドのテスト端末を用意することを検討
実際の操作手順としては、
- [設定] → [Windows Update]
- [更新プログラムのチェック] を実行
- 再起動が必要な更新があれば適用
を繰り返し、すべての重要な更新が適用された状態にします。
MAUI の更新方針:ワークロード更新は本当に必要?
MAUI アプリでトラブルが起きると、つい
dotnet workload update maui
を実行したくなりますが、Windows + Visual Studio 環境では、必ずしもこれが正解とは限りません。
Windows + Visual Studio の場合
- MAUI 本体は NuGet パッケージ(
Microsoft.Maui.Controlsなど)としてプロジェクトに入っている - Visual Studio で「.NET Multi‑platform App UI 開発ワークロード」を入れていれば、基本的なテンプレートやビルドツールは VS が面倒を見てくれる
- そのため、通常は
dotnet workload install/update mauiを手動で叩く必要はない
MAUI を新しくしたい場合は、
- Visual Studio を最新バージョンに更新
- プロジェクトの NuGet 管理画面から
Microsoft.Maui.*パッケージを最新安定版へ更新
という順番がおすすめです。
Mac/CLI 中心の場合
Mac や CI/CD 環境など、Visual Studio を前提としない場合は話が変わります。このケースでは、
dotnet workload install maui
dotnet workload update maui
といったコマンドでワークロード自体を更新する必要があります。ただし、本記事のテーマである「Windows 11 上の self‑contained exe が起動しない問題」は、主にクライアント OS と .NET ランタイムの組み合わせが原因なので、ワークロードの更新よりも先に OS/SDK の更新を優先して確認するのが効率的です。
Visual Studio と SDK の組み合わせでハマりやすいポイント
MAUI + .NET 9 の開発では、次のような「バージョンのねじれ」が起きやすくなります。
- Visual Studio のバージョンが古いのに、.NET 9 SDK だけ新しく入れてしまう
- 逆に、Visual Studio は新しいが、ビルドに使っている SDK が古いままになっている
これを避けるために、次のチェックを行うと良いでしょう。
| チェック項目 | 確認方法 | OK の条件 |
|---|---|---|
| Visual Studio のバージョン | メニュー [ヘルプ] → [Microsoft Visual Studio について] | 17.13 以降など、.NET 9 対応の最新系であること |
| 既定の SDK バージョン | dotnet --version | 9.0.2 以上になっていること |
| プロジェクトで参照される SDK | global.json の有無と内容 | 存在する場合は、ここに書かれたバージョンが 9.0.2 以上になっていること |
特に CI サーバーやビルドサーバーでは、
- 開発者のローカル PC とは別に SDK がインストールされている
- 古い SDK のままビルドしてしまい、問題を再現させてしまう
といったことが起こりがちです。ビルド環境ごとに SDK バージョンを明確にしておきましょう。
チェックリスト:発行前に確認しておきたいポイント
再発を防ぐために、発行前に次のチェックリストを軽くなぞっておくことをおすすめします。
| チェック | 内容 | 補足 |
|---|---|---|
| □ | dotnet --version が 9.0.2 以上になっている | 古い SDK で発行すると、coreclr.dll も古いまま同梱される |
| □ | Windows 11 を最新ビルドまで更新している | 22H2/23H2 どちらでも良いが、更新プログラムはすべて適用しておく |
| □ | 発行オプションに -r win-x64 と -p:SelfContained=true を指定 | 標準 RID を使い、self‑contained であることを明示 |
| □ | -p:WindowsPackageType=None と -p:WindowsAppSDKSelfContained=true を指定 | MSIX ではなく exe 配布で、Windows App SDK も同梱 |
| □ | -p:RuntimeIdentifierOverride=... を指定していない | どうしても必要な場合を除き外す。標準 RID の方が安全 |
| □ | NuGet の Microsoft.Maui.* パッケージを最新安定版に更新 | バグ修正が多数入るため、最低限の更新はしておくと安心 |
| □ | 出力フォルダー内の coreclr.dll のファイル バージョンを確認 | 右クリック → [プロパティ] → [詳細] で発行前後の違いを見ておく |
「self‑contained なのに、なぜ Windows Update で直るのか?」をもう少し詳しく
よくある疑問として、
「ランタイムを同梱している self‑contained アプリなのに、OS を更新したら直るのはなぜ?」
というものがあります。これにはいくつかの理由が考えられます。
理由 1:coreclr.dll は OS の機能を大量に利用している
.NET ランタイム(coreclr.dll)は、単なる「計算ライブラリ」ではなく、
- スレッドやプロセスの管理(Win32 API)
- メモリ管理・例外処理
- JIT コンパイル
- ファイル I/O
- ネイティブ インターフェイス(P/Invoke)
といった多くの機能を OS 側に依存して実現しています。OS 側にバグがあり、特定の呼び出しパターンでクラッシュするような場合、coreclr.dll は「被害者」として巻き込まれてしまいます。
理由 2:セキュリティ パッチによる振る舞いの変化
近年の Windows Update では、
- メモリ保護(Stack/Heap 保護)の強化
- コード インテグリティ チェックの強化
- 古い API の互換レイヤー調整
といったセキュリティ寄りの変更も多く含まれます。これにより、
- 以前は「たまたま動いていた」パターンが不正アクセスとして検知される
- 逆に、元々問題があった経路が修正されて正常に動くようになる
といった変化が起こります。今回のような「Windows Update を当てたら急に動くようになった」ケースは、後者である可能性が高いと考えられます。
理由 3:ドライバや GPU まわりの改善
.NET MAUI の Windows アプリは、WinUI 3 やグラフィックス API を通じて GPU を利用します。特定の GPU ドライバや組み合わせでクラッシュが出る場合、
- Windows Update 経由のドライバ更新
- グラフィックス スタックの修正
などによって安定することも少なくありません。
いずれにせよ、self‑contained アプリであっても、
「OS の更新状態が安定性に影響する」
ことは避けられないため、トラブル時は必ず OS のアップデート状況を確認しましょう。
それでも落ちる場合の追加トラブルシューティング
上記の対処(OS 更新+SDK 更新+再発行)を行ってもなおクラッシュする場合は、もう一歩踏み込んだ調査が必要になります。現場で使いやすい手順をいくつか挙げておきます。
イベント ビューアーで詳細ログを確認
- [イベント ビューアー] を開く
- [Windows ログ] → [アプリケーション] を選択
- 障害発生時刻付近の「エラー」をフィルタリング
- ソースが .NET Runtime または Application Error のものを重点的に確認
ここで、
- 障害モジュール名(coreclr.dll なのか、それ以外なのか)
- 例外コード(0xc0000602 以外のコードかどうか)
- 障害オフセットやアプリケーション名
を確認し、OS 側のログと付き合わせることで原因の切り分けが進みます。
プロセス ダンプを取得して解析
再現頻度が高い場合は、プロセス ダンプを採取して原因を特定することも可能です。
- Windows の「問題のレポートとソリューション」または「Windows エラー報告」で自動ダンプ取得を有効化
- または、Sysinternals の
procdumpなどを使ってクラッシュ時にダンプを取得 - WinDbg や Visual Studio の「ダンプを開く」機能でスタックトレースを確認
これらはやや高度な手順ですが、
- 自分のコードが落としているのか
- ランタイム/OS の深いところで落ちているのか
を見分けるのに役立ちます。
別バージョンの Windows で検証する
社内で複数の Windows バージョンを用意できる場合は、
- 最新の Windows 11 23H2
- 安定運用中の 22H2
- 仮想環境(Hyper-V/VMware 等)でクリーンインストールした環境
など、複数の組み合わせで self‑contained exe の挙動を確認してみましょう。環境によって再現/非再現が分かれる場合、OS ビルドやドライバの違いが原因である可能性が高くなります。
運用面での再発防止策
最後に、同様のトラブルを繰り返さないための運用上の工夫をいくつか紹介します。
ビルド環境ごとの「OS + SDK バージョン表」を作る
CI/ビルドサーバー・開発者 PC を含め、
- OS ビルド(Windows 11 22H2/23H2 + ビルド番号)
- .NET SDK バージョン(例:9.0.21)
- Visual Studio バージョン(例:17.13.x)
を一覧にしておくと、トラブル時の切り分けが非常に楽になります。Excel や Wiki、Notion など、チームで共有しやすい形で管理しておきましょう。
global.json で SDK バージョンを固定する
開発者の環境によって SDK バージョンがバラバラになるのを防ぐために、リポジトリ直下に global.json を置いて SDK を固定するのも有効です。
{
"sdk": {
"version": "9.0.2xx",
"rollForward": "latestFeature"
}
}
こうしておくと、「ある開発者だけ古い SDK でビルドしてしまい、self‑contained のランタイムが古くなる」といった事故を防ぎやすくなります。
テスト用に「クリーンな Windows 11 環境」を 1 台用意する
長期運用の MAUI アプリであれば、
- Hyper-V や VMware で素の Windows 11 を 1 台用意
- 重要なリリースのたびに「まっさらな状態」に戻して検証
といった運用を行うと、
- 「開発者 PC では再現しないのに、お客様環境では落ちる」
といったギャップを早めに発見できます。self‑contained 発行との相性を確認する意味でもおすすめです。
まとめ:Windows 11 で self‑contained exe が起動しないときの処方箋
本記事で扱った「Windows 11 で self‑contained .NET MAUI exe が起動しない」問題は、
- OS 側の更新(Windows Update)
- .NET SDK/ランタイムの更新(9.0.2 以降)
という 2 つの軸で解消できるケースが多いトラブルです。具体的なおすすめ手順を改めて整理すると、次のようになります。
- Windows 11 を最新ビルドまで更新する
self‑contained であっても OS のバグ修正・セキュリティ更新の影響を受けるため、まず OS を最新にする。 - .NET SDK を 9.0.2 以降へ更新し、Visual Studio を再起動
dotnet --versionやdotnet --list-sdksで確認し、古い SDK を使っていないかチェック。 - NuGet の MAUI パッケージを最新安定版へ更新
Microsoft.Maui.*パッケージをまとめて更新し、既知のバグ修正を取り込む。 - 推奨の publish コマンドで self‑contained 再発行
-r win-x64と-p:SelfContained=true、-p:WindowsPackageType=None、-p:WindowsAppSDKSelfContained=trueを指定し、RuntimeIdentifierOverrideは使わない。 - それでも落ちる場合はイベント ビューアー/ダンプで詳細を確認
発行物内の coreclr.dll のバージョンや OS ビルドと付き合わせて、ランタイムかアプリコードかを切り分ける。
この流れを一度テンプレート化しておけば、今後同じような「Windows 11 で self‑contained exe が起動しない」問題に遭遇した際も、慌てずに原因を切り分けて、再現なく解消していけるはずです。

コメント