不存在函数的C#DllImport

不存在函数的C#DllImport,c#,dllimport,C#,Dllimport,我们有一些C代码,它从外部DLL调用非托管代码。外部DLL用作插件,可能有不同的版本。不同的版本包含一组稍微不同的可用函数 当我们导入一个不存在的函数时会发生什么? 当我们叫它时会发生什么? 在调用Dll之前,我们能知道Dll中是否有特定的函数可用吗 更具体地说,DLL的最新版本有一个函数提供版本。因此,对于这些版本,很容易知道哪些功能可用。但是我们还需要知道DLL的版本是否比引入此函数的版本旧。net运行时将根据需要JIT您的代码。这就是你如何做到这一点 如果您依赖于代码的延迟实例化,而代码的

我们有一些C代码,它从外部DLL调用非托管代码。外部DLL用作插件,可能有不同的版本。不同的版本包含一组稍微不同的可用函数

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


更具体地说,DLL的最新版本有一个函数提供版本。因此,对于这些版本,很容易知道哪些功能可用。但是我们还需要知道DLL的版本是否比引入此函数的版本旧。

net运行时将根据需要JIT您的代码。这就是你如何做到这一点

如果您依赖于代码的延迟实例化,而代码的延迟实例化依赖于可能存在或不存在的DLL函数。您可以使用该函数检查该函数。如果我们编写的是好的旧Win32代码,我们就会这样做

以下是Jon Skeet关于懒惰的一个简单例子:

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();
  }
}

这里的懒惰是在紧张中遗传的,这不是真的必要。但是,它确实允许我们保持一致的命名约定。

用于在调用该方法之前检查它是否有效。

如果尝试调用不存在的函数,将抛出一个
EntryPointNotFoundException

如果您试图调用一个不存在的函数,将抛出一个
EntryPointNotFoundException
。@taffer,将此作为正确的答案,我将接受它作为解决方案。一个简单的(也许是显而易见的)解决方案。除非有人指出任何明显的缺点,否则我将采用这种方法。这个答案是有利的,因为它可以用于测试方法,而无需调用它们,因此更易于在测试中使用。