我们有一些C#代码从外部DLL调用非托管代码。外部DLL用作插件,可能有不同的版本。不同的版本包含一组略有不同的可用功能。
当我们DllImport一个不存在的函数时会发生什么? 我们称之为会发生什么? 在调用它之前,我们能否知道Dll中是否有特定的功能?
更具体地说,DLL的最新版本具有给我们版本的功能。因此,对于这些版本,很容易知道哪些功能可用。但是我们还需要知道DLL的版本是否比引入此函数的版本更早。
答案 0 :(得分:1)
.net运行时将按需JIT代码。这就是你如何做到这一点。
如果您依赖于依赖于DLL函数的代码的延迟实例化,该函数可能存在也可能不存在。您可以使用GetProcAddress功能检查功能。如果我们编写好的旧Win32代码,我们会这样做。
这是Jon Skeet article关于懒惰的一个简单例子:
public sealed class Singleton
{
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public bool IsQueryFullProcessImageNameSupported { get; private set; }
public string QueryFullProcessImageName(IntrPtr handle)
{
if (!IsQueryFullProcessImageNameSupported) {
throw new Exception("Does not compute!");
}
int capacity = 1024;
var sb = new StringBuilder(capacity);
Nested.QueryFullProcessImageName(handle, 0, sb, ref capacity);
return sb.ToString(0, capacity);
}
private Singleton()
{
// You can use the trick suggested by @leppie to check for the method
// or do it like this. However you need to ensure that the module
// is loaded for GetModuleHandle to work, otherwise see LoadLibrary
IntPtr m = GetModuleHandle("kernel32.dll");
if (GetProcAddress(m, "QueryFullProcessImageNameW") != IntrPtr.Zero)
{
IsQueryFullProcessImageNameSupported = true;
}
}
public static Singleton Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
// Code here will only ever run if you access the type.
}
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);
public static readonly Singleton instance = new Singleton();
}
}
这里的懒惰是在JITting中继承的,它并不是必需的。但是,它确实允许我们保持一致的命名约定。
答案 1 :(得分:1)
在调用方法之前,使用Marshal.Prelink(MethodInfo)
检查它是否有效。
答案 2 :(得分:1)
如果您尝试调用不存在的函数,则会抛出EntryPointNotFoundException
。