2010-05-12 139 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