2012-02-13 127 views
3

可能重複:
Specify the search path for DllImport in .NET非託管DLL的相對路徑

我有一個非託管的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

是的,我試過這種方法。但它沒有奏效。對不起。 – 2012-02-13 07:31:17

+0

你試過PATH hack或SetDllDirectory()? – IanNorton 2012-02-13 07:32:55

+0

我試過SetDllDirectory() – 2012-02-13 07:33:55

回答

1

此錯誤消息:

無法在DLL'mydll中找到名爲'SetDllDirectory'的入口點。 DLL」。

說不能找到DLL。它說你的P/Invoke定義不正確。在您的DLL中沒有名爲SetDllDirectory的函數(mydll.dll)。爲什麼要這樣呢?從DLL中導出的唯一函數是您明確編碼和導出的函數。由於您沒有編寫SetDllDirectory的代碼,並且表明它應該從mydll.dll導出,所以它不存在於DLL中。

除此之外,這個問題是無法回答的,除非你用真實的代碼更新你的問題。您至少需要發佈您試圖從非託管DLL調用的函數的簽名,以及您在C#(託管)端嘗試過的P/Invoke代碼。

問題是,它的Windows應用程序和用戶可以安裝在他們選擇的任何目錄。所以我不能用靜態路徑來引用它,而且我也找不到一個給出相對路徑的方法。

這不是一個真正的問題。相對路徑工作得很好,它們的工作方式與您的問題表明您已經嘗試過的方式完全相同。您只需在P/Invoke定義中包含DLL的名稱。默認的DLL搜索順序負責其他所有操作。如果託管的EXE與您要P/Invoke的非託管DLL位於同一目錄中,則所有內容都可以無縫工作。

只要DLL和EXE位於同一文件夾中,用戶選擇安裝應用程序的位置並不重要。這就是你的安裝程序的工作。

而只要你使用相對路徑,你絕對需要使用SetDllDirectory函數從Win32 API(這是在kernel32.dll實際上定義)。

+0

- 感謝人...你已經度過了我的一天。 – 2012-02-13 09:27:23

4

如果您試圖調入非標準位置的非託管庫,則需要將此位置添加到Windows用來查找dll文件的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

謝謝諾頓。但最終用戶不瞭解DLL。這種方法在這種情況下會起作用嗎? – 2012-02-13 07:53:18

+1

您發佈的代碼數量超過必要。所有你需要的是'SetDllDirectory';讓P/Invoke封送員完成剩下的工作。有關詳細信息和示例代碼,請參見[我的答案](http://stackoverflow.com/a/8861895/366904)。 – 2012-02-13 08:57:09

+0

@Deepak如果最終用戶不知道DLL在哪裏,你怎麼找到它?你可以搜索文件系統,然後使用這個我想。 – IanNorton 2012-02-13 20:04:48