プログラミングメモ

ソフトウェア開発に関する技術メモ。

「サイド バイ サイド構成が正しくないため、アプリケーションを開始できませんでした。」

作成したアプリケーション(.exe)を、開発環境とは別のマシンで起動させたら、以下のメッセージが表示された。この場合の調査方法について。

  • ダイアログボックス

このアプリケーションのサイド バイ サイド構成が正しくないため、アプリケーションを開始できませんでした。詳細については、アプリケーションのイベントログを参照してください。

  • イベントログ (アプリケーション)

"C:\foo\bar.exe" のアクティブ化コンテキストの生成に失敗しました。
従属アセンブリ Microsoft.VC80.CRT,processorArchitecture="x86",
publicKeyToken="1fc8b3b9a1e18e3b",type="win32",version="8.0.50727.4053"
が見つかりませんでした。 詳細な診断を行うには sxstrace.exe を実行してください。

サイドバイサイド アセンブリ(side-by-side assembly)

DLL, COM, Windowクラス, type libraries(??), interfaces(??)のグループ。

個々のサイドバイサイドアセンブリには名前とバージョンが付いている。
アプリケーションは自分が必要とするサイドバイサイドアセンブリの名前、バージョンを、そのアプリケーションの「マニフェスト(manifest)」に書いておくと、アプリケーション実行時にそのサイドバイサイドアセンブリがOSによって読み込まれる。

マニフェストは、サイドバイサイドアセンブリも持っており、そこにはサイドバイサイドアセンブリを構成するファイルや、サイドバイサイドアセンブリの依存関係が記述されている。




問題のexeでどのアセンブリ(ライブラリ)を必要としているのか?

マニフェストは.exeに埋め込まれている場合と、.exeと同じフォルダに〜.exe.manifestという名前で存在する場合とがある。マニフェストXMLで記述されており、後者の場合はエディタで参照できる。

前者の場合のマニフェストの確認方法:

  • Visual Studioの[ファイル]-[ファイルを開く]で問題のexeを選択。exeのリソースが表示される。
  • リソースの[RT_MANIFEST] の 「1[英語(米国)]」を選択して表示。(exeでなくてDLLの場合は1ではなく2になる?)

マニフェストは以下のような内容。

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

この例の場合、x86用のMicrosoft.VC80.CRTのバージョン8.0.50727.762が必要だと言っている。

そのサイドバイサイドアセンブリは、問題が発生したマシンに存在するのか?

上記の例の場合、以下のファイルがあるか確認。

C:\Windows\WinSxS\Manifests\
x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.762_
none_10b2f55f9bffb8f8.manifest

  ※「1fc8b3b9a1e18e3b」の部分はマニフェストのpublicKeyTokenと一致している模様
  ※「none_10b2f55f9bffb8f8」の部分は規則が不明。

このファイルが無ければマシンに存在しないと判断してよさそう。

別のバージョンのアセンブリで置き換えるように「リダイレクト」する仕組みもあるらしい。この場合、リダイレクト先は以下のファイルで設定されるらしい。

C:\Windows\WinSxS\Policies\x86_policy.8.0.Microsoft.VC80.CRT_
1fc8b3b9a1e18e3b_????\8.0.50727.762.policy

マシンに存在しなかった場合の対処

インストーラを作成する以外の解決方法について。

Visual C++ 再頒布可能パッケージをインストール (必要なサイドバイサイドアセンブリがCランタイムライブラリの場合)

MSDN 配置方法の選択

.exeと同じフォルダに置く(プライベート アセンブリとしての配置)

MSDN 方法:XCopyを使用して配置する

静的にリンクする

Cランタイムライブラリについては、プロジェクトのプロパティの[C/C++]-[コード生成]-[ランタイムライブラリ]で(/MDの代わりに)/MTを選ぶ。

要求するバージョンを下げる? (問題のマシンにそのサイドバイサイドアセンブリはあるが、より古いバージョンしか存在しない場合)

マニフェストはexeのビルド時にVisual Studioによって自動生成されるが、その環境で利用可能な最新のバージョンのサイドバイサイドアセンブリを要求するようにマニフェストが生成されているように見える。このため、より古いバージョンのサイドバイサイドアセンブリしかインストールされていない環境にそのexeを持っていくと、冒頭のエラーメッセージが出る。要求するバージョンを下げれば問題は解決するが、その標準的な方法が不明。ひとつの方法としては、マニフェストを〜.exe.manifestに外出しにし、テキストエディタで書き換えればよい。

JavaとWindowsネイティブを連携させたい

(2009/10/17 更新)


Windowsネイティブプログラミングが要求されるようなソフトウェアを作るならC++C#を使えばよいわけですが、いまさらそれらに習熟したくないという場合にはどうしたらよいか。

Pure Javaでは不足でネイティブが必要なケースとして考えられるのは・・・


JavaからWindowsネイティブへの呼び出しが必要なケース

  • 1-1. レジストリにアクセスする
  • 1-2. イベントログにログを記録する
  • 1-3. 既存のDLLを利用する
  • 1-4. 既存のCOMコンポーネントを利用する
  • 1-5. (SwingやAWTではなく)ネイティブの部品でUIを作成する
  • 1-6. 別のアプリケーションのウィンドウを操作する(操作・テストの自動化など)
  • 1-7. DirectX, Direct3D, DirectShowなど、パフォーマンスの要求される画面描画処理を行う

WindowsネイティブからJavaへの呼び出しが必要なケース

  • 2-1. Javaで作成したソフトウェアをWindowsのサービスとして動かす
  • 2-2. 見せ方としてjava.exeやjarを見せずに、ネイティブアプリケーションと同様に独自の.exeファイルとして見せたい
  • 2-3. DLLやCOMを作りたい?

こんなところ?

Java Win32API実行クラス

http://www.ne.jp/asahi/hishidama/home/tech/soft/java/hmwin32.html

Win32 APIのラッパー。ウィンドウやUI部品関連とCOM関連のAPI 約50個ほどをサポート。別アプリのウィンドウをJavaで操作したいというのが動機で作成された模様。そのためか、ウィンドウを作成するAPIについてはサポートされていない。

Jarwin - a Java/Win32 interoperability project

http://jawinproject.sourceforge.net/

JNIを使わずにCOM, DLLを呼び出せるらしい (legacy な COM/DLLを呼び出せる、とあるが、COM/DLLにレガシーとかそうでないとかがあるんだろうか)。加えて、レジストリやイベントログへのアクセスも可能とのこと。
COM呼び出しのスタブの生成機能もあるらしい。

バージョンが2.0アルファのまま4年以上更新がないのが気がかり。

FuncPtr msgBox = null;

msgBox = new FuncPtr("USER32.DLL", "MessageBoxW");
msgBox.invoke_I(0, "Hello From a DLL", "From Jawin", 0, ReturnFlags.CHECK_FALSE);

J/Invoke

http://www.jinvoke.com/

ネイティブ呼び出しラッパー。有料。http://www.jinvoke.com/gettingstartedを見る限り、個々のAPIのラッパーをJNI経由のDLLで提供しているのではなく、プログラマJavaソース中に宣言したメソッドを自動的にAPIに中継してくれる仕組みらしい。呼び出したいAPIをstatic native付き(本体なし)のメソッドとして記述し、そのメソッドにJ/Invokeが提供するアノテーションを付け、そのアノテーション呼び出し先のDLLを指定する。

public class Example {
   @NativeImport(library="User32")
   public static native int MessageBox(int hwnd, String text, String caption, int type);
}

ということは、このライブラリがどのAPIをサポートしているか、というのは気にする必要がなく、任意のAPIが呼び出せるということか。

Java Native Access (JNA)

https://jna.dev.java.net/

ネイティブ呼び出しラッパー。無料。
J/Invoke同様に、メソッドを宣言するとネイティブに中継してくれる仕組み。
メソッドは、Interface内に宣言する。アノテーションは使用しない。

public interface Kernel32 extends StdCallLibrary { 
    Kernel32 INSTANCE = (Kernel32)
        Native.loadLibrary("kernel32", Kernel32.class);

    void GetSystemTime(SYSTEMTIME result);
}

ユーザー定義インタフェースの実装クラスをNative.loadLibrary内で自動生成しているのだろうか。

xFunction

http://www.excelsior-usa.com/xfunction.html

ネイティブ呼び出しラッパー。有料。J/Invoke同様に汎用と思われる。ネイティブのfunctionの呼び出し方は、リフレクションを使ってJavaメソッドを呼び出すのと似ている。呼び出すfunctionの名前、引数(シグネチャ)を引数にxFunctionオブジェクトをnewすることで、そのオブジェクト経由でネイティブのfunctionを呼び出す。

JNIWrapper

http://www.teamdev.com/jniwrapper/

ネイティブ呼び出しラッパー。有料。J/Invoke同様に汎用と思われる。xFunctionに似ているが、functionの名前を指定すればよく、引数(シグネチャ)の指定は不要に見える。Cの構造体定義から、対応するJavaクラス(ラッパー)を生成するツールも提供されているらしい。

Java Service Wrapper

http://www.tanukisoftware.com/ja/products.php
http://wrapper.tanukisoftware.org/doc/japanese/introduction.html

WindowsサービスとしてJavaアプリケーションを動かすためのソフトウェア。有料(OSSの一部として使う場合は無料?)。VMの監視機能などもあって、安定稼動重視で商用向けと見られる。

launch4j

http://launch4j.sourceforge.net/

Javaアプリをexeにラップしてアイコンをつけたり、JREが無ければJavaのダウンロード画面に誘導してくれたりするらしい。


その他・・・

  • Java COM Bridge COMを呼び出す
  • NativeCall DLLを呼ぶための汎用ラッパー
  • ・・・DirectX, Direct3D, DirectShowのラッパーについては検索するとそれなりにヒットするが未調査


2-3.のパターンについては既存のライブラリは今のところ見つからず。