0

私はC#で簡単なライブラリを構築しています。このDLLには2つの機能があります。1つはコンピューターのMACアドレスを取得し、もう1つはCPUIDを取得します。DLLの最終的な目的は、これらの関数を呼び出すNSISスクリプトから呼び出すことです。

NSISスクリプトでは次のように呼んでいます。

CLR::Call /NOUNLOAD "CypherLibrary.dll" "CpuMacGetter1.HwInfoRetriever" "GetMacAddress" 0

実行すると、次のエラーが返されます。

.NETDLLメソッドの呼び出し中にエラーが発生しました。呼び出しのターゲットによって例外がスローされました。

これは、この種のオブジェクトを使用した場合にのみ発生します。

IPGlobalProperties computerProperties = IPGlobalProperties.GetIPGlobalProperties();

または:

ManagementClass mc = new ManagementClass( "Win32_NetworkAdapterConfiguration");

たとえば、現在の時刻を返すと問題ありません。

さらに、エラーは.NET 4 Frameworkでビルドした場合にのみ発生し、.NET 3.5では発生しません(はい、両方をインストールしています)。そして、これが最終ユーザーのコンピューターで十分でなかった場合、それは反対です。4バージョンで動作しますが、3.5では動作しません。

この行動の背後にある手がかりはありますか?

事前にどうもありがとうございました!!

4

1 に答える 1

1

この質問は 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の手順でイベントにサブスクライブします。CallCLRLoadAssembly

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プラグインフォルダーに再デプロイした後、インストーラーパッケージも再構築し、この変更により問題が解決しました。

于 2013-09-15T13:19:23.920 に答える