Вы можете P / Invoke на LoadLibraryW
загрузить shlwapi.dll, а затем P / Invoke на GetProcAddressW
, чтобы найти «StrCmpLogicalW».Если возвращается NULL, то его там нет.
Вам не нужно фактическое возвращаемое значение из GetProcAddressW
- поскольку это не NULL, вы знаете, что можете использовать декларацию P / Invoke по вашему выбору.
Обратите внимание, что GetProcAddressW
также поддерживает функции, экспортируемые по порядковому значению.
РЕДАКТИРОВАТЬ: Если вы хотите следовать некоторому шаблону, это может работать:
Сначала определите вспомогательный класс NativeMethodResolver
, который сообщает вам, существует ли метод в библиотеке:
public static class NativeMethodResolver
{
public static bool MethodExists(string libraryName, string methodName)
{
var libraryPtr = LoadLibrary(libraryName);
var procPtr = GetProcAddress(libraryPtr, methodName);
return libraryPtr != UIntPtr.Zero && procPtr != UIntPtr.Zero;
}
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern UIntPtr LoadLibrary(string lpFileName);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
private static extern UIntPtr GetProcAddress(UIntPtr hModule, string lpProcName);
}
Приведенный выше вспомогательный класс может использоваться производными классами SafeNativeMethod
, которые помогают вНе стоит забывать о некоторых типичных вещах:
public abstract class SafeNativeMethod
{
private readonly string libraryName;
private readonly string methodName;
private bool resolved;
private bool exists;
protected SafeNativeMethod(string libraryName, string methodName)
{
this.libraryName = libraryName;
this.methodName = methodName;
}
protected bool CanInvoke
{
get
{
if (!this.resolved)
{
this.exists = Resolve();
this.resolved = true;
}
return this.exists;
}
}
private bool Resolve()
{
return NativeMethodResolver.MethodExists(this.libraryName, this.methodName);
}
}
Производный класс, который определяет свой собственный метод Invoke
, может затем вызвать базовый CanInvoke
, чтобы узнать, следует ли вернуть значение по умолчанию (или реализацию по умолчанию) на местевозвращаемого значения искомого нативного метода.Из вашего вопроса я возьму shlwapi.dll / StrCmpLogicalW и dwmapi.dll / DwmIsCompositionEnabled в качестве примера реализации для SafeNativeMethod
:
public sealed class SafeStrCmpLogical : SafeNativeMethod
{
public SafeStrCmpLogical()
: base("shlwapi.dll", "StrCmpLogicalW")
{
}
public int Invoke(string psz1, string psz2)
{
return CanInvoke ? StrCmpLogicalW(psz1, psz2) : 0;
}
[DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int StrCmpLogicalW(string psz1, string psz2);
}
public sealed class SafeDwmIsCompositionEnabled : SafeNativeMethod
{
public SafeDwmIsCompositionEnabled()
: base("dwmapi.dll", "DwmIsCompositionEnabled")
{
}
public bool Invoke()
{
return CanInvoke ? DwmIsCompositionEnabled() : false;
}
[DllImport("dwmapi.dll", SetLastError = true, PreserveSig = false)]
private static extern bool DwmIsCompositionEnabled();
}
Эти двазатем можно использовать так:
static void Main()
{
var StrCmpLogical = new SafeStrCmpLogical();
var relation = StrCmpLogical.Invoke("first", "second");
var DwmIsCompositionEnabled = new SafeDwmIsCompositionEnabled();
var enabled = DwmIsCompositionEnabled.Invoke();
}