2015-11-06 6 views
1

У нас есть код C#, который вызывает неуправляемый код из внешней DLL. Внешние библиотеки DLL используются в качестве плагинов и могут быть разных версий. Различные версии содержат немного другой набор доступных функций.C# DllImport несуществующей функции

Что происходит, когда мы DllImport несуществующей функции? Что происходит, когда мы называем это? Можем ли мы узнать, доступна ли какая-либо функция в Dll до ее вызова?

В частности, последние версии DLL имеют функцию, предоставляющую нам версию. Поэтому для этих версий легко узнать, какие функции доступны. Но нам также нужно знать, имеет ли DLL версию старше, чем эта функция была введена.

+1

Если вы попытаетесь вызвать несуществующую функцию, будет выбрано 'EntryPointNotFoundException'. – taffer

+0

@taffer, напишите это как правильный ответ, и я приму его как решение. – matli

ответ

1

Если вы попытаетесь вызвать несуществующую функцию, будет выбрано значение EntryPointNotFoundException.

+0

Простое (и, возможно, очевидное) решение. Я пойду с этим, если кто-то не укажет на какие-либо существенные недостатки. – matli

1

. Время выполнения .net будет использовать ваш код по требованию. Вот как вы это делаете.

Если вы полагаетесь на ленивую копию кода, которая зависит от функции DLL, которая может быть или не быть. Вы можете использовать функцию GetProcAddress для проверки функции. Это то, что мы будем делать, если бы мы писали старый добрый код Win32.

Вот простой пример из Jon Скита 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, это на самом деле не нужно. Однако это позволяет нам придерживаться последовательного соглашения об именах.

Смежные вопросы