黙々とC#

"In a mad world of VBA, only the mad are sane" 『VBAという名の狂った世界で狂っているというのなら私の気は確かだ』

System.BadImageFormatException が発生して.NET アプリケーションが起動しない問題の原因と解決策

f:id:d_ymkw:20170526122449j:plain

過去にC# (ターゲットフレームワークを.NET Framework3.5に設定)で作成したアプリケーションの、ターゲットフレームワークを .NET Framework4.* に変更したところ、System.BadImageFormatExceptionが発生して起動できなくなった。

原因がわかったのでメモしておく。

結論から先にいうと、アプリケーション構成ファイル(App.config)で古いランライムをサポートするよう設定したままにしていたのが原因だった。

状況

  • VisualStudio 2015 or 2017を使用
  • ターゲットフレームワークが.NET Framework3.5に設定されたC# プロジェクトを開く
  • ソースコードには変更を加えず、ターゲットフレームワークを.NET Framework4.6に変更
  • ビルドは通るが、exeファイルを起動しようとするとエラーが発生する

発生したエラー

System.BadImageFormatException: ‘ファイルまたはアセンブリ ’****.exe'、またはその依存関係の 1 つが読み込めませんでした。このアセンブリは現在読み込まれているランタイムより新しいランタイムでビルドされているため、読み込むことができません。'

アプリケーションのエントリポイントに到達するより早くエラーが発生するので一切デバッグ情報が手に入らなかった。

原因

アプリケーション構成ファイル(App.config)で、.NET 3.5(.NET 2.0の系列)のランタイムでの動作を許可していた。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v2.0.50727"/>
    <supportedRuntime version="v4.0"/>
  </startup>
</configuration>

上記設定について簡単に説明すると、

『このアプリケーションは .NET 3.5のランタイムと.NET 4.xのランライム、どちらでも動作しますよ』

という宣言をしている感じ。構成ファイルについて詳しくは、MSDNを。

この設定を記載していた理由は、.NET Framework 3.5で作成したアプリケーションをWindows 8以降で起動しようとすると、上位互換性のある.NET Framework 4.xがdefaultでインストールされている(4.xのランタイムを使ってアプリケーションを動作させられる)にも関わらず、.NET Framework 3.5をインストールするように促されてしまうのをふせぐため。

この設定があると、.NET 4.xはインストールされているが、.NET 3.5がインストールされていないWindows(defaultのWindows8や10) で、追加インストールなしに、.NET 2.0や3.5をターゲットフレームワークとして作成されたアプリケーションを動作させられるようになる*1

閑話休題。

解決策

構成ファイルから下記記載(.NET Framework 3.5での動作のサポート)を削除した。

<supportedRuntime version="v2.0.50727"/>

※原因の推測

構成ファイルに従って、.NET 4.xで作成したアプリケーションを、.NET 3.5のランタイムで動かそうとしてエラーが発生していたと思われる。

つまるところ『VisualStudio上でターゲットフレームワークを変更した際に、App.configの中までは精査してくれない』ということなので、ターゲットフレームワークを変更する際はconfigファイルに何を書いていたかは注意する必要がある。

余談

構成ファイルで呼び出すランタイムの順序を逆にする(.NET 4.xを先に呼び出すようにする)ことでもアプリケーションは起動するようになった。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>/>
    <supportedRuntime version="v4.0"/>
    <supportedRuntime version="v2.0.50727"
  </startup>
</configuration>

(が、.NET 4.xがインストールされていない環境で問題を起こすことが明らかなのでまったくオススメしない。)

*1:特定のVersionのランタイムに依存したコードがあるとダメらしい。具体的にどういうコードがダメなのかは残念ながら知らない。