Ответ 1
Вы можете 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();
}