2010-05-12 173 views
6

我正在使用使用PInvoke和DllImport屬性的外部非託管dll。例如。動態設置DllImport屬性

[DllImport("mcs_apiD.dll", CharSet = CharSet.Auto)] 
private static extern byte start_api(byte pid, byte stat, byte dbg, byte ka); 

我想知道是否有可能以某種方式dynmically改變dll文件的詳細信息(mcs_apiD.dll在這個例子中),舉例來說如果我想建立對另一個DLL版本

回答

2

可以不要更改dll的名稱,但可以更改正在加載的庫的路徑(例如通過從註冊表或配置文件中讀取它)並使用kernel32的函數see my answer there手動加載它。

+0

好的。但在我的例子中,我已經指定了一個特定的函數原型,以便我可以正確地封裝參數,一些API函數具有複雜的結構作爲參數。如何以這種方式進行工作? – user226356 2010-05-12 12:19:01

+0

如果參數從一個版本的DLL更改爲另一個版本,那麼我真的很幸運,我提到了 – 2010-05-12 12:20:47

5

是的,這是可能的,你必須做P/Invoke編組工作的一部分。加載DLL並找到導出函數的入口點。通過聲明委託其簽名的導出函數相匹配開始:

private delegate byte start_api(byte pid, byte stat, byte dbg, byte ka); 

然後使用這樣的代碼:

using System.ComponentModel; 
using System.Runtime.InteropServices; 
    ... 

    static IntPtr dllHandle; 
    ... 
     if (dllHandle == IntPtr.Zero) { 
      dllHandle = LoadLibrary("mcs_apiD.dll"); 
      if (dllHandle == IntPtr.Zero) throw new Win32Exception(); 
     } 
     IntPtr addr = GetProcAddress(dllHandle, "[email protected]"); 
     if (addr == IntPtr.Zero) throw new Win32Exception(); 
     var func = (start_api)Marshal.GetDelegateForFunctionPointer(addr, typeof(start_api)); 
     var retval = func(1, 2, 3, 4); 
    ... 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr LoadLibrary(string name); 
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] 
    private static extern IntPtr GetProcAddress(IntPtr hModule, string name); 

很多方法可以得到這個錯誤,當然。請注意,您必須使用DLL中的實際導出名稱,您不再從P/Invoke編組人員處獲得幫助進行名稱修飾的幫助。如果您不確定導出名稱的樣子,請使用DLL上的dumpbin.exe/exports。

+0

的方法,每個版本的DLL API與GetProcAddress組合在一起的代理類型,你將會走出困境it – 2010-05-12 13:11:47

+0

有關於此的Microsoft博客文章:http://blogs.msdn.com/b/jonathanswift/archive/2006/10/03/dynamically-calling-an-unmanaged-dll-from-.net-_2800_c_23002900_的.aspx – Deanna 2011-06-16 15:40:52