我們有一些C#代碼調用來自外部DLL的非託管代碼。外部DLL被用作插件,並且可能具有不同的版本。不同版本包含一組稍微不同的可用功能。C#DllImport不存在的函數
當我們導入一個不存在的函數時會發生什麼? 當我們打電話時會發生什麼? 在調用它之前,我們能否知道在Dll中是否有特定的函數?
更具體地說,該DLL的最新版本有一個函數給我們的版本。所以對於這些版本,很容易知道哪些功能可用。但是我們也需要知道DLL的版本是否比引入該函數的版本更早。
我們有一些C#代碼調用來自外部DLL的非託管代碼。外部DLL被用作插件,並且可能具有不同的版本。不同版本包含一組稍微不同的可用功能。C#DllImport不存在的函數
當我們導入一個不存在的函數時會發生什麼? 當我們打電話時會發生什麼? 在調用它之前,我們能否知道在Dll中是否有特定的函數?
更具體地說,該DLL的最新版本有一個函數給我們的版本。所以對於這些版本,很容易知道哪些功能可用。但是我們也需要知道DLL的版本是否比引入該函數的版本更早。
.net運行時將按需要JIT您的代碼。這是你如何完成這一點。
如果您依賴於依賴於可能存在或可能不存在的DLL函數的代碼的惰性實例化。您可以使用GetProcAddress函數來檢查函數。如果我們寫的是舊的Win32代碼,這就是我們要做的。
下面是喬恩斯基特的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被繼承,這是不是真的有必要。但是,它確實允許我們保持一致的命名約定。
使用Marshal.Prelink(MethodInfo)
在調用方法之前檢查它是否工作。
如果您嘗試調用不存在的函數,則會拋出'EntryPointNotFoundException'。 – taffer
@taffer,寫下這是一個正確的答案,我會接受它作爲解決方案。 – matli