2012-02-13 78 views
3

可能性の重複:
Specify the search path for DllImport in .NET相対パス

私はアンマネージドDLLを持っています。クリアランスについては、私のC#コードで使用したいC++のDLLです。 問題は、Windowsアプリケーションとユーザーが任意のディレクトリにインストールできることです。だから私は静的なパスでそれを参照することはできませんし、私は相対的なパスを与える方法を見つけることができませんでした。 ここで私が試したコードです:

[DllImport("mydll.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    static extern bool SetDllDirectory(string lpPathName); 

    public void SetDllDirectory(string lpPathName) 
     { 
      try 
      { 
       bool r = SetDllDirectory(lpPathName); 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 
     } 

     public void SetDirectoryPath() 
     { 
      try 
      { 
       DirectoryInfo directory = new DirectoryInfo(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)); 
       if (directory.Exists) 
        SetDllDirectory(directory.ToString() + "\\mydll.dll"); 

      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 
     } 

は、以下私が受け付けておりエラーです。

DLL 'mydll.dll'に 'SetDllDirectory'という名前のエントリポイントが見つかりません。

この質問は

"C++ unmanaged DLL in c#"

そのため申し訳ありませんが、 "Relative Path to DLL in Platform Invoke Statement"

のレプリカかもしれないが、私はこれらの文献のいずれかの解決策を見つけることができませんでした。

+0

はい、私はその方法を試しました。しかし、それは動作しませんでした。そのために残念。 –

+0

PATHハックまたはSetDllDirectory()を試しましたか? – IanNorton

+0

私はSetDllDirectory()を試しました –

答えて

1

このエラーメッセージ:

DLL 'mydllに' SetDllDirectory 'という名前のエントリポイントが見つかりません。 dll '。

は、DLLを見つけることができないことは何も言いません。 P/Invokeの定義が間違っています。 DLLにSetDllDirectoryという名前の関数がありません(mydll.dll)。なぜそこにすべきでしょうか? DLLからエクスポートされる関数は、明示的にコード化してエクスポートする関数だけです。 SetDllDirectoryのコードを書いておらず、mydll.dllからエクスポートする必要があることを示すため、DLLには存在しません。

それ以外では、質問を実際のコードで更新しない限り、この質問は答えられません。 C#(管理対象)側で試したP/Invokeコードとともに、アンマネージDLLから呼び出す関数のシグネチャを少なくとも投稿する必要があります。

問題は、Windowsアプリケーションとユーザーが任意のディレクトリにインストールできることです。だから私は静的なパスでそれを参照することはできませんし、私は相対的なパスを与える方法を見つけることができませんでした。

これは実際の問題ではありません。相対パスはうまく動作し、あなたの質問があなたがすでに試したことを示す方法で正確に動作します。 P/Invokeの定義にDLLの名前を入れるだけです。デフォルトのDLL検索順序は、他のすべてを処理します。マネージEXEがP/InvokeするアンマネージDLLと同じディレクトリにある場合、すべてがシームレスに動作します。

DLLとEXEが同じフォルダにある限り、ユーザーはどこにアプリケーションをインストールするかは関係ありません。それがインストーラの仕事です。

そして限り、あなたは相対パスを使用して、あなたは絶対には(実際にはkernel32.dllで定義されている)のWin32 APIからSetDllDirectory機能を使用する必要はありません。

+0

- ありがとうございました。あなたは私の一日を作りました。 –

4

非標準の場所にあるアンマネージライブラリにピンボケしようとすると、dllファイルを探すためにWindowsが使用するdll検索パスにこの場所を追加する必要があります。

c/C++ライブラリファイルがどこにあるのかをユーザーがプログラムに伝えることができる場合は、ユーザーが手動で読み込むことができます。

public class UnsafeNativeMethods { 
    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern bool SetDllDirectory(string lpPathName); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern int GetDllDirectory(int bufsize, StringBuilder buf); 

    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] 
    public static extern IntPtr LoadLibrary(string librayName); 

    [DllImport("mylibrary")] 
    public static extern void InitMyLibrary(); 
} 

あなたはそのようなプリロード・ルーチンの何らかの形で上記を呼び出すことができます。

public void LoadDllFile(string dllfolder, string libname) { 
    var currentpath = new StringBuilder(255); 
    UnsafeNativeMethods.GetDllDirectory(currentpath.Length, currentpath); 

    // use new path 
    UnsafeNativeMethods.SetDllDirectory(dllfolder); 

    UnsafeNativeMethods.LoadLibrary(libname); 

    // restore old path 
    UnsafeNativeMethods.SetDllDirectory(currentpath); 
} 

あなたがそのようにようにそれを呼ぶかもしれない:

LoadDllFile("c:\whatever", "mylibrary.dll"); 
+0

Nortonに感謝します。しかし、エンドユーザーはDLLについての知識がありません。このアプローチはこのシナリオでは機能しますか? –

+1

あなたが投稿したコードの量は、必要以上に*ウェイ*です。必要なのは 'SetDllDirectory'だけです。 P/Invokeマーシャラに残りのすべてをさせてください。詳細とサンプルコードについては、[my answer here](http://stackoverflow.com/a/8861895/366904)を参照してください。 –

+0

@DeepakエンドユーザーがDLLの場所を知らない場合、どのように見つけますか?あなたはファイルシステムを検索して、これを使うといいでしょう。 – IanNorton