この質問は 1 年早いことはわかっていますが、何もしないよりは遅いほうがよいと思います。:)
本当の問題を見つける
まず、例外メッセージが一般的すぎることに注意してください。より詳細なメッセージは、何が問題なのかを明確にします。これを実現するには、NSIS プラグイン自体を変更する必要があります。
プラグインの公式ページで、そのソース コードをダウンロードできます。解凍して Visual Studio で開きます。(私はVS2010を使用しました。)(おそらくアップグレードした後)デバッグとリリースでソリューションを構築してみてください。リリース構成には、出力 DLL をコンピューターにインストールされている NSIS Plugins フォルダーにコピーするビルド後のイベントがあります。(x64 マシンを使用している場合は、このイベントを変更して (x86)
、パスの Program Files 部分に接尾辞を追加する必要があります。)したがって、すべてのリリース ビルドで現在の NSIS CLR プラグインが更新されます。
詳細な例外メッセージを生成するには、メインの catch ブロックNSIS_CLS_Loader.cpp
(145 行目) を見つけ、メッセージを .logex->ToString()
ではなくlog に変更しますex->Message
。プラグインを再構築します。(もちろん、この手順は開発段階で使用する必要があります。これは、スタック トレース全体をディスプレイにダンプするためです。)
また、NSIS インストーラーを再構築してインストールしようとすると、詳細な例外メッセージが表示され、潜在的な問題を特定できます。依存アセンブリを読み込めなかったことを伝えるメッセージになると確信しています。これはこの NSIS プラグインの既知の問題であり、作成者自身がプラグインのページで次のように述べています。
もう 1 つの問題は、.NET dll から .NET dll を呼び出す場合、インストーラーが 2 番目の .NET dll を見つけられないことです。当面の解決策は、インストーラーを別のインストーラーでラップすることです。この別のインストーラーは、インストーラーの実行元と同じディレクトリに .NET dll を配置する必要があります。インストーラーが実行されると、.NET dll が見つかるようになります。配布される設定ファイルは 1 つだけです。
詳細な例外メッセージが異なる場合は、メッセージに基づいて解決策を見つける必要があります。ただし、同じ場合は、次の回避策で問題を解決できる可能性があります。
解決
アセンブリをロードしてこのプロセスが失敗すると、AssemblyResolve
イベントが発生します。非常に簡単な解決策は、このイベントをサブスクライブし、イベント ハンドラー メソッドで依存アセンブリを読み込むことです。
そのため、 51 行目の呼び出しの直前AssemblyResolve
の手順でイベントにサブスクライブします。CallCLR
LoadAssembly
AppDomain::CurrentDomain->AssemblyResolve += gcnew ResolveEventHandler(&MyResolveEventHandler);
イベント ハンドラーとディクショナリ オブジェクトを作成して、同じアセンブリが複数回読み込まれないようにします。コンカレント ディクショナリは、コンカレンシーの問題を処理するために使用されます。
ref class Container {
public:
static ConcurrentDictionary<String^, Assembly^>^ LoadedAssemblies = gcnew ConcurrentDictionary<String^, Assembly^>();
};
static Assembly^ MyResolveEventHandler(Object^ sender, ResolveEventArgs^ args)
{
AssemblyName^ assemblyName = gcnew AssemblyName(args->Name);
String^ assemblyFileName = ".\\" + assemblyName->Name + ".dll";
if (!Container::LoadedAssemblies->ContainsKey(assemblyFileName))
{
Assembly^ loadedAssembly = LoadAssembly(assemblyFileName);
return Container::LoadedAssemblies->GetOrAdd(assemblyFileName, loadedAssembly);
}
return nullptr;
}
の最後に割り当てられたリソースをクリーンアップすることを忘れないでくださいCallCLR
。
もちろん、NSIS インストーラーを変更して、依存するアセンブリ ファイルを$PLUGINSDIR
ディレクトリにコピーすることが不可欠です。
この問題に最初に遭遇したとき、プラグインがlog4net.dll
.
このソリューションのガイドラインを提供してくれた同僚の Attila に感謝します。
編集 (03.10.2013.)
展開
変更したプラグインをビルドしたら、それを NSIS の plugins フォルダー (通常はC:\Program Files (x86)\NSIS\Plugins
) に展開し、インストーラーを再構築する必要があります。私のマシン (および Hudson ビルド サーバー) では問題なく動作しましたが、インストーラーをコピー先の PC にコピーすると、エラー メッセージが表示されて再び失敗しましたCould not load CLR.DLL
。
問題は、ソース コードのソリューションを Visual Studio 2012 に変換したことであることが判明しました。この変換により、ターゲットの C++ プラットフォームも Visual Studio 2012 (v110) に設定されました。ターゲット PC には、失敗の理由である Visual Studio 2012 用の C++ 再頒布可能パッケージがありませんでした。インストールされているプログラムを検索したところ、ターゲット PC に Visual Sudio 2010 用の C++ 再頒布可能パッケージが見つかったため、ソリューションの設定を変更する必要がありました。(必要なバージョンに移動しProject Property pages\Configuration Properties\General
て設定Platform Toolset
します。私の場合はVisual Studio 2010(v100)でした)プラグインを再構築してNSISプラグインフォルダーに再デプロイした後、インストーラーパッケージも再構築し、この変更により問題が解決しました。