簡體   English   中英

C#DllImport不存在的功能

[英]C# DllImport of non-existent function

我們有一些C#代碼,可從外部DLL調用非托管代碼。 外部DLL用作插件,並且可以具有不同的版本。 不同版本包含的可用功能略有不同。

當我們DllImport一個不存在的函數時會發生什么? 當我們稱呼它會怎樣? 我們可以在調用Dll之前知道Dll中是否有特定功能嗎?

更具體地說,DLL的最新版本具有為我們提供該版本的功能。 因此,對於這些版本,很容易知道哪些功能可用。 但是,我們還需要知道DLL是否具有比引入此功能的地方更舊的版本。

.net運行時將按需JIT您的代碼。 這就是您完成此操作的方式。

如果您依賴依賴於可能存在或可能不存在DLL函數的代碼的惰性實例化。 您可以使用GetProcAddress函數檢查該函數。 如果我們正在編寫舊的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();
  }
}

懶惰是在JITting中繼承的,這並不是必須的。 但是,它確實允許我們保持一致的命名約定。

在調用方法之前,使用Marshal.Prelink(MethodInfo)檢查它是否有效。

如果您嘗試調用不存在的函數,則會拋出EntryPointNotFoundException

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM