6

次のように、いくつかのハードウェア (USB デバイス) とやり取りする C# アプリケーションがあります C# application -> intermediate DLL -> hardware DLL -> hardware。中間 DLL とハードウェア DLL は USB デバイスに付属しているため、これらを制御することはできません。

これは私が呼び出すものであるため、VSプロジェクトに含める必要があるのは中間DLLだけですハードウェア DLL は同じディレクトリにあるため、自動的に検出される必要があります。

ハードウェア デバイスの新しいバージョンが、別のハードウェア DLLと共にリリースされました。古い DLL は新しいハードウェアと互換性がなく、新しい DLL は古いハードウェアと互換性がありません。

アプリケーションを両方のハードウェアで動作させるにはどうすればよいですか? 必要に応じて、各 DLL をロードおよびアンロードする必要があると思いますか?

4

3 に答える 3

4

同様の問題に対して私が行うことは次のとおりです。作業したいコードのチャンクがありますが、実行時に dll をロードする必要があります。そのため、プロジェクトで参照していますが、残りのアセンブリと同じディレクトリには配置していません。代わりに、消費コードには、次のようなコードがあります。

// constructor called from a static constructor elsewhere
MyDllLoader(string hardwareFolder) {
    _hardwareFolder = hardwareFolder;
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    SeeIfAlreadyLoaded();
}


private void SeeIfAlreadyLoaded() {
    // if the assembly is still in the current app domain then the AssemblyResolve event will
    // never fire.
    // Since we need to know where the assembly is, we have to look for it
    // here.
    Assembly[] assems = AppDomain.CurrentDomain.GetAssemblies();
    foreach (Assembly am in assems)
    {
        // if it matches, just mark the local _loaded as true and get as much
        // other information as you need
    }
}

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
    string name = args.Name;
    if (name.StartsWith("Intermediate.dll,"))
    {
        string candidatePath = Path.Combine(_hardwareFolder, "Intermediate.dll");
        try {
            Assembly assem = Assembly.LoadFrom(candidatePath);
            if (assem != null) {
                _location = candidateFolder;
                _fullPath = candidatePath;
                _loaded = true;
                return assem;
            }
        }
        catch (Exception err) {
            sb.Append(err.Message);
        }
    }
    return null;
}

別の解決策もあります - それは複雑ですが、私はそれを行い、あなたのために仕事をしました. 必要なメソッドのシグネチャを持つ MyHardwareAbstraction などの抽象クラスを宣言し、そのインターフェイスに対してコーディングします。次に、アセンブリへのパスを指定してロードし、MyHardwareAbstraction に一致する新しいクラスを動的に定義して、必要な実際のオブジェクトのインスタンスにマップするコードを記述します。 これを行う方法について数年前にブログを書きました

これを行うことの良い点は、コードで抽象型を使用し、それに対して作業すると、アダプター コンパイラが実行時に、他の型をターゲット型として使用してその抽象型を完成させる新しいクラスをコンパイルすることです。それもかなり効率的です。

于 2013-06-03T18:21:27.477 に答える
0

編集:

中間 DLL が .Net アセンブリの場合、ここで説明するメソッドを使用して、既存のコードを変更することなく、中間 DLL を使用するメソッドを呼び出すに、中間 DLL を探す場所を指定できます。

Mainメソッドが呼び出される前に .Net アセンブリが検出されて読み込まれるため、C# プロジェクトで DLL を直接参照しないでください。代わりに、AppDomainまたはその他の方法を使用して中間 DLL を動的にロードし、リフレクションまたはオブジェクトを使用してライブラリを使用する必要がありdynamicます。

どうやら、これはプログラミングを非常に面倒なものにするでしょう。ただし、別の方法があります。元のアプリケーションをロードし (.exe ファイルをライブラリとしてロードできます)、元のプログラムのメソッドを反射的に呼び出すランチャー プログラムを作成できます。Main正しい中間 DLL がロードされていることを確認するには、ランチャー プログラムが元のアプリケーションをロードしている間に、ここに記載されている方法を使用できます。

次の説明は、ハードウェア DLL にも当てはまります。


次の場合は有効です。

  1. 一度に 1 つのバージョンの dll のみが必要です (アプリケーションが実行されている間)。
  2. 中間 DLL の 2 つのバージョンには、まったく同じ API があります。

MSDN によると、DLL 検索パスには、PATH 環境変数で指定されたディレクトリが含まれます。( http://msdn.microsoft.com/en-us/library/7d83bc18%28v=vs.80%29.aspx )。したがって、中間 DLL の 2 つのバージョンを、アプリケーション ディレクトリの下の別々のサブディレクトリに配置できますが、各ディレクトリの下にはまったく同じ名前を付けます。次に例を示します。

bin\
   hardware-intermediate-v1\
       intermediate.dll
   hardware-intermediate-v2\
       intermediate.dll

次に、起動時にアプリケーションが使用するバージョンを決定した後、上記のディレクトリのいずれかを PATH 環境変数に追加できます。

using System;
using System.Reflection;
using System.IO;
...
Environment.SetEnvironmentVariable(
    "PATH", 
    Environment.GetEnvironmentVariable("PATH") + ";" + 
        Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + 
        "\\hardware-intermediate-v1"
);

次に、P-Invoke メソッド (DLLImport) を呼び出すと、対応するバージョンの DLL が読み込まれます。すべての DLL をすぐにロードするには、DllImport を参照してください。DLL がロードされているかどうかを確認する方法は? .

ただし、アプリケーションを再起動せずに 2 つのバージョンの DLL を一緒に使用する場合、またはメソッド名および/またはパラメーターのカウント/タイプのレベルで 2 つの DLL 間に API の違いがある場合は、2 つの別個のセットを作成する必要があります。 P-Invoke メソッドのそれぞれが、対応するバージョンの中間 DLL にバインドされます。

于 2013-06-03T08:06:07.313 に答える
0

両方の dll をプログラムに共存させたい場合は、 こちらで説明されているように、AppDomains を使用する必要があります。

それ以外の場合は、ユーザーが必要なバージョンを明確に選択した後、単に LoadLibrary を使用できますか?

于 2013-06-03T08:08:07.433 に答える