2009-04-10 32 views
1

我有一個需要從中訪問方法的DLL。從非靜態路徑的DLL調用函數

在這樣的大多數情況下,我只是使用[DllImport]從非託管程序集訪問方法,但是在這種情況下,問題是它需要在實例化時訪問DLL的路徑,所以需要一個常量字符串。

這種特殊的DLL是一個獲取與我的應用程序安裝,我不能保證在安裝程序後,這將是(我寧願不把它放在靜態喜歡的%SystemRoot%)。

那麼,有沒有在C#的方式,我可以聲明,並在運行時使用的方法從DLL具有可變路徑?

任何意見或建議,將不勝感激!

+0

認沽在安裝過程中註冊表中的路徑,並在加載dll之前調用它。 – jmcecil 2009-04-10 19:07:26

+0

我不明白這是如何幫助我的,在運行時獲取dll的路徑不是問題。它使用那個動態路徑來聲明代碼中的函數,我試圖找出它。 – 2009-04-10 19:08:57

回答

2

這有點劈,但因爲你說,你可以找到的路徑在運行時的DLL,爲什麼不把它複製到當前的工作目錄,你使用任何功能之前?這樣,DLL就會存在於你的exe旁邊,並且會被LoadLibrary找到。在你的DllImport中不需要任何額外的路徑。

使用方法從動態路徑的唯一另一種方法是做到這一點:
1)執行必要的P/Invoke簽名LoadLibrary & GetProcAddress
2)負載從所期望的路徑的庫(的LoadLibrary)
3)找到想要的功能(GetProcAddress)
4)將指針投向代理Marshal.GetDelegateForFunctionPointer
5)調用它。

當然,您將需要爲每個要以這種方式「導入」的函數聲明一個委託,因爲您必須將指針轉換爲委託。

2

根本不使用路徑。當Windows試圖動態地或靜態地從中加載一個函數時,Windows使用默認的方法來搜索DLL。

確切的搜索邏輯在文檔在MSDN文檔爲LoadLibrary - 基本上,如果DLL只是使用你的應用程序,放在同一文件夾作爲您的應用程序在安裝過程中,不要擔心。如果它是一個常用的DLL,將它放在由LoadLibrary()搜索到的文件夾結構中的某個地方,它就會被找到。

+0

在這個特定的實例中,我無法將該DLL放在與我的應用程序相同的目錄中,它位於我的應用程序的子目錄中,我嘗試使用相對路徑來聲明它。哪些在一些機器上有效,但並不一致。 = \ – 2009-04-10 19:34:23

+0

嘗試從Kernel32導入SetDllDirectory並將其設置爲Application.StartupPath。 當我今天回家時,我會在家裏嘗試一個項目,當我測試它時,我會回覆評論。 希望有幫助 – Zack 2009-04-10 19:55:59

+0

@Zack:這聽起來像個好主意,我會試一試。 – 2009-04-10 20:01:42

0

我有類似的情況。我使用機器上安裝的SDK中的DLL。我從該SDK註冊表項中獲取DLL的目錄位置。我在正在執行的用戶PATH變量上設置DLL位置(只是臨時修改)。基本上它允許你爲你想調用的DLL設置一個動態路徑,所以它不一定是來自注冊表。請注意,PATH var是Windows查找DLL的最後一個地方。但另一方面,它不會改變Windows尋找DLL的其他地方。

例子:

API我要打電話,在DLL:使用Microsoft

[DllImport("My.DLL")] 
private static extern IntPtr ApiCall(int param); 

獲取註冊表項(需要。Win32的;):

private static string GetRegistryKeyPath() { 
     string environmentPath = null; 

     using (var rk = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\SOMENNAME")) 
     { 
      if (rk != null) 
      { 
       environmentPath = rk.GetValue("Path(or whatever your key is)").ToString(); 
      } 
      if (string.IsNullOrEmpty(environmentPath)) 
      { 
       Log.Warn(
        string.Format("Path not found in Windows registry, using key: {0}. Will default to {1}", 
         @"SOFTWARE\SOMETHING", @"C:\DefaultPath")); 
       environmentPath = @"C:\DefaultPath"; 
      } 
     } 
     return environmentPath; 
    } 

添加DLL的路徑上的PATH VAR(CONCAT()Linq中被發現):

void UpdatePath(IEnumerable<string> paths){ 
    var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? "" }; 
    path = path.Concat(paths); 
    string modified = string.Join(Path.PathSeparator.ToString(), path); 
    Environment.SetEnvironmentVariable("PATH", modified); 
} 

開始使用API​​調用:

var sdkPathToAdd = GetRegistryKeyPath(); 
IList<string> paths = new List<string> 
     { 
      Path.Combine(sdkPathToAdd), 
      Path.Combine("c:\anotherPath") 
     }; 
UpdatePath(paths); 

//Start using 
ApiCall(int numberOfEyes);