C#DllImport不存在的函数

问题描述:

我们有一些C#代码调用来自外部DLL的非托管代码。外部DLL被用作插件,并且可能具有不同的版本。不同版本包含一组稍微不同的可用功能。C#DllImport不存在的函数

当我们导入一个不存在的函数时会发生什么? 当我们打电话时会发生什么? 在调用它之前,我们能否知道在Dll中是否有特定的函数?

更具体地说,该DLL的最新版本有一个函数给我们的版本。所以对于这些版本,很容易知道哪些功能可用。但是我们也需要知道DLL的版本是否比引入该函数的版本更早。

+1

如果您尝试调用不存在的函数,则会抛出'EntryPointNotFoundException'。 – taffer

+0

@taffer,写下这是一个正确的答案,我会接受它作为解决方案。 – matli

如果您尝试调用不存在的功能,则会引发EntryPointNotFoundException

+0

一个简单的(也许很明显的)解决方案。除非有人指出任何重大缺点,否则我会继续这样做。 – matli

.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)在调用方法之前检查它是否工作。