モジュールはアセンブリ マニフェストを含んでいなければなりません dll

先月くらいから、私の開発環境で『見つかったアセンブリのマニフェスト定義はアセンブリ参照に一致しません。 (HRESULT からの例外: 0x80131040)』のエラーが発生しました。
ちなみに私のエラーは、PC環境を変えたため、必要なDLLが見つからないというエラーではありません。

エラーの背景に社外・社内を問わずプログラム修正を行いたいため、開発に使用しているPCが数台あります。
ちゃんと費用を掛けてネットワーク構築及びVSSやTFSを立てたりすれば発生しないエラーかもしれないのですが、一人開発なので勿体無くて費用をかけていません。そのかわり利便性を向上させるために、どこからでもアクセスできるようインターネット上にディスクスペースを借りてそこにソースを置いています。
一人なので排他制御しなくていいし。

で、今まではWindows7+VS2010で主に開発をしていました。
最近は、Windows8+VS2012/VS2010の環境が入ってきて混在している状況です。
今までは上の問題が出て記憶が無いのですが、最近、社内はWindows8(64bit)、社外はWindows7(64bit/32bit)の混在でプログラムを修正するようなケースが発生したためか、3回程度発生しています。

64bit/32bitの混在が不味いのか。。。。Windows8+VS2010/windows7+VS2010の環境がいけないのか。。。
その両方なのか。。。

たまにしか発生していないのですが、64bit開発マシンで修正後32bit開発マシンで修正する際に発生しているので(頻発するわけだなくたまになので曖昧です。。。)、64bit/32bitの混在が不味い気がするのですが。。。

で、原因がはっきりわからない(きちんと調べても居ません)ので対処が正解かわからないのですが、いつも手っ取り早く修正したい時に発生するので、自分用にとりあえずの対処法を備忘録としてメモっておきます。

(対応)プロジェクトフォルダ内のbinフォルダに上のメッセージで読み込めないと名指しされているxxxxx.dllが存在しているので、そのdllファイルを削除してしまいます。

上の作業で、エラーが消えます。私のエラーの場合です。
一般的な、DLLが見つからない、読めない等々のエラーの場合は、本当に無いか、バージョン違いや64bit-dllを32bit環境で読もうとしてエラーが出ているなどなどなので、上の対応はもちろん該当しません。

以上、エラー対応備忘録でした。

windows10を使用しているのですが、いつからか下記のエラーが出るようになってしまい、 いろいろなアプリなどが使えなくなってしまいました。 なにかをインストールしたせいでこうなってしまったのかはわかりませんが、対処方法がわかりません。 一度パソコンを初期化させたのですが、それでも治りませんでした。 どなたか対処方法がわかる方がいましたら、 教えてもらえたらうれしいです。 文字数がたりなくなってしまったので、続きは画像になります。すいません。 アプリケーションのコンポーネントで、ハンドルされていない例外が発生しました。[継続]をクリックすると、アプリケーションはこのエラーを無視し、続行しようとします。 ファイルまたはアセンブリ 'Accessibility, Version=4.0.0.0. Culture=neutral.PublicKeyToken=b03f5f7f11d50a3a、またはその依存関係の1つが読み込まれませんでした。モジュールはアセンブリ マニフェストを含んでいなければなりません。。 Just-In-Time (JIT) デバッグを呼び出すための詳細については、 ダイアログ ボックスではなく、このメッセージの最後を参照してください。 ************** 例外テキスト ************** System.BadImageFormatException: ファイルまたはアセンブリ 'Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'、またはその依存関係の 1 つが読み込めませんでした。モジュールはアセンブリ マニフェストを含んでいなければなりません。 ファイル名 'Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' です。'Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' 場所 System.Windows.Forms.Control.OnHandleCreated(EventArgs e) 場所 System.Windows.Forms.Control.WmCreate(Message& m) 場所 System.Windows.Forms.Control.WndProc(Message& m) 場所 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 警告: アセンブリ バインドのログ記録がオフにされています。 アセンブリ バインドのエラー ログを有効にするには、レジストリ値 [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) を 1 に設定してください。 注意: アセンブリ バインドのエラー ログに関連するパフォーマンス ペナルティがあります。 この機能をオフにするには、レジストリ値 [HKLM\Software\Microsoft\Fusion!EnableLog] を削除します。 ************** 読み込まれたアセンブリ ************** mscorlib アセンブリ バージョン:4.0.0.0 Win32 バージョン:4.6.1055.0 built by: NETFXREL2 コードベース:file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll ---------------------------------------- TamiyasuOperator アセンブリ バージョン:0.0.35.0 Win32 バージョン:0.0.35.0 コードベース:file:///C:/Users/maneki/Downloads/TamiyasuOperator-alpha35/TamiyasuOperator-alpha35/TamiyasuOperator.exe ---------------------------------------- System アセンブリ バージョン:4.0.0.0 Win32 バージョン:4.6.1055.0 built by: NETFXREL2 コードベース:file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll ---------------------------------------- System.Windows.Forms アセンブリ バージョン:4.0.0.0 Win32 バージョン:4.6.1055.0 built by: NETFXREL2 コードベース:file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll ---------------------------------------- System.Drawing アセンブリ バージョン:4.0.0.0 Win32 バージョン:4.6.1055.0 built by: NETFXREL2 コードベース:file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll ---------------------------------------- System.Data アセンブリ バージョン:4.0.0.0 Win32 バージョン:4.6.1055.0 built by: NETFXREL2 コードベース:file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_64/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll ---------------------------------------- System.Core アセンブリ バージョン:4.0.0.0 Win32 バージョン:4.6.1055.0 built by: NETFXREL2 コードベース:file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll ---------------------------------------- TamiorePlugin アセンブリ バージョン:1.0.3.0 Win32 バージョン:1.0.3.0 コードベース:file:///C:/Users/maneki/Downloads/TamiyasuOperator-alpha35/TamiyasuOpe

一般的な開発では滅多に使われることはありませんが、.NET Framework SDKにはILAsmと呼ばれる、中間言語を直接記述できるアセンブラが含まれています。本稿では、高水準言語を使わずに、ILAsmを使ったアセンブリ言語による .NET Frameworkアプリケーション開発を説明します。

はじめに

実践的な開発経験のある.NET Frameworkアプリケーションプログラマであれば、ILDASMを使ってプログラムを逆アセンブルしたコードを見たことがあるでしょう。.NET Frameworkアプリケーション開発は、Visual BasicやC#、C++/CLIなど、多くの言語を使って開発できますが、最終的に生成されるのは標準化されているCIL(Common Intermediate Language)と呼ばれる中間言語です。Microsoft Intermediate Language(MSIL)とも呼ばれ、単純にILと略されることもあります。中間言語を含む共通言語基盤CLI(Common Language Infrastructure)は、既にEcma-335やISO/IEC 23271、JIS X3016などで標準化されているため、Microsoftによって独占されている技術ではありません。

ILDASMで表示されるテキストは、中間言語に直接対応しているCILアセンブリ言語(CIL Assembly Language)で書かれたコードです。このアセンブリ言語を理解することで、コンパイラが生成した中間言語を読むことができるようになり、高水準言語で記述したコードが、どのような中間言語に変換されたのかを理解できるようになります。またCILを理解することは.NET Frameworkの本質にも迫ることになります。

.NET Framework SDKには、ILDASMに対応するアセンブラILASMを提供しています。ILASMは、テキストで書かれたCILコードをアセンブルして.NET Frameworkアプリケーションを生成します。高水準言語のコンパイラと同じように、実行可能ファイルやDLLファイルを生成することができ、開発に実用することも可能です。

CILアセンブリ言語は中間言語に直接対応する唯一の言語です。高水準言語では、言語仕様による多くの制約を受けますが、CILアセンブリ言語には制約はありません。.NET Frameworkでできるすべてのことを表現できる唯一の言語であり、アセンブリを理解することで、動的なコード生成など、.NET Frameworkアプリケーションでの応用も広がります。

アセンブリ言語を使った開発方法

.NET Framework SDKには、CILアセンブリ言語で書かれたソースコードをアセンブルするILASMというツールが含まれています。最新のILASMは、.NET Framework 2.0に含まれているものです。.NET Framework 3.5では、言語仕様に変更が加えられているC#やVisual Basicのコンパイラが含まれていますが、CILそのものに変更はないためILASMは含まれていません。Windows Vistaへのデフォルトのインストール設定では、以下のフォルダに格納されています。

  • C:\Windows\Microsoft.NET\Framework\v2.0.50727

このフォルダ内にあるILASM.EXEがアセンブラです。使い方は、CSC.EXEなどと同じように、コマンド名に続いてアセンブルするソースファイルを指定します。必要に応じてオプションを指定することもできますが、詳細はVisual Studioに付属しているドキュメントやILASMのヘルプを参照してください。

CILアセンブリ言語のソースファイルは、通常はilという拡張子のテキストファイルです。後は、他の高水準言語と同じように、テキストファイルにコードを書いてILASMでアセンブルし、実行可能ファイルやDLLファイルを生成できます。

簡単なサンプル

まずは、何もしないプログラムを作成して、ILASMを使って実行ファイルを生成できるかどうかを試してみましょう。「il」という拡張子のテキストファイルを用意してください。

ソースファイルに記述するコードは、当然CILアセンブリ言語の構文に従うものでなければなりません。トークンの概念などは、他の高水準言語と大きな違いはありません。トークンは、ホワイトスペースや記号で区切られるため、トークンの並びが適切で、構文に従っているのであれば改行やタブを自由に挿入できます。

細かい構文については後述するので、この場ではエントリーポイントとなるメソッドを用意します。C#言語におけるMain()メソッドに相当するものです。エントリーポイントがなければEXEファイルを生成できずエラーとなります。

Sample01

Sample01

.method static void Main() cil managed {
    .entrypoint
    ret
}

Sample01は、なにもせずに制御を返すだけのプログラムです。このソースファイルをILASMに渡すと、正しくアセンブルが行われ実行ファイルが出力されることを確認できます。実行すると、なにもせずに終了することを期待してしまいますが、結果は例外が発生して終了します。

実行結果

>test

ハンドルされていない例外: System.BadImageFormatException: ファイル
またはアセンブリ 'test.exe'、またはその依存関係の 1 つが読み込め
ませんでした。モジュールはアセンブリ マニフェストを含んでいなければ
なりません。
ファイル名 'test.exe' です。

これは、上記のコードがアセンブリマニフェストを含んでいないために発生する例外です。高水準言語であれば、コンパイラや開発環境が自動的に設定してくれていた項目ですが、CILアセンブリ言語では、マニフェストを明示的に定義しなければなりません。アセンブリを定義するには、次のような行を加えます。

.assembly アセンブリ名 { アセンブリ情報... }

アセンブリ名には、このマニフェストに含めるアセンブリ名を指定します。その後、{ }内に任意のアセンブリ情報を指定できます。マニフェストには、バージョン情報やカルチャなどを設定できますが必須ではありません。この場では空の{ }を指定します。testというアセンブリ名でマニフェストを作成するには、次のようになるでしょう。

.NET Frameworkで定められているアセンブリで必須なのはマニフェストだけです。そのため、型メタデータやコードが無くてもアセンブリを作成することは可能です。実行可能ファイルの作成には、エントリーポイントが必須となるためメソッドが必要ですが、DLLファイルの生成であれば、上記のような空のマニフェストの宣言だけでも正しくアセンブルできます。.assemblyは、グローバルなスコープ上であればどこでも記述できますが、同一のアセンブリ内に複数のマニフェストを含めることはできません。通常は、ファイルの先頭に記述することになるでしょう。

Sample02

.assembly test { }

.method static void Main() cil managed {
    .entrypoint
    ret
}

Sample02は、マニフェストを含む何もしないエントリーポイントMain()メソッドを定義するコードです。アセンブルして生成されたファイルを実行してください。今度はマニフェストを含んでいるため、プログラムは何もせずに正しく終了します。

クラスを持たないMain()メソッドが、グローバルなスコープに配置されていることにC#プログラマは驚くかもしれませんが、C++/CLIでは可能だったことです。同じように、CILアセンブリ言語ではグローバル変数も使うことができ、言語的な制約を受けません。

また、Main()メソッドのブロック内に.entrypointという記述があることに注目してください。これは、このメソッドがエントリーポイントであることを表しています。ここから想像できるように、CILアセンブリ言語ではエントリーポイントのメソッド名は任意です。Main()メソッドである必要はなく、Start()メソッドでもInit()メソッドでも構いません。

Hello World

次に、いわゆる"Hello world"サンプルを作りましょう。文字列をコンソールに表示する、最も簡単なプログラムです。.NET Frameworkアプリケーション開発者であれば、方法は既に理解しています。System.Console.WriteLine()メソッドに、文字列オブジェクトを渡せばよいのです。

メソッド本体に記述するコードは、計算やメソッドの呼び出しなど、共通言語ランタイムが実行する実質的な命令となります。命令は、ネイティブのアセンブリ言語の仕組みと同じように、命令を表す整数、すなわちオペコードに直接対応しています。メソッドの呼び出しにはcall命令を使います。

ただし、アセンブリ言語では高水準言語のようにパラメータを渡すことはできません。メソッドを呼び出す前にパラメータとして渡す値を読み込む必要があります。文字列をWriteLine()メソッドに渡すために、ldstr命令を使って文字列リテラルを事前に読み込みます。詳しくは後述しますが、データはスタックに積み上げられます。

stringには、読み込む文字列リテラルを指定します。メソッドの呼び出しやパラメータの受け渡しの詳細は、割愛させていただきます。この場では、ldstr命令で文字列を読み込み、その後にcall命令でWriteLine()メソッドを呼び出すことで、直前に読み込んだ文字列がパラメータとして渡されるという流れを理解していただければ十分でしょう。

Sample03

.assembly extern mscorlib { }
.assembly test { }

.method static void Main() cil managed {
    .entrypoint
    ldstr "さすが ILAsm!C# にはできないことを平然とやってのける"
    call void [mscorlib]System.Console::WriteLine(string)
    ret
}

実行結果

さすが ILAsm!C# にはできないことを平然とやってのける

Sample03は、ldstr命令で文字列リテラルを読み込み、文字列オブジェクトをパラメータとして受け取るWriteLine()メソッドを呼び出しています。CILアセンブリ言語でも、識別子の考え方は高水準言語と同じです。識別子から、対象のフィールドやメソッドなどのメンバにアクセスできます。System.Consoleクラスはmscorlibアセンブリ内にあるので、ファイルの先頭でmscorlibアセンブリを参照することを宣言しています。