4

私は.NET 4.0用にC#で書かれたプロジェクトに取り組んでいます(Visual Studio 2010経由)。C/C++ DLL の使用を必要とするサード パーティ ツールがあり、C# の 32 ビット アプリケーションと 64 ビット アプリケーションの例があります。

問題は、32 ビット デモが 32 ビット DLL に静的にリンクし、64 ビット デモが 64 ビット DLL に静的にリンクすることです。.NET アプリケーションであるため、クライアント PC 上で 32 ビットまたは 64 ビットのプロセスとして実行できます。

.NET 4.0 フレームワークは、アプリケーションが 64 ビット プロセスとして実行されている場合に true を返す Environment.Is64BitProcess プロパティを提供します。

私がやりたいことは、Is64BitProcess プロパティをチェックした後、正しい DLL を動的にロードすることです。ただし、動的にロードするライブラリを調査すると、常に次のことがわかります。

[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);

[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);

これらのメソッドは、32 ビット オペレーティング システム専用のようです。64 ビットに相当するものはありますか?

Is64BitProcess チェックに基づいて適切なメソッドが呼び出される限り、32 ビット ライブラリと 64 ビット ライブラリの両方を静的にリンクすると問題が発生しますか?

public class key32
{
    [DllImport("KEYDLL32.DLL", CharSet = CharSet.Auto)]
    private static extern uint KFUNC(int arg1, int arg2, int arg3, int arg4);

    public static bool IsValid()
    {
       ... calls KFUNC() ...
    }
}

public class key64
{
    [DllImport("KEYDLL64.DLL", CharSet = CharSet.Auto)]
    private static extern uint KFUNC(int arg1, int arg2, int arg3, int arg4);

    public static bool IsValid()
    {
       ... calls KFUNC() ...
    }
}

...

if (Environment.Is64BitProcess)
{
    Key64.IsValid();
}
else
{
    Key32.IsValid();
}

ありがとうございました!!

4

4 に答える 4

4

これを行うには多くの方法があります:

  • これは展開の問題です。インストーラーによってコピーされた適切な DLL を取得し、同じ名前を付けてください。

  • 64 ビット コードによって提供される膨大なアドレス空間を実際に必要とするプログラムはほとんどありません。プラットフォーム ターゲットを x86 に設定するだけです

  • [DllImport] 属性の EntryPoint フィールドを使用します。「KFUNC」に設定します。そして、メソッドに異なる名前を付けます。IntPtr.Size の値に基づいて、どちらか一方を呼び出すことができます。

最後の解決策のデモンストレーション:

[DllImport("KEYDLL32.DLL", EntryPoint = "KFUNC")]
private static extern uint KFUNC32(int arg1, int arg2, int arg3, int arg4);

[DllImport("KEYDLL64.DLL", EntryPoint = "KFUNC")]
private static extern uint KFUNC64(int arg1, int arg2, int arg3, int arg4);

...

if (IntPtr.Size == 8) KFUNC64(1, 2, 3, 4);
else                  KFUNC32(1, 2, 3, 4);
于 2012-05-25T16:31:24.843 に答える
1

皮肉なことに、64 ビット システムでは、kernel32.dll(常駐%windir%\System32\) は 64 ビット バージョンであり、%windir%\SysWOW64\バージョンは 32 ビット システムです。ここで非常に残念なネーミングが行われています...

とにかく、できることは、リンクしたパスを使用して、両方LoadLibraryのバージョンにバインドし、2 つの異なる変数名 (たとえば、system32バージョンとバージョン)LoadLibrary32にバインドすることですsyswow64。次に、32 ビット システムでは を使用するだけLoadLibraryで、64 ビット システムが検出された場合はLoadLibraryが 64 ビット バージョンにLoadLibrary32なり、 が 32 ビット バージョンになります。

ただし、ビット数の不一致に動的にバインドできるとは思わないため、これが役立つとは思いません(これ言葉にします!)動的ライブラリ... 2番目の例に役立つと思いますが、実際に2つの異なるものを取得しますケースごとに 1 つのライブラリ。

于 2012-05-25T16:30:19.370 に答える
0

低レベルの相互運用を行う代わりに、より多くの.Netルートに進むことを検討します-プラグインのようなアセンブリを使用して対処します。

  • DLL の x86 および x64 バージョンにリンクする (および正しいプラットフォーム用にコンパイルする) 2 つのアセンブリを作成します。
  • このアセンブリを作成して、同じインターフェイス (またはそれらを同じにする他の方法) を実装するクラスを公開します。残りのコードがライブラリのいずれかを使用できることを確認してください。基本型/インターフェイスを使用した 3 番目のアセンブリが必要になる場合があります。
  • 実行時に、必要なアセンブリを手動で読み込みます。誤って自動的に読み込まれることを避けるために、たまたま検索パスに含まれていないことを確認してください。

2 番目のアプローチ (ビット数に基づくピッキング方法) は正常に機能することに注意してください。各 DLL へのすべてのアクセスを同じインターフェイスを持つクラスにラップし、実行時に正しいものだけをインスタンス化できるようにします。

于 2012-05-25T16:33:16.590 に答える